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