Credit Andrew - improve in-tree documentation
[goodguy/cinelerra.git] / cinelerra / vdevicex11.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008-2017 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "assets.h"
23 #include "autos.h"
24 #include "bccapture.h"
25 #include "bccmodels.h"
26 #include "bcsignals.h"
27 #include "canvas.h"
28 #include "edl.h"
29 #include "edlsession.h"
30 #include "file.h"
31 #include "maskauto.h"
32 #include "maskautos.h"
33 #include "mwindow.h"
34 #include "mwindowgui.h"
35 #include "playback3d.h"
36 #include "playbackconfig.h"
37 #include "preferences.h"
38 #include "recordconfig.h"
39 #include "strategies.inc"
40 #include "vdevicex11.h"
41 #include "vframe.h"
42 #include "videodevice.h"
43 #include "videowindow.h"
44 #include "videowindowgui.h"
45
46 #include <string.h>
47 #include <unistd.h>
48
49 VDeviceX11::VDeviceX11(VideoDevice *device, Canvas *output)
50  : VDeviceBase(device)
51 {
52         reset_parameters();
53         this->output = output;
54 }
55
56 VDeviceX11::~VDeviceX11()
57 {
58         close_all();
59 }
60
61 int VDeviceX11::reset_parameters()
62 {
63         output_frame = 0;
64         window_id = 0;
65         bitmap = 0;
66         bitmap_type = 0;
67         bitmap_w = 0;
68         bitmap_h = 0;
69         output_x1 = 0;
70         output_y1 = 0;
71         output_x2 = 0;
72         output_y2 = 0;
73         canvas_x1 = 0;
74         canvas_y1 = 0;
75         canvas_x2 = 0;
76         canvas_y2 = 0;
77         capture_bitmap = 0;
78         color_model_selected = 0;
79         is_cleared = 0;
80
81         for( int i = 0; i < SCREENCAP_BORDERS; i++ ) {
82                 screencap_border[i] = 0;
83         }
84         return 0;
85 }
86
87 int VDeviceX11::open_input()
88 {
89 //printf("VDeviceX11::open_input 1\n");
90         capture_bitmap = new BC_Capture(device->in_config->w,
91                 device->in_config->h,
92                 device->in_config->screencapture_display);
93 //printf("VDeviceX11::open_input 2\n");
94
95 // create overlay
96         device->mwindow->gui->lock_window("VDeviceX11::close_all");
97
98         screencap_border[0] = new BC_Popup(device->mwindow->gui,
99                         device->input_x - SCREENCAP_PIXELS, device->input_y - SCREENCAP_PIXELS,
100                         device->in_config->w + SCREENCAP_PIXELS * 2, SCREENCAP_PIXELS,
101                         SCREENCAP_COLOR, 1);
102         screencap_border[1] = new BC_Popup(device->mwindow->gui,
103                         device->input_x - SCREENCAP_PIXELS, device->input_y,
104                         SCREENCAP_PIXELS, device->in_config->h,
105                         SCREENCAP_COLOR, 1);
106         screencap_border[2] = new BC_Popup(device->mwindow->gui,
107                         device->input_x - SCREENCAP_PIXELS, device->input_y + device->in_config->h,
108                         device->in_config->w + SCREENCAP_PIXELS * 2, SCREENCAP_PIXELS,
109                         SCREENCAP_COLOR, 1);
110         screencap_border[3] = new BC_Popup(device->mwindow->gui,
111                         device->input_x + device->in_config->w, device->input_y,
112                         SCREENCAP_PIXELS, device->in_config->h,
113                         SCREENCAP_COLOR, 1);
114 usleep(500000); // avoids a bug in gnome-shell 2017/10/19
115
116         for( int i=0; i<SCREENCAP_BORDERS; ++i )
117                 screencap_border[i]->show_window(0);
118
119         device->mwindow->gui->flush();
120         device->mwindow->gui->unlock_window();
121
122         return 0;
123 }
124
125 int VDeviceX11::open_output()
126 {
127         if( output ) {
128                 output->lock_canvas("VDeviceX11::open_output");
129                 output->get_canvas()->lock_window("VDeviceX11::open_output");
130                 if( !device->single_frame )
131                         output->start_video();
132                 else
133                         output->start_single();
134                 output->get_canvas()->unlock_window();
135
136 // Enable opengl in the first routine that needs it, to reduce the complexity.
137                 output->unlock_canvas();
138         }
139         return 0;
140 }
141
142
143 int VDeviceX11::output_visible()
144 {
145         if( !output ) return 0;
146
147         output->lock_canvas("VDeviceX11::output_visible");
148         if( output->get_canvas()->get_hidden() ) {
149                 output->unlock_canvas();
150                 return 0;
151         }
152         else {
153                 output->unlock_canvas();
154                 return 1;
155         }
156 }
157
158
159 int VDeviceX11::close_all()
160 {
161         if( output ) {
162                 output->lock_canvas("VDeviceX11::close_all 1");
163                 output->get_canvas()->lock_window("VDeviceX11::close_all 1");
164                 int video_on = output->get_canvas()->get_video_on();
165 // Update the status bug
166                 if( !device->single_frame ) {
167                         output->stop_video();
168                 }
169                 else {
170                         output->stop_single();
171                 }
172                 if( output_frame ) {
173                         output->update_refresh(device, output_frame);
174 // if the last frame is good, don't draw over it
175                         if( !video_on || output->need_overlays() )
176                                 output->draw_refresh(1);
177                 }
178         }
179
180         delete bitmap;          bitmap = 0;
181         delete output_frame;    output_frame = 0;
182         delete capture_bitmap;  capture_bitmap = 0;
183
184         if( output ) {
185                 output->get_canvas()->unlock_window();
186                 output->unlock_canvas();
187         }
188
189         if( device->mwindow ) {
190                 device->mwindow->gui->lock_window("VDeviceX11::close_all");
191                 for( int i=0; i<SCREENCAP_BORDERS; ++i ) {
192                         delete screencap_border[i];
193                         screencap_border[i] = 0;
194                 }
195                 device->mwindow->gui->unlock_window();
196         }
197
198         reset_parameters();
199
200         return 0;
201 }
202
203 int VDeviceX11::read_buffer(VFrame *frame)
204 {
205 //printf("VDeviceX11::read_buffer %d colormodel=%d\n", __LINE__, frame->get_color_model());
206         device->mwindow->gui->lock_window("VDeviceX11::close_all");
207
208         screencap_border[0]->reposition_window(device->input_x - SCREENCAP_PIXELS,
209                         device->input_y - SCREENCAP_PIXELS);
210         screencap_border[1]->reposition_window(device->input_x - SCREENCAP_PIXELS,
211                         device->input_y);
212         screencap_border[2]->reposition_window(device->input_x - SCREENCAP_PIXELS,
213                         device->input_y + device->in_config->h);
214         screencap_border[3]->reposition_window(device->input_x + device->in_config->w,
215                         device->input_y);
216         device->mwindow->gui->flush();
217         device->mwindow->gui->unlock_window();
218
219
220         capture_bitmap->capture_frame(frame,
221                 device->input_x, device->input_y, device->do_cursor);
222         return 0;
223 }
224
225
226 int VDeviceX11::get_best_colormodel(Asset *asset)
227 {
228         return File::get_best_colormodel(asset, SCREENCAPTURE);
229 //      return BC_RGB888;
230 }
231
232
233 int VDeviceX11::get_display_colormodel(int file_colormodel)
234 {
235         int result = -1;
236
237         if( device->out_config->driver == PLAYBACK_X11_GL ) {
238                 if( file_colormodel == BC_RGB888 ||
239                     file_colormodel == BC_RGBA8888 ||
240                     file_colormodel == BC_YUV888 ||
241                     file_colormodel == BC_YUVA8888 ||
242                     file_colormodel == BC_RGB_FLOAT ||
243                     file_colormodel == BC_RGBA_FLOAT ) {
244                         return file_colormodel;
245                 }
246
247                 return BC_RGB888;
248         }
249
250         if( !device->single_frame ) {
251                 switch( file_colormodel ) {
252                 case BC_YUV420P:
253                 case BC_YUV422P:
254                 case BC_YUV422:
255                         result = file_colormodel;
256                         break;
257                 }
258         }
259
260         if( result < 0 ) {
261                 switch( file_colormodel ) {
262                 case BC_RGB888:
263                 case BC_RGBA8888:
264                 case BC_YUV888:
265                 case BC_YUVA8888:
266                 case BC_RGB_FLOAT:
267                 case BC_RGBA_FLOAT:
268                         result = file_colormodel;
269                         break;
270
271                 default:
272                         output->lock_canvas("VDeviceX11::get_display_colormodel");
273                         result = output->get_canvas()->get_color_model();
274                         output->unlock_canvas();
275                         break;
276                 }
277         }
278
279         return result;
280 }
281
282
283 void VDeviceX11::new_output_buffer(VFrame **result, int file_colormodel, EDL *edl)
284 {
285 // printf("VDeviceX11::new_output_buffer %d hardware_scaling=%d\n",
286 // __LINE__, bitmap ? bitmap->hardware_scaling() : 0);
287         output->lock_canvas("VDeviceX11::new_output_buffer");
288         output->get_canvas()->lock_window("VDeviceX11::new_output_buffer 1");
289
290 // Get the best colormodel the display can handle.
291         int display_colormodel = get_display_colormodel(file_colormodel);
292
293 //printf("VDeviceX11::new_output_buffer %d file_colormodel=%d display_colormodel=%d\n",
294 // __LINE__, file_colormodel, display_colormodel);
295 // Only create OpenGL Pbuffer and texture.
296         if( device->out_config->driver == PLAYBACK_X11_GL ) {
297 // Create bitmap for initial load into texture.
298 // Not necessary to do through Playback3D.....yet
299                 if( !output_frame ) {
300                         output_frame = new VFrame(device->out_w, device->out_h, file_colormodel);
301                 }
302
303                 window_id = output->get_canvas()->get_id();
304                 output_frame->set_opengl_state(VFrame::RAM);
305         }
306         else {
307                 output->get_transfers(edl,
308                         output_x1, output_y1, output_x2, output_y2,
309                         canvas_x1, canvas_y1, canvas_x2, canvas_y2,
310 // Canvas may be a different size than the temporary bitmap for pure software
311                         -1, -1);
312                 canvas_w = canvas_x2 - canvas_x1;
313                 canvas_h = canvas_y2 - canvas_y1;
314 // can the direct frame be used?
315                 int direct_supported =
316                         device->out_config->use_direct_x11 &&
317                         !output->xscroll && !output->yscroll &&
318                         output_x1 == 0 && output_x2 == device->out_w &&
319                         output_y1 == 0 && output_y2 == device->out_h;
320
321 // file wants direct frame but we need a temp
322                 if( !direct_supported && file_colormodel == BC_BGR8888 )
323                         file_colormodel = BC_RGB888;
324
325 // Conform existing bitmap to new colormodel and output size
326                 if( bitmap ) {
327 // printf("VDeviceX11::new_output_buffer %d bitmap=%dx%d canvas=%dx%d canvas=%dx%d\n",
328 // __LINE__, bitmap->get_w(), bitmap->get_h(), canvas_w, canvas_h,);
329                         int size_change = (
330                                 bitmap->get_w() != canvas_w ||
331                                 bitmap->get_h() != canvas_h );
332
333 // Restart if output size changed or output colormodel changed.
334 // May have to recreate if transferring between windowed and fullscreen.
335                         if( !color_model_selected ||
336                             file_colormodel != output_frame->get_color_model() ||
337                             (!bitmap->hardware_scaling() && size_change) ) {
338 //printf("VDeviceX11::new_output_buffer %d file_colormodel=%d prev "
339 // "file_colormodel=%d bitmap=%p output_frame=%p\n", __LINE__,
340 // file_colormodel, output_frame->get_color_model(), bitmap, output_frame);
341                                 delete bitmap;        bitmap = 0;
342                                 delete output_frame;  output_frame = 0;
343 // Clear borders if size changed
344                                 if( size_change ) {
345 //printf("VDeviceX11::new_output_buffer %d w=%d h=%d "
346 // "canvas_x1=%d canvas_y1=%d canvas_x2=%d canvas_y2=%d\n",
347 // __LINE__, // (int)output->w, (int)output->h,
348 // (int)canvas_x1, (int)canvas_y1, (int)canvas_x2, (int)canvas_y2);
349                                         output->get_canvas()->set_color(BLACK);
350
351                                         if( canvas_y1 > 0 ) {
352                                                 output->get_canvas()->draw_box(0, 0, output->w, canvas_y1);
353                                                 output->get_canvas()->flash(0, 0, output->w, canvas_y1);
354                                         }
355
356                                         if( canvas_y2 < output->h ) {
357                                                 output->get_canvas()->draw_box(0, canvas_y2, output->w, output->h - canvas_y2);
358                                                 output->get_canvas()->flash(0, canvas_y2, output->w, output->h - canvas_y2);
359                                         }
360
361                                         if( canvas_x1 > 0 ) {
362                                                 output->get_canvas()->draw_box(0, canvas_y1, canvas_x1, canvas_y2 - canvas_y1);
363                                                 output->get_canvas()->flash(0, canvas_y1, canvas_x1, canvas_y2 - canvas_y1);
364                                         }
365
366                                         if( canvas_x2 < output->w ) {
367                                                 output->get_canvas()->draw_box(canvas_x2, canvas_y1,
368                                                         output->w - canvas_x2, canvas_y2 - canvas_y1);
369                                                 output->get_canvas()->flash(canvas_x2, canvas_y1,
370                                                         output->w - canvas_x2, canvas_y2 - canvas_y1);
371                                         }
372                                 }
373                         }
374                 }
375
376 // Create new bitmap
377                 if( !bitmap ) {
378                         int use_direct = 0;
379                         bitmap_type = BITMAP_TEMP;
380 //printf("VDeviceX11::new_output_buffer %d file_colormodel=%d display_colormodel=%d\n",
381 // __LINE__, file_colormodel, display_colormodel);
382
383 // Try hardware accelerated
384                         switch( display_colormodel ) {
385 // blit from the codec directly to the window, using the standard X11 color model.
386 // Must scale in the codec.  No cropping
387                         case BC_BGR8888:
388                                 if( direct_supported ) {
389                                         bitmap_type = BITMAP_PRIMARY;
390                                         use_direct = 1;
391                                 }
392                                 break;
393
394                         case BC_YUV420P:
395                                 if( device->out_config->driver == PLAYBACK_X11_XV &&
396                                     output->get_canvas()->accel_available(display_colormodel, 0) &&
397                                     !output->use_scrollbars )
398                                         bitmap_type = BITMAP_PRIMARY;
399                                 break;
400
401                         case BC_YUV422P:
402                                 if( device->out_config->driver == PLAYBACK_X11_XV &&
403                                     output->get_canvas()->accel_available(display_colormodel, 0) &&
404                                     !output->use_scrollbars )
405                                         bitmap_type = BITMAP_PRIMARY;
406                                 else if( device->out_config->driver == PLAYBACK_X11_XV &&
407                                     output->get_canvas()->accel_available(BC_YUV422, 0) ) {
408                                         bitmap = new BC_Bitmap(output->get_canvas(),
409                                                 device->out_w, device->out_h, BC_YUV422, 1);
410                                 }
411                                 break;
412
413                         case BC_YUV422:
414                                 if( device->out_config->driver == PLAYBACK_X11_XV &&
415                                     output->get_canvas()->accel_available(display_colormodel, 0) &&
416                                     !output->use_scrollbars ) {
417                                         bitmap_type = BITMAP_PRIMARY;
418                                 }
419                                 else if( device->out_config->driver == PLAYBACK_X11_XV &&
420                                     output->get_canvas()->accel_available(BC_YUV422P, 0) ) {
421                                         bitmap = new BC_Bitmap(output->get_canvas(),
422                                                 device->out_w, device->out_h, BC_YUV422P, 1);
423                                 }
424                                 break;
425                         }
426                         if( bitmap_type == BITMAP_PRIMARY ) {
427                                 int bitmap_w = use_direct ? canvas_w : device->out_w;
428                                 int bitmap_h = use_direct ? canvas_h : device->out_h;
429                                 bitmap = new BC_Bitmap(output->get_canvas(),
430                                         bitmap_w, bitmap_h,  display_colormodel, -1);
431                                 output_frame = new VFrame(bitmap,
432                                         bitmap_w, bitmap_h, display_colormodel, -1);
433                         }
434 // Make an intermediate frame
435                         if( !bitmap ) {
436                                 display_colormodel = output->get_canvas()->get_color_model();
437 // printf("VDeviceX11::new_output_buffer %d creating temp display_colormodel=%d "
438 // "file_colormodel=%d %dx%d %dx%d %dx%d\n", __LINE__,
439 // display_colormodel, file_colormodel, device->out_w, device->out_h,
440 // output->get_canvas()->get_w(), output->get_canvas()->get_h(), canvas_w, canvas_h);
441                                 bitmap = new BC_Bitmap(output->get_canvas(),
442                                         canvas_w, canvas_h, display_colormodel, 1);
443                                 bitmap_type = BITMAP_TEMP;
444                         }
445
446                         if( bitmap_type == BITMAP_TEMP ) {
447 // Intermediate frame
448 //printf("VDeviceX11::new_output_buffer %d creating output_frame\n", __LINE__);
449                                 output_frame = new VFrame(device->out_w, device->out_h, file_colormodel);
450                         }
451                         color_model_selected = 1;
452                 }
453                 else if( bitmap_type == BITMAP_PRIMARY ) {
454                         output_frame->set_memory(bitmap);
455                 }
456         }
457
458         *result = output_frame;
459 //printf("VDeviceX11::new_output_buffer 10 %d\n", output->get_canvas()->get_window_lock());
460
461         output->get_canvas()->unlock_window();
462         output->unlock_canvas();
463 }
464
465
466 int VDeviceX11::start_playback()
467 {
468 // Record window is initialized when its monitor starts.
469         if( !device->single_frame )
470                 output->start_video();
471         return 0;
472 }
473
474 int VDeviceX11::stop_playback()
475 {
476         if( !device->single_frame )
477                 output->stop_video();
478 // Record window goes back to monitoring
479 // get the last frame played and store it in the video_out
480         return 0;
481 }
482
483 int VDeviceX11::write_buffer(VFrame *output_channels, EDL *edl)
484 {
485         output->lock_canvas("VDeviceX11::write_buffer");
486         output->get_canvas()->lock_window("VDeviceX11::write_buffer 1");
487 //      if( device->out_config->driver == PLAYBACK_X11_GL &&
488 //          output_frame->get_color_model() != BC_RGB888 ) {
489 // this is handled by overlay call in virtualvnode, using flatten alpha
490 // invoked when is_nested = -1 is passed to vdevicex11->overlay(...)
491 //      }
492
493 // printf("VDeviceX11::write_buffer %d %d bitmap_type=%d\n",
494 // __LINE__,
495 // output->get_canvas()->get_video_on(),
496 // bitmap_type);
497
498 //      int use_bitmap_extents = 0;
499 //      canvas_w = -1;  canvas_h = -1;
500 // // Canvas may be a different size than the temporary bitmap for pure software
501 //      if( bitmap_type == BITMAP_TEMP && !bitmap->hardware_scaling() ) {
502 //              canvas_w = bitmap->get_w();
503 //              canvas_h = bitmap->get_h();
504 //      }
505 //
506 //      output->get_transfers(edl,
507 //              output_x1, output_y1, output_x2, output_y2,
508 //              canvas_x1, canvas_y1, canvas_x2, canvas_y2,
509 //              canvas_w, canvas_h);
510
511 // Convert colormodel
512         if( bitmap_type == BITMAP_TEMP ) {
513 // printf("VDeviceX11::write_buffer 1 %d %d, %d %d %d %d -> %d %d %d %d\n",
514 //   output->w, output->h, in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h);
515 // fflush(stdout);
516
517 // printf("VDeviceX11::write_buffer %d output_channels=%p\n", __LINE__, output_channels);
518 // printf("VDeviceX11::write_buffer %d input color_model=%d output color_model=%d\n",
519 // __LINE__, output_channels->get_color_model(), bitmap->get_color_model());
520                 if( bitmap->hardware_scaling() ) {
521                         BC_CModels::transfer(bitmap->get_row_pointers(), output_channels->get_rows(), 0, 0, 0,
522                                 output_channels->get_y(), output_channels->get_u(), output_channels->get_v(),
523                                 0, 0, output_channels->get_w(), output_channels->get_h(),
524                                 0, 0, bitmap->get_w(), bitmap->get_h(),
525                                 output_channels->get_color_model(), bitmap->get_color_model(),
526                                 -1, output_channels->get_w(), bitmap->get_w());
527                 }
528                 else {
529                         BC_CModels::transfer(bitmap->get_row_pointers(), output_channels->get_rows(), 0, 0, 0,
530                                 output_channels->get_y(), output_channels->get_u(), output_channels->get_v(),
531                                 (int)output_x1, (int)output_y1, (int)(output_x2 - output_x1), (int)(output_y2 - output_y1),
532                                 0, 0, (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
533                                 output_channels->get_color_model(), bitmap->get_color_model(),
534                                 -1, output_channels->get_w(), bitmap->get_w());
535                 }
536         }
537
538 //printf("VDeviceX11::write_buffer 4 %p\n", bitmap);
539 //for( i = 0; i < 1000; i += 4 ) bitmap->get_data()[i] = 128;
540 //printf("VDeviceX11::write_buffer 2 %d %d %d\n", bitmap_type,
541 //      bitmap->get_color_model(),
542 //      output->get_color_model());fflush(stdout);
543
544 // printf("VDeviceX11::write_buffer %d %dx%d %f %f %f %f -> %f %f %f %f\n",
545 // __LINE__, // output->w, output->h,
546 // output_x1, output_y1, output_x2, output_y2,
547 // canvas_x1, canvas_y1, canvas_x2, canvas_y2);
548
549 // Cause X server to display it
550         if( device->out_config->driver == PLAYBACK_X11_GL ) {
551 // Output is drawn in close_all if no video.
552                 if( output->get_canvas()->get_video_on() ) {
553                         canvas_w = -1;  canvas_h = -1;
554 // Canvas may be a different size than the temporary bitmap for pure software
555                         if( bitmap_type == BITMAP_TEMP &&
556                                 !bitmap->hardware_scaling() ) {
557                                 canvas_w = bitmap->get_w();
558                                 canvas_h = bitmap->get_h();
559                         }
560
561                         output->get_transfers(edl,
562                                 output_x1, output_y1, output_x2, output_y2,
563                                 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
564                                 canvas_w, canvas_h);
565
566 //printf("VDeviceX11::write_buffer %d\n", __LINE__);
567 // Draw output frame directly.  Not used for compositing.
568                         output->get_canvas()->unlock_window();
569                         output->unlock_canvas();
570                         output->mwindow->playback_3d->write_buffer(output, output_frame,
571                                 output_x1, output_y1, output_x2, output_y2,
572                                 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
573                                 is_cleared);
574                         is_cleared = 0;
575                         output->lock_canvas("VDeviceX11::write_buffer 2");
576                         output->get_canvas()->lock_window("VDeviceX11::write_buffer 2");
577                 }
578         }
579         else {
580                 if( bitmap->hardware_scaling() ) {
581                         output->get_canvas()->draw_bitmap(bitmap, !device->single_frame,
582                                 (int)canvas_x1, (int)canvas_y1,
583                                 (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
584                                 (int)output_x1, (int)output_y1,
585                                 (int)(output_x2 - output_x1), (int)(output_y2 - output_y1),
586                                 0);
587                 }
588                 else {
589 //printf("VDeviceX11::write_buffer %d x=%d y=%d w=%d h=%d\n",
590 // __LINE__, (int)canvas_x1, (int)canvas_y1,
591 // output->get_canvas()->get_w(), output->get_canvas()->get_h());
592                         output->get_canvas()->draw_bitmap(bitmap, !device->single_frame,
593                                 (int)canvas_x1, (int)canvas_y1,
594                                 (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
595                                 0, 0,
596                                 (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
597                                 0);
598 //printf("VDeviceX11::write_buffer %d bitmap=%p\n", __LINE__, bitmap);
599                 }
600                 if( !output->get_canvas()->get_video_on() )
601                         output->get_canvas()->flash(0);
602         }
603
604         output->get_canvas()->unlock_window();
605         output->unlock_canvas();
606         return 0;
607 }
608
609
610 void VDeviceX11::clear_output()
611 {
612         is_cleared = 1;
613         output->mwindow->playback_3d->clear_output(output, 0);
614         output->mwindow->playback_3d->clear_output(output, output_frame);
615 }
616
617
618 void VDeviceX11::clear_input(VFrame *frame)
619 {
620         this->output->mwindow->playback_3d->clear_input(this->output, frame);
621 }
622
623 void VDeviceX11::convert_cmodel(VFrame *output, int dst_cmodel)
624 {
625         this->output->mwindow->playback_3d->convert_cmodel(this->output,
626                 output, 
627                 dst_cmodel);
628 }
629
630 void VDeviceX11::do_camera(VFrame *output, VFrame *input,
631         float in_x1, float in_y1, float in_x2, float in_y2,
632         float out_x1, float out_y1, float out_x2, float out_y2)
633 {
634         this->output->mwindow->playback_3d->do_camera(this->output,
635                 output, input,
636                 in_x1, in_y1, in_x2, in_y2,
637                 out_x1, out_y1, out_x2, out_y2);
638 }
639
640
641 void VDeviceX11::do_fade(VFrame *output_temp, float fade)
642 {
643         this->output->mwindow->playback_3d->do_fade(this->output, output_temp, fade);
644 }
645
646 bool VDeviceX11::can_mask(int64_t start_position_project, MaskAutos *keyframe_set)
647 {
648         Auto *current = 0;
649         MaskAuto *keyframe = (MaskAuto*)keyframe_set->
650                 get_prev_auto(start_position_project, PLAY_FORWARD, current);
651         return keyframe->disable_opengl_masking ? 0 : 1;
652 }
653
654 void VDeviceX11::do_mask(VFrame *output_temp, int64_t start_position_project,
655                 MaskAutos *keyframe_set, MaskAuto *keyframe, MaskAuto *default_auto)
656 {
657         this->output->mwindow->playback_3d->do_mask(output, output_temp,
658                 start_position_project, keyframe_set, keyframe, default_auto);
659 }
660
661 void VDeviceX11::overlay(VFrame *output_frame, VFrame *input,
662                 float in_x1, float in_y1, float in_x2, float in_y2,
663                 float out_x1, float out_y1, float out_x2, float out_y2,
664                 float alpha, int mode, EDL *edl, int is_nested)
665 {
666         int interpolation_type = edl->session->interpolation_type;
667         output->mwindow->playback_3d->overlay(output, input,
668                 in_x1, in_y1, in_x2, in_y2,
669                 out_x1, out_y1, out_x2, out_y2, alpha, // 0 - 1
670                 mode, interpolation_type, output_frame, is_nested);
671 }
672
673 void VDeviceX11::run_plugin(PluginClient *client)
674 {
675         output->mwindow->playback_3d->run_plugin(output, client);
676 }
677
678 void VDeviceX11::copy_frame(VFrame *dst, VFrame *src)
679 {
680         output->mwindow->playback_3d->copy_from(output, dst, src, 1);
681 }
682