r878: This is Cinelerra 2.1.
[cinelerra_cv/ct.git] / guicast / bcsynchronous.C
blobb2a8dae9dc1e1240cfd213d723b183df5c2e5abd
1 #define GL_GLEXT_PROTOTYPES
2 #include "bcresources.h"
3 #include "bcsignals.h"
4 #include "bcsynchronous.h"
5 #include "bcwindowbase.h"
6 #include "condition.h"
7 #include "mutex.h"
10 #ifdef HAVE_GL
11 #include <GL/gl.h>
12 #endif
13 #include <unistd.h>
15 #include <string.h>
18 TextureID::TextureID(int window_id, int id, int w, int h, int components)
20         this->window_id = window_id;
21         this->id = id;
22         this->w = w;
23         this->h = h;
24         this->components = components;
25         in_use = 1;
28 ShaderID::ShaderID(int window_id, unsigned int handle, char *source)
30         this->window_id = window_id;
31         this->handle = handle;
32         this->source = strdup(source);
35 ShaderID::~ShaderID()
37         free(source);
40 #ifdef HAVE_GL
41 PBufferID::PBufferID(int window_id, 
42         GLXPbuffer pbuffer, 
43         GLXContext gl_context, 
44         int w, 
45         int h)
47         this->pbuffer = pbuffer;
48         this->gl_context = gl_context;
49         this->window_id = window_id;
50         this->w = w;
51         this->h = h;
52         in_use = 1;
54 #endif
58 BC_SynchronousCommand::BC_SynchronousCommand()
60         command = BC_SynchronousCommand::NONE;
61         frame = 0;
62         frame_return = 0;
63         result = 0;
64         command_done = new Condition(0, "BC_SynchronousCommand::command_done", 0);
67 BC_SynchronousCommand::~BC_SynchronousCommand()
69         delete command_done;
72 void BC_SynchronousCommand::copy_from(BC_SynchronousCommand *command)
74         this->command =               command->command;
75         this->colormodel =      command->colormodel;
76         this->window =        command->window;
77         this->frame =         command->frame;
78         this->window_id =       command->window_id;
80         this->frame_return =    command->frame_return;
82         this->id =                    command->id;
83         this->w =                     command->w;
84         this->h =                     command->h;
90 BC_Synchronous::BC_Synchronous()
91  : Thread(1, 0, 0)
93         next_command = new Condition(0, "BC_Synchronous::next_command", 0);
94         command_lock = new Mutex("BC_Synchronous::command_lock");
95         table_lock = new Mutex("BC_Synchronous::table_lock");
96         done = 0;
97         is_running = 0;
98         current_window = 0;
99         BC_WindowBase::get_resources()->set_synchronous(this);
102 BC_Synchronous::~BC_Synchronous()
104         commands.remove_all_objects();
107 BC_SynchronousCommand* BC_Synchronous::new_command()
109         return new BC_SynchronousCommand;
112 void BC_Synchronous::create_objects()
116 void BC_Synchronous::start()
118         run();
121 void BC_Synchronous::quit()
123         command_lock->lock("BC_Synchronous::quit");
124         BC_SynchronousCommand *command = new_command();
125         commands.append(command);
126         command->command = BC_SynchronousCommand::QUIT;
127         command_lock->unlock();
129         next_command->unlock();
132 int BC_Synchronous::send_command(BC_SynchronousCommand *command)
134         command_lock->lock("BC_Synchronous::send_command");
135         BC_SynchronousCommand *command2 = new_command();
136         commands.append(command2);
137         command2->copy_from(command);
138         command_lock->unlock();
140         next_command->unlock();
141 //printf("BC_Synchronous::send_command 1 %d\n", next_command->get_value());
143 // Wait for completion
144         command2->command_done->lock("BC_Synchronous::send_command");
145         int result = command2->result;
146         delete command2;
147         return result;
150 void BC_Synchronous::run()
152         is_running = 1;
153         while(!done)
154         {
155                 next_command->lock("BC_Synchronous::run");
158                 command_lock->lock("BC_Synchronous::run");
159                 BC_SynchronousCommand *command = 0;
160                 if(commands.total)
161                 {
162                         command = commands.values[0];
163                         commands.remove_number(0);
164                 }
165 // Prevent executing the same command twice if spurious unlock.
166                 command_lock->unlock();
167 //printf("BC_Synchronous::run %d\n", command->command);
169                 handle_command_base(command);
170 //              delete command;
171         }
172         is_running = 0;
175 void BC_Synchronous::handle_command_base(BC_SynchronousCommand *command)
178         if(command)
179         {
180 //printf("BC_Synchronous::handle_command_base 1 %d\n", command->command);
181                 switch(command->command)
182                 {
183                         case BC_SynchronousCommand::QUIT:
184                                 done = 1;
185                                 break;
187                         default:
188                                 handle_command(command);
189                                 break;
190                 }
191         }
193         handle_garbage();
195         if(command)
196         {
197                 command->command_done->unlock();
198         }
201 void BC_Synchronous::handle_command(BC_SynchronousCommand *command)
205 void BC_Synchronous::handle_garbage()
207         while(1)
208         {
209                 table_lock->lock("BC_Synchronous::handle_garbage");
210                 if(!garbage.total)
211                 {
212                         table_lock->unlock();
213                         return;
214                 }
216                 BC_SynchronousCommand *command = garbage.values[0];
217                 garbage.remove_number(0);
218                 table_lock->unlock();
220                 switch(command->command)
221                 {
222                         case BC_SynchronousCommand::DELETE_WINDOW:
223                                 delete_window_sync(command);
224                                 break;
226                         case BC_SynchronousCommand::DELETE_PIXMAP:
227                                 delete_pixmap_sync(command);
228                                 break;
229                 }
231                 delete command;
232         }
235 void BC_Synchronous::put_texture(int id, int w, int h, int components)
237         if(id >= 0)
238         {
239                 table_lock->lock("BC_Resources::put_texture");
240 // Search for duplicate
241                 for(int i = 0; i < texture_ids.total; i++)
242                 {
243                         TextureID *ptr = texture_ids.values[i];
244                         if(ptr->window_id == current_window->get_id() &&
245                                 ptr->id == id)
246                         {
247                                 printf("BC_Synchronous::push_texture: texture exists\n"
248                                         "exists: window=%d id=%d w=%d h=%d\n"
249                                         "new:    window=%d id=%d w=%d h=%d\n",
250                                         ptr->window_id,
251                                         ptr->id,
252                                         ptr->w,
253                                         ptr->h,
254                                         current_window->get_id(),
255                                         id,
256                                         w,
257                                         h);
258                                 table_lock->unlock();
259                                 return;
260                         }
261                 }
263                 TextureID *new_id = new TextureID(current_window->get_id(), 
264                         id, 
265                         w, 
266                         h,
267                         components);
268                 texture_ids.append(new_id);
269                 table_lock->unlock();
270         }
273 int BC_Synchronous::get_texture(int w, int h, int components)
275         table_lock->lock("BC_Resources::get_texture");
276         for(int i = 0; i < texture_ids.total; i++)
277         {
278                 if(texture_ids.values[i]->w == w &&
279                         texture_ids.values[i]->h == h &&
280                         texture_ids.values[i]->components == components &&
281                         !texture_ids.values[i]->in_use &&
282                         texture_ids.values[i]->window_id == current_window->get_id())
283                 {
284                         int result = texture_ids.values[i]->id;
285                         texture_ids.values[i]->in_use = 1;
286                         table_lock->unlock();
287                         return result;
288                 }
289         }
290         table_lock->unlock();
291         return -1;
294 void BC_Synchronous::release_texture(int window_id, int id)
296         table_lock->lock("BC_Resources::release_texture");
297         for(int i = 0; i < texture_ids.total; i++)
298         {
299                 if(texture_ids.values[i]->id == id &&
300                         texture_ids.values[i]->window_id == window_id)
301                 {
302                         texture_ids.values[i]->in_use = 0;
303                         table_lock->unlock();
304                         return;
305                 }
306         }
307         table_lock->unlock();
314 unsigned int BC_Synchronous::get_shader(char *source, int *got_it)
316         table_lock->lock("BC_Resources::get_shader");
317         for(int i = 0; i < shader_ids.total; i++)
318         {
319                 if(shader_ids.values[i]->window_id == current_window->get_id() &&
320                         !strcmp(shader_ids.values[i]->source, source))
321                 {
322                         unsigned int result = shader_ids.values[i]->handle;
323                         table_lock->unlock();
324                         *got_it = 1;
325                         return result;
326                 }
327         }
328         table_lock->unlock();
329         *got_it = 0;
330         return 0;
333 void BC_Synchronous::put_shader(unsigned int handle, 
334         char *source)
336         table_lock->lock("BC_Resources::put_shader");
337         shader_ids.append(new ShaderID(current_window->get_id(), handle, source));
338         table_lock->unlock();
341 void BC_Synchronous::dump_shader(unsigned int handle)
343         int got_it = 0;
344         table_lock->lock("BC_Resources::dump_shader");
345         for(int i = 0; i < shader_ids.total; i++)
346         {
347                 if(shader_ids.values[i]->handle == handle)
348                 {
349                         printf("BC_Synchronous::dump_shader\n"
350                                 "%s", shader_ids.values[i]->source);
351                         got_it = 1;
352                         break;
353                 }
354         }
355         table_lock->unlock();
356         if(!got_it) printf("BC_Synchronous::dump_shader couldn't find %d\n", handle);
360 void BC_Synchronous::delete_window(BC_WindowBase *window)
362 #ifdef HAVE_GL
363         BC_SynchronousCommand *command = new_command();
364         command->command = BC_SynchronousCommand::DELETE_WINDOW;
365         command->window_id = window->get_id();
366         command->display = window->get_display();
367         command->win = window->win;
368         command->gl_context = window->gl_win_context;
370         send_garbage(command);
371 #endif
374 void BC_Synchronous::delete_window_sync(BC_SynchronousCommand *command)
376 #ifdef HAVE_GL
377         int window_id = command->window_id;
378         Display *display = command->display;
379         Window win = command->win;
380         GLXContext gl_context = command->gl_context;
381 int debug = 0;
383 // texture ID's are unique to different contexts
384         glXMakeCurrent(display,
385                 win,
386                 gl_context);
388         table_lock->lock("BC_Resources::release_textures");
389         for(int i = 0; i < texture_ids.total; i++)
390         {
391                 if(texture_ids.values[i]->window_id == window_id)
392                 {
393                         GLuint id = texture_ids.values[i]->id;
394                         glDeleteTextures(1, &id);
395 if(debug)
396 printf("BC_Synchronous::delete_window_sync texture_id=%d window_id=%d\n", 
398 window_id);
399                         texture_ids.remove_object_number(i);
400                         i--;
401                 }
402         }
404         for(int i = 0; i < shader_ids.total; i++)
405         {
406                 if(shader_ids.values[i]->window_id == window_id)
407                 {
408                         glDeleteShader(shader_ids.values[i]->handle);
409 if(debug)
410 printf("BC_Synchronous::delete_window_sync shader_id=%d window_id=%d\n", 
411 shader_ids.values[i]->handle,
412 window_id);
413                         shader_ids.remove_object_number(i);
414                         i--;
415                 }
416         }
418         for(int i = 0; i < pbuffer_ids.total; i++)
419         {
420                 if(pbuffer_ids.values[i]->window_id == window_id)
421                 {
422                         glXDestroyPbuffer(display, pbuffer_ids.values[i]->pbuffer);
423                         glXDestroyContext(display, pbuffer_ids.values[i]->gl_context);
424 if(debug)
425 printf("BC_Synchronous::delete_window_sync pbuffer_id=%p window_id=%d\n", 
426 pbuffer_ids.values[i]->pbuffer,
427 window_id);
428                         pbuffer_ids.remove_object_number(i);
429                         i--;
430                 }
431         }
434         table_lock->unlock();
436         XDestroyWindow(display, win);
437         if(gl_context) glXDestroyContext(display, gl_context);
438 #endif
443 #ifdef HAVE_GL
444 void BC_Synchronous::put_pbuffer(int w, 
445         int h, 
446         GLXPbuffer pbuffer, 
447         GLXContext gl_context)
449         int exists = 0;
450         table_lock->lock("BC_Resources::release_textures");
451         for(int i = 0; i < pbuffer_ids.total; i++)
452         {
453                 PBufferID *ptr = pbuffer_ids.values[i];
454                 if(ptr->w == w &&
455                         ptr->h == h &&
456                         ptr->pbuffer == pbuffer)
457                 {
458 // Exists
459                         exists = 1;
460                         break;
461                 }
462         }
465         if(!exists)
466         {
467                 PBufferID *ptr = new PBufferID(current_window->get_id(),
468                         pbuffer,
469                         gl_context,
470                         w,
471                         h);
472                 pbuffer_ids.append(ptr);
473         }
474         table_lock->unlock();
477 GLXPbuffer BC_Synchronous::get_pbuffer(int w, 
478         int h, 
479         int *window_id, 
480         GLXContext *gl_context)
482         table_lock->lock("BC_Resources::release_textures");
483         for(int i = 0; i < pbuffer_ids.total; i++)
484         {
485                 PBufferID *ptr = pbuffer_ids.values[i];
486                 if(ptr->w == w &&
487                         ptr->h == h &&
488                         ptr->window_id == current_window->get_id() &&
489                         !ptr->in_use)
490                 {
491                         GLXPbuffer result = ptr->pbuffer;
492                         *gl_context = ptr->gl_context;
493                         *window_id = ptr->window_id;
494                         ptr->in_use = 1;
495                         table_lock->unlock();
496                         return result;
497                 }
498         }
499         table_lock->unlock();
500         return 0;
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         {
508                 PBufferID *ptr = pbuffer_ids.values[i];
509                 if(ptr->window_id == window_id)
510                 {
511                         ptr->in_use = 0;
512                 }
513         }
514         table_lock->unlock();
517 void BC_Synchronous::delete_pixmap(BC_WindowBase *window, 
518         GLXPixmap pixmap, 
519         GLXContext context)
521         BC_SynchronousCommand *command = new_command();
522         command->command = BC_SynchronousCommand::DELETE_PIXMAP;
523         command->window_id = window->get_id();
524         command->display = window->get_display();
525         command->win = window->win;
526         command->gl_pixmap = pixmap;
527         command->gl_context = context;
529         send_garbage(command);
531 #endif
533 void BC_Synchronous::delete_pixmap_sync(BC_SynchronousCommand *command)
535 #ifdef HAVE_GL
536         Display *display = command->display;
537         Window win = command->win;
538         glXMakeCurrent(display,
539                 win,
540                 command->gl_context);
541         glXDestroyContext(display, command->gl_context);
542         glXDestroyGLXPixmap(display, command->gl_pixmap);
543 #endif
548 void BC_Synchronous::send_garbage(BC_SynchronousCommand *command)
550         table_lock->lock("BC_Synchronous::delete_window");
551         garbage.append(command);
552         table_lock->unlock();
554         next_command->unlock();
557 BC_WindowBase* BC_Synchronous::get_window()
559         return current_window;