793047ac184c065e6a053f2a76cff5bec546af71
[goodguy/history.git] / cinelerra-5.1 / 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
115         for( int i=0; i<SCREENCAP_BORDERS; ++i ) {
116                 BC_Popup *box = screencap_border[i];
117                 box->set_bg_color(SCREENCAP_COLOR);
118                 box->clear_box(0, 0, box->get_w(), box->get_h());
119                 box->flash(0);
120                 box->show_window();
121         }
122
123         device->mwindow->gui->unlock_window();
124
125         return 0;
126 }
127
128 int VDeviceX11::open_output()
129 {
130         if( output ) {
131                 output->lock_canvas("VDeviceX11::open_output");
132                 output->get_canvas()->lock_window("VDeviceX11::open_output");
133                 if( !device->single_frame )
134                         output->start_video();
135                 else
136                         output->start_single();
137                 output->get_canvas()->unlock_window();
138
139 // Enable opengl in the first routine that needs it, to reduce the complexity.
140                 output->unlock_canvas();
141         }
142         return 0;
143 }
144
145
146 int VDeviceX11::output_visible()
147 {
148         if( !output ) return 0;
149
150         output->lock_canvas("VDeviceX11::output_visible");
151         if( output->get_canvas()->get_hidden() ) {
152                 output->unlock_canvas();
153                 return 0; 
154         }
155         else {
156                 output->unlock_canvas();
157                 return 1;
158         }
159 }
160
161
162 int VDeviceX11::close_all()
163 {
164         if( output ) {
165                 output->lock_canvas("VDeviceX11::close_all 1");
166                 output->get_canvas()->lock_window("VDeviceX11::close_all 1");
167         }
168
169         if( output && output_frame ) {
170                 output->update_refresh(device, output_frame);
171                 if( device->single_frame )
172                         output->draw_refresh();
173         }
174
175         delete bitmap;          bitmap = 0;
176         delete output_frame;    output_frame = 0;
177         delete capture_bitmap;  capture_bitmap = 0;
178
179         if( output ) {
180 // Update the status bug
181                 if( !device->single_frame ) {
182                         output->stop_video();
183                 }
184                 else {
185                         output->stop_single();
186                 }
187
188                 output->get_canvas()->unlock_window();
189                 output->unlock_canvas();
190         }
191
192         if( device->mwindow ) {
193                 device->mwindow->gui->lock_window("VDeviceX11::close_all");
194                 for( int i=0; i<SCREENCAP_BORDERS; ++i ) {
195                         delete screencap_border[i];
196                         screencap_border[i] = 0;
197                 }
198                 device->mwindow->gui->unlock_window();
199         }
200         
201         reset_parameters();
202
203         return 0;
204 }
205
206 int VDeviceX11::read_buffer(VFrame *frame)
207 {
208 //printf("VDeviceX11::read_buffer %d colormodel=%d\n", __LINE__, frame->get_color_model());
209         device->mwindow->gui->lock_window("VDeviceX11::close_all");
210
211         screencap_border[0]->reposition_window(device->input_x - SCREENCAP_PIXELS,
212                         device->input_y - SCREENCAP_PIXELS);
213         screencap_border[1]->reposition_window(device->input_x - SCREENCAP_PIXELS,
214                         device->input_y);
215         screencap_border[2]->reposition_window(device->input_x - SCREENCAP_PIXELS,
216                         device->input_y + device->in_config->h);
217         screencap_border[3]->reposition_window(device->input_x + device->in_config->w,
218                         device->input_y);
219         device->mwindow->gui->flush();
220         device->mwindow->gui->unlock_window();
221
222
223         capture_bitmap->capture_frame(frame, 
224                 device->input_x, device->input_y, device->do_cursor);
225         return 0;
226 }
227
228
229 int VDeviceX11::get_best_colormodel(Asset *asset)
230 {
231         return File::get_best_colormodel(asset, SCREENCAPTURE);
232 //      return BC_RGB888;
233 }
234
235
236 int VDeviceX11::get_display_colormodel(int file_colormodel)
237 {
238         int result = -1;
239
240         if( device->out_config->driver == PLAYBACK_X11_GL ) {
241                 if( file_colormodel == BC_RGB888 ||
242                         file_colormodel == BC_RGBA8888 ||
243                         file_colormodel == BC_YUV888 ||
244                         file_colormodel == BC_YUVA8888 ||
245                         file_colormodel == BC_RGB_FLOAT ||
246                         file_colormodel == BC_RGBA_FLOAT ) {
247                         return file_colormodel;
248                 }
249                 
250                 return BC_RGB888;
251         }
252
253         if( !device->single_frame ) {
254                 switch( file_colormodel ) {
255                 case BC_YUV420P:
256                 case BC_YUV422P:
257                 case BC_YUV422:
258                         result = file_colormodel;
259                         break;
260                 }
261         }
262
263 // 2 more colormodels are supported by OpenGL
264         if( device->out_config->driver == PLAYBACK_X11_GL ) {
265                 if( file_colormodel == BC_RGB_FLOAT ||
266                     file_colormodel == BC_RGBA_FLOAT )
267                         result = file_colormodel;
268         }
269
270         if( result < 0 ) {
271                 switch( file_colormodel ) {
272                 case BC_RGB888:
273                 case BC_RGBA8888:
274                 case BC_YUV888:
275                 case BC_YUVA8888:
276                 case BC_RGB_FLOAT:
277                 case BC_RGBA_FLOAT:
278                         result = file_colormodel;
279                         break;
280
281                 default:
282                         output->lock_canvas("VDeviceX11::get_display_colormodel");
283                         result = output->get_canvas()->get_color_model();
284                         output->unlock_canvas();
285                         break;
286                 }
287         }
288
289         return result;
290 }
291
292
293 void VDeviceX11::new_output_buffer(VFrame **result, int file_colormodel, EDL *edl)
294 {
295 // printf("VDeviceX11::new_output_buffer %d hardware_scaling=%d\n",
296 // __LINE__, bitmap ? bitmap->hardware_scaling() : 0);
297         output->lock_canvas("VDeviceX11::new_output_buffer");
298         output->get_canvas()->lock_window("VDeviceX11::new_output_buffer 1");
299
300 // Get the best colormodel the display can handle.
301         int display_colormodel = get_display_colormodel(file_colormodel);
302
303 //printf("VDeviceX11::new_output_buffer %d file_colormodel=%d display_colormodel=%d\n",
304 // __LINE__, file_colormodel, display_colormodel);
305 // Only create OpenGL Pbuffer and texture.
306         if( device->out_config->driver == PLAYBACK_X11_GL ) {
307 // Create bitmap for initial load into texture.
308 // Not necessary to do through Playback3D.....yet
309                 if( !output_frame ) {
310                         output_frame = new VFrame(device->out_w, device->out_h, file_colormodel);
311                 }
312
313                 window_id = output->get_canvas()->get_id();
314                 output_frame->set_opengl_state(VFrame::RAM);
315         }
316         else {
317                 output->get_transfers(edl, 
318                         output_x1, output_y1, output_x2, output_y2, 
319                         canvas_x1, canvas_y1, canvas_x2, canvas_y2,
320 // Canvas may be a different size than the temporary bitmap for pure software
321                         -1, -1);
322                 canvas_w = canvas_x2 - canvas_x1;
323                 canvas_h = canvas_y2 - canvas_y1;
324 // can the direct frame be used?
325                 int direct_supported = 
326                         device->out_config->use_direct_x11 &&
327                         !output->xscroll && !output->yscroll &&
328                         output_x1 == 0 && output_x2 == device->out_w &&
329                         output_y1 == 0 && output_y2 == device->out_h;
330
331 // file wants direct frame but we need a temp
332                 if( !direct_supported && file_colormodel == BC_BGR8888 )
333                         file_colormodel = BC_RGB888;
334
335 // Conform existing bitmap to new colormodel and output size
336                 if( bitmap ) {
337 // printf("VDeviceX11::new_output_buffer %d bitmap=%dx%d canvas=%dx%d canvas=%dx%d\n",
338 // __LINE__, bitmap->get_w(), bitmap->get_h(), canvas_w, canvas_h,);
339                         int size_change = (
340                                 bitmap->get_w() != canvas_w ||
341                                 bitmap->get_h() != canvas_h );
342
343 // Restart if output size changed or output colormodel changed.
344 // May have to recreate if transferring between windowed and fullscreen.
345                         if( !color_model_selected ||
346                             file_colormodel != output_frame->get_color_model() ||
347                             (!bitmap->hardware_scaling() && size_change) ) {
348 //printf("VDeviceX11::new_output_buffer %d file_colormodel=%d prev "
349 // "file_colormodel=%d bitmap=%p output_frame=%p\n", __LINE__,
350 // file_colormodel, output_frame->get_color_model(), bitmap, output_frame);
351                                 delete bitmap;        bitmap = 0;
352                                 delete output_frame;  output_frame = 0;
353 // Clear borders if size changed
354                                 if( size_change ) {
355 //printf("VDeviceX11::new_output_buffer %d w=%d h=%d "
356 // "canvas_x1=%d canvas_y1=%d canvas_x2=%d canvas_y2=%d\n",
357 // __LINE__, // (int)output->w, (int)output->h,
358 // (int)canvas_x1, (int)canvas_y1, (int)canvas_x2, (int)canvas_y2);
359                                         output->get_canvas()->set_color(BLACK);
360
361                                         if( canvas_y1 > 0 ) {
362                                                 output->get_canvas()->draw_box(0, 0, output->w, canvas_y1);
363                                                 output->get_canvas()->flash(0, 0, output->w, canvas_y1);
364                                         }
365
366                                         if( canvas_y2 < output->h ) {
367                                                 output->get_canvas()->draw_box(0, canvas_y2, output->w, output->h - canvas_y2);
368                                                 output->get_canvas()->flash(0, canvas_y2, output->w, output->h - canvas_y2);
369                                         }
370
371                                         if( canvas_x1 > 0 ) {
372                                                 output->get_canvas()->draw_box(0, canvas_y1, canvas_x1, canvas_y2 - canvas_y1);
373                                                 output->get_canvas()->flash(0, canvas_y1, canvas_x1, canvas_y2 - canvas_y1);
374                                         }
375
376                                         if( canvas_x2 < output->w ) {
377                                                 output->get_canvas()->draw_box(canvas_x2, canvas_y1,
378                                                         output->w - canvas_x2, canvas_y2 - canvas_y1);
379                                                 output->get_canvas()->flash(canvas_x2, canvas_y1,
380                                                         output->w - canvas_x2, canvas_y2 - canvas_y1);
381                                         }
382                                 }
383                         }
384                 }
385
386 // Create new bitmap
387                 if( !bitmap ) {
388                         int use_direct = 0;
389                         bitmap_type = BITMAP_TEMP;
390 //printf("VDeviceX11::new_output_buffer %d file_colormodel=%d display_colormodel=%d\n", 
391 // __LINE__, file_colormodel, display_colormodel);
392
393 // Try hardware accelerated
394                         switch( display_colormodel ) {
395 // blit from the codec directly to the window, using the standard X11 color model.
396 // Must scale in the codec.  No cropping
397                         case BC_BGR8888:
398                                 if( direct_supported ) {
399                                         bitmap_type = BITMAP_PRIMARY;
400                                         use_direct = 1;
401                                 }
402                                 break;
403
404                         case BC_YUV420P:
405                                 if( device->out_config->driver == PLAYBACK_X11_XV &&
406                                     output->get_canvas()->accel_available(display_colormodel, 0) &&
407                                     !output->use_scrollbars )
408                                         bitmap_type = BITMAP_PRIMARY;
409                                 break;
410
411                         case BC_YUV422P:
412                                 if( device->out_config->driver == PLAYBACK_X11_XV &&
413                                     output->get_canvas()->accel_available(display_colormodel, 0) &&
414                                     !output->use_scrollbars )
415                                         bitmap_type = BITMAP_PRIMARY;
416                                 else if( device->out_config->driver == PLAYBACK_X11_XV &&
417                                     output->get_canvas()->accel_available(BC_YUV422, 0) ) {
418                                         bitmap = new BC_Bitmap(output->get_canvas(), 
419                                                 device->out_w, device->out_h, BC_YUV422, 1);
420                                 }
421                                 break;
422
423                         case BC_YUV422:
424                                 if( device->out_config->driver == PLAYBACK_X11_XV &&
425                                     output->get_canvas()->accel_available(display_colormodel, 0) &&
426                                     !output->use_scrollbars ) {
427                                         bitmap_type = BITMAP_PRIMARY;
428                                 }
429                                 else if( device->out_config->driver == PLAYBACK_X11_XV &&
430                                     output->get_canvas()->accel_available(BC_YUV422P, 0) ) {
431                                         bitmap = new BC_Bitmap(output->get_canvas(), 
432                                                 device->out_w, device->out_h, BC_YUV422P, 1);
433                                 }
434                                 break;
435                         }
436                         if( bitmap_type == BITMAP_PRIMARY ) {
437                                 int bitmap_w = use_direct ? canvas_w : device->out_w;
438                                 int bitmap_h = use_direct ? canvas_h : device->out_h;
439                                 bitmap = new BC_Bitmap(output->get_canvas(),
440                                         bitmap_w, bitmap_h,  display_colormodel, -1);
441                                 output_frame = new VFrame(bitmap,
442                                         bitmap_w, bitmap_h, display_colormodel, -1);
443                         }
444 // Make an intermediate frame
445                         if( !bitmap ) {
446                                 display_colormodel = output->get_canvas()->get_color_model();
447 // printf("VDeviceX11::new_output_buffer %d creating temp display_colormodel=%d "
448 // "file_colormodel=%d %dx%d %dx%d %dx%d\n", __LINE__,
449 // display_colormodel, file_colormodel, device->out_w, device->out_h,
450 // output->get_canvas()->get_w(), output->get_canvas()->get_h(), canvas_w, canvas_h);
451                                 bitmap = new BC_Bitmap(output->get_canvas(), 
452                                         canvas_w, canvas_h, display_colormodel, 1);
453                                 bitmap_type = BITMAP_TEMP;
454                         }
455
456                         if( bitmap_type == BITMAP_TEMP ) {
457 // Intermediate frame
458 //printf("VDeviceX11::new_output_buffer %d creating output_frame\n", __LINE__);
459                                 output_frame = new VFrame(device->out_w, device->out_h, file_colormodel);
460                         }
461                         color_model_selected = 1;
462                 }
463                 else if( bitmap_type == BITMAP_PRIMARY ) {
464                         output_frame->set_memory(bitmap);
465                 }
466         }
467
468         *result = output_frame;
469 //printf("VDeviceX11::new_output_buffer 10 %d\n", output->get_canvas()->get_window_lock());
470
471         output->get_canvas()->unlock_window();
472         output->unlock_canvas();
473 }
474
475
476 int VDeviceX11::start_playback()
477 {
478 // Record window is initialized when its monitor starts.
479         if( !device->single_frame )
480                 output->start_video();
481         return 0;
482 }
483
484 int VDeviceX11::stop_playback()
485 {
486         if( !device->single_frame )
487                 output->stop_video();
488 // Record window goes back to monitoring
489 // get the last frame played and store it in the video_out
490         return 0;
491 }
492
493 int VDeviceX11::write_buffer(VFrame *output_channels, EDL *edl)
494 {
495         output->lock_canvas("VDeviceX11::write_buffer");
496         output->get_canvas()->lock_window("VDeviceX11::write_buffer 1");
497 //      if( device->out_config->driver == PLAYBACK_X11_GL &&
498 //          output_frame->get_color_model() != BC_RGB888 ) {
499 // this is handled by overlay call in virtualvnode, using flatten alpha
500 // invoked when is_nested = -1 is passed to vdevicex11->overlay(...)
501 //      }
502
503 // printf("VDeviceX11::write_buffer %d %d bitmap_type=%d\n", 
504 // __LINE__, 
505 // output->get_canvas()->get_video_on(),
506 // bitmap_type);
507
508 //      int use_bitmap_extents = 0;
509 //      canvas_w = -1;  canvas_h = -1;
510 // // Canvas may be a different size than the temporary bitmap for pure software
511 //      if( bitmap_type == BITMAP_TEMP && !bitmap->hardware_scaling() ) {
512 //              canvas_w = bitmap->get_w();
513 //              canvas_h = bitmap->get_h();
514 //      }
515 // 
516 //      output->get_transfers(edl, 
517 //              output_x1, output_y1, output_x2, output_y2, 
518 //              canvas_x1, canvas_y1, canvas_x2, canvas_y2,
519 //              canvas_w, canvas_h);
520
521 // Convert colormodel
522         if( bitmap_type == BITMAP_TEMP ) {
523 // printf("VDeviceX11::write_buffer 1 %d %d, %d %d %d %d -> %d %d %d %d\n",
524 //   output->w, output->h, in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h);
525 // fflush(stdout);
526
527 // printf("VDeviceX11::write_buffer %d output_channels=%p\n", __LINE__, output_channels);
528 // printf("VDeviceX11::write_buffer %d input color_model=%d output color_model=%d\n", 
529 // __LINE__, output_channels->get_color_model(), bitmap->get_color_model());
530                 if( bitmap->hardware_scaling() ) {
531                         BC_CModels::transfer(bitmap->get_row_pointers(), output_channels->get_rows(), 0, 0, 0,
532                                 output_channels->get_y(), output_channels->get_u(), output_channels->get_v(),
533                                 0, 0, output_channels->get_w(), output_channels->get_h(),
534                                 0, 0, bitmap->get_w(), bitmap->get_h(),
535                                 output_channels->get_color_model(), bitmap->get_color_model(),
536                                 0, output_channels->get_w(), bitmap->get_w());
537                 }
538                 else {
539                         BC_CModels::transfer(bitmap->get_row_pointers(), output_channels->get_rows(), 0, 0, 0,
540                                 output_channels->get_y(), output_channels->get_u(), output_channels->get_v(),
541                                 (int)output_x1, (int)output_y1, (int)(output_x2 - output_x1), (int)(output_y2 - output_y1),
542                                 0, 0, (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
543                                 output_channels->get_color_model(), bitmap->get_color_model(),
544                                 0, output_channels->get_w(), bitmap->get_w());
545                 }
546         }
547
548 //printf("VDeviceX11::write_buffer 4 %p\n", bitmap);
549 //for( i = 0; i < 1000; i += 4 ) bitmap->get_data()[i] = 128;
550 //printf("VDeviceX11::write_buffer 2 %d %d %d\n", bitmap_type, 
551 //      bitmap->get_color_model(), 
552 //      output->get_color_model());fflush(stdout);
553
554 // printf("VDeviceX11::write_buffer %d %dx%d %f %f %f %f -> %f %f %f %f\n",
555 // __LINE__, // output->w, output->h,
556 // output_x1, output_y1, output_x2, output_y2,
557 // canvas_x1, canvas_y1, canvas_x2, canvas_y2);
558
559 // Cause X server to display it
560         if( device->out_config->driver == PLAYBACK_X11_GL ) {
561 // Output is drawn in close_all if no video.
562                 if( output->get_canvas()->get_video_on() ) {
563                         canvas_w = -1;  canvas_h = -1;
564 // Canvas may be a different size than the temporary bitmap for pure software
565                         if( bitmap_type == BITMAP_TEMP && 
566                                 !bitmap->hardware_scaling() ) {
567                                 canvas_w = bitmap->get_w();
568                                 canvas_h = bitmap->get_h();
569                         }
570
571                         output->get_transfers(edl, 
572                                 output_x1, output_y1, output_x2, output_y2, 
573                                 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
574                                 canvas_w, canvas_h);
575
576 //printf("VDeviceX11::write_buffer %d\n", __LINE__);
577 // Draw output frame directly.  Not used for compositing.
578                         output->get_canvas()->unlock_window();
579                         output->unlock_canvas();
580                         output->mwindow->playback_3d->write_buffer(output, output_frame,
581                                 output_x1, output_y1, output_x2, output_y2,
582                                 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
583                                 is_cleared);
584                         is_cleared = 0;
585                         output->lock_canvas("VDeviceX11::write_buffer 2");
586                         output->get_canvas()->lock_window("VDeviceX11::write_buffer 2");
587                 }
588         }
589         else
590         if( bitmap->hardware_scaling() ) {
591                 output->get_canvas()->draw_bitmap(bitmap, !device->single_frame,
592                         (int)canvas_x1, (int)canvas_y1,
593                         (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
594                         (int)output_x1, (int)output_y1,
595                         (int)(output_x2 - output_x1), (int)(output_y2 - output_y1),
596                         0);
597         }
598         else {
599 //printf("VDeviceX11::write_buffer %d x=%d y=%d w=%d h=%d\n", 
600 // __LINE__, (int)canvas_x1, (int)canvas_y1,
601 // output->get_canvas()->get_w(), output->get_canvas()->get_h());
602
603                 output->get_canvas()->draw_bitmap(bitmap, !device->single_frame,
604                         (int)canvas_x1, (int)canvas_y1,
605                         (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
606                         0, 0, 
607                         (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
608                         0);
609 //printf("VDeviceX11::write_buffer %d bitmap=%p\n", __LINE__, bitmap);
610         }
611
612         output->get_canvas()->unlock_window();
613         output->unlock_canvas();
614         return 0;
615 }
616
617
618 void VDeviceX11::clear_output()
619 {
620         is_cleared = 1;
621
622         output->mwindow->playback_3d->clear_output(output,
623                 output->get_canvas()->get_video_on() ? 0 : output_frame);
624
625 }
626
627
628 void VDeviceX11::clear_input(VFrame *frame)
629 {
630         this->output->mwindow->playback_3d->clear_input(this->output, frame);
631 }
632
633 void VDeviceX11::convert_cmodel(VFrame *output, int dst_cmodel)
634 {
635         this->output->mwindow->playback_3d->convert_cmodel(this->output,
636                 output, 
637                 dst_cmodel);
638 }
639
640 void VDeviceX11::do_camera(VFrame *output, VFrame *input,
641         float in_x1, float in_y1, float in_x2, float in_y2, 
642         float out_x1, float out_y1, float out_x2, float out_y2)
643 {
644         this->output->mwindow->playback_3d->do_camera(this->output, 
645                 output, input,
646                 in_x1, in_y1, in_x2, in_y2, 
647                 out_x1, out_y1, out_x2, out_y2);
648 }
649
650
651 void VDeviceX11::do_fade(VFrame *output_temp, float fade)
652 {
653         this->output->mwindow->playback_3d->do_fade(this->output, output_temp, fade);
654 }
655
656 bool VDeviceX11::can_mask(int64_t start_position_project, MaskAutos *keyframe_set)
657 {
658         Auto *current = 0;
659         MaskAuto *keyframe = (MaskAuto*)keyframe_set->
660                 get_prev_auto(start_position_project, PLAY_FORWARD, current);
661         return keyframe->disable_opengl_masking ? 0 : 1;
662 }
663
664 void VDeviceX11::do_mask(VFrame *output_temp, int64_t start_position_project,
665                 MaskAutos *keyframe_set, MaskAuto *keyframe, MaskAuto *default_auto)
666 {
667         this->output->mwindow->playback_3d->do_mask(output, output_temp,
668                 start_position_project, keyframe_set, keyframe, default_auto);
669 }
670
671 void VDeviceX11::overlay(VFrame *output_frame, VFrame *input, 
672 // This is the transfer from track to output frame
673                 float in_x1, float in_y1, float in_x2, float in_y2, 
674                 float out_x1, float out_y1, float out_x2, float out_y2, 
675                 float alpha,        // 0 - 1
676                 int mode, EDL *edl, int is_nested)
677 {
678         int interpolation_type = edl->session->interpolation_type;
679
680 // printf("VDeviceX11::overlay 1:\n"
681 // "in_x1=%f in_y1=%f in_x2=%f in_y2=%f\n"
682 // "out_x1=%f out_y1=%f out_x2=%f out_y2=%f\n",
683 // in_x1, in_y1, in_x2, in_y2, out_x1, out_y1, out_x2, out_y2);
684 // Convert node coords to canvas coords in here
685
686 // If single frame playback or nested EDL, use full sized PBuffer as output.
687         if( device->single_frame || is_nested > 0 ) {
688                 output->mwindow->playback_3d->overlay(output, input,
689                         in_x1, in_y1, in_x2, in_y2, 
690                         out_x1, out_y1, out_x2, out_y2, alpha, // 0 - 1
691                         mode, interpolation_type, output_frame, is_nested);
692 // printf("VDeviceX11::overlay 1 %p %d %d %d\n", 
693 // output_frame, output_frame->get_w(), output_frame->get_h(),
694 // output_frame->get_opengl_state());
695         }
696         else {
697                 output->lock_canvas("VDeviceX11::overlay");
698                 output->get_canvas()->lock_window("VDeviceX11::overlay");
699
700 // This is the transfer from output frame to canvas
701                 output->get_transfers(edl, 
702                         output_x1, output_y1, output_x2, output_y2, 
703                         canvas_x1, canvas_y1, canvas_x2, canvas_y2,
704                         -1, -1);
705
706                 output->get_canvas()->unlock_window();
707                 output->unlock_canvas();
708
709
710 // Get transfer from track to canvas
711                 float track_xscale = (out_x2 - out_x1) / (in_x2 - in_x1);
712                 float track_yscale = (out_y2 - out_y1) / (in_y2 - in_y1);
713                 float canvas_xscale = (float)(canvas_x2 - canvas_x1) / (output_x2 - output_x1);
714                 float canvas_yscale = (float)(canvas_y2 - canvas_y1) / (output_y2 - output_y1);
715
716
717 // Get coordinates of canvas relative to track frame
718                 float track_x1 = (float)(output_x1 - out_x1) / track_xscale + in_x1;
719                 float track_y1 = (float)(output_y1 - out_y1) / track_yscale + in_y1;
720                 float track_x2 = (float)(output_x2 - out_x2) / track_xscale + in_x2;
721                 float track_y2 = (float)(output_y2 - out_y2) / track_yscale + in_y2;
722
723 // Clamp canvas coords to track boundary
724                 if( track_x1 < 0 ) {
725                         float difference = -track_x1;
726                         track_x1 += difference;
727                         canvas_x1 += difference * track_xscale * canvas_xscale;
728                 }
729                 if( track_y1 < 0 ) {
730                         float difference = -track_y1;
731                         track_y1 += difference;
732                         canvas_y1 += difference * track_yscale * canvas_yscale;
733                 }
734
735                 if( track_x2 > input->get_w() ) {
736                         float difference = track_x2 - input->get_w();
737                         track_x2 -= difference;
738                         canvas_x2 -= difference * track_xscale * canvas_xscale;
739                 }
740                 if( track_y2 > input->get_h() ) {
741                         float difference = track_y2 - input->get_h();
742                         track_y2 -= difference;
743                         canvas_y2 -= difference * track_yscale * canvas_yscale;
744                 }
745
746 // Overlay directly from track buffer to canvas, skipping output buffer
747                 if( track_x2 > track_x1 && track_y2 > track_y1 &&
748                         canvas_x2 > canvas_x1 && canvas_y2 > canvas_y1 ) {
749                         output->mwindow->playback_3d->overlay(output, input,
750                                 track_x1, track_y1, track_x2, track_y2, 
751                                 canvas_x1, canvas_y1, canvas_x2, canvas_y2, alpha, // 0 - 1
752                                 mode, interpolation_type, 0, is_nested);
753                 }
754         }
755 }
756
757 void VDeviceX11::run_plugin(PluginClient *client)
758 {
759         output->mwindow->playback_3d->run_plugin(output, client);
760 }
761
762 void VDeviceX11::copy_frame(VFrame *dst, VFrame *src)
763 {
764         output->mwindow->playback_3d->copy_from(output, dst, src, 1);
765 }
766