Cleanup: style, use braces for editors
[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_USE_GPENCIL;
385       ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(depsgraph,
386                                                         scene,
387                                                         OB_SOLID,
388                                                         scene->camera,
389                                                         oglrender->sizex,
390                                                         oglrender->sizey,
391                                                         IB_rectfloat,
392                                                         draw_flags,
393                                                         alpha_mode,
394                                                         oglrender->ofs_samples,
395                                                         viewname,
396                                                         oglrender->ofs,
397                                                         err_out);
398       camera = scene->camera;
399     }
400
401     if (ibuf_view) {
402       ibuf_result = ibuf_view;
403       rectf = (float *)ibuf_view->rect_float;
404     }
405     else {
406       fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
407     }
408   }
409
410   if (ibuf_result != NULL) {
411     if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
412       BKE_image_stamp_buf(scene, camera, NULL, NULL, rectf, rr->rectx, rr->recty, 4);
413     }
414     RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id);
415     IMB_freeImBuf(ibuf_result);
416   }
417 }
418
419 static void screen_opengl_render_write(OGLRender *oglrender)
420 {
421   Scene *scene = oglrender->scene;
422   RenderResult *rr;
423   bool ok;
424   char name[FILE_MAX];
425
426   rr = RE_AcquireResultRead(oglrender->re);
427
428   BKE_image_path_from_imformat(name,
429                                scene->r.pic,
430                                BKE_main_blendfile_path(oglrender->bmain),
431                                scene->r.cfra,
432                                &scene->r.im_format,
433                                (scene->r.scemode & R_EXTENSION) != 0,
434                                false,
435                                NULL);
436
437   /* write images as individual images or stereo */
438   BKE_render_result_stamp_info(scene, scene->camera, rr, false);
439   ok = RE_WriteRenderViewsImage(oglrender->reports, rr, scene, false, name);
440
441   RE_ReleaseResultImage(oglrender->re);
442
443   if (ok) {
444     printf("OpenGL Render written to '%s'\n", name);
445   }
446   else {
447     printf("OpenGL Render failed to write '%s'\n", name);
448   }
449 }
450
451 static void UNUSED_FUNCTION(addAlphaOverFloat)(float dest[4], const float source[4])
452 {
453   /* d = s + (1-alpha_s)d*/
454   float mul;
455
456   mul = 1.0f - source[3];
457
458   dest[0] = (mul * dest[0]) + source[0];
459   dest[1] = (mul * dest[1]) + source[1];
460   dest[2] = (mul * dest[2]) + source[2];
461   dest[3] = (mul * dest[3]) + source[3];
462 }
463
464 static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
465 {
466   RenderResult *rr;
467   RenderView *rv;
468   int view_id;
469   ImBuf *ibuf;
470   void *lock;
471
472   if (oglrender->is_sequencer) {
473     Scene *scene = oglrender->scene;
474
475     SeqRenderData context;
476     SpaceSeq *sseq = oglrender->sseq;
477     int chanshown = sseq ? sseq->chanshown : 0;
478
479     BKE_sequencer_new_render_data(oglrender->bmain,
480                                   oglrender->depsgraph,
481                                   scene,
482                                   oglrender->sizex,
483                                   oglrender->sizey,
484                                   100.0f,
485                                   false,
486                                   &context);
487
488     for (view_id = 0; view_id < oglrender->views_len; view_id++) {
489       context.view_id = view_id;
490       context.gpu_offscreen = oglrender->ofs;
491       context.gpu_full_samples = oglrender->ofs_full_samples;
492
493       oglrender->seq_data.ibufs_arr[view_id] = BKE_sequencer_give_ibuf(&context, CFRA, chanshown);
494     }
495   }
496
497   rr = RE_AcquireResultRead(oglrender->re);
498   for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) {
499     BLI_assert(view_id < oglrender->views_len);
500     RE_SetActiveRenderView(oglrender->re, rv->name);
501     oglrender->view_id = view_id;
502     /* render composite */
503     screen_opengl_render_doit(C, oglrender, rr);
504   }
505
506   RE_ReleaseResult(oglrender->re);
507
508   ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
509   if (ibuf) {
510     ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
511   }
512   BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
513
514   if (oglrender->write_still) {
515     screen_opengl_render_write(oglrender);
516   }
517 }
518
519 static bool screen_opengl_fullsample_enabled(Scene *scene)
520 {
521   if (scene->r.scemode & R_FULL_SAMPLE) {
522     return true;
523   }
524   else {
525     /* XXX TODO:
526      * Technically if the hardware supports MSAA we could keep using Blender 2.7x approach.
527      * However anti-aliasing without full_sample is not playing well even in 2.7x.
528      *
529      * For example, if you enable depth of field, there is aliasing, even if the viewport is fine.
530      * For 2.8x this is more complicated because so many things rely on shader.
531      * So until we fix the gpu_framebuffer anti-aliasing suupport we need to force full sample.
532      */
533     return true;
534   }
535 }
536
537 static bool screen_opengl_render_init(bContext *C, wmOperator *op)
538 {
539   /* new render clears all callbacks */
540   wmWindowManager *wm = CTX_wm_manager(C);
541   wmWindow *win = CTX_wm_window(C);
542   WorkSpace *workspace = CTX_wm_workspace(C);
543
544   Scene *scene = CTX_data_scene(C);
545   ScrArea *prevsa = CTX_wm_area(C);
546   ARegion *prevar = CTX_wm_region(C);
547   GPUOffScreen *ofs;
548   OGLRender *oglrender;
549   int sizex, sizey;
550   const int samples = (scene->r.mode & R_OSA) ? scene->r.osa : 0;
551   const bool full_samples = (samples != 0) && screen_opengl_fullsample_enabled(scene);
552   bool is_view_context = RNA_boolean_get(op->ptr, "view_context");
553   const bool is_animation = RNA_boolean_get(op->ptr, "animation");
554   const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
555   const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
556   char err_out[256] = "unknown";
557
558   if (G.background) {
559     BKE_report(
560         op->reports, RPT_ERROR, "Cannot use OpenGL render in background mode (no opengl context)");
561     return false;
562   }
563
564   /* only one render job at a time */
565   if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) {
566     return false;
567   }
568
569   if (is_sequencer) {
570     is_view_context = false;
571   }
572   else {
573     /* ensure we have a 3d view */
574     if (!ED_view3d_context_activate(C)) {
575       RNA_boolean_set(op->ptr, "view_context", false);
576       is_view_context = false;
577     }
578
579     if (!is_view_context && scene->camera == NULL) {
580       BKE_report(op->reports, RPT_ERROR, "Scene has no camera");
581       return false;
582     }
583   }
584
585   if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) {
586     BKE_report(
587         op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected");
588     return false;
589   }
590
591   /* stop all running jobs, except screen one. currently previews frustrate Render */
592   WM_jobs_kill_all_except(wm, CTX_wm_screen(C));
593
594   /* create offscreen buffer */
595   sizex = (scene->r.size * scene->r.xsch) / 100;
596   sizey = (scene->r.size * scene->r.ysch) / 100;
597
598   /* corrects render size with actual size, not every card supports non-power-of-two dimensions */
599   DRW_opengl_context_enable(); /* Offscreen creation needs to be done in DRW context. */
600   ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, true, true, err_out);
601   DRW_opengl_context_disable();
602
603   if (!ofs) {
604     BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out);
605     return false;
606   }
607
608   /* allocate opengl render */
609   oglrender = MEM_callocN(sizeof(OGLRender), "OGLRender");
610   op->customdata = oglrender;
611
612   oglrender->ofs = ofs;
613   oglrender->ofs_samples = samples;
614   oglrender->ofs_full_samples = full_samples;
615   oglrender->sizex = sizex;
616   oglrender->sizey = sizey;
617   oglrender->bmain = CTX_data_main(C);
618   oglrender->scene = scene;
619   oglrender->workspace = workspace;
620   oglrender->view_layer = CTX_data_view_layer(C);
621   oglrender->depsgraph = CTX_data_depsgraph(C);
622   oglrender->cfrao = scene->r.cfra;
623
624   oglrender->write_still = is_write_still && !is_animation;
625   oglrender->is_animation = is_animation;
626
627   oglrender->views_len = BKE_scene_multiview_num_views_get(&scene->r);
628
629   oglrender->is_sequencer = is_sequencer;
630   if (is_sequencer) {
631     oglrender->sseq = CTX_wm_space_seq(C);
632     ImBuf **ibufs_arr = MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__);
633     oglrender->seq_data.ibufs_arr = ibufs_arr;
634   }
635
636   oglrender->prevsa = prevsa;
637   oglrender->prevar = prevar;
638
639   if (is_view_context) {
640     /* so quad view renders camera */
641     ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->ar);
642
643     oglrender->rv3d = oglrender->ar->regiondata;
644
645     /* MUST be cleared on exit */
646     memset(&oglrender->scene->customdata_mask_modal,
647            0,
648            sizeof(oglrender->scene->customdata_mask_modal));
649     ED_view3d_datamask(
650         C, oglrender->scene, oglrender->v3d, &oglrender->scene->customdata_mask_modal);
651
652     /* apply immediately in case we're rendering from a script,
653      * running notifiers again will overwrite */
654     CustomData_MeshMasks_update(&oglrender->scene->customdata_mask,
655                                 &oglrender->scene->customdata_mask_modal);
656   }
657
658   /* create render */
659   oglrender->re = RE_NewSceneRender(scene);
660
661   /* create image and image user */
662   oglrender->ima = BKE_image_verify_viewer(oglrender->bmain, IMA_TYPE_R_RESULT, "Render Result");
663   BKE_image_signal(oglrender->bmain, oglrender->ima, NULL, IMA_SIGNAL_FREE);
664   BKE_image_backup_render(oglrender->scene, oglrender->ima, true);
665
666   oglrender->iuser.scene = scene;
667   oglrender->iuser.ok = 1;
668
669   /* create render result */
670   RE_InitState(oglrender->re, NULL, &scene->r, &scene->view_layers, NULL, sizex, sizey, NULL);
671
672   /* create render views */
673   screen_opengl_views_setup(oglrender);
674
675   /* wm vars */
676   oglrender->wm = wm;
677   oglrender->win = win;
678
679   oglrender->totvideos = 0;
680   oglrender->mh = NULL;
681   oglrender->movie_ctx_arr = NULL;
682
683   if (is_animation) {
684     TaskScheduler *task_scheduler = BLI_task_scheduler_get();
685     if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
686       task_scheduler = BLI_task_scheduler_create(1);
687       oglrender->task_scheduler = task_scheduler;
688       oglrender->task_pool = BLI_task_pool_create_background(task_scheduler, oglrender);
689     }
690     else {
691       oglrender->task_scheduler = NULL;
692       oglrender->task_pool = BLI_task_pool_create(task_scheduler, oglrender);
693     }
694     oglrender->pool_ok = true;
695     BLI_spin_init(&oglrender->reports_lock);
696   }
697   else {
698     oglrender->task_scheduler = NULL;
699     oglrender->task_pool = NULL;
700   }
701   oglrender->num_scheduled_frames = 0;
702   BLI_mutex_init(&oglrender->task_mutex);
703   BLI_condition_init(&oglrender->task_condition);
704
705 #ifdef DEBUG_TIME
706   oglrender->time_start = PIL_check_seconds_timer();
707 #endif
708
709   return true;
710 }
711
712 static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
713 {
714   Main *bmain = CTX_data_main(C);
715   Scene *scene = oglrender->scene;
716   int i;
717
718   if (oglrender->is_animation) {
719     /* Trickery part for movie output:
720      *
721      * We MUST write frames in an exact order, so we only let background
722      * thread to work on that, and main thread is simply waits for that
723      * thread to do all the dirty work.
724      *
725      * After this loop is done work_and_wait() will have nothing to do,
726      * so we don't run into wrong order of frames written to the stream.
727      */
728     if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
729       BLI_mutex_lock(&oglrender->task_mutex);
730       while (oglrender->num_scheduled_frames > 0) {
731         BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
732       }
733       BLI_mutex_unlock(&oglrender->task_mutex);
734     }
735     BLI_task_pool_work_and_wait(oglrender->task_pool);
736     BLI_task_pool_free(oglrender->task_pool);
737     /* Depending on various things we might or might not use global scheduler. */
738     if (oglrender->task_scheduler != NULL) {
739       BLI_task_scheduler_free(oglrender->task_scheduler);
740     }
741     BLI_spin_end(&oglrender->reports_lock);
742   }
743   BLI_mutex_end(&oglrender->task_mutex);
744   BLI_condition_end(&oglrender->task_condition);
745
746 #ifdef DEBUG_TIME
747   printf("Total render time: %f\n", PIL_check_seconds_timer() - oglrender->time_start);
748 #endif
749
750   if (oglrender->mh) {
751     if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
752       for (i = 0; i < oglrender->totvideos; i++) {
753         oglrender->mh->end_movie(oglrender->movie_ctx_arr[i]);
754         oglrender->mh->context_free(oglrender->movie_ctx_arr[i]);
755       }
756     }
757
758     if (oglrender->movie_ctx_arr) {
759       MEM_freeN(oglrender->movie_ctx_arr);
760     }
761   }
762
763   if (oglrender->timer) { /* exec will not have a timer */
764     Depsgraph *depsgraph = oglrender->depsgraph;
765     scene->r.cfra = oglrender->cfrao;
766     BKE_scene_graph_update_for_newframe(depsgraph, bmain);
767
768     WM_event_remove_timer(oglrender->wm, oglrender->win, oglrender->timer);
769   }
770
771   WM_cursor_modal_restore(oglrender->win);
772
773   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene);
774
775   DRW_opengl_context_enable();
776   GPU_offscreen_free(oglrender->ofs);
777   DRW_opengl_context_disable();
778
779   if (oglrender->is_sequencer) {
780     MEM_freeN(oglrender->seq_data.ibufs_arr);
781   }
782
783   memset(&oglrender->scene->customdata_mask_modal,
784          0,
785          sizeof(oglrender->scene->customdata_mask_modal));
786
787   CTX_wm_area_set(C, oglrender->prevsa);
788   CTX_wm_region_set(C, oglrender->prevar);
789
790   MEM_freeN(oglrender);
791 }
792
793 static void screen_opengl_render_cancel(bContext *C, wmOperator *op)
794 {
795   screen_opengl_render_end(C, op->customdata);
796 }
797
798 /* share between invoke and exec */
799 static bool screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
800 {
801   /* initialize animation */
802   OGLRender *oglrender;
803   Scene *scene;
804
805   oglrender = op->customdata;
806   scene = oglrender->scene;
807   oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
808
809   oglrender->reports = op->reports;
810
811   if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
812     size_t width, height;
813     int i;
814
815     BKE_scene_multiview_videos_dimensions_get(
816         &scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
817     oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
818
819     if (oglrender->mh == NULL) {
820       BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported");
821       screen_opengl_render_end(C, oglrender);
822       return false;
823     }
824
825     oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies");
826
827     for (i = 0; i < oglrender->totvideos; i++) {
828       const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
829
830       oglrender->movie_ctx_arr[i] = oglrender->mh->context_create();
831       if (!oglrender->mh->start_movie(oglrender->movie_ctx_arr[i],
832                                       scene,
833                                       &scene->r,
834                                       oglrender->sizex,
835                                       oglrender->sizey,
836                                       oglrender->reports,
837                                       PRVRANGEON != 0,
838                                       suffix)) {
839         screen_opengl_render_end(C, oglrender);
840         return false;
841       }
842     }
843   }
844
845   oglrender->cfrao = scene->r.cfra;
846   oglrender->nfra = PSFRA;
847   scene->r.cfra = PSFRA;
848
849   return true;
850 }
851
852 typedef struct WriteTaskData {
853   RenderResult *rr;
854   Scene tmp_scene;
855 } WriteTaskData;
856
857 static void write_result_func(TaskPool *__restrict pool, void *task_data_v, int UNUSED(thread_id))
858 {
859   OGLRender *oglrender = (OGLRender *)BLI_task_pool_userdata(pool);
860   WriteTaskData *task_data = (WriteTaskData *)task_data_v;
861   Scene *scene = &task_data->tmp_scene;
862   RenderResult *rr = task_data->rr;
863   const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
864   const int cfra = scene->r.cfra;
865   bool ok;
866   /* Don't attempt to write if we've got an error. */
867   if (!oglrender->pool_ok) {
868     RE_FreeRenderResult(rr);
869     BLI_mutex_lock(&oglrender->task_mutex);
870     oglrender->num_scheduled_frames--;
871     BLI_condition_notify_all(&oglrender->task_condition);
872     BLI_mutex_unlock(&oglrender->task_mutex);
873     return;
874   }
875   /* Construct local thread0safe copy of reports structure which we can
876    * safely pass to the underlying functions.
877    */
878   ReportList reports;
879   BKE_reports_init(&reports, oglrender->reports->flag & ~RPT_PRINT);
880   /* Do actual save logic here, depending on the file format.
881    *
882    * NOTE: We have to construct temporary scene with proper scene->r.cfra.
883    * This is because underlying calls do not use r.cfra but use scene
884    * for that.
885    */
886   if (is_movie) {
887     ok = RE_WriteRenderViewsMovie(&reports,
888                                   rr,
889                                   scene,
890                                   &scene->r,
891                                   oglrender->mh,
892                                   oglrender->movie_ctx_arr,
893                                   oglrender->totvideos,
894                                   PRVRANGEON != 0);
895   }
896   else {
897     /* TODO(sergey): We can in theory save some CPU ticks here because we
898      * calculate file name again here.
899      */
900     char name[FILE_MAX];
901     BKE_image_path_from_imformat(name,
902                                  scene->r.pic,
903                                  BKE_main_blendfile_path(oglrender->bmain),
904                                  cfra,
905                                  &scene->r.im_format,
906                                  (scene->r.scemode & R_EXTENSION) != 0,
907                                  true,
908                                  NULL);
909
910     BKE_render_result_stamp_info(scene, scene->camera, rr, false);
911     ok = RE_WriteRenderViewsImage(NULL, rr, scene, true, name);
912     if (!ok) {
913       BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", name);
914     }
915   }
916   if (reports.list.first != NULL) {
917     BLI_spin_lock(&oglrender->reports_lock);
918     for (Report *report = reports.list.first; report != NULL; report = report->next) {
919       BKE_report(oglrender->reports, report->type, report->message);
920     }
921     BLI_spin_unlock(&oglrender->reports_lock);
922   }
923   if (!ok) {
924     oglrender->pool_ok = false;
925   }
926   RE_FreeRenderResult(rr);
927   BLI_mutex_lock(&oglrender->task_mutex);
928   oglrender->num_scheduled_frames--;
929   BLI_condition_notify_all(&oglrender->task_condition);
930   BLI_mutex_unlock(&oglrender->task_mutex);
931 }
932
933 static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
934 {
935   if (!oglrender->pool_ok) {
936     RE_FreeRenderResult(rr);
937     return false;
938   }
939   Scene *scene = oglrender->scene;
940   WriteTaskData *task_data = MEM_mallocN(sizeof(WriteTaskData), "write task data");
941   task_data->rr = rr;
942   task_data->tmp_scene = *scene;
943   BLI_mutex_lock(&oglrender->task_mutex);
944   oglrender->num_scheduled_frames++;
945   if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) {
946     BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
947   }
948   BLI_mutex_unlock(&oglrender->task_mutex);
949   BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, TASK_PRIORITY_LOW);
950   return true;
951 }
952
953 static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
954 {
955   Main *bmain = CTX_data_main(C);
956   OGLRender *oglrender = op->customdata;
957   Scene *scene = oglrender->scene;
958   Depsgraph *depsgraph = oglrender->depsgraph;
959   char name[FILE_MAX];
960   bool ok = false;
961   const bool view_context = (oglrender->v3d != NULL);
962   bool is_movie;
963   RenderResult *rr;
964
965   /* go to next frame */
966   if (CFRA < oglrender->nfra) {
967     CFRA++;
968   }
969   while (CFRA < oglrender->nfra) {
970     BKE_scene_graph_update_for_newframe(depsgraph, bmain);
971     CFRA++;
972   }
973
974   is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
975
976   if (!is_movie) {
977     BKE_image_path_from_imformat(name,
978                                  scene->r.pic,
979                                  BKE_main_blendfile_path(oglrender->bmain),
980                                  scene->r.cfra,
981                                  &scene->r.im_format,
982                                  (scene->r.scemode & R_EXTENSION) != 0,
983                                  true,
984                                  NULL);
985
986     if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
987       BLI_spin_lock(&oglrender->reports_lock);
988       BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name);
989       BLI_spin_unlock(&oglrender->reports_lock);
990       ok = true;
991       goto finally;
992     }
993   }
994
995   WM_cursor_time(oglrender->win, scene->r.cfra);
996
997   BKE_scene_graph_update_for_newframe(depsgraph, bmain);
998
999   if (view_context) {
1000     if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera &&
1001         oglrender->v3d->scenelock) {
1002       /* since BKE_scene_graph_update_for_newframe() is used rather
1003        * then ED_update_for_newframe() the camera needs to be set */
1004       if (BKE_scene_camera_switch_update(scene)) {
1005         oglrender->v3d->camera = scene->camera;
1006       }
1007     }
1008   }
1009   else {
1010     BKE_scene_camera_switch_update(scene);
1011   }
1012
1013   /* render into offscreen buffer */
1014   screen_opengl_render_apply(C, oglrender);
1015
1016   /* save to disk */
1017   rr = RE_AcquireResultRead(oglrender->re);
1018   RenderResult *new_rr = RE_DuplicateRenderResult(rr);
1019   RE_ReleaseResult(oglrender->re);
1020
1021   ok = schedule_write_result(oglrender, new_rr);
1022
1023 finally: /* Step the frame and bail early if needed */
1024
1025   /* go to next frame */
1026   oglrender->nfra += scene->r.frame_step;
1027
1028   /* stop at the end or on error */
1029   if (CFRA >= PEFRA || !ok) {
1030     screen_opengl_render_end(C, op->customdata);
1031     return 0;
1032   }
1033
1034   return 1;
1035 }
1036
1037 static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event)
1038 {
1039   OGLRender *oglrender = op->customdata;
1040   const bool anim = RNA_boolean_get(op->ptr, "animation");
1041   bool ret;
1042
1043   switch (event->type) {
1044     case ESCKEY:
1045       /* cancel */
1046       oglrender->pool_ok = false; /* Flag pool for cancel. */
1047       screen_opengl_render_end(C, op->customdata);
1048       return OPERATOR_FINISHED;
1049     case TIMER:
1050       /* render frame? */
1051       if (oglrender->timer == event->customdata) {
1052         break;
1053       }
1054       ATTR_FALLTHROUGH;
1055     default:
1056       /* nothing to do */
1057       return OPERATOR_RUNNING_MODAL;
1058   }
1059
1060   /* run first because screen_opengl_render_anim_step can free oglrender */
1061   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene);
1062
1063   if (anim == 0) {
1064     screen_opengl_render_apply(C, op->customdata);
1065     screen_opengl_render_end(C, op->customdata);
1066     return OPERATOR_FINISHED;
1067   }
1068   else {
1069     ret = screen_opengl_render_anim_step(C, op);
1070   }
1071
1072   /* stop at the end or on error */
1073   if (ret == false) {
1074     return OPERATOR_FINISHED;
1075   }
1076
1077   return OPERATOR_RUNNING_MODAL;
1078 }
1079
1080 static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1081 {
1082   OGLRender *oglrender;
1083   const bool anim = RNA_boolean_get(op->ptr, "animation");
1084
1085   if (!screen_opengl_render_init(C, op)) {
1086     return OPERATOR_CANCELLED;
1087   }
1088
1089   if (anim) {
1090     if (!screen_opengl_render_anim_initialize(C, op)) {
1091       return OPERATOR_CANCELLED;
1092     }
1093   }
1094
1095   oglrender = op->customdata;
1096   render_view_open(C, event->x, event->y, op->reports);
1097
1098   /* view may be changed above (R_OUTPUT_WINDOW) */
1099   oglrender->win = CTX_wm_window(C);
1100
1101   WM_event_add_modal_handler(C, op);
1102   oglrender->timer = WM_event_add_timer(oglrender->wm, oglrender->win, TIMER, 0.01f);
1103
1104   return OPERATOR_RUNNING_MODAL;
1105 }
1106
1107 /* executes blocking render */
1108 static int screen_opengl_render_exec(bContext *C, wmOperator *op)
1109 {
1110   const bool is_animation = RNA_boolean_get(op->ptr, "animation");
1111
1112   if (!screen_opengl_render_init(C, op)) {
1113     return OPERATOR_CANCELLED;
1114   }
1115
1116   if (!is_animation) { /* same as invoke */
1117     /* render image */
1118     screen_opengl_render_apply(C, op->customdata);
1119     screen_opengl_render_end(C, op->customdata);
1120
1121     return OPERATOR_FINISHED;
1122   }
1123   else {
1124     bool ret = true;
1125
1126     if (!screen_opengl_render_anim_initialize(C, op)) {
1127       return OPERATOR_CANCELLED;
1128     }
1129
1130     while (ret) {
1131       ret = screen_opengl_render_anim_step(C, op);
1132     }
1133   }
1134
1135   /* no redraw needed, we leave state as we entered it */
1136   //  ED_update_for_newframe(C);
1137   WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, CTX_data_scene(C));
1138
1139   return OPERATOR_FINISHED;
1140 }
1141
1142 void RENDER_OT_opengl(wmOperatorType *ot)
1143 {
1144   PropertyRNA *prop;
1145
1146   /* identifiers */
1147   ot->name = "Viewport Render";
1148   ot->description = "Take a snapshot of the active viewport";
1149   ot->idname = "RENDER_OT_opengl";
1150
1151   /* api callbacks */
1152   ot->invoke = screen_opengl_render_invoke;
1153   ot->exec = screen_opengl_render_exec; /* blocking */
1154   ot->modal = screen_opengl_render_modal;
1155   ot->cancel = screen_opengl_render_cancel;
1156
1157   ot->poll = ED_operator_screenactive;
1158
1159   prop = RNA_def_boolean(ot->srna,
1160                          "animation",
1161                          0,
1162                          "Animation",
1163                          "Render files from the animation range of this scene");
1164   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1165   prop = RNA_def_boolean(
1166       ot->srna, "sequencer", 0, "Sequencer", "Render using the sequencer's OpenGL display");
1167   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1168   prop = RNA_def_boolean(
1169       ot->srna,
1170       "write_still",
1171       0,
1172       "Write Image",
1173       "Save rendered the image to the output path (used only when animation is disabled)");
1174   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1175   prop = RNA_def_boolean(ot->srna,
1176                          "view_context",
1177                          1,
1178                          "View Context",
1179                          "Use the current 3D view for rendering, else use scene settings");
1180   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1181 }
1182
1183 /* function for getting an opengl buffer from a View3D, used by sequencer */
1184 // extern void *sequencer_view3d_cb;