4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define GL_GLEXT_PROTOTYPES
23 #include "bcresources.h"
24 #include "bcsignals.h"
25 #include "bcsynchronous.h"
26 #include "bcwindowbase.h"
27 #include "condition.h"
39 TextureID::TextureID(int window_id, int id, int w, int h, int components)
41 this->window_id = window_id;
45 this->components = components;
49 ShaderID::ShaderID(int window_id, unsigned int handle,
50 const char *vert, const char *frag)
52 this->window_id = window_id;
53 this->handle = handle;
54 if( !vert ) vert = "";
55 if( !frag ) frag = "";
56 this->vert = cstrdup(vert);
57 this->frag = cstrdup(frag);
67 PBufferID::PBufferID(int window_id, GLXPbuffer glx_pbuffer, GLXContext glx_context, int w, int h)
69 this->glx_pbuffer = glx_pbuffer;
70 this->glx_context = glx_context;
71 this->window_id = window_id;
80 BC_SynchronousCommand::BC_SynchronousCommand()
82 command = BC_SynchronousCommand::NONE;
86 command_done = new Condition(0, "BC_SynchronousCommand::command_done", 0);
89 BC_SynchronousCommand::~BC_SynchronousCommand()
94 void BC_SynchronousCommand::copy_from(BC_SynchronousCommand *command)
96 this->command = command->command;
97 this->colormodel = command->colormodel;
98 this->window = command->window;
99 this->frame = command->frame;
100 this->window_id = command->window_id;
101 this->frame_return = command->frame_return;
102 this->id = command->id;
103 this->w = command->w;
104 this->h = command->h;
110 BC_Synchronous::BC_Synchronous()
113 lock_sync = new Mutex("BC_Synchronous::lock_sync");
114 next_command = new Condition(0, "BC_Synchronous::next_command", 1);
115 command_lock = new Mutex("BC_Synchronous::command_lock");
116 table_lock = new Mutex("BC_Synchronous::table_lock");
120 BC_WindowBase::get_resources()->set_synchronous(this);
123 BC_Synchronous::~BC_Synchronous()
129 commands.remove_all_objects();
136 void BC_Synchronous::sync_lock(const char *cp)
141 void BC_Synchronous::sync_unlock()
146 BC_SynchronousCommand* BC_Synchronous::new_command()
148 return new BC_SynchronousCommand();
151 void BC_Synchronous::create_objects()
155 void BC_Synchronous::start()
162 void BC_Synchronous::quit()
164 if( !is_started ) return;
166 BC_SynchronousCommand *command = BC_Synchronous::new_command();
167 command->command = BC_SynchronousCommand::QUIT;
168 send_garbage(command);
169 command->command_done->lock("BC_Synchronous::quit");
173 long BC_Synchronous::send_command(BC_SynchronousCommand *command)
175 BC_SynchronousCommand *command2 = new_command();
176 command2->copy_from(command);
177 command_lock->lock("BC_Synchronous::send_command");
178 commands.append(command2);
179 command_lock->unlock();
180 next_command->unlock();
181 //printf("BC_Synchronous::send_command 1 %d\n", next_command->get_value());
183 // Wait for completion
184 command2->command_done->lock("BC_Synchronous::send_command");
185 long result = command2->result;
190 void BC_Synchronous::run()
192 sync_lock("BC_Synchronous::run 0");
194 command_lock->lock("BC_Synchronous::run");
195 BC_SynchronousCommand *command = 0;
197 command = commands.values[0];
198 commands.remove_number(0);
200 command_lock->unlock();
203 next_command->lock("BC_Synchronous::run");
204 sync_lock("BC_Synchronous::run 1");
207 //printf("BC_Synchronous::run %d\n", command->command);
208 handle_command_base(command);
213 void BC_Synchronous::handle_command_base(BC_SynchronousCommand *command)
215 switch(command->command) {
216 case BC_SynchronousCommand::QUIT:
218 command->command_done->unlock();
221 case BC_SynchronousCommand::DELETE_WINDOW:
222 delete_window_sync(command);
223 command->command_done->unlock();
226 case BC_SynchronousCommand::DELETE_PIXMAP:
227 delete_pixmap_sync(command);
230 case BC_SynchronousCommand::DELETE_DISPLAY:
231 delete_display_sync(command);
235 handle_command(command);
236 command->command_done->unlock();
242 void BC_Synchronous::handle_command(BC_SynchronousCommand *command)
246 void BC_Synchronous::put_texture(int id, int w, int h, int components)
249 table_lock->lock("BC_Resources::put_texture");
250 // Search for duplicate
251 for( int i = 0; i < texture_ids.total; i++ ) {
252 TextureID *ptr = texture_ids.values[i];
253 if( ptr->window_id == current_window->get_id() && ptr->id == id ) {
254 printf("BC_Synchronous::push_texture: texture exists\n"
255 "exists: window=%d id=%d w=%d h=%d\n"
256 "new: window=%d id=%d w=%d h=%d\n",
257 ptr->window_id, ptr->id, ptr->w, ptr->h,
258 current_window->get_id(), id, w, h);
259 table_lock->unlock();
264 TextureID *new_id = new TextureID(current_window->get_id(),
265 id, w, h, components);
266 texture_ids.append(new_id);
267 table_lock->unlock();
271 int BC_Synchronous::get_texture(int w, int h, int components)
273 table_lock->lock("BC_Resources::get_texture");
274 for(int i = 0; i < texture_ids.total; i++)
276 if(texture_ids.values[i]->w == w &&
277 texture_ids.values[i]->h == h &&
278 texture_ids.values[i]->components == components &&
279 !texture_ids.values[i]->in_use &&
280 texture_ids.values[i]->window_id == current_window->get_id())
282 int result = texture_ids.values[i]->id;
283 texture_ids.values[i]->in_use = 1;
284 table_lock->unlock();
288 table_lock->unlock();
292 void BC_Synchronous::release_texture(int window_id, int id)
294 table_lock->lock("BC_Resources::release_texture");
295 for(int i = 0; i < texture_ids.total; i++)
297 if(texture_ids.values[i]->id == id &&
298 texture_ids.values[i]->window_id == window_id)
300 texture_ids.values[i]->in_use = 0;
301 table_lock->unlock();
305 table_lock->unlock();
312 int BC_Synchronous::get_shader(unsigned int *handle,
313 const char *vert, const char *frag)
315 unsigned int shader = 0, ret = 0;
316 if( !vert ) vert = "";
317 if( !frag ) frag = "";
318 table_lock->lock("BC_Resources::get_shader");
319 for( int i=0; !ret && i<shader_ids.size(); ++i ) {
320 ShaderID &sp = *shader_ids[i];
321 if( sp.window_id == current_window->get_id() &&
322 !strcmp(sp.vert, vert) && !strcmp(sp.frag, frag) ) {
323 shader = shader_ids.values[i]->handle;
327 table_lock->unlock();
332 void BC_Synchronous::put_shader(unsigned int handle,
333 const char *vert, const char *frag)
335 table_lock->lock("BC_Resources::put_shader");
336 shader_ids.append(new ShaderID(current_window->get_id(), handle, vert, frag));
337 table_lock->unlock();
340 void BC_Synchronous::dump_shader(unsigned int handle)
343 table_lock->lock("BC_Resources::dump_shader");
344 for( int i=0; i<shader_ids.size(); ++i ) {
345 if( shader_ids.values[i]->handle == handle ) {
346 printf("BC_Synchronous::dump_shader\n"
347 "vert: %s\nfrag: %s\n",
348 shader_ids[i]->vert, shader_ids[i]->frag);
353 table_lock->unlock();
355 printf("BC_Synchronous::dump_shader couldn't find %d\n", handle);
358 void BC_Synchronous::delete_window(BC_WindowBase *window)
361 BC_SynchronousCommand *command = BC_Synchronous::new_command();
362 command->command = BC_SynchronousCommand::DELETE_WINDOW;
363 command->window_id = window->get_id();
364 command->display = window->get_display();
365 command->win = window->win;
366 command->glx_win = window->glx_win;
367 command->glx_context = window->glx_win_context;
369 send_garbage(command);
370 command->command_done->lock("BC_Synchronous::quit");
375 void BC_Synchronous::delete_window_sync(BC_SynchronousCommand *command)
378 int window_id = command->window_id;
379 Display *display = command->display;
380 // Window win = command->win;
381 GLXWindow glx_win = command->glx_win;
382 GLXContext glx_context = command->glx_context;
383 XLockDisplay(display);
386 // texture ID's are unique to different contexts
387 glXMakeContextCurrent(display, glx_win, glx_win, glx_context);
389 table_lock->lock("BC_Resources::release_textures");
390 for(int i = 0; i < texture_ids.total; i++) {
391 if(texture_ids.values[i]->window_id == window_id) {
392 GLuint id = texture_ids.values[i]->id;
393 glDeleteTextures(1, &id);
394 //if(debug) printf("BC_Synchronous::delete_window_sync texture_id=%d window_id=%d\n",
396 texture_ids.remove_object_number(i);
401 for(int i = 0; i < shader_ids.total; i++)
403 if(shader_ids.values[i]->window_id == window_id)
405 glDeleteShader(shader_ids.values[i]->handle);
407 //printf("BC_Synchronous::delete_window_sync shader_id=%d window_id=%d\n",
408 //shader_ids.values[i]->handle, window_id);
409 shader_ids.remove_object_number(i);
414 for(int i = 0; i < pbuffer_ids.total; i++)
416 if(pbuffer_ids.values[i]->window_id == window_id)
418 glXDestroyPbuffer(display, pbuffer_ids.values[i]->glx_pbuffer);
419 glXDestroyContext(display, pbuffer_ids.values[i]->glx_context);
421 //printf("BC_Synchronous::delete_window_sync pbuffer_id=%p window_id=%d\n",
422 // (void*)pbuffer_ids.values[i]->pbuffer, window_id);
423 pbuffer_ids.remove_object_number(i);
429 table_lock->unlock();
431 glXMakeContextCurrent(display, None, None, 0);
433 glXDestroyContext(display, glx_context);
434 // causes xerror BadWindow (invalid Window parameter)
435 // XDestroyWindow(display, glx_win);
436 // win destroyed in bcwindowbase
437 XUnlockDisplay(display);
441 void BC_Synchronous::delete_display(BC_WindowBase *window)
444 BC_SynchronousCommand *command = BC_Synchronous::new_command();
445 command->command = BC_SynchronousCommand::DELETE_DISPLAY;
446 command->display = window->get_display();
448 send_garbage(command);
452 void BC_Synchronous::delete_display_sync(BC_SynchronousCommand *command)
455 Display *display = command->display;
456 XLockDisplay(display);
457 XUnlockDisplay(display);
458 glXMakeContextCurrent(display, None, None, 0);
459 XCloseDisplay(display);
464 void BC_Synchronous::put_pbuffer(int w, int h,
465 GLXPbuffer glx_pbuffer, GLXContext glx_context)
468 table_lock->lock("BC_Resources::release_textures");
469 for(int i = 0; i < pbuffer_ids.total; i++) {
470 PBufferID *ptr = pbuffer_ids.values[i];
471 if( ptr->w == w && ptr->h == h && ptr->glx_pbuffer == glx_pbuffer ) {
478 PBufferID *ptr = new PBufferID(current_window->get_id(),
479 glx_pbuffer, glx_context, w, h);
480 pbuffer_ids.append(ptr);
482 table_lock->unlock();
485 GLXPbuffer BC_Synchronous::get_pbuffer(int w, int h, GLXContext *glx_context)
487 table_lock->lock("BC_Resources::release_textures");
488 for(int i = 0; i < pbuffer_ids.total; i++) {
489 PBufferID *ptr = pbuffer_ids.values[i];
490 if(ptr->w == w && ptr->h == h && !ptr->in_use &&
491 ptr->window_id == current_window->get_id() ) {
492 GLXPbuffer result = ptr->glx_pbuffer;
493 *glx_context = ptr->glx_context;
495 table_lock->unlock();
499 table_lock->unlock();
503 void BC_Synchronous::release_pbuffer(int window_id, GLXPbuffer pbuffer)
505 table_lock->lock("BC_Resources::release_textures");
506 for(int i = 0; i < pbuffer_ids.total; i++) {
507 PBufferID *ptr = pbuffer_ids.values[i];
508 if( ptr->window_id == window_id &&
509 ptr->glx_pbuffer == pbuffer ) {
513 table_lock->unlock();
516 void BC_Synchronous::delete_pixmap(BC_WindowBase *window,
517 GLXPixmap glx_pixmap, GLXContext glx_context)
519 BC_SynchronousCommand *command = BC_Synchronous::new_command();
520 command->command = BC_SynchronousCommand::DELETE_PIXMAP;
521 command->window_id = window->get_id();
522 command->display = window->get_display();
523 command->win = window->win;
524 command->glx_win = window->glx_win;
525 command->glx_pixmap = glx_pixmap;
526 command->glx_context = glx_context;
528 send_garbage(command);
532 void BC_Synchronous::delete_pixmap_sync(BC_SynchronousCommand *command)
535 Display *display = command->display;
536 GLXWindow glx_win = command->glx_win;
537 XLockDisplay(display);
538 glXMakeContextCurrent(display, glx_win, glx_win, command->glx_context);
539 glXDestroyContext(display, command->glx_context);
540 glXDestroyGLXPixmap(display, command->glx_pixmap);
541 XUnlockDisplay(display);
547 void BC_Synchronous::send_garbage(BC_SynchronousCommand *command)
549 command_lock->lock("BC_Synchronous::send_garbage");
550 commands.append(command);
551 command_lock->unlock();
552 next_command->unlock();
555 BC_WindowBase* BC_Synchronous::get_window()
557 return current_window;