Fix T56799: Custom render passes missing when using Save Buffers
[blender.git] / source / blender / render / intern / source / external_engine.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) 2006 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/render/intern/source/external_engine.c
29  *  \ingroup render
30  */
31
32 #include <stddef.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLT_translation.h"
39
40 #include "BLI_listbase.h"
41 #include "BLI_string.h"
42 #include "BLI_utildefines.h"
43
44 #include "BKE_camera.h"
45 #include "BKE_global.h"
46 #include "BKE_colortools.h"
47 #include "BKE_report.h"
48 #include "BKE_scene.h"
49
50 #include "RNA_access.h"
51
52 #ifdef WITH_PYTHON
53 #include "BPY_extern.h"
54 #endif
55
56 #include "RE_engine.h"
57 #include "RE_pipeline.h"
58 #include "RE_bake.h"
59
60 #include "initrender.h"
61 #include "renderpipeline.h"
62 #include "render_types.h"
63 #include "render_result.h"
64 #include "rendercore.h"
65
66 /* Render Engine Types */
67
68 static RenderEngineType internal_render_type = {
69         NULL, NULL,
70         "BLENDER_RENDER", N_("Blender Render"), RE_INTERNAL,
71         NULL, NULL, NULL, NULL, NULL, NULL, render_internal_update_passes,
72         {NULL, NULL, NULL}
73 };
74
75 #ifdef WITH_GAMEENGINE
76
77 static RenderEngineType internal_game_type = {
78         NULL, NULL,
79         "BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME,
80         NULL, NULL, NULL, NULL, NULL, NULL, NULL,
81         {NULL, NULL, NULL}
82 };
83
84 #endif
85
86 ListBase R_engines = {NULL, NULL};
87
88 void RE_engines_init(void)
89 {
90         BLI_addtail(&R_engines, &internal_render_type);
91 #ifdef WITH_GAMEENGINE
92         BLI_addtail(&R_engines, &internal_game_type);
93 #endif
94 }
95
96 void RE_engines_exit(void)
97 {
98         RenderEngineType *type, *next;
99
100         for (type = R_engines.first; type; type = next) {
101                 next = type->next;
102
103                 BLI_remlink(&R_engines, type);
104
105                 if (!(type->flag & RE_INTERNAL)) {
106                         if (type->ext.free)
107                                 type->ext.free(type->ext.data);
108
109                         MEM_freeN(type);
110                 }
111         }
112 }
113
114 RenderEngineType *RE_engines_find(const char *idname)
115 {
116         RenderEngineType *type;
117
118         type = BLI_findstring(&R_engines, idname, offsetof(RenderEngineType, idname));
119         if (!type)
120                 type = &internal_render_type;
121
122         return type;
123 }
124
125 bool RE_engine_is_external(Render *re)
126 {
127         RenderEngineType *type = RE_engines_find(re->r.engine);
128         return (type && type->render);
129 }
130
131 /* Create, Free */
132
133 RenderEngine *RE_engine_create(RenderEngineType *type)
134 {
135         return RE_engine_create_ex(type, false);
136 }
137
138 RenderEngine *RE_engine_create_ex(RenderEngineType *type, bool use_for_viewport)
139 {
140         RenderEngine *engine = MEM_callocN(sizeof(RenderEngine), "RenderEngine");
141         engine->type = type;
142
143         if (use_for_viewport) {
144                 engine->flag |= RE_ENGINE_USED_FOR_VIEWPORT;
145
146                 BLI_threaded_malloc_begin();
147         }
148
149         BLI_mutex_init(&engine->update_render_passes_mutex);
150
151         return engine;
152 }
153
154 void RE_engine_free(RenderEngine *engine)
155 {
156 #ifdef WITH_PYTHON
157         if (engine->py_instance) {
158                 BPY_DECREF_RNA_INVALIDATE(engine->py_instance);
159         }
160 #endif
161
162         if (engine->flag & RE_ENGINE_USED_FOR_VIEWPORT) {
163                 BLI_threaded_malloc_end();
164         }
165
166         BLI_mutex_end(&engine->update_render_passes_mutex);
167
168         MEM_freeN(engine);
169 }
170
171 /* Render Results */
172
173 static RenderPart *get_part_from_result(Render *re, RenderResult *result)
174 {
175         RenderPart *pa;
176
177         for (pa = re->parts.first; pa; pa = pa->next) {
178                 if (result->tilerect.xmin == pa->disprect.xmin - re->disprect.xmin &&
179                     result->tilerect.ymin == pa->disprect.ymin - re->disprect.ymin &&
180                     result->tilerect.xmax == pa->disprect.xmax - re->disprect.xmin &&
181                     result->tilerect.ymax == pa->disprect.ymax - re->disprect.ymin)
182                 {
183                         return pa;
184                 }
185         }
186
187         return NULL;
188 }
189
190 RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname)
191 {
192         Render *re = engine->re;
193         RenderResult *result;
194         rcti disprect;
195
196         /* ensure the coordinates are within the right limits */
197         CLAMP(x, 0, re->result->rectx);
198         CLAMP(y, 0, re->result->recty);
199         CLAMP(w, 0, re->result->rectx);
200         CLAMP(h, 0, re->result->recty);
201
202         if (x + w > re->result->rectx)
203                 w = re->result->rectx - x;
204         if (y + h > re->result->recty)
205                 h = re->result->recty - y;
206
207         /* allocate a render result */
208         disprect.xmin = x;
209         disprect.xmax = x + w;
210         disprect.ymin = y;
211         disprect.ymax = y + h;
212
213         result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername, viewname);
214
215         /* todo: make this thread safe */
216
217         /* can be NULL if we CLAMP the width or height to 0 */
218         if (result) {
219                 render_result_clone_passes(re, result, viewname);
220
221                 RenderPart *pa;
222
223                 /* Copy EXR tile settings, so pipeline knows whether this is a result
224                  * for Save Buffers enabled rendering.
225                  */
226                 result->do_exr_tile = re->result->do_exr_tile;
227
228                 BLI_addtail(&engine->fullresult, result);
229
230                 result->tilerect.xmin += re->disprect.xmin;
231                 result->tilerect.xmax += re->disprect.xmin;
232                 result->tilerect.ymin += re->disprect.ymin;
233                 result->tilerect.ymax += re->disprect.ymin;
234
235                 pa = get_part_from_result(re, result);
236
237                 if (pa)
238                         pa->status = PART_STATUS_IN_PROGRESS;
239         }
240
241         return result;
242 }
243
244 void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
245 {
246         Render *re = engine->re;
247
248         if (result) {
249                 result->renlay = result->layers.first; /* weak, draws first layer always */
250                 re->display_update(re->duh, result, NULL);
251         }
252 }
253
254 void RE_engine_add_pass(RenderEngine *engine, const char *name, int channels, const char *chan_id, const char *layername)
255 {
256         Render *re = engine->re;
257
258         if (!re || !re->result) {
259                 return;
260         }
261
262         render_result_add_pass(re->result, name, channels, chan_id, layername, NULL);
263 }
264
265 void RE_engine_end_result(RenderEngine *engine, RenderResult *result, bool cancel, bool highlight, bool merge_results)
266 {
267         Render *re = engine->re;
268
269         if (!result) {
270                 return;
271         }
272
273         /* merge. on break, don't merge in result for preview renders, looks nicer */
274         if (!highlight) {
275                 /* for exr tile render, detect tiles that are done */
276                 RenderPart *pa = get_part_from_result(re, result);
277
278                 if (pa) {
279                         pa->status = (!cancel && merge_results)? PART_STATUS_MERGED: PART_STATUS_RENDERED;
280                 }
281                 else if (re->result->do_exr_tile) {
282                         /* if written result does not match any tile and we are using save
283                          * buffers, we are going to get openexr save errors */
284                         fprintf(stderr, "RenderEngine.end_result: dimensions do not match any OpenEXR tile.\n");
285                 }
286         }
287
288         if (!cancel || merge_results) {
289                 if (re->result->do_exr_tile) {
290                         if (!cancel && merge_results) {
291                                 render_result_exr_file_merge(re->result, result, re->viewname);
292                         }
293                 }
294                 else if (!(re->test_break(re->tbh) && (re->r.scemode & R_BUTS_PREVIEW)))
295                         render_result_merge(re->result, result);
296
297                 /* draw */
298                 if (!re->test_break(re->tbh)) {
299                         result->renlay = result->layers.first; /* weak, draws first layer always */
300                         re->display_update(re->duh, result, NULL);
301                 }
302         }
303
304         /* free */
305         BLI_remlink(&engine->fullresult, result);
306         render_result_free(result);
307 }
308
309 RenderResult *RE_engine_get_result(RenderEngine *engine)
310 {
311         return engine->re->result;
312 }
313
314 /* Cancel */
315
316 bool RE_engine_test_break(RenderEngine *engine)
317 {
318         Render *re = engine->re;
319
320         if (re)
321                 return re->test_break(re->tbh);
322
323         return 0;
324 }
325
326 /* Statistics */
327
328 void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info)
329 {
330         Render *re = engine->re;
331
332         /* stats draw callback */
333         if (re) {
334                 re->i.statstr = stats;
335                 re->i.infostr = info;
336                 re->stats_draw(re->sdh, &re->i);
337                 re->i.infostr = NULL;
338                 re->i.statstr = NULL;
339         }
340
341         /* set engine text */
342         engine->text[0] = '\0';
343
344         if (stats && stats[0] && info && info[0])
345                 BLI_snprintf(engine->text, sizeof(engine->text), "%s | %s", stats, info);
346         else if (info && info[0])
347                 BLI_strncpy(engine->text, info, sizeof(engine->text));
348         else if (stats && stats[0])
349                 BLI_strncpy(engine->text, stats, sizeof(engine->text));
350 }
351
352 void RE_engine_update_progress(RenderEngine *engine, float progress)
353 {
354         Render *re = engine->re;
355
356         if (re) {
357                 CLAMP(progress, 0.0f, 1.0f);
358                 re->progress(re->prh, progress);
359         }
360 }
361
362 void RE_engine_update_memory_stats(RenderEngine *engine, float mem_used, float mem_peak)
363 {
364         Render *re = engine->re;
365
366         if (re) {
367                 re->i.mem_used = mem_used;
368                 re->i.mem_peak = mem_peak;
369         }
370 }
371
372 void RE_engine_report(RenderEngine *engine, int type, const char *msg)
373 {
374         Render *re = engine->re;
375
376         if (re)
377                 BKE_report(engine->re->reports, type, msg);
378         else if (engine->reports)
379                 BKE_report(engine->reports, type, msg);
380 }
381
382 void RE_engine_set_error_message(RenderEngine *engine, const char *msg)
383 {
384         Render *re = engine->re;
385         if (re != NULL) {
386                 RenderResult *rr = RE_AcquireResultRead(re);
387                 if (rr) {
388                         if (rr->error != NULL) {
389                                 MEM_freeN(rr->error);
390                         }
391                         rr->error = BLI_strdup(msg);
392                 }
393                 RE_ReleaseResult(re);
394         }
395 }
396
397 const char *RE_engine_active_view_get(RenderEngine *engine)
398 {
399         Render *re = engine->re;
400         return RE_GetActiveRenderView(re);
401 }
402
403 void RE_engine_active_view_set(RenderEngine *engine, const char *viewname)
404 {
405         Render *re = engine->re;
406         RE_SetActiveRenderView(re, viewname);
407 }
408
409 float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera, bool use_spherical_stereo)
410 {
411         Render *re = engine->re;
412
413         /* when using spherical stereo, get camera shift without multiview, leaving stereo to be handled by the engine */
414         if (use_spherical_stereo)
415                 re = NULL;
416
417         return BKE_camera_multiview_shift_x(re ? &re->r : NULL, camera, re->viewname);
418 }
419
420 void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, bool use_spherical_stereo, float *r_modelmat)
421 {
422         Render *re = engine->re;
423
424         /* when using spherical stereo, get model matrix without multiview, leaving stereo to be handled by the engine */
425         if (use_spherical_stereo)
426                 re = NULL;
427
428         BKE_camera_multiview_model_matrix(re ? &re->r : NULL, camera, re->viewname, (float (*)[4])r_modelmat);
429 }
430
431 bool RE_engine_get_spherical_stereo(RenderEngine *engine, Object *camera)
432 {
433         Render *re = engine->re;
434         return BKE_camera_multiview_spherical_stereo(re ? &re->r : NULL, camera) ? 1 : 0;
435 }
436
437 rcti* RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_free)
438 {
439         static rcti tiles_static[BLENDER_MAX_THREADS];
440         const int allocation_step = BLENDER_MAX_THREADS;
441         RenderPart *pa;
442         int total_tiles = 0;
443         rcti *tiles = tiles_static;
444         int allocation_size = BLENDER_MAX_THREADS;
445
446         BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_READ);
447
448         *r_needs_free = false;
449
450         if (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) {
451                 *r_total_tiles = 0;
452                 BLI_rw_mutex_unlock(&re->partsmutex);
453                 return NULL;
454         }
455
456         for (pa = re->parts.first; pa; pa = pa->next) {
457                 if (pa->status == PART_STATUS_IN_PROGRESS) {
458                         if (total_tiles >= allocation_size) {
459                                 /* Just in case we're using crazy network rendering with more
460                                  * workers than BLENDER_MAX_THREADS.
461                                  */
462                                 allocation_size += allocation_step;
463                                 if (tiles == tiles_static) {
464                                         /* Can not realloc yet, tiles are pointing to a
465                                          * stack memory.
466                                          */
467                                         tiles = MEM_mallocN(allocation_size * sizeof(rcti), "current engine tiles");
468                                 }
469                                 else {
470                                         tiles = MEM_reallocN(tiles, allocation_size * sizeof(rcti));
471                                 }
472                                 *r_needs_free = true;
473                         }
474                         tiles[total_tiles] = pa->disprect;
475
476                         if (pa->crop) {
477                                 tiles[total_tiles].xmin += pa->crop;
478                                 tiles[total_tiles].ymin += pa->crop;
479                                 tiles[total_tiles].xmax -= pa->crop;
480                                 tiles[total_tiles].ymax -= pa->crop;
481                         }
482
483                         total_tiles++;
484                 }
485         }
486         BLI_rw_mutex_unlock(&re->partsmutex);
487         *r_total_tiles = total_tiles;
488         return tiles;
489 }
490
491 RenderData *RE_engine_get_render_data(Render *re)
492 {
493         return &re->r;
494 }
495
496 /* Bake */
497 void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
498 {
499         re->scene = scene;
500         re->main = bmain;
501         render_copy_renderdata(&re->r, &scene->r);
502 }
503
504 bool RE_bake_has_engine(Render *re)
505 {
506         RenderEngineType *type = RE_engines_find(re->r.engine);
507         return (type->bake != NULL);
508 }
509
510 bool RE_bake_engine(
511         Render *re, Object *object,
512         const int object_id, const BakePixel pixel_array[],
513         const size_t num_pixels, const int depth,
514         const eScenePassType pass_type, const int pass_filter,
515         float result[])
516 {
517         RenderEngineType *type = RE_engines_find(re->r.engine);
518         RenderEngine *engine;
519         bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0;
520
521         /* set render info */
522         re->i.cfra = re->scene->r.cfra;
523         BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name) - 2);
524         re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0;
525
526         /* render */
527         engine = re->engine;
528
529         if (!engine) {
530                 engine = RE_engine_create(type);
531                 re->engine = engine;
532         }
533
534         engine->flag |= RE_ENGINE_RENDERING;
535
536         /* TODO: actually link to a parent which shouldn't happen */
537         engine->re = re;
538
539         engine->resolution_x = re->winx;
540         engine->resolution_y = re->winy;
541
542         RE_parts_init(re, false);
543         engine->tile_x = re->r.tilex;
544         engine->tile_y = re->r.tiley;
545
546         /* update is only called so we create the engine.session */
547         if (type->update)
548                 type->update(engine, re->main, re->scene);
549
550         if (type->bake)
551                 type->bake(engine, re->scene, object, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result);
552
553         engine->tile_x = 0;
554         engine->tile_y = 0;
555         engine->flag &= ~RE_ENGINE_RENDERING;
556
557         BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
558
559         /* re->engine becomes zero if user changed active render engine during render */
560         if (!persistent_data || !re->engine) {
561                 RE_engine_free(engine);
562                 re->engine = NULL;
563         }
564
565         RE_parts_free(re);
566         BLI_rw_mutex_unlock(&re->partsmutex);
567
568         if (BKE_reports_contain(re->reports, RPT_ERROR))
569                 G.is_break = true;
570
571         return true;
572 }
573
574 void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
575 {
576         Render *re = engine->re;
577         Scene *scene = re->scene;
578         double cfra = (double)frame + (double)subframe;
579
580         CLAMP(cfra, MINAFRAME, MAXFRAME);
581         BKE_scene_frame_set(scene, cfra);
582
583 #ifdef WITH_PYTHON
584         BPy_BEGIN_ALLOW_THREADS;
585 #endif
586
587         /* It's possible that here we're including layers which were never visible before. */
588         BKE_scene_update_for_newframe_ex(re->eval_ctx, re->main, scene, (1 << 20) - 1, true);
589
590 #ifdef WITH_PYTHON
591         BPy_END_ALLOW_THREADS;
592 #endif
593
594         BKE_scene_camera_switch_update(scene);
595 }
596
597 /* Render */
598
599 static bool render_layer_exclude_animated(Scene *scene, SceneRenderLayer *srl)
600 {
601         PointerRNA ptr;
602         PropertyRNA *prop;
603
604         RNA_pointer_create(&scene->id, &RNA_SceneRenderLayer, srl, &ptr);
605         prop = RNA_struct_find_property(&ptr, "layers_exclude");
606
607         return RNA_property_animated(&ptr, prop);
608 }
609
610 int RE_engine_render(Render *re, int do_all)
611 {
612         RenderEngineType *type = RE_engines_find(re->r.engine);
613         RenderEngine *engine;
614         bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0;
615
616         /* verify if we can render */
617         if (!type->render)
618                 return 0;
619         if ((re->r.scemode & R_BUTS_PREVIEW) && !(type->flag & RE_USE_PREVIEW))
620                 return 0;
621         if (do_all && !(type->flag & RE_USE_POSTPROCESS))
622                 return 0;
623         if (!do_all && (type->flag & RE_USE_POSTPROCESS))
624                 return 0;
625
626         /* Lock drawing in UI during data phase. */
627         if (re->draw_lock) {
628                 re->draw_lock(re->dlh, 1);
629         }
630
631         /* update animation here so any render layer animation is applied before
632          * creating the render result */
633         if ((re->r.scemode & (R_NO_FRAME_UPDATE | R_BUTS_PREVIEW)) == 0) {
634                 unsigned int lay = re->lay;
635
636                 /* don't update layers excluded on all render layers */
637                 if (type->flag & RE_USE_EXCLUDE_LAYERS) {
638                         SceneRenderLayer *srl;
639                         unsigned int non_excluded_lay = 0;
640
641                         if (re->r.scemode & R_SINGLE_LAYER) {
642                                 srl = BLI_findlink(&re->r.layers, re->r.actlay);
643                                 if (srl) {
644                                         non_excluded_lay |= ~(srl->lay_exclude & ~srl->lay_zmask);
645
646                                         /* in this case we must update all because animation for
647                                          * the scene has not been updated yet, and so may not be
648                                          * up to date until after BKE_scene_update_for_newframe */
649                                         if (render_layer_exclude_animated(re->scene, srl))
650                                                 non_excluded_lay |= ~0;
651                                 }
652                         }
653                         else {
654                                 for (srl = re->r.layers.first; srl; srl = srl->next) {
655                                         if (!(srl->layflag & SCE_LAY_DISABLE)) {
656                                                 non_excluded_lay |= ~(srl->lay_exclude & ~srl->lay_zmask);
657
658                                                 if (render_layer_exclude_animated(re->scene, srl))
659                                                         non_excluded_lay |= ~0;
660                                         }
661                                 }
662                         }
663
664                         lay &= non_excluded_lay;
665                 }
666
667                 BKE_scene_update_for_newframe_ex(re->eval_ctx, re->main, re->scene, lay, true);
668                 render_update_anim_renderdata(re, &re->scene->r);
669         }
670
671         /* create render result */
672         BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
673         if (re->result == NULL || !(re->r.scemode & R_BUTS_PREVIEW)) {
674                 int savebuffers = RR_USE_MEM;
675
676                 if (re->result)
677                         render_result_free(re->result);
678
679                 if ((type->flag & RE_USE_SAVE_BUFFERS) && (re->r.scemode & R_EXR_TILE_FILE))
680                         savebuffers = RR_USE_EXR;
681                 re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS, RR_ALL_VIEWS);
682         }
683         BLI_rw_mutex_unlock(&re->resultmutex);
684
685         if (re->result == NULL) {
686                 /* Clear UI drawing locks. */
687                 if (re->draw_lock) {
688                         re->draw_lock(re->dlh, 0);
689                 }
690                 /* Too small image is handled earlier, here it could only happen if
691                  * there was no sufficient memory to allocate all passes.
692                  */
693                 BKE_report(re->reports, RPT_ERROR, "Failed allocate render result, out of memory");
694                 G.is_break = true;
695                 return 1;
696         }
697
698         /* set render info */
699         re->i.cfra = re->scene->r.cfra;
700         BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name));
701         re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0;
702
703         /* render */
704         engine = re->engine;
705
706         if (!engine) {
707                 engine = RE_engine_create(type);
708                 re->engine = engine;
709         }
710
711         engine->flag |= RE_ENGINE_RENDERING;
712
713         /* TODO: actually link to a parent which shouldn't happen */
714         engine->re = re;
715
716         if (re->flag & R_ANIMATION)
717                 engine->flag |= RE_ENGINE_ANIMATION;
718         if (re->r.scemode & R_BUTS_PREVIEW)
719                 engine->flag |= RE_ENGINE_PREVIEW;
720         engine->camera_override = re->camera_override;
721         engine->layer_override = re->layer_override;
722
723         engine->resolution_x = re->winx;
724         engine->resolution_y = re->winy;
725
726         RE_parts_init(re, false);
727         engine->tile_x = re->partx;
728         engine->tile_y = re->party;
729
730         if (re->result->do_exr_tile)
731                 render_result_exr_file_begin(re, engine);
732
733         if (type->update)
734                 type->update(engine, re->main, re->scene);
735
736         /* Clear UI drawing locks. */
737         if (re->draw_lock) {
738                 re->draw_lock(re->dlh, 0);
739         }
740
741         if (type->render)
742                 type->render(engine, re->scene);
743
744         engine->tile_x = 0;
745         engine->tile_y = 0;
746         engine->flag &= ~RE_ENGINE_RENDERING;
747
748         render_result_free_list(&engine->fullresult, engine->fullresult.first);
749
750         BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
751
752         if (re->result->do_exr_tile) {
753                 BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
754                 render_result_save_empty_result_tiles(re);
755                 render_result_exr_file_end(re, engine);
756                 BLI_rw_mutex_unlock(&re->resultmutex);
757         }
758
759         /* re->engine becomes zero if user changed active render engine during render */
760         if (!persistent_data || !re->engine) {
761                 RE_engine_free(engine);
762                 re->engine = NULL;
763         }
764
765         if (re->r.scemode & R_EXR_CACHE_FILE) {
766                 BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
767                 render_result_exr_file_cache_write(re);
768                 BLI_rw_mutex_unlock(&re->resultmutex);
769         }
770
771         RE_parts_free(re);
772         BLI_rw_mutex_unlock(&re->partsmutex);
773
774         if (BKE_reports_contain(re->reports, RPT_ERROR))
775                 G.is_break = true;
776
777 #ifdef WITH_FREESTYLE
778         if (re->r.mode & R_EDGE_FRS)
779                 RE_RenderFreestyleExternal(re);
780 #endif
781
782         return 1;
783 }
784
785 void RE_engine_update_render_passes(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl,
786                                     update_render_passes_cb_t callback)
787 {
788         if (!(scene && srl && engine && callback && engine->type->update_render_passes)) {
789                 return;
790         }
791
792         BLI_mutex_lock(&engine->update_render_passes_mutex);
793
794         engine->update_render_passes_cb = callback;
795         engine->type->update_render_passes(engine, scene, srl);
796
797         BLI_mutex_unlock(&engine->update_render_passes_mutex);
798 }
799
800 void RE_engine_register_pass(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl,
801                              const char *name, int channels, const char *chanid, int type)
802 {
803         if (!(scene && srl && engine && engine->update_render_passes_cb)) {
804                 return;
805         }
806
807         engine->update_render_passes_cb(engine, scene, srl, name, channels, chanid, type);
808 }