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