342c6269419d0dc65c7c56ea0828eea58712f00e
[blender.git] / source / blender / editors / render / render_opengl.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edrend
22  */
23
24 #include <math.h>
25 #include <string.h>
26 #include <stddef.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "DNA_camera_types.h"
31 #include "BLI_math.h"
32 #include "BLI_math_color_blend.h"
33 #include "BLI_blenlib.h"
34 #include "BLI_utildefines.h"
35 #include "BLI_threads.h"
36 #include "BLI_task.h"
37
38 #include "DNA_scene_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_gpencil_types.h"
41
42 #include "BKE_camera.h"
43 #include "BKE_context.h"
44 #include "BKE_customdata.h"
45 #include "BKE_global.h"
46 #include "BKE_image.h"
47 #include "BKE_main.h"
48 #include "BKE_report.h"
49 #include "BKE_scene.h"
50 #include "BKE_sequencer.h"
51 #include "BKE_writeavi.h"
52
53 #include "DEG_depsgraph.h"
54
55 #include "DRW_engine.h"
56
57 #include "WM_api.h"
58 #include "WM_types.h"
59
60 #include "ED_screen.h"
61 #include "ED_view3d.h"
62 #include "ED_gpencil.h"
63
64 #include "RE_pipeline.h"
65 #include "IMB_imbuf_types.h"
66 #include "IMB_imbuf.h"
67 #include "IMB_colormanagement.h"
68
69 #include "RNA_access.h"
70 #include "RNA_define.h"
71
72 #include "GPU_framebuffer.h"
73 #include "GPU_glew.h"
74 #include "GPU_matrix.h"
75
76 #include "render_intern.h"
77
78 /* Define this to get timing information. */
79 // #undef DEBUG_TIME
80
81 #ifdef DEBUG_TIME
82 #  include "PIL_time.h"
83 #endif
84
85 // TODO(sergey): Find better approximation of the scheduled frames.
86 // For really highres renders it might fail still.
87 #define MAX_SCHEDULED_FRAMES 8
88
89 typedef struct OGLRender {
90   Main *bmain;
91   Render *re;
92   Scene *scene;
93   WorkSpace *workspace;
94   ViewLayer *view_layer;
95   Depsgraph *depsgraph;
96
97   View3D *v3d;
98   RegionView3D *rv3d;
99   ARegion *ar;
100
101   ScrArea *prevsa;
102   ARegion *prevar;
103
104   int views_len; /* multi-view views */
105
106   bool is_sequencer;
107   SpaceSeq *sseq;
108   struct {
109     ImBuf **ibufs_arr;
110   } seq_data;
111
112   Image *ima;
113   ImageUser iuser;
114
115   GPUOffScreen *ofs;
116   int ofs_samples;
117   bool ofs_full_samples;
118   int sizex, sizey;
119   int write_still;
120
121   ReportList *reports;
122   bMovieHandle *mh;
123   int cfrao, nfra;
124
125   int totvideos;
126
127   /* quick lookup */
128   int view_id;
129
130   /* wm vars for timer and progress cursor */
131   wmWindowManager *wm;
132   wmWindow *win;
133
134   wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/
135   void **movie_ctx_arr;
136
137   TaskScheduler *task_scheduler;
138   TaskPool *task_pool;
139   bool pool_ok;
140   bool is_animation;
141   SpinLock reports_lock;
142   unsigned int num_scheduled_frames;
143   ThreadMutex task_mutex;
144   ThreadCondition task_condition;
145
146 #ifdef DEBUG_TIME
147   double time_start;
148 #endif
149 } OGLRender;
150
151 static bool screen_opengl_is_multiview(OGLRender *oglrender)
152 {
153   View3D *v3d = oglrender->v3d;
154   RegionView3D *rv3d = oglrender->rv3d;
155   RenderData *rd = &oglrender->scene->r;
156
157   if ((rd == NULL) || ((v3d != NULL) && (rv3d == NULL))) {
158     return false;
159   }
160
161   return (rd->scemode & R_MULTIVIEW) &&
162          ((v3d == NULL) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
163 }
164
165 static void screen_opengl_views_setup(OGLRender *oglrender)
166 {
167   RenderResult *rr;
168   RenderView *rv;
169   SceneRenderView *srv;
170   bool is_multiview;
171   Object *camera;
172   View3D *v3d = oglrender->v3d;
173
174   RenderData *rd = &oglrender->scene->r;
175
176   rr = RE_AcquireResultWrite(oglrender->re);
177
178   is_multiview = screen_opengl_is_multiview(oglrender);
179
180   if (!is_multiview) {
181     /* we only have one view when multiview is off */
182     rv = rr->views.first;
183
184     if (rv == NULL) {
185       rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
186       BLI_addtail(&rr->views, rv);
187     }
188
189     while (rv->next) {
190       RenderView *rv_del = rv->next;
191       BLI_remlink(&rr->views, rv_del);
192
193       if (rv_del->rectf) {
194         MEM_freeN(rv_del->rectf);
195       }
196
197       if (rv_del->rectz) {
198         MEM_freeN(rv_del->rectz);
199       }
200
201       if (rv_del->rect32) {
202         MEM_freeN(rv_del->rect32);
203       }
204
205       MEM_freeN(rv_del);
206     }
207   }
208   else {
209     if (v3d) {
210       RE_SetOverrideCamera(oglrender->re, V3D_CAMERA_SCENE(oglrender->scene, v3d));
211     }
212
213     /* remove all the views that are not needed */
214     rv = rr->views.last;
215     while (rv) {
216       srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name));
217       if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
218         rv = rv->prev;
219       }
220       else {
221         RenderView *rv_del = rv;
222         rv = rv_del->prev;
223
224         BLI_remlink(&rr->views, rv_del);
225
226         if (rv_del->rectf) {
227           MEM_freeN(rv_del->rectf);
228         }
229
230         if (rv_del->rectz) {
231           MEM_freeN(rv_del->rectz);
232         }
233
234         if (rv_del->rect32) {
235           MEM_freeN(rv_del->rect32);
236         }
237
238         MEM_freeN(rv_del);
239       }
240     }
241
242     /* create all the views that are needed */
243     for (srv = rd->views.first; srv; srv = srv->next) {
244       if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) {
245         continue;
246       }
247
248       rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name));
249
250       if (rv == NULL) {
251         rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
252         BLI_strncpy(rv->name, srv->name, sizeof(rv->name));
253         BLI_addtail(&rr->views, rv);
254       }
255     }
256   }
257
258   if (!(is_multiview && BKE_scene_multiview_is_stereo3d(rd))) {
259     oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
260   }
261
262   /* will only work for non multiview correctly */
263   if (v3d) {
264     camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, "new opengl render view");
265     BKE_render_result_stamp_info(oglrender->scene, camera, rr, false);
266   }
267   else {
268     BKE_render_result_stamp_info(oglrender->scene, oglrender->scene->camera, rr, false);
269   }
270
271   RE_ReleaseResult(oglrender->re);
272 }
273
274 static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, RenderResult *rr)
275 {
276   Depsgraph *depsgraph = CTX_data_depsgraph(C);
277   Scene *scene = oglrender->scene;
278   ARegion *ar = oglrender->ar;
279   View3D *v3d = oglrender->v3d;
280   RegionView3D *rv3d = oglrender->rv3d;
281   Object *camera = NULL;
282   int sizex = oglrender->sizex;
283   int sizey = oglrender->sizey;
284   const short view_context = (v3d != NULL);
285   bool draw_sky = (scene->r.alphamode == R_ADDSKY);
286   float *rectf = NULL;
287   const char *viewname = RE_GetActiveRenderView(oglrender->re);
288   ImBuf *ibuf_result = NULL;
289
290   if (oglrender->is_sequencer) {
291     SpaceSeq *sseq = oglrender->sseq;
292     struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_SHOW_GPENCIL)) ? sseq->gpd : NULL;
293
294     /* use pre-calculated ImBuf (avoids deadlock), see: */
295     ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id];
296
297     if (ibuf) {
298       ImBuf *out = IMB_dupImBuf(ibuf);
299       IMB_freeImBuf(ibuf);
300       /* OpenGL render is considered to be preview and should be
301        * as fast as possible. So currently we're making sure sequencer
302        * result is always byte to simplify color management pipeline.
303        *
304        * TODO(sergey): In the case of output to float container (EXR)
305        * it actually makes sense to keep float buffer instead.
306        */
307       if (out->rect_float != NULL) {
308         IMB_rect_from_float(out);
309         imb_freerectfloatImBuf(out);
310       }
311       BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y));
312       RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
313       IMB_freeImBuf(out);
314     }
315     else if (gpd) {
316       /* If there are no strips, Grease Pencil still needs a buffer to draw on */
317       ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect);
318       RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
319       IMB_freeImBuf(out);
320     }
321
322     if (gpd) {
323       int i;
324       unsigned char *gp_rect;
325       unsigned char *render_rect =
326           (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
327
328       DRW_opengl_context_enable();
329       GPU_offscreen_bind(oglrender->ofs, true);
330
331       GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);
332       GPU_clear(GPU_COLOR_BIT | GPU_DEPTH_BIT);
333
334       wmOrtho2(0, sizex, 0, sizey);
335       GPU_matrix_translate_2f(sizex / 2, sizey / 2);
336
337       G.f |= G_FLAG_RENDER_VIEWPORT;
338       ED_annotation_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
339       G.f &= ~G_FLAG_RENDER_VIEWPORT;
340
341       gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
342       GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect);
343
344       for (i = 0; i < sizex * sizey * 4; i += 4) {
345         blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]);
346       }
347       GPU_offscreen_unbind(oglrender->ofs, true);
348       DRW_opengl_context_disable();
349
350       MEM_freeN(gp_rect);
351     }
352   }
353   else {
354     /* shouldnt suddenly give errors mid-render but possible */
355     char err_out[256] = "unknown";
356     ImBuf *ibuf_view;
357     const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL;
358
359     unsigned int draw_flags = V3D_OFSDRAW_NONE;
360     draw_flags |= (oglrender->ofs_full_samples) ? V3D_OFSDRAW_USE_FULL_SAMPLE : 0;
361
362     if (view_context) {
363       ibuf_view = ED_view3d_draw_offscreen_imbuf(depsgraph,
364                                                  scene,
365                                                  v3d->shading.type,
366                                                  v3d,
367                                                  ar,
368                                                  sizex,
369                                                  sizey,
370                                                  IB_rectfloat,
371                                                  draw_flags,
372                                                  alpha_mode,
373                                                  oglrender->ofs_samples,
374                                                  viewname,
375                                                  oglrender->ofs,
376                                                  err_out);
377
378       /* for stamp only */
379       if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
380         camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
381       }
382     }
383     else {
384       draw_flags |= V3D_OFSDRAW_SHOW_ANNOTATION;
385       ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(depsgraph,
386                                                         scene,
387                                                         NULL,
388                                                         OB_SOLID,
389                                                         scene->camera,
390                                                         oglrender->sizex,
391                                                         oglrender->sizey,
392                                                         IB_rectfloat,
393                                                         draw_flags,
394                                                         alpha_mode,
395                                                         oglrender->ofs_samples,
396                                                         viewname,
397                                                         oglrender->ofs,
398                                                         err_out);
399       camera = scene->camera;
400     }
401
402     if (ibuf_view) {
403       ibuf_result = ibuf_view;
404       rectf = (float *)ibuf_view->rect_float;
405     }
406     else {
407       fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
408     }
409   }
410
411   if (ibuf_result != NULL) {
412     if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
413       BKE_image_stamp_buf(scene, camera, NULL, NULL, rectf, rr->rectx, rr->recty, 4);
414     }
415     RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id);
416     IMB_freeImBuf(ibuf_result);
417   }
418 }
419
420 static void screen_opengl_render_write(OGLRender *oglrender)
421 {
422   Scene *scene = oglrender->scene;
423   RenderResult *rr;
424   bool ok;
425   char name[FILE_MAX];
426
427   rr = RE_AcquireResultRead(oglrender->re);
428
429   BKE_image_path_from_imformat(name,
430                                scene->r.pic,
431                                BKE_main_blendfile_path(oglrender->bmain),
432                                scene->r.cfra,
433                                &scene->r.im_format,
434                                (scene->r.scemode & R_EXTENSION) != 0,
435                                false,
436                                NULL);
437
438   /* write images as individual images or stereo */
439   BKE_render_result_stamp_info(scene, scene->camera, rr, false);
440   ok = RE_WriteRenderViewsImage(oglrender->reports, rr, scene, false, name);
441
442   RE_ReleaseResultImage(oglrender->re);
443
444   if (ok) {
445     printf("OpenGL Render written to '%s'\n", name);
446   }
447   else {
448     printf("OpenGL Render failed to write '%s'\n", name);
449   }
450 }
451
452 static void UNUSED_FUNCTION(addAlphaOverFloat)(float dest[4], const float source[4])
453 {
454   /* d = s + (1-alpha_s)d*/
455   float mul;
456
457   mul = 1.0f - source[3];
458
459   dest[0] = (mul * dest[0]) + source[0];
460   dest[1] = (mul * dest[1]) + source[1];
461   dest[2] = (mul * dest[2]) + source[2];
462   dest[3] = (mul * dest[3]) + source[3];
463 }
464
465 static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
466 {
467   RenderResult *rr;
468   RenderView *rv;
469   int view_id;
470   ImBuf *ibuf;
471   void *lock;
472
473   if (oglrender->is_sequencer) {
474     Scene *scene = oglrender->scene;
475
476     SeqRenderData context;
477     SpaceSeq *sseq = oglrender->sseq;
478     int chanshown = sseq ? sseq->chanshown : 0;
479
480     BKE_sequencer_new_render_data(oglrender->bmain,
481                                   oglrender->depsgraph,
482                                   scene,
483                                   oglrender->sizex,
484                                   oglrender->sizey,
485                                   100.0f,
486                                   false,
487                                   &context);
488
489     for (view_id = 0; view_id < oglrender->views_len; view_id++) {
490       context.view_id = view_id;
491       context.gpu_offscreen = oglrender->ofs;
492       oglrender->seq_data.ibufs_arr[view_id] = BKE_sequencer_give_ibuf(&context, CFRA, chanshown);
493     }
494   }
495
496   rr = RE_AcquireResultRead(oglrender->re);
497   for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) {
498     BLI_assert(view_id < oglrender->views_len);
499     RE_SetActiveRenderView(oglrender->re, rv->name);
500     oglrender->view_id = view_id;
501     /* render composite */
502     screen_opengl_render_doit(C, oglrender, rr);
503   }
504
505   RE_ReleaseResult(oglrender->re);
506
507   ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
508   if (ibuf) {
509     ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
510   }
511   BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
512
513   if (oglrender->write_still) {
514     screen_opengl_render_write(oglrender);
515   }
516 }
517
518 static bool screen_opengl_render_init(bContext *C, wmOperator *op)
519 {
520   /* new render clears all callbacks */
521   wmWindowManager *wm = CTX_wm_manager(C);
522   wmWindow *win = CTX_wm_window(C);
523   WorkSpace *workspace = CTX_wm_workspace(C);
524
525   Scene *scene = CTX_data_scene(C);
526   ScrArea *prevsa = CTX_wm_area(C);
527   ARegion *prevar = CTX_wm_region(C);
528   GPUOffScreen *ofs;
529   OGLRender *oglrender;
530   int sizex, sizey;
531   bool is_view_context = RNA_boolean_get(op->ptr, "view_context");
532   const bool is_animation = RNA_boolean_get(op->ptr, "animation");
533   const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
534   const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
535   char err_out[256] = "unknown";
536
537   if (G.background) {
538     BKE_report(
539         op->reports, RPT_ERROR, "Cannot use OpenGL render in background mode (no opengl context)");
540     return false;
541   }
542
543   /* only one render job at a time */
544   if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) {
545     return false;
546   }
547
548   if (is_sequencer) {
549     is_view_context = false;
550   }
551   else {
552     /* ensure we have a 3d view */
553     if (!ED_view3d_context_activate(C)) {
554       RNA_boolean_set(op->ptr, "view_context", false);
555       is_view_context = false;
556     }
557
558     if (!is_view_context && scene->camera == NULL) {
559       BKE_report(op->reports, RPT_ERROR, "Scene has no camera");
560       return false;
561     }
562   }
563
564   if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) {
565     BKE_report(
566         op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected");
567     return false;
568   }
569
570   /* stop all running jobs, except screen one. currently previews frustrate Render */
571   WM_jobs_kill_all_except(wm, CTX_wm_screen(C));
572
573   /* create offscreen buffer */
574   sizex = (scene->r.size * scene->r.xsch) / 100;
575   sizey = (scene->r.size * scene->r.ysch) / 100;
576
577   /* corrects render size with actual size, not every card supports non-power-of-two dimensions */
578   DRW_opengl_context_enable(); /* Offscreen creation needs to be done in DRW context. */
579   ofs = GPU_offscreen_create(sizex, sizey, 0, true, true, err_out);
580   DRW_opengl_context_disable();
581
582   if (!ofs) {
583     BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out);
584     return false;
585   }
586
587   /* allocate opengl render */
588   oglrender = MEM_callocN(sizeof(OGLRender), "OGLRender");
589   op->customdata = oglrender;
590
591   oglrender->ofs = ofs;
592   oglrender->sizex = sizex;
593   oglrender->sizey = sizey;
594   oglrender->bmain = CTX_data_main(C);
595   oglrender->scene = scene;
596   oglrender->workspace = workspace;
597   oglrender->view_layer = CTX_data_view_layer(C);
598   oglrender->depsgraph = CTX_data_depsgraph(C);
599   oglrender->cfrao = scene->r.cfra;
600
601   oglrender->write_still = is_write_still && !is_animation;
602   oglrender->is_animation = is_animation;
603
604   oglrender->views_len = BKE_scene_multiview_num_views_get(&scene->r);
605
606   oglrender->is_sequencer = is_sequencer;
607   if (is_sequencer) {
608     oglrender->sseq = CTX_wm_space_seq(C);
609     ImBuf **ibufs_arr = MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__);
610     oglrender->seq_data.ibufs_arr = ibufs_arr;
611   }
612
613   oglrender->prevsa = prevsa;
614   oglrender->prevar = prevar;
615
616   if (is_view_context) {
617     /* so quad view renders camera */
618     ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->ar);
619
620     oglrender->rv3d = oglrender->ar->regiondata;
621
622     /* MUST be cleared on exit */
623     memset(&oglrender->scene->customdata_mask_modal,
624            0,
625            sizeof(oglrender->scene->customdata_mask_modal));
626     ED_view3d_datamask(
627         C, oglrender->scene, oglrender->v3d, &oglrender->scene->customdata_mask_modal);
628
629     /* apply immediately in case we're rendering from a script,
630      * running notifiers again will overwrite */
631     CustomData_MeshMasks_update(&oglrender->scene->customdata_mask,
632                                 &oglrender->scene->customdata_mask_modal);
633   }
634
635   /* create render */
636   oglrender->re = RE_NewSceneRender(scene);
637
638   /* create image and image user */
639   oglrender->ima = BKE_image_verify_viewer(oglrender->bmain, IMA_TYPE_R_RESULT, "Render Result");
640   BKE_image_signal(oglrender->bmain, oglrender->ima, NULL, IMA_SIGNAL_FREE);
641   BKE_image_backup_render(oglrender->scene, oglrender->ima, true);
642
643   oglrender->iuser.scene = scene;
644   oglrender->iuser.ok = 1;
645
646   /* create render result */
647   RE_InitState(oglrender->re, NULL, &scene->r, &scene->view_layers, NULL, sizex, sizey, NULL);
648
649   /* create render views */
650   screen_opengl_views_setup(oglrender);
651
652   /* wm vars */
653   oglrender->wm = wm;
654   oglrender->win = win;
655
656   oglrender->totvideos = 0;
657   oglrender->mh = NULL;
658   oglrender->movie_ctx_arr = NULL;
659
660   if (is_animation) {
661     TaskScheduler *task_scheduler = BLI_task_scheduler_get();
662     if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
663       task_scheduler = BLI_task_scheduler_create(1);
664       oglrender->task_scheduler = task_scheduler;
665       oglrender->task_pool = BLI_task_pool_create_background(task_scheduler, oglrender);
666     }
667     else {
668       oglrender->task_scheduler = NULL;
669       oglrender->task_pool = BLI_task_pool_create(task_scheduler, oglrender);
670     }
671     oglrender->pool_ok = true;
672     BLI_spin_init(&oglrender->reports_lock);
673   }
674   else {
675     oglrender->task_scheduler = NULL;
676     oglrender->task_pool = NULL;
677   }
678   oglrender->num_scheduled_frames = 0;
679   BLI_mutex_init(&oglrender->task_mutex);
680   BLI_condition_init(&oglrender->task_condition);
681
682 #ifdef DEBUG_TIME
683   oglrender->time_start = PIL_check_seconds_timer();
684 #endif
685
686   return true;
687 }
688
689 static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
690 {
691   Main *bmain = CTX_data_main(C);
692   Scene *scene = oglrender->scene;
693   int i;
694
695   if (oglrender->is_animation) {
696     /* Trickery part for movie output:
697      *
698      * We MUST write frames in an exact order, so we only let background
699      * thread to work on that, and main thread is simply waits for that
700      * thread to do all the dirty work.
701      *
702      * After this loop is done work_and_wait() will have nothing to do,
703      * so we don't run into wrong order of frames written to the stream.
704      */
705     if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
706       BLI_mutex_lock(&oglrender->task_mutex);
707       while (oglrender->num_scheduled_frames > 0) {
708         BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
709       }
710       BLI_mutex_unlock(&oglrender->task_mutex);
711     }
712     BLI_task_pool_work_and_wait(oglrender->task_pool);
713     BLI_task_pool_free(oglrender->task_pool);
714     /* Depending on various things we might or might not use global scheduler. */
715     if (oglrender->task_scheduler != NULL) {
716       BLI_task_scheduler_free(oglrender->task_scheduler);
717     }
718     BLI_spin_end(&oglrender->reports_lock);
719   }
720   BLI_mutex_end(&oglrender->task_mutex);
721   BLI_condition_end(&oglrender->task_condition);
722
723 #ifdef DEBUG_TIME
724   printf("Total render time: %f\n", PIL_check_seconds_timer() - oglrender->time_start);
725 #endif
726
727   if (oglrender->mh) {
728     if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
729       for (i = 0; i < oglrender->totvideos; i++) {
730         oglrender->mh->end_movie(oglrender->movie_ctx_arr[i]);
731         oglrender->mh->context_free(oglrender->movie_ctx_arr[i]);
732       }
733     }
734
735     if (oglrender->movie_ctx_arr) {
736       MEM_freeN(oglrender->movie_ctx_arr);
737     }
738   }
739
740   if (oglrender->timer) { /* exec will not have a timer */
741     Depsgraph *depsgraph = oglrender->depsgraph;
742     scene->r.cfra = oglrender->cfrao;
743     BKE_scene_graph_update_for_newframe(depsgraph, bmain);
744
745     WM_event_remove_timer(oglrender->wm, oglrender->win, oglrender->timer);
746   }
747
748   WM_cursor_modal_restore(oglrender->win);
749
750   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene);
751
752   DRW_opengl_context_enable();
753   GPU_offscreen_free(oglrender->ofs);
754   DRW_opengl_context_disable();
755
756   if (oglrender->is_sequencer) {
757     MEM_freeN(oglrender->seq_data.ibufs_arr);
758   }
759
760   memset(&oglrender->scene->customdata_mask_modal,
761          0,
762          sizeof(oglrender->scene->customdata_mask_modal));
763
764   CTX_wm_area_set(C, oglrender->prevsa);
765   CTX_wm_region_set(C, oglrender->prevar);
766
767   MEM_freeN(oglrender);
768 }
769
770 static void screen_opengl_render_cancel(bContext *C, wmOperator *op)
771 {
772   screen_opengl_render_end(C, op->customdata);
773 }
774
775 /* share between invoke and exec */
776 static bool screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
777 {
778   /* initialize animation */
779   OGLRender *oglrender;
780   Scene *scene;
781
782   oglrender = op->customdata;
783   scene = oglrender->scene;
784   oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
785
786   oglrender->reports = op->reports;
787
788   if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
789     size_t width, height;
790     int i;
791
792     BKE_scene_multiview_videos_dimensions_get(
793         &scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
794     oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
795
796     if (oglrender->mh == NULL) {
797       BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported");
798       screen_opengl_render_end(C, oglrender);
799       return false;
800     }
801
802     oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies");
803
804     for (i = 0; i < oglrender->totvideos; i++) {
805       const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
806
807       oglrender->movie_ctx_arr[i] = oglrender->mh->context_create();
808       if (!oglrender->mh->start_movie(oglrender->movie_ctx_arr[i],
809                                       scene,
810                                       &scene->r,
811                                       oglrender->sizex,
812                                       oglrender->sizey,
813                                       oglrender->reports,
814                                       PRVRANGEON != 0,
815                                       suffix)) {
816         screen_opengl_render_end(C, oglrender);
817         return false;
818       }
819     }
820   }
821
822   oglrender->cfrao = scene->r.cfra;
823   oglrender->nfra = PSFRA;
824   scene->r.cfra = PSFRA;
825
826   return true;
827 }
828
829 typedef struct WriteTaskData {
830   RenderResult *rr;
831   Scene tmp_scene;
832 } WriteTaskData;
833
834 static void write_result_func(TaskPool *__restrict pool, void *task_data_v, int UNUSED(thread_id))
835 {
836   OGLRender *oglrender = (OGLRender *)BLI_task_pool_userdata(pool);
837   WriteTaskData *task_data = (WriteTaskData *)task_data_v;
838   Scene *scene = &task_data->tmp_scene;
839   RenderResult *rr = task_data->rr;
840   const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
841   const int cfra = scene->r.cfra;
842   bool ok;
843   /* Don't attempt to write if we've got an error. */
844   if (!oglrender->pool_ok) {
845     RE_FreeRenderResult(rr);
846     BLI_mutex_lock(&oglrender->task_mutex);
847     oglrender->num_scheduled_frames--;
848     BLI_condition_notify_all(&oglrender->task_condition);
849     BLI_mutex_unlock(&oglrender->task_mutex);
850     return;
851   }
852   /* Construct local thread0safe copy of reports structure which we can
853    * safely pass to the underlying functions.
854    */
855   ReportList reports;
856   BKE_reports_init(&reports, oglrender->reports->flag & ~RPT_PRINT);
857   /* Do actual save logic here, depending on the file format.
858    *
859    * NOTE: We have to construct temporary scene with proper scene->r.cfra.
860    * This is because underlying calls do not use r.cfra but use scene
861    * for that.
862    */
863   if (is_movie) {
864     ok = RE_WriteRenderViewsMovie(&reports,
865                                   rr,
866                                   scene,
867                                   &scene->r,
868                                   oglrender->mh,
869                                   oglrender->movie_ctx_arr,
870                                   oglrender->totvideos,
871                                   PRVRANGEON != 0);
872   }
873   else {
874     /* TODO(sergey): We can in theory save some CPU ticks here because we
875      * calculate file name again here.
876      */
877     char name[FILE_MAX];
878     BKE_image_path_from_imformat(name,
879                                  scene->r.pic,
880                                  BKE_main_blendfile_path(oglrender->bmain),
881                                  cfra,
882                                  &scene->r.im_format,
883                                  (scene->r.scemode & R_EXTENSION) != 0,
884                                  true,
885                                  NULL);
886
887     BKE_render_result_stamp_info(scene, scene->camera, rr, false);
888     ok = RE_WriteRenderViewsImage(NULL, rr, scene, true, name);
889     if (!ok) {
890       BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", name);
891     }
892   }
893   if (reports.list.first != NULL) {
894     BLI_spin_lock(&oglrender->reports_lock);
895     for (Report *report = reports.list.first; report != NULL; report = report->next) {
896       BKE_report(oglrender->reports, report->type, report->message);
897     }
898     BLI_spin_unlock(&oglrender->reports_lock);
899   }
900   if (!ok) {
901     oglrender->pool_ok = false;
902   }
903   RE_FreeRenderResult(rr);
904   BLI_mutex_lock(&oglrender->task_mutex);
905   oglrender->num_scheduled_frames--;
906   BLI_condition_notify_all(&oglrender->task_condition);
907   BLI_mutex_unlock(&oglrender->task_mutex);
908 }
909
910 static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
911 {
912   if (!oglrender->pool_ok) {
913     RE_FreeRenderResult(rr);
914     return false;
915   }
916   Scene *scene = oglrender->scene;
917   WriteTaskData *task_data = MEM_mallocN(sizeof(WriteTaskData), "write task data");
918   task_data->rr = rr;
919   task_data->tmp_scene = *scene;
920   BLI_mutex_lock(&oglrender->task_mutex);
921   oglrender->num_scheduled_frames++;
922   if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) {
923     BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
924   }
925   BLI_mutex_unlock(&oglrender->task_mutex);
926   BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, TASK_PRIORITY_LOW);
927   return true;
928 }
929
930 static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
931 {
932   Main *bmain = CTX_data_main(C);
933   OGLRender *oglrender = op->customdata;
934   Scene *scene = oglrender->scene;
935   Depsgraph *depsgraph = oglrender->depsgraph;
936   char name[FILE_MAX];
937   bool ok = false;
938   const bool view_context = (oglrender->v3d != NULL);
939   bool is_movie;
940   RenderResult *rr;
941
942   /* go to next frame */
943   if (CFRA < oglrender->nfra) {
944     CFRA++;
945   }
946   while (CFRA < oglrender->nfra) {
947     BKE_scene_graph_update_for_newframe(depsgraph, bmain);
948     CFRA++;
949   }
950
951   is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
952
953   if (!is_movie) {
954     BKE_image_path_from_imformat(name,
955                                  scene->r.pic,
956                                  BKE_main_blendfile_path(oglrender->bmain),
957                                  scene->r.cfra,
958                                  &scene->r.im_format,
959                                  (scene->r.scemode & R_EXTENSION) != 0,
960                                  true,
961                                  NULL);
962
963     if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
964       BLI_spin_lock(&oglrender->reports_lock);
965       BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name);
966       BLI_spin_unlock(&oglrender->reports_lock);
967       ok = true;
968       goto finally;
969     }
970   }
971
972   WM_cursor_time(oglrender->win, scene->r.cfra);
973
974   BKE_scene_graph_update_for_newframe(depsgraph, bmain);
975
976   if (view_context) {
977     if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera &&
978         oglrender->v3d->scenelock) {
979       /* since BKE_scene_graph_update_for_newframe() is used rather
980        * then ED_update_for_newframe() the camera needs to be set */
981       if (BKE_scene_camera_switch_update(scene)) {
982         oglrender->v3d->camera = scene->camera;
983       }
984     }
985   }
986   else {
987     BKE_scene_camera_switch_update(scene);
988   }
989
990   /* render into offscreen buffer */
991   screen_opengl_render_apply(C, oglrender);
992
993   /* save to disk */
994   rr = RE_AcquireResultRead(oglrender->re);
995   RenderResult *new_rr = RE_DuplicateRenderResult(rr);
996   RE_ReleaseResult(oglrender->re);
997
998   ok = schedule_write_result(oglrender, new_rr);
999
1000 finally: /* Step the frame and bail early if needed */
1001
1002   /* go to next frame */
1003   oglrender->nfra += scene->r.frame_step;
1004
1005   /* stop at the end or on error */
1006   if (CFRA >= PEFRA || !ok) {
1007     screen_opengl_render_end(C, op->customdata);
1008     return 0;
1009   }
1010
1011   return 1;
1012 }
1013
1014 static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event)
1015 {
1016   OGLRender *oglrender = op->customdata;
1017   const bool anim = RNA_boolean_get(op->ptr, "animation");
1018   bool ret;
1019
1020   switch (event->type) {
1021     case ESCKEY:
1022       /* cancel */
1023       oglrender->pool_ok = false; /* Flag pool for cancel. */
1024       screen_opengl_render_end(C, op->customdata);
1025       return OPERATOR_FINISHED;
1026     case TIMER:
1027       /* render frame? */
1028       if (oglrender->timer == event->customdata) {
1029         break;
1030       }
1031       ATTR_FALLTHROUGH;
1032     default:
1033       /* nothing to do */
1034       return OPERATOR_RUNNING_MODAL;
1035   }
1036
1037   /* run first because screen_opengl_render_anim_step can free oglrender */
1038   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene);
1039
1040   if (anim == 0) {
1041     screen_opengl_render_apply(C, op->customdata);
1042     screen_opengl_render_end(C, op->customdata);
1043     return OPERATOR_FINISHED;
1044   }
1045   else {
1046     ret = screen_opengl_render_anim_step(C, op);
1047   }
1048
1049   /* stop at the end or on error */
1050   if (ret == false) {
1051     return OPERATOR_FINISHED;
1052   }
1053
1054   return OPERATOR_RUNNING_MODAL;
1055 }
1056
1057 static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1058 {
1059   OGLRender *oglrender;
1060   const bool anim = RNA_boolean_get(op->ptr, "animation");
1061
1062   if (!screen_opengl_render_init(C, op)) {
1063     return OPERATOR_CANCELLED;
1064   }
1065
1066   if (anim) {
1067     if (!screen_opengl_render_anim_initialize(C, op)) {
1068       return OPERATOR_CANCELLED;
1069     }
1070   }
1071
1072   oglrender = op->customdata;
1073   render_view_open(C, event->x, event->y, op->reports);
1074
1075   /* view may be changed above (R_OUTPUT_WINDOW) */
1076   oglrender->win = CTX_wm_window(C);
1077
1078   WM_event_add_modal_handler(C, op);
1079   oglrender->timer = WM_event_add_timer(oglrender->wm, oglrender->win, TIMER, 0.01f);
1080
1081   return OPERATOR_RUNNING_MODAL;
1082 }
1083
1084 /* executes blocking render */
1085 static int screen_opengl_render_exec(bContext *C, wmOperator *op)
1086 {
1087   const bool is_animation = RNA_boolean_get(op->ptr, "animation");
1088
1089   if (!screen_opengl_render_init(C, op)) {
1090     return OPERATOR_CANCELLED;
1091   }
1092
1093   if (!is_animation) { /* same as invoke */
1094     /* render image */
1095     screen_opengl_render_apply(C, op->customdata);
1096     screen_opengl_render_end(C, op->customdata);
1097
1098     return OPERATOR_FINISHED;
1099   }
1100   else {
1101     bool ret = true;
1102
1103     if (!screen_opengl_render_anim_initialize(C, op)) {
1104       return OPERATOR_CANCELLED;
1105     }
1106
1107     while (ret) {
1108       ret = screen_opengl_render_anim_step(C, op);
1109     }
1110   }
1111
1112   /* no redraw needed, we leave state as we entered it */
1113   //  ED_update_for_newframe(C);
1114   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, CTX_data_scene(C));
1115
1116   return OPERATOR_FINISHED;
1117 }
1118
1119 void RENDER_OT_opengl(wmOperatorType *ot)
1120 {
1121   PropertyRNA *prop;
1122
1123   /* identifiers */
1124   ot->name = "Viewport Render";
1125   ot->description = "Take a snapshot of the active viewport";
1126   ot->idname = "RENDER_OT_opengl";
1127
1128   /* api callbacks */
1129   ot->invoke = screen_opengl_render_invoke;
1130   ot->exec = screen_opengl_render_exec; /* blocking */
1131   ot->modal = screen_opengl_render_modal;
1132   ot->cancel = screen_opengl_render_cancel;
1133
1134   ot->poll = ED_operator_screenactive;
1135
1136   prop = RNA_def_boolean(ot->srna,
1137                          "animation",
1138                          0,
1139                          "Animation",
1140                          "Render files from the animation range of this scene");
1141   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1142   prop = RNA_def_boolean(
1143       ot->srna, "sequencer", 0, "Sequencer", "Render using the sequencer's OpenGL display");
1144   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1145   prop = RNA_def_boolean(
1146       ot->srna,
1147       "write_still",
1148       0,
1149       "Write Image",
1150       "Save rendered the image to the output path (used only when animation is disabled)");
1151   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1152   prop = RNA_def_boolean(ot->srna,
1153                          "view_context",
1154                          1,
1155                          "View Context",
1156                          "Use the current 3D view for rendering, else use scene settings");
1157   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1158 }
1159
1160 /* function for getting an opengl buffer from a View3D, used by sequencer */
1161 // extern void *sequencer_view3d_cb;