00001 #define GL_GLEXT_PROTOTYPES
00002 #include "bcresources.h"
00003 #include "bcsignals.h"
00004 #include "bcsynchronous.h"
00005 #include "bcwindowbase.h"
00006 #include "condition.h"
00007 #include "mutex.h"
00008
00009
00010 #ifdef HAVE_GL
00011 #include <GL/gl.h>
00012 #endif
00013 #include <unistd.h>
00014
00015 #include <string.h>
00016
00017
00018 TextureID::TextureID(int window_id, int id, int w, int h, int components)
00019 {
00020 this->window_id = window_id;
00021 this->id = id;
00022 this->w = w;
00023 this->h = h;
00024 this->components = components;
00025 in_use = 1;
00026 }
00027
00028 ShaderID::ShaderID(int window_id, unsigned int handle, char *source)
00029 {
00030 this->window_id = window_id;
00031 this->handle = handle;
00032 this->source = strdup(source);
00033 }
00034
00035 ShaderID::~ShaderID()
00036 {
00037 free(source);
00038 }
00039
00040 #ifdef HAVE_GL
00041 PBufferID::PBufferID(int window_id,
00042 GLXPbuffer pbuffer,
00043 GLXContext gl_context,
00044 int w,
00045 int h)
00046 {
00047 this->pbuffer = pbuffer;
00048 this->gl_context = gl_context;
00049 this->window_id = window_id;
00050 this->w = w;
00051 this->h = h;
00052 in_use = 1;
00053 }
00054 #endif
00055
00056
00057
00058 BC_SynchronousCommand::BC_SynchronousCommand()
00059 {
00060 command = BC_SynchronousCommand::NONE;
00061 frame = 0;
00062 frame_return = 0;
00063 result = 0;
00064 command_done = new Condition(0, "BC_SynchronousCommand::command_done", 0);
00065 }
00066
00067 BC_SynchronousCommand::~BC_SynchronousCommand()
00068 {
00069 delete command_done;
00070 }
00071
00072 void BC_SynchronousCommand::copy_from(BC_SynchronousCommand *command)
00073 {
00074 this->command = command->command;
00075 this->colormodel = command->colormodel;
00076 this->window = command->window;
00077 this->frame = command->frame;
00078 this->window_id = command->window_id;
00079
00080 this->frame_return = command->frame_return;
00081
00082 this->id = command->id;
00083 this->w = command->w;
00084 this->h = command->h;
00085 }
00086
00087
00088
00089
00090 BC_Synchronous::BC_Synchronous()
00091 : Thread(1, 0, 0)
00092 {
00093 next_command = new Condition(0, "BC_Synchronous::next_command", 0);
00094 command_lock = new Mutex("BC_Synchronous::command_lock");
00095 table_lock = new Mutex("BC_Synchronous::table_lock");
00096 done = 0;
00097 is_running = 0;
00098 current_window = 0;
00099 BC_WindowBase::get_resources()->set_synchronous(this);
00100 }
00101
00102 BC_Synchronous::~BC_Synchronous()
00103 {
00104 commands.remove_all_objects();
00105 }
00106
00107 BC_SynchronousCommand* BC_Synchronous::new_command()
00108 {
00109 return new BC_SynchronousCommand;
00110 }
00111
00112 void BC_Synchronous::create_objects()
00113 {
00114 }
00115
00116 void BC_Synchronous::start()
00117 {
00118 run();
00119 }
00120
00121 void BC_Synchronous::quit()
00122 {
00123 command_lock->lock("BC_Synchronous::quit");
00124 BC_SynchronousCommand *command = new_command();
00125 commands.append(command);
00126 command->command = BC_SynchronousCommand::QUIT;
00127 command_lock->unlock();
00128
00129 next_command->unlock();
00130 }
00131
00132 int BC_Synchronous::send_command(BC_SynchronousCommand *command)
00133 {
00134 command_lock->lock("BC_Synchronous::send_command");
00135 BC_SynchronousCommand *command2 = new_command();
00136 commands.append(command2);
00137 command2->copy_from(command);
00138 command_lock->unlock();
00139
00140 next_command->unlock();
00141
00142
00143
00144 command2->command_done->lock("BC_Synchronous::send_command");
00145 int result = command2->result;
00146 delete command2;
00147 return result;
00148 }
00149
00150 void BC_Synchronous::run()
00151 {
00152 is_running = 1;
00153 while(!done)
00154 {
00155 next_command->lock("BC_Synchronous::run");
00156
00157
00158 command_lock->lock("BC_Synchronous::run");
00159 BC_SynchronousCommand *command = 0;
00160 if(commands.total)
00161 {
00162 command = commands.values[0];
00163 commands.remove_number(0);
00164 }
00165
00166 command_lock->unlock();
00167
00168
00169 handle_command_base(command);
00170
00171 }
00172 is_running = 0;
00173 }
00174
00175 void BC_Synchronous::handle_command_base(BC_SynchronousCommand *command)
00176 {
00177
00178 if(command)
00179 {
00180
00181 switch(command->command)
00182 {
00183 case BC_SynchronousCommand::QUIT:
00184 done = 1;
00185 break;
00186
00187 default:
00188 handle_command(command);
00189 break;
00190 }
00191 }
00192
00193 handle_garbage();
00194
00195 if(command)
00196 {
00197 command->command_done->unlock();
00198 }
00199 }
00200
00201 void BC_Synchronous::handle_command(BC_SynchronousCommand *command)
00202 {
00203 }
00204
00205 void BC_Synchronous::handle_garbage()
00206 {
00207 while(1)
00208 {
00209 table_lock->lock("BC_Synchronous::handle_garbage");
00210 if(!garbage.total)
00211 {
00212 table_lock->unlock();
00213 return;
00214 }
00215
00216 BC_SynchronousCommand *command = garbage.values[0];
00217 garbage.remove_number(0);
00218 table_lock->unlock();
00219
00220 switch(command->command)
00221 {
00222 case BC_SynchronousCommand::DELETE_WINDOW:
00223 delete_window_sync(command);
00224 break;
00225
00226 case BC_SynchronousCommand::DELETE_PIXMAP:
00227 delete_pixmap_sync(command);
00228 break;
00229 }
00230
00231 delete command;
00232 }
00233 }
00234
00235 void BC_Synchronous::put_texture(int id, int w, int h, int components)
00236 {
00237 if(id >= 0)
00238 {
00239 table_lock->lock("BC_Resources::put_texture");
00240
00241 for(int i = 0; i < texture_ids.total; i++)
00242 {
00243 TextureID *ptr = texture_ids.values[i];
00244 if(ptr->window_id == current_window->get_id() &&
00245 ptr->id == id)
00246 {
00247 printf("BC_Synchronous::push_texture: texture exists\n"
00248 "exists: window=%d id=%d w=%d h=%d\n"
00249 "new: window=%d id=%d w=%d h=%d\n",
00250 ptr->window_id,
00251 ptr->id,
00252 ptr->w,
00253 ptr->h,
00254 current_window->get_id(),
00255 id,
00256 w,
00257 h);
00258 table_lock->unlock();
00259 return;
00260 }
00261 }
00262
00263 TextureID *new_id = new TextureID(current_window->get_id(),
00264 id,
00265 w,
00266 h,
00267 components);
00268 texture_ids.append(new_id);
00269 table_lock->unlock();
00270 }
00271 }
00272
00273 int BC_Synchronous::get_texture(int w, int h, int components)
00274 {
00275 table_lock->lock("BC_Resources::get_texture");
00276 for(int i = 0; i < texture_ids.total; i++)
00277 {
00278 if(texture_ids.values[i]->w == w &&
00279 texture_ids.values[i]->h == h &&
00280 texture_ids.values[i]->components == components &&
00281 !texture_ids.values[i]->in_use &&
00282 texture_ids.values[i]->window_id == current_window->get_id())
00283 {
00284 int result = texture_ids.values[i]->id;
00285 texture_ids.values[i]->in_use = 1;
00286 table_lock->unlock();
00287 return result;
00288 }
00289 }
00290 table_lock->unlock();
00291 return -1;
00292 }
00293
00294 void BC_Synchronous::release_texture(int window_id, int id)
00295 {
00296 table_lock->lock("BC_Resources::release_texture");
00297 for(int i = 0; i < texture_ids.total; i++)
00298 {
00299 if(texture_ids.values[i]->id == id &&
00300 texture_ids.values[i]->window_id == window_id)
00301 {
00302 texture_ids.values[i]->in_use = 0;
00303 table_lock->unlock();
00304 return;
00305 }
00306 }
00307 table_lock->unlock();
00308 }
00309
00310
00311
00312
00313
00314 unsigned int BC_Synchronous::get_shader(char *source, int *got_it)
00315 {
00316 table_lock->lock("BC_Resources::get_shader");
00317 for(int i = 0; i < shader_ids.total; i++)
00318 {
00319 if(shader_ids.values[i]->window_id == current_window->get_id() &&
00320 !strcmp(shader_ids.values[i]->source, source))
00321 {
00322 unsigned int result = shader_ids.values[i]->handle;
00323 table_lock->unlock();
00324 *got_it = 1;
00325 return result;
00326 }
00327 }
00328 table_lock->unlock();
00329 *got_it = 0;
00330 return 0;
00331 }
00332
00333 void BC_Synchronous::put_shader(unsigned int handle,
00334 char *source)
00335 {
00336 table_lock->lock("BC_Resources::put_shader");
00337 shader_ids.append(new ShaderID(current_window->get_id(), handle, source));
00338 table_lock->unlock();
00339 }
00340
00341 void BC_Synchronous::dump_shader(unsigned int handle)
00342 {
00343 int got_it = 0;
00344 table_lock->lock("BC_Resources::dump_shader");
00345 for(int i = 0; i < shader_ids.total; i++)
00346 {
00347 if(shader_ids.values[i]->handle == handle)
00348 {
00349 printf("BC_Synchronous::dump_shader\n"
00350 "%s", shader_ids.values[i]->source);
00351 got_it = 1;
00352 break;
00353 }
00354 }
00355 table_lock->unlock();
00356 if(!got_it) printf("BC_Synchronous::dump_shader couldn't find %d\n", handle);
00357 }
00358
00359
00360 void BC_Synchronous::delete_window(BC_WindowBase *window)
00361 {
00362 #ifdef HAVE_GL
00363 BC_SynchronousCommand *command = new_command();
00364 command->command = BC_SynchronousCommand::DELETE_WINDOW;
00365 command->window_id = window->get_id();
00366 command->display = window->get_display();
00367 command->win = window->win;
00368 command->gl_context = window->gl_win_context;
00369
00370 send_garbage(command);
00371 #endif
00372 }
00373
00374 void BC_Synchronous::delete_window_sync(BC_SynchronousCommand *command)
00375 {
00376 #ifdef HAVE_GL
00377 int window_id = command->window_id;
00378 Display *display = command->display;
00379 Window win = command->win;
00380 GLXContext gl_context = command->gl_context;
00381 int debug = 0;
00382
00383
00384 glXMakeCurrent(display,
00385 win,
00386 gl_context);
00387
00388 table_lock->lock("BC_Resources::release_textures");
00389 for(int i = 0; i < texture_ids.total; i++)
00390 {
00391 if(texture_ids.values[i]->window_id == window_id)
00392 {
00393 GLuint id = texture_ids.values[i]->id;
00394 glDeleteTextures(1, &id);
00395 if(debug)
00396 printf("BC_Synchronous::delete_window_sync texture_id=%d window_id=%d\n",
00397 id,
00398 window_id);
00399 texture_ids.remove_object_number(i);
00400 i--;
00401 }
00402 }
00403
00404 for(int i = 0; i < shader_ids.total; i++)
00405 {
00406 if(shader_ids.values[i]->window_id == window_id)
00407 {
00408 glDeleteShader(shader_ids.values[i]->handle);
00409 if(debug)
00410 printf("BC_Synchronous::delete_window_sync shader_id=%d window_id=%d\n",
00411 shader_ids.values[i]->handle,
00412 window_id);
00413 shader_ids.remove_object_number(i);
00414 i--;
00415 }
00416 }
00417
00418 for(int i = 0; i < pbuffer_ids.total; i++)
00419 {
00420 if(pbuffer_ids.values[i]->window_id == window_id)
00421 {
00422 glXDestroyPbuffer(display, pbuffer_ids.values[i]->pbuffer);
00423 glXDestroyContext(display, pbuffer_ids.values[i]->gl_context);
00424 if(debug)
00425 printf("BC_Synchronous::delete_window_sync pbuffer_id=%p window_id=%d\n",
00426 pbuffer_ids.values[i]->pbuffer,
00427 window_id);
00428 pbuffer_ids.remove_object_number(i);
00429 i--;
00430 }
00431 }
00432
00433
00434 table_lock->unlock();
00435
00436 XDestroyWindow(display, win);
00437 if(gl_context) glXDestroyContext(display, gl_context);
00438 #endif
00439 }
00440
00441
00442
00443 #ifdef HAVE_GL
00444 void BC_Synchronous::put_pbuffer(int w,
00445 int h,
00446 GLXPbuffer pbuffer,
00447 GLXContext gl_context)
00448 {
00449 int exists = 0;
00450 table_lock->lock("BC_Resources::release_textures");
00451 for(int i = 0; i < pbuffer_ids.total; i++)
00452 {
00453 PBufferID *ptr = pbuffer_ids.values[i];
00454 if(ptr->w == w &&
00455 ptr->h == h &&
00456 ptr->pbuffer == pbuffer)
00457 {
00458
00459 exists = 1;
00460 break;
00461 }
00462 }
00463
00464
00465 if(!exists)
00466 {
00467 PBufferID *ptr = new PBufferID(current_window->get_id(),
00468 pbuffer,
00469 gl_context,
00470 w,
00471 h);
00472 pbuffer_ids.append(ptr);
00473 }
00474 table_lock->unlock();
00475 }
00476
00477 GLXPbuffer BC_Synchronous::get_pbuffer(int w,
00478 int h,
00479 int *window_id,
00480 GLXContext *gl_context)
00481 {
00482 table_lock->lock("BC_Resources::release_textures");
00483 for(int i = 0; i < pbuffer_ids.total; i++)
00484 {
00485 PBufferID *ptr = pbuffer_ids.values[i];
00486 if(ptr->w == w &&
00487 ptr->h == h &&
00488 ptr->window_id == current_window->get_id() &&
00489 !ptr->in_use)
00490 {
00491 GLXPbuffer result = ptr->pbuffer;
00492 *gl_context = ptr->gl_context;
00493 *window_id = ptr->window_id;
00494 ptr->in_use = 1;
00495 table_lock->unlock();
00496 return result;
00497 }
00498 }
00499 table_lock->unlock();
00500 return 0;
00501 }
00502
00503 void BC_Synchronous::release_pbuffer(int window_id, GLXPbuffer pbuffer)
00504 {
00505 table_lock->lock("BC_Resources::release_textures");
00506 for(int i = 0; i < pbuffer_ids.total; i++)
00507 {
00508 PBufferID *ptr = pbuffer_ids.values[i];
00509 if(ptr->window_id == window_id)
00510 {
00511 ptr->in_use = 0;
00512 }
00513 }
00514 table_lock->unlock();
00515 }
00516
00517 void BC_Synchronous::delete_pixmap(BC_WindowBase *window,
00518 GLXPixmap pixmap,
00519 GLXContext context)
00520 {
00521 BC_SynchronousCommand *command = new_command();
00522 command->command = BC_SynchronousCommand::DELETE_PIXMAP;
00523 command->window_id = window->get_id();
00524 command->display = window->get_display();
00525 command->win = window->win;
00526 command->gl_pixmap = pixmap;
00527 command->gl_context = context;
00528
00529 send_garbage(command);
00530 }
00531 #endif
00532
00533 void BC_Synchronous::delete_pixmap_sync(BC_SynchronousCommand *command)
00534 {
00535 #ifdef HAVE_GL
00536 Display *display = command->display;
00537 Window win = command->win;
00538 glXMakeCurrent(display,
00539 win,
00540 command->gl_context);
00541 glXDestroyContext(display, command->gl_context);
00542 glXDestroyGLXPixmap(display, command->gl_pixmap);
00543 #endif
00544 }
00545
00546
00547
00548 void BC_Synchronous::send_garbage(BC_SynchronousCommand *command)
00549 {
00550 table_lock->lock("BC_Synchronous::delete_window");
00551 garbage.append(command);
00552 table_lock->unlock();
00553
00554 next_command->unlock();
00555 }
00556
00557 BC_WindowBase* BC_Synchronous::get_window()
00558 {
00559 return current_window;
00560 }
00561
00562
00563
00564
00565
00566
00567