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