e1b5c2a91dbc0112ce2f1a714be9b8816a265517
[goodguy/history.git] / cinelerra-5.1 / cinelerra / vdevicex11.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 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 "bccapture.h"
24 #include "bcsignals.h"
25 #include "canvas.h"
26 #include "bccmodels.h"
27 #include "edl.h"
28 #include "edlsession.h"
29 #include "mwindow.h"
30 #include "playback3d.h"
31 #include "playbackconfig.h"
32 #include "preferences.h"
33 #include "recordconfig.h"
34 #include "strategies.inc"
35 #include "vdevicex11.h"
36 #include "vframe.h"
37 #include "videodevice.h"
38 #include "videowindow.h"
39 #include "videowindowgui.h"
40
41 #include <string.h>
42 #include <unistd.h>
43
44 VDeviceX11::VDeviceX11(VideoDevice *device, Canvas *output)
45  : VDeviceBase(device)
46 {
47         reset_parameters();
48         this->output = output;
49 }
50
51 VDeviceX11::~VDeviceX11()
52 {
53         close_all();
54 }
55
56 int VDeviceX11::reset_parameters()
57 {
58         output_frame = 0;
59         window_id = 0;
60         bitmap = 0;
61         bitmap_type = 0;
62         bitmap_w = 0;
63         bitmap_h = 0;
64         output_x1 = 0;
65         output_y1 = 0;
66         output_x2 = 0;
67         output_y2 = 0;
68         canvas_x1 = 0;
69         canvas_y1 = 0;
70         canvas_x2 = 0;
71         canvas_y2 = 0;
72         capture_bitmap = 0;
73         color_model_selected = 0;
74         is_cleared = 0;
75         return 0;
76 }
77
78 int VDeviceX11::open_input()
79 {
80 //printf("VDeviceX11::open_input 1\n");
81         capture_bitmap = new BC_Capture(device->in_config->w,
82                 device->in_config->h,
83                 device->in_config->screencapture_display);
84 //printf("VDeviceX11::open_input 2\n");
85
86         return 0;
87 }
88
89 int VDeviceX11::open_output()
90 {
91         if(output)
92         {
93                 output->lock_canvas("VDeviceX11::open_output");
94                 output->get_canvas()->lock_window("VDeviceX11::open_output");
95                 if(!device->single_frame)
96                         output->start_video();
97                 else
98                         output->start_single();
99                 output->get_canvas()->unlock_window();
100
101 // Enable opengl in the first routine that needs it, to reduce the complexity.
102
103                 output->unlock_canvas();
104         }
105         return 0;
106 }
107
108
109 int VDeviceX11::output_visible()
110 {
111         if(!output) return 0;
112
113         output->lock_canvas("VDeviceX11::output_visible");
114         if(output->get_canvas()->get_hidden())
115         {
116                 output->unlock_canvas();
117                 return 0;
118         }
119         else
120         {
121                 output->unlock_canvas();
122                 return 1;
123         }
124 }
125
126
127 int VDeviceX11::close_all()
128 {
129         if(output)
130         {
131                 output->lock_canvas("VDeviceX11::close_all 1");
132                 output->get_canvas()->lock_window("VDeviceX11::close_all 1");
133         }
134
135         if(output && output_frame)
136         {
137 // Copy our output frame buffer to the canvas's permanent frame buffer.
138 // They must be different buffers because the output frame is being written
139 // while the user is redrawing the canvas frame buffer over and over.
140
141                 int use_opengl = device->out_config->driver == PLAYBACK_X11_GL &&
142                         output_frame->get_opengl_state() == VFrame::SCREEN;
143                 int best_color_model = output_frame->get_color_model();
144
145 // OpenGL does YUV->RGB in the compositing step
146                 if(use_opengl)
147                         best_color_model = BC_RGB888;
148
149                 if(output->refresh_frame &&
150                         (output->refresh_frame->get_w() != device->out_w ||
151                         output->refresh_frame->get_h() != device->out_h ||
152                         output->refresh_frame->get_color_model() != best_color_model))
153                 {
154                         delete output->refresh_frame;
155                         output->refresh_frame = 0;
156                 }
157
158                 if(!output->refresh_frame)
159                 {
160                         output->refresh_frame = new VFrame(0, -1,
161                                 device->out_w, device->out_h,
162                                 best_color_model, -1);
163                 }
164
165                 if(use_opengl)
166                 {
167                         output->get_canvas()->unlock_window();
168                         output->unlock_canvas();
169
170                         output->mwindow->playback_3d->copy_from(output,
171                                 output->refresh_frame, output_frame, 0);
172                         output->lock_canvas("VDeviceX11::close_all 2");
173                         output->get_canvas()->lock_window("VDeviceX11::close_all 2");
174                 }
175                 else
176                         output->refresh_frame->copy_from(output_frame);
177
178 // // Update the status bug
179 //              if(!device->single_frame)
180 //              {
181 //                      output->stop_video();
182 //              }
183 //              else
184 //              {
185 //                      output->stop_single();
186 //              }
187
188 // Draw the first refresh with new frame.
189 // Doesn't work if video and openGL because OpenGL doesn't have
190 // the output buffer for video.
191 // Not necessary for any case if we mandate a frame advance after
192 // every stop.
193                 if(/* device->out_config->driver != PLAYBACK_X11_GL ||
194                         */ device->single_frame)
195                         output->draw_refresh();
196         }
197
198
199
200
201         if(bitmap)
202         {
203                 delete bitmap;
204                 bitmap = 0;
205         }
206
207         if(output_frame)
208         {
209                 delete output_frame;
210                 output_frame = 0;
211         }
212
213         if(capture_bitmap) delete capture_bitmap;
214
215         if(output)
216         {
217
218 // Update the status bug
219                 if(!device->single_frame)
220                 {
221                         output->stop_video();
222                 }
223                 else
224                 {
225                         output->stop_single();
226                 }
227
228                 output->get_canvas()->unlock_window();
229                 output->unlock_canvas();
230         }
231
232
233         reset_parameters();
234         return 0;
235 }
236
237 int VDeviceX11::read_buffer(VFrame *frame)
238 {
239         capture_bitmap->capture_frame(frame, device->input_x, device->input_y);
240         return 0;
241 }
242
243
244 int VDeviceX11::get_best_colormodel(Asset *asset)
245 {
246         return BC_RGB888;
247 }
248
249
250 int VDeviceX11::get_best_colormodel(int colormodel)
251 {
252         int result = -1;
253
254         if(device->out_config->driver == PLAYBACK_X11_GL)
255         {
256                 if(colormodel == BC_RGB888 ||
257                         colormodel == BC_RGBA8888 ||
258                         colormodel == BC_YUV888 ||
259                         colormodel == BC_YUVA8888 ||
260                         colormodel == BC_RGB_FLOAT ||
261                         colormodel == BC_RGBA_FLOAT)
262                 {
263                         return colormodel;
264                 }
265                 return BC_RGB888;
266         }
267
268         if(!device->single_frame)
269         {
270                 switch(colormodel)
271                 {
272                         case BC_YUV420P:
273                         case BC_YUV422P:
274                         case BC_YUV422:
275                                 result = colormodel;
276                                 break;
277                 }
278         }
279
280 // 2 more colormodels are supported by OpenGL
281         if(device->out_config->driver == PLAYBACK_X11_GL)
282         {
283                 if(colormodel == BC_RGB_FLOAT ||
284                         colormodel == BC_RGBA_FLOAT)
285                         result = colormodel;
286         }
287
288         if(result < 0)
289         {
290                 switch(colormodel)
291                 {
292                         case BC_RGB888:
293                         case BC_RGBA8888:
294                         case BC_YUV888:
295                         case BC_YUVA8888:
296                                 result = colormodel;
297                                 break;
298
299                         default:
300                                 output->lock_canvas("VDeviceX11::get_best_colormodel");
301                                 result = output->get_canvas()->get_color_model();
302                                 output->unlock_canvas();
303                                 break;
304                 }
305         }
306
307         return result;
308 }
309
310
311 void VDeviceX11::new_output_buffer(VFrame **result, int colormodel)
312 {
313 //printf("VDeviceX11::new_output_buffer 1\n");
314         output->lock_canvas("VDeviceX11::new_output_buffer");
315         output->get_canvas()->lock_window("VDeviceX11::new_output_buffer 1");
316
317 // Get the best colormodel the display can handle.
318         int best_colormodel = get_best_colormodel(colormodel);
319
320 // Only create OpenGL Pbuffer and texture.
321         if(device->out_config->driver == PLAYBACK_X11_GL)
322         {
323 // Create bitmap for initial load into texture.
324 // Not necessary to do through Playback3D.....yet
325                 if(!output_frame)
326                 {
327                         output_frame = new VFrame(0, -1,
328                                 device->out_w, device->out_h,
329                                 colormodel, -1);
330 //BUFFER2(output_frame->get_rows()[0], "VDeviceX11::new_output_buffer 1");
331                 }
332
333                 window_id = output->get_canvas()->get_id();
334                 output_frame->set_opengl_state(VFrame::RAM);
335         }
336         else
337         {
338 // Conform existing bitmap to new colormodel and output size
339                 if(bitmap)
340                 {
341 // Restart if output size changed or output colormodel changed.
342 // May have to recreate if transferring between windowed and fullscreen.
343                         if(!color_model_selected ||
344                                 (!bitmap->hardware_scaling() &&
345                                         (bitmap->get_w() != output->get_canvas()->get_w() ||
346                                         bitmap->get_h() != output->get_canvas()->get_h())) ||
347                                 colormodel != output_frame->get_color_model())
348                         {
349                                 int size_change = (bitmap->get_w() != output->get_canvas()->get_w() ||
350                                         bitmap->get_h() != output->get_canvas()->get_h());
351 //printf("VDeviceX11::new_output_buffer %d\n", __LINE__);
352                                 delete bitmap;
353                                 delete output_frame;
354                                 bitmap = 0;
355                                 output_frame = 0;
356
357 // Blank only if size changed
358                                 if(size_change)
359                                 {
360                                         output->get_canvas()->set_color(BLACK);
361                                         output->get_canvas()->draw_box(0, 0, output->w, output->h);
362                                         output->get_canvas()->flash();
363                                 }
364                         }
365                         else
366 // Update the ring buffer
367                         if(bitmap_type == BITMAP_PRIMARY)
368                         {
369 //printf("VDeviceX11::new_output_buffer %d\n", __LINE__);
370                                 output_frame->set_memory(bitmap);
371                         }
372                 }
373
374 // Create new bitmap
375                 if(!bitmap)
376                 {
377 // Try hardware accelerated
378                         switch(best_colormodel)
379                         {
380                                 case BC_YUV420P:
381                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
382                                                 output->get_canvas()->accel_available(best_colormodel, 0) &&
383                                                 !output->use_scrollbars)
384                                         {
385                                                 bitmap = new BC_Bitmap(output->get_canvas(),
386                                                         device->out_w, device->out_h,
387                                                         best_colormodel, 1);
388                                                 output_frame = new VFrame(bitmap,
389                                                         device->out_w, device->out_h,
390                                                         best_colormodel, -1);
391                                                 bitmap_type = BITMAP_PRIMARY;
392                                         }
393                                         break;
394
395                                 case BC_YUV422P:
396                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
397                                                 output->get_canvas()->accel_available(best_colormodel, 0) &&
398                                                 !output->use_scrollbars)
399                                         {
400                                                 bitmap = new BC_Bitmap(output->get_canvas(),
401                                                         device->out_w, device->out_h,
402                                                         best_colormodel, 1);
403                                                 output_frame = new VFrame(bitmap,
404                                                         device->out_w, device->out_h,
405                                                         best_colormodel, -1);
406                                                 bitmap_type = BITMAP_PRIMARY;
407                                         }
408                                         else
409                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
410                                                 output->get_canvas()->accel_available(BC_YUV422, 0))
411                                         {
412                                                 bitmap = new BC_Bitmap(output->get_canvas(),
413                                                         device->out_w,
414                                                         device->out_h,
415                                                         BC_YUV422,
416                                                         1);
417                                                 bitmap_type = BITMAP_TEMP;
418                                         }
419                                         break;
420
421                                 case BC_YUV422:
422                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
423                                                 output->get_canvas()->accel_available(best_colormodel, 0) &&
424                                                 !output->use_scrollbars)
425                                         {
426                                                 bitmap = new BC_Bitmap(output->get_canvas(),
427                                                         device->out_w, device->out_h,
428                                                         best_colormodel, 1);
429                                                 output_frame = new VFrame(bitmap,
430                                                         device->out_w, device->out_h,
431                                                         best_colormodel, -1);
432                                                 bitmap_type = BITMAP_PRIMARY;
433                                         }
434                                         else
435                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
436                                                 output->get_canvas()->accel_available(BC_YUV422P, 0))
437                                         {
438                                                 bitmap = new BC_Bitmap(output->get_canvas(),
439                                                         device->out_w, device->out_h,
440                                                         BC_YUV422P, 1);
441                                                 bitmap_type = BITMAP_TEMP;
442                                         }
443                                         break;
444                         }
445
446 // Try default colormodel
447                         if(!bitmap)
448                         {
449                                 best_colormodel = output->get_canvas()->get_color_model();
450                                 bitmap = new BC_Bitmap(output->get_canvas(),
451                                         output->get_canvas()->get_w(),
452                                         output->get_canvas()->get_h(),
453                                         best_colormodel, 1);
454                                 bitmap_type = BITMAP_TEMP;
455                         }
456
457                         if(bitmap_type == BITMAP_TEMP)
458                         {
459 // Intermediate frame
460                                 output_frame = new VFrame(0, -1,
461                                         device->out_w, device->out_h,
462                                         colormodel, -1);
463 //BUFFER2(output_frame->get_rows()[0], "VDeviceX11::new_output_buffer 2");
464                                 bitmap_type = BITMAP_TEMP;
465                         }
466                         color_model_selected = 1;
467                 }
468         }
469
470         *result = output_frame;
471 //printf("VDeviceX11::new_output_buffer 10 %d\n", output->get_canvas()->get_window_lock());
472
473         output->get_canvas()->unlock_window();
474         output->unlock_canvas();
475 }
476
477
478 int VDeviceX11::start_playback()
479 {
480 // Record window is initialized when its monitor starts.
481         if(!device->single_frame)
482                 output->start_video();
483         return 0;
484 }
485
486 int VDeviceX11::stop_playback()
487 {
488         if(!device->single_frame)
489                 output->stop_video();
490 // Record window goes back to monitoring
491 // get the last frame played and store it in the video_out
492         return 0;
493 }
494
495 int VDeviceX11::write_buffer(VFrame *output_channels, EDL *edl)
496 {
497 // The reason for not drawing single frame is that it is _always_ drawn
498 // when drawing draw_refresh in cwindowgui and vwindowgui
499         if (device->single_frame)
500                 return 0;
501
502         output->lock_canvas("VDeviceX11::write_buffer");
503         output->get_canvas()->lock_window("VDeviceX11::write_buffer 1");
504
505 // Canvas may be a different size than the temporary bitmap for pure software
506         int xfr_w, xfr_h;
507         if(bitmap_type == BITMAP_TEMP && !bitmap->hardware_scaling()) {
508                 xfr_w = bitmap->get_w();
509                 xfr_h = bitmap->get_h();
510         }
511         else
512                 xfr_w = xfr_h = -1;
513
514 //printf("VDeviceX11::write_buffer %d %d\n", __LINE__, output->get_canvas()->get_video_on());
515         output->get_transfers(edl, output_x1, output_y1, output_x2, output_y2,
516                 canvas_x1, canvas_y1, canvas_x2, canvas_y2, xfr_w, xfr_h);
517
518 // Convert colormodel
519 #if 0
520 // this is handled by overlay call in virtualvnode, using flatten alpha
521 // invoked when is_nested = -1 is passed to vdevicex11->overlay(...)
522         if(device->out_config->driver == PLAYBACK_X11_GL &&
523             output_frame->get_color_model() != BC_RGB888) {
524                 int cmodel = BC_RGB888;
525                 output->get_canvas()->unlock_window();
526                 output->unlock_canvas();
527                 output->mwindow->playback_3d->convert_cmodel(output, output_frame, cmodel);
528                 output_frame->reallocate(0,-1,0,0,0,output_frame->get_w(),output_frame->get_h(),cmodel,-1);
529                 output->lock_canvas("VDeviceX11::write_buffer 3");
530                 output->get_canvas()->lock_window("VDeviceX11::write_buffer 3");
531         }
532         else
533 #endif
534         if(bitmap_type == BITMAP_TEMP) {
535 // printf("VDeviceX11::write_buffer 1 %d %d, %d %d %d %d -> %d %d %d %d\n",
536 //  output->w, output->h, in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h );
537 // fflush(stdout);
538 //printf("VDeviceX11::write_buffer %d output_channels=%p\n", __LINE__, output_channels);
539
540
541                 if(bitmap->hardware_scaling())
542                 {
543                         BC_CModels::transfer(bitmap->get_row_pointers(),
544                                 output_channels->get_rows(), 0, 0, 0,
545                                 output_channels->get_y(),
546                                 output_channels->get_u(),
547                                 output_channels->get_v(),
548                                 0, 0,
549                                 output_channels->get_w(),
550                                 output_channels->get_h(),
551                                 0, 0,
552                                 bitmap->get_w(),
553                                 bitmap->get_h(),
554                                 output_channels->get_color_model(),
555                                 bitmap->get_color_model(),
556                                 0,
557                                 output_channels->get_w(),
558                                 bitmap->get_w());
559                 }
560                 else
561                 {
562                         BC_CModels::transfer(bitmap->get_row_pointers(),
563                                 output_channels->get_rows(), 0, 0, 0,
564                                 output_channels->get_y(),
565                                 output_channels->get_u(),
566                                 output_channels->get_v(),
567                                 (int)output_x1,
568                                 (int)output_y1,
569                                 (int)(output_x2 - output_x1),
570                                 (int)(output_y2 - output_y1),
571                                 0, 0,
572                                 (int)(canvas_x2 - canvas_x1),
573                                 (int)(canvas_y2 - canvas_y1),
574                                 output_channels->get_color_model(),
575                                 bitmap->get_color_model(),
576                                 0,
577                                 output_channels->get_w(),
578                                 bitmap->get_w());
579                 }
580         }
581
582 //printf("VDeviceX11::write_buffer 4 %p\n", bitmap);
583 //for(i = 0; i < 1000; i += 4) bitmap->get_data()[i] = 128;
584 //printf("VDeviceX11::write_buffer 2 %d %d %d\n", bitmap_type,
585 //  bitmap->get_color_model(), output->get_color_model());
586 //fflush(stdout);
587 //printf("VDeviceX11::write_buffer 2 %d %d, %f %f %f %f -> %f %f %f %f\n",
588 // output->w, output->h, output_x1, output_y1, output_x2, output_y2,
589 // canvas_x1, canvas_y1, canvas_x2, canvas_y2);
590
591 // Cause X server to display it
592         if(device->out_config->driver == PLAYBACK_X11_GL)
593         {
594 // Output is drawn in close_all if no video.
595                 if(output->get_canvas()->get_video_on())
596                 {
597 // Draw output frame directly.  Not used for compositing.
598                         output->get_canvas()->unlock_window();
599                         output->unlock_canvas();
600                         output->mwindow->playback_3d->write_buffer(output,
601                                 output_frame, output_x1, output_y1, output_x2, output_y2,
602                                 canvas_x1, canvas_y1, canvas_x2, canvas_y2, is_cleared);
603                         is_cleared = 0;
604                         output->lock_canvas("VDeviceX11::write_buffer 2");
605                         output->get_canvas()->lock_window("VDeviceX11::write_buffer 2");
606                 }
607         }
608         else
609         if(bitmap->hardware_scaling())
610         {
611                 output->get_canvas()->draw_bitmap(bitmap,
612                         !device->single_frame,
613                         (int)canvas_x1, (int)canvas_y1,
614                         (int)(canvas_x2 - canvas_x1),
615                         (int)(canvas_y2 - canvas_y1),
616                         (int)output_x1, (int)output_y1,
617                         (int)(output_x2 - output_x1),
618                         (int)(output_y2 - output_y1),
619                         0);
620         }
621         else
622         {
623 //printf("VDeviceX11::write_buffer %d bitmap=%p\n", __LINE__, bitmap);
624                 output->get_canvas()->draw_bitmap(bitmap,
625                         !device->single_frame,
626                         (int)canvas_x1, (int)canvas_y1,
627                         (int)(canvas_x2 - canvas_x1),
628                         (int)(canvas_y2 - canvas_y1),
629                         0, 0,
630                         (int)(canvas_x2 - canvas_x1),
631                         (int)(canvas_y2 - canvas_y1),
632                         0);
633 //printf("VDeviceX11::write_buffer %d bitmap=%p\n", __LINE__, bitmap);
634         }
635
636
637         output->get_canvas()->unlock_window();
638         output->unlock_canvas();
639         return 0;
640 }
641
642
643 void VDeviceX11::clear_output()
644 {
645         is_cleared = 1;
646
647         output->mwindow->playback_3d->clear_output(output,
648                 output->get_canvas()->get_video_on() ? 0 : output_frame);
649
650 }
651
652
653 void VDeviceX11::clear_input(VFrame *frame)
654 {
655         this->output->mwindow->playback_3d->clear_input(this->output, frame);
656 }
657
658 void VDeviceX11::convert_cmodel(VFrame *output, int dst_cmodel)
659 {
660         this->output->mwindow->playback_3d->convert_cmodel(this->output,
661                 output,
662                 dst_cmodel);
663 }
664
665 void VDeviceX11::do_camera(VFrame *output, VFrame *input,
666         float in_x1, float in_y1, float in_x2, float in_y2,
667         float out_x1, float out_y1, float out_x2, float out_y2)
668 {
669         this->output->mwindow->playback_3d->do_camera(
670                 this->output, output, input,
671                 in_x1, in_y1, in_x2, in_y2,
672                 out_x1, out_y1, out_x2, out_y2);
673 }
674
675
676 void VDeviceX11::do_fade(VFrame *output_temp, float fade)
677 {
678         this->output->mwindow->playback_3d->do_fade(this->output, output_temp, fade);
679 }
680
681 void VDeviceX11::do_mask(VFrame *output_temp, int64_t start_position_project,
682                 MaskAutos *keyframe_set, MaskAuto *keyframe,
683                 MaskAuto *default_auto)
684 {
685         this->output->mwindow->playback_3d->do_mask(output,
686                 output_temp, start_position_project,
687                 keyframe_set, keyframe, default_auto);
688 }
689
690 void VDeviceX11::overlay(VFrame *output_frame, VFrame *input,
691 // This is the transfer from track to output frame
692                 float in_x1, float in_y1, float in_x2, float in_y2,
693                 float out_x1, float out_y1, float out_x2, float out_y2,
694                 float alpha /*0-1*/, int mode, EDL *edl, int is_nested)
695 {
696         int interpolation_type = edl->session->interpolation_type;
697
698 // printf("VDeviceX11::overlay 1:\n"
699 // "in_x1=%f in_y1=%f in_x2=%f in_y2=%f\n"
700 // "out_x1=%f out_y1=%f out_x2=%f out_y2=%f\n",
701 // in_x1, in_y1, in_x2, in_y2,
702 // out_x1, out_y1, out_x2, out_y2);
703 // Convert node coords to canvas coords in here
704
705 // If single frame playback or nested EDL, use full sized PBuffer as output.
706         if(device->single_frame || is_nested > 0)
707         {
708                 output->mwindow->playback_3d->overlay(output, input,
709                         in_x1, in_y1, in_x2, in_y2,
710                         out_x1, out_y1, out_x2, out_y2,
711                         alpha, mode, interpolation_type,
712                         output_frame, is_nested);
713 // printf("VDeviceX11::overlay 1 %p %d %d %d\n",
714 // output_frame,
715 // output_frame->get_w(),
716 // output_frame->get_h(),
717 // output_frame->get_opengl_state());
718         }
719         else
720         {
721                 output->lock_canvas("VDeviceX11::overlay");
722                 output->get_canvas()->lock_window("VDeviceX11::overlay");
723
724 // This is the transfer from output frame to canvas
725                 output->get_transfers(edl,
726                         output_x1, output_y1, output_x2, output_y2,
727                         canvas_x1, canvas_y1, canvas_x2, canvas_y2,
728                         -1, -1);
729
730                 output->get_canvas()->unlock_window();
731                 output->unlock_canvas();
732
733
734 // Get transfer from track to canvas
735                 float track_xscale = (out_x2 - out_x1) / (in_x2 - in_x1);
736                 float track_yscale = (out_y2 - out_y1) / (in_y2 - in_y1);
737                 float canvas_xscale = (float)(canvas_x2 - canvas_x1) / (output_x2 - output_x1);
738                 float canvas_yscale = (float)(canvas_y2 - canvas_y1) / (output_y2 - output_y1);
739
740
741 // Get coordinates of canvas relative to track frame
742                 float track_x1 = (float)(output_x1 - out_x1) / track_xscale + in_x1;
743                 float track_y1 = (float)(output_y1 - out_y1) / track_yscale + in_y1;
744                 float track_x2 = (float)(output_x2 - out_x2) / track_xscale + in_x2;
745                 float track_y2 = (float)(output_y2 - out_y2) / track_yscale + in_y2;
746
747 // Clamp canvas coords to track boundary
748                 if(track_x1 < 0)
749                 {
750                         float difference = -track_x1;
751                         track_x1 += difference;
752                         canvas_x1 += difference * track_xscale * canvas_xscale;
753                 }
754                 if(track_y1 < 0)
755                 {
756                         float difference = -track_y1;
757                         track_y1 += difference;
758                         canvas_y1 += difference * track_yscale * canvas_yscale;
759                 }
760
761                 if(track_x2 > input->get_w())
762                 {
763                         float difference = track_x2 - input->get_w();
764                         track_x2 -= difference;
765                         canvas_x2 -= difference * track_xscale * canvas_xscale;
766                 }
767                 if(track_y2 > input->get_h())
768                 {
769                         float difference = track_y2 - input->get_h();
770                         track_y2 -= difference;
771                         canvas_y2 -= difference * track_yscale * canvas_yscale;
772                 }
773
774 // Overlay directly from track buffer to canvas, skipping output buffer
775                 if(track_x2 > track_x1 && track_y2 > track_y1 &&
776                         canvas_x2 > canvas_x1 && canvas_y2 > canvas_y1)
777                 {
778                         output->mwindow->playback_3d->overlay(output, input,
779                                 track_x1, track_y1, track_x2, track_y2,
780                                 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
781                                 alpha, mode, interpolation_type, 0, is_nested);
782                 }
783         }
784 }
785
786 void VDeviceX11::run_plugin(PluginClient *client)
787 {
788         output->mwindow->playback_3d->run_plugin(output, client);
789 }
790
791 void VDeviceX11::copy_frame(VFrame *dst, VFrame *src)
792 {
793         output->mwindow->playback_3d->copy_from(output, dst, src, 1);
794 }
795