Cleanup: style, use braces for render
[blender.git] / source / blender / render / intern / source / external_engine.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2006 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup render
22  */
23
24 #include <stddef.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "BLT_translation.h"
31
32 #include "BLI_listbase.h"
33 #include "BLI_string.h"
34 #include "BLI_utildefines.h"
35
36 #include "DNA_object_types.h"
37
38 #include "BKE_camera.h"
39 #include "BKE_global.h"
40 #include "BKE_colortools.h"
41 #include "BKE_layer.h"
42 #include "BKE_node.h"
43 #include "BKE_report.h"
44 #include "BKE_scene.h"
45
46 #include "DEG_depsgraph.h"
47 #include "DEG_depsgraph_debug.h"
48 #include "DEG_depsgraph_query.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 "DRW_engine.h"
61
62 #include "initrender.h"
63 #include "renderpipeline.h"
64 #include "render_types.h"
65 #include "render_result.h"
66
67 /* Render Engine Types */
68
69 ListBase R_engines = {NULL, NULL};
70
71 void RE_engines_init(void)
72 {
73   DRW_engines_register();
74 }
75
76 void RE_engines_exit(void)
77 {
78   RenderEngineType *type, *next;
79
80   DRW_engines_free();
81
82   for (type = R_engines.first; type; type = next) {
83     next = type->next;
84
85     BLI_remlink(&R_engines, type);
86
87     if (!(type->flag & RE_INTERNAL)) {
88       if (type->ext.free) {
89         type->ext.free(type->ext.data);
90       }
91
92       MEM_freeN(type);
93     }
94   }
95 }
96
97 void RE_engines_register(RenderEngineType *render_type)
98 {
99   if (render_type->draw_engine) {
100     DRW_engine_register(render_type->draw_engine);
101   }
102   BLI_addtail(&R_engines, render_type);
103 }
104
105 RenderEngineType *RE_engines_find(const char *idname)
106 {
107   RenderEngineType *type;
108
109   type = BLI_findstring(&R_engines, idname, offsetof(RenderEngineType, idname));
110   if (!type) {
111     type = BLI_findstring(&R_engines, "BLENDER_EEVEE", offsetof(RenderEngineType, idname));
112   }
113
114   return type;
115 }
116
117 bool RE_engine_is_external(Render *re)
118 {
119   return (re->engine && re->engine->type && re->engine->type->render);
120 }
121
122 bool RE_engine_is_opengl(RenderEngineType *render_type)
123 {
124   /* TODO refine? Can we have ogl render engine without ogl render pipeline? */
125   return (render_type->draw_engine != NULL) && DRW_engine_render_support(render_type->draw_engine);
126 }
127
128 /* Create, Free */
129
130 RenderEngine *RE_engine_create(RenderEngineType *type)
131 {
132   return RE_engine_create_ex(type, false);
133 }
134
135 RenderEngine *RE_engine_create_ex(RenderEngineType *type, bool use_for_viewport)
136 {
137   RenderEngine *engine = MEM_callocN(sizeof(RenderEngine), "RenderEngine");
138   engine->type = type;
139
140   if (use_for_viewport) {
141     engine->flag |= RE_ENGINE_USED_FOR_VIEWPORT;
142
143     BLI_threaded_malloc_begin();
144   }
145
146   BLI_mutex_init(&engine->update_render_passes_mutex);
147
148   return engine;
149 }
150
151 void RE_engine_free(RenderEngine *engine)
152 {
153 #ifdef WITH_PYTHON
154   if (engine->py_instance) {
155     BPY_DECREF_RNA_INVALIDATE(engine->py_instance);
156   }
157 #endif
158
159   if (engine->flag & RE_ENGINE_USED_FOR_VIEWPORT) {
160     BLI_threaded_malloc_end();
161   }
162
163   BLI_mutex_end(&engine->update_render_passes_mutex);
164
165   MEM_freeN(engine);
166 }
167
168 /* Render Results */
169
170 static RenderPart *get_part_from_result(Render *re, RenderResult *result)
171 {
172   RenderPart *pa;
173
174   for (pa = re->parts.first; pa; pa = pa->next) {
175     if (result->tilerect.xmin == pa->disprect.xmin - re->disprect.xmin &&
176         result->tilerect.ymin == pa->disprect.ymin - re->disprect.ymin &&
177         result->tilerect.xmax == pa->disprect.xmax - re->disprect.xmin &&
178         result->tilerect.ymax == pa->disprect.ymax - re->disprect.ymin) {
179       return pa;
180     }
181   }
182
183   return NULL;
184 }
185
186 RenderResult *RE_engine_begin_result(
187     RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname)
188 {
189   Render *re = engine->re;
190   RenderResult *result;
191   rcti disprect;
192
193   /* ensure the coordinates are within the right limits */
194   CLAMP(x, 0, re->result->rectx);
195   CLAMP(y, 0, re->result->recty);
196   CLAMP(w, 0, re->result->rectx);
197   CLAMP(h, 0, re->result->recty);
198
199   if (x + w > re->result->rectx) {
200     w = re->result->rectx - x;
201   }
202   if (y + h > re->result->recty) {
203     h = re->result->recty - y;
204   }
205
206   /* allocate a render result */
207   disprect.xmin = x;
208   disprect.xmax = x + w;
209   disprect.ymin = y;
210   disprect.ymax = y + h;
211
212   result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername, viewname);
213
214   /* todo: make this thread safe */
215
216   /* can be NULL if we CLAMP the width or height to 0 */
217   if (result) {
218     render_result_clone_passes(re, result, viewname);
219
220     RenderPart *pa;
221
222     /* Copy EXR tile settings, so pipeline knows whether this is a result
223      * for Save Buffers enabled rendering.
224      */
225     result->do_exr_tile = re->result->do_exr_tile;
226
227     BLI_addtail(&engine->fullresult, result);
228
229     result->tilerect.xmin += re->disprect.xmin;
230     result->tilerect.xmax += re->disprect.xmin;
231     result->tilerect.ymin += re->disprect.ymin;
232     result->tilerect.ymax += re->disprect.ymin;
233
234     pa = get_part_from_result(re, result);
235
236     if (pa) {
237       pa->status = PART_STATUS_IN_PROGRESS;
238     }
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,
255                         const char *name,
256                         int channels,
257                         const char *chan_id,
258                         const char *layername)
259 {
260   Render *re = engine->re;
261
262   if (!re || !re->result) {
263     return;
264   }
265
266   render_result_add_pass(re->result, name, channels, chan_id, layername, NULL);
267 }
268
269 void RE_engine_end_result(
270     RenderEngine *engine, RenderResult *result, bool cancel, bool highlight, bool merge_results)
271 {
272   Render *re = engine->re;
273
274   if (!result) {
275     return;
276   }
277
278   /* merge. on break, don't merge in result for preview renders, looks nicer */
279   if (!highlight) {
280     /* for exr tile render, detect tiles that are done */
281     RenderPart *pa = get_part_from_result(re, result);
282
283     if (pa) {
284       pa->status = (!cancel && merge_results) ? PART_STATUS_MERGED : PART_STATUS_RENDERED;
285     }
286     else if (re->result->do_exr_tile) {
287       /* if written result does not match any tile and we are using save
288        * buffers, we are going to get openexr save errors */
289       fprintf(stderr, "RenderEngine.end_result: dimensions do not match any OpenEXR tile.\n");
290     }
291   }
292
293   if (!cancel || merge_results) {
294     if (re->result->do_exr_tile) {
295       if (!cancel && merge_results) {
296         render_result_exr_file_merge(re->result, result, re->viewname);
297       }
298     }
299     else if (!(re->test_break(re->tbh) && (re->r.scemode & R_BUTS_PREVIEW))) {
300       render_result_merge(re->result, result);
301     }
302
303     /* draw */
304     if (!re->test_break(re->tbh)) {
305       result->renlay = result->layers.first; /* weak, draws first layer always */
306       re->display_update(re->duh, result, NULL);
307     }
308   }
309
310   /* free */
311   BLI_remlink(&engine->fullresult, result);
312   render_result_free(result);
313 }
314
315 RenderResult *RE_engine_get_result(RenderEngine *engine)
316 {
317   return engine->re->result;
318 }
319
320 /* Cancel */
321
322 bool RE_engine_test_break(RenderEngine *engine)
323 {
324   Render *re = engine->re;
325
326   if (re) {
327     return re->test_break(re->tbh);
328   }
329
330   return 0;
331 }
332
333 /* Statistics */
334
335 void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info)
336 {
337   Render *re = engine->re;
338
339   /* stats draw callback */
340   if (re) {
341     re->i.statstr = stats;
342     re->i.infostr = info;
343     re->stats_draw(re->sdh, &re->i);
344     re->i.infostr = NULL;
345     re->i.statstr = NULL;
346   }
347
348   /* set engine text */
349   engine->text[0] = '\0';
350
351   if (stats && stats[0] && info && info[0]) {
352     BLI_snprintf(engine->text, sizeof(engine->text), "%s | %s", stats, info);
353   }
354   else if (info && info[0]) {
355     BLI_strncpy(engine->text, info, sizeof(engine->text));
356   }
357   else if (stats && stats[0]) {
358     BLI_strncpy(engine->text, stats, sizeof(engine->text));
359   }
360 }
361
362 void RE_engine_update_progress(RenderEngine *engine, float progress)
363 {
364   Render *re = engine->re;
365
366   if (re) {
367     CLAMP(progress, 0.0f, 1.0f);
368     re->progress(re->prh, progress);
369   }
370 }
371
372 void RE_engine_update_memory_stats(RenderEngine *engine, float mem_used, float mem_peak)
373 {
374   Render *re = engine->re;
375
376   if (re) {
377     re->i.mem_used = mem_used;
378     re->i.mem_peak = mem_peak;
379   }
380 }
381
382 void RE_engine_report(RenderEngine *engine, int type, const char *msg)
383 {
384   Render *re = engine->re;
385
386   if (re) {
387     BKE_report(engine->re->reports, type, msg);
388   }
389   else if (engine->reports) {
390     BKE_report(engine->reports, type, msg);
391   }
392 }
393
394 void RE_engine_set_error_message(RenderEngine *engine, const char *msg)
395 {
396   Render *re = engine->re;
397   if (re != NULL) {
398     RenderResult *rr = RE_AcquireResultRead(re);
399     if (rr) {
400       if (rr->error != NULL) {
401         MEM_freeN(rr->error);
402       }
403       rr->error = BLI_strdup(msg);
404     }
405     RE_ReleaseResult(re);
406   }
407 }
408
409 const char *RE_engine_active_view_get(RenderEngine *engine)
410 {
411   Render *re = engine->re;
412   return RE_GetActiveRenderView(re);
413 }
414
415 void RE_engine_active_view_set(RenderEngine *engine, const char *viewname)
416 {
417   Render *re = engine->re;
418   RE_SetActiveRenderView(re, viewname);
419 }
420
421 float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera, bool use_spherical_stereo)
422 {
423   Render *re = engine->re;
424
425   /* When using spherical stereo, get camera shift without multiview,
426    * leaving stereo to be handled by the engine. */
427   if (use_spherical_stereo) {
428     re = NULL;
429   }
430
431   return BKE_camera_multiview_shift_x(re ? &re->r : NULL, camera, re->viewname);
432 }
433
434 void RE_engine_get_camera_model_matrix(RenderEngine *engine,
435                                        Object *camera,
436                                        bool use_spherical_stereo,
437                                        float *r_modelmat)
438 {
439   Render *re = engine->re;
440
441   /* When using spherical stereo, get model matrix without multiview,
442    * leaving stereo to be handled by the engine. */
443   if (use_spherical_stereo) {
444     re = NULL;
445   }
446
447   BKE_camera_multiview_model_matrix(
448       re ? &re->r : NULL, camera, re->viewname, (float(*)[4])r_modelmat);
449 }
450
451 bool 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          * workers than 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       total_tiles++;
497     }
498   }
499   BLI_rw_mutex_unlock(&re->partsmutex);
500   *r_total_tiles = total_tiles;
501   return tiles;
502 }
503
504 RenderData *RE_engine_get_render_data(Render *re)
505 {
506   return &re->r;
507 }
508
509 /* Depsgraph */
510 static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer)
511 {
512   Main *bmain = engine->re->main;
513   Scene *scene = engine->re->scene;
514
515   engine->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
516   DEG_debug_name_set(engine->depsgraph, "RENDER");
517
518   BKE_scene_graph_update_for_newframe(engine->depsgraph, bmain);
519 }
520
521 static void engine_depsgraph_free(RenderEngine *engine)
522 {
523   DEG_graph_free(engine->depsgraph);
524
525   engine->depsgraph = NULL;
526 }
527
528 void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
529 {
530   if (!engine->depsgraph) {
531     return;
532   }
533
534 #ifdef WITH_PYTHON
535   BPy_BEGIN_ALLOW_THREADS;
536 #endif
537
538   Render *re = engine->re;
539   double cfra = (double)frame + (double)subframe;
540
541   CLAMP(cfra, MINAFRAME, MAXFRAME);
542   BKE_scene_frame_set(re->scene, cfra);
543   BKE_scene_graph_update_for_newframe(engine->depsgraph, re->main);
544
545   BKE_scene_camera_switch_update(re->scene);
546
547 #ifdef WITH_PYTHON
548   BPy_END_ALLOW_THREADS;
549 #endif
550 }
551
552 /* Bake */
553 void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
554 {
555   re->scene = scene;
556   re->main = bmain;
557   render_copy_renderdata(&re->r, &scene->r);
558 }
559
560 bool RE_bake_has_engine(Render *re)
561 {
562   RenderEngineType *type = RE_engines_find(re->r.engine);
563   return (type->bake != NULL);
564 }
565
566 bool RE_bake_engine(Render *re,
567                     Depsgraph *depsgraph,
568                     Object *object,
569                     const int object_id,
570                     const BakePixel pixel_array[],
571                     const size_t num_pixels,
572                     const int depth,
573                     const eScenePassType pass_type,
574                     const int pass_filter,
575                     float result[])
576 {
577   RenderEngineType *type = RE_engines_find(re->r.engine);
578   RenderEngine *engine;
579   bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0;
580
581   /* set render info */
582   re->i.cfra = re->scene->r.cfra;
583   BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name) - 2);
584   re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0;
585
586   /* render */
587   engine = re->engine;
588
589   if (!engine) {
590     engine = RE_engine_create(type);
591     re->engine = engine;
592   }
593
594   engine->flag |= RE_ENGINE_RENDERING;
595
596   /* TODO: actually link to a parent which shouldn't happen */
597   engine->re = re;
598
599   engine->resolution_x = re->winx;
600   engine->resolution_y = re->winy;
601
602   RE_parts_init(re);
603   engine->tile_x = re->r.tilex;
604   engine->tile_y = re->r.tiley;
605
606   if (type->bake) {
607     engine->depsgraph = depsgraph;
608
609     /* update is only called so we create the engine.session */
610     if (type->update) {
611       type->update(engine, re->main, engine->depsgraph);
612     }
613
614     type->bake(engine,
615                engine->depsgraph,
616                object,
617                pass_type,
618                pass_filter,
619                object_id,
620                pixel_array,
621                num_pixels,
622                depth,
623                result);
624
625     engine->depsgraph = NULL;
626   }
627
628   engine->tile_x = 0;
629   engine->tile_y = 0;
630   engine->flag &= ~RE_ENGINE_RENDERING;
631
632   BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
633
634   /* re->engine becomes zero if user changed active render engine during render */
635   if (!persistent_data || !re->engine) {
636     RE_engine_free(engine);
637     re->engine = NULL;
638   }
639
640   RE_parts_free(re);
641   BLI_rw_mutex_unlock(&re->partsmutex);
642
643   if (BKE_reports_contain(re->reports, RPT_ERROR)) {
644     G.is_break = true;
645   }
646
647   return true;
648 }
649
650 /* Render */
651
652 int RE_engine_render(Render *re, int do_all)
653 {
654   RenderEngineType *type = RE_engines_find(re->r.engine);
655   RenderEngine *engine;
656   bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0;
657
658   /* verify if we can render */
659   if (!type->render) {
660     return 0;
661   }
662   if ((re->r.scemode & R_BUTS_PREVIEW) && !(type->flag & RE_USE_PREVIEW)) {
663     return 0;
664   }
665   if (do_all && !(type->flag & RE_USE_POSTPROCESS)) {
666     return 0;
667   }
668   if (!do_all && (type->flag & RE_USE_POSTPROCESS)) {
669     return 0;
670   }
671
672   /* Lock drawing in UI during data phase. */
673   if (re->draw_lock) {
674     re->draw_lock(re->dlh, 1);
675   }
676
677   /* update animation here so any render layer animation is applied before
678    * creating the render result */
679   if ((re->r.scemode & (R_NO_FRAME_UPDATE | R_BUTS_PREVIEW)) == 0) {
680     render_update_anim_renderdata(re, &re->scene->r, &re->scene->view_layers);
681   }
682
683   /* create render result */
684   BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
685   if (re->result == NULL || !(re->r.scemode & R_BUTS_PREVIEW)) {
686     int savebuffers = RR_USE_MEM;
687
688     if (re->result) {
689       render_result_free(re->result);
690     }
691
692     if ((type->flag & RE_USE_SAVE_BUFFERS) && (re->r.scemode & R_EXR_TILE_FILE)) {
693       savebuffers = RR_USE_EXR;
694     }
695     re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS, RR_ALL_VIEWS);
696   }
697   BLI_rw_mutex_unlock(&re->resultmutex);
698
699   if (re->result == NULL) {
700     /* Clear UI drawing locks. */
701     if (re->draw_lock) {
702       re->draw_lock(re->dlh, 0);
703     }
704     /* Too small image is handled earlier, here it could only happen if
705      * there was no sufficient memory to allocate all passes.
706      */
707     BKE_report(re->reports, RPT_ERROR, "Failed allocate render result, out of memory");
708     G.is_break = true;
709     return 1;
710   }
711
712   /* set render info */
713   re->i.cfra = re->scene->r.cfra;
714   BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name));
715   re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0;
716
717   /* render */
718   engine = re->engine;
719
720   if (!engine) {
721     engine = RE_engine_create(type);
722     re->engine = engine;
723   }
724
725   engine->flag |= RE_ENGINE_RENDERING;
726
727   /* TODO: actually link to a parent which shouldn't happen */
728   engine->re = re;
729
730   if (re->flag & R_ANIMATION) {
731     engine->flag |= RE_ENGINE_ANIMATION;
732   }
733   if (re->r.scemode & R_BUTS_PREVIEW) {
734     engine->flag |= RE_ENGINE_PREVIEW;
735   }
736   engine->camera_override = re->camera_override;
737
738   engine->resolution_x = re->winx;
739   engine->resolution_y = re->winy;
740
741   RE_parts_init(re);
742   engine->tile_x = re->partx;
743   engine->tile_y = re->party;
744
745   if (re->result->do_exr_tile) {
746     render_result_exr_file_begin(re, engine);
747   }
748
749   /* Clear UI drawing locks. */
750   if (re->draw_lock) {
751     re->draw_lock(re->dlh, 0);
752   }
753
754   if (type->render) {
755     FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer_iter) {
756       if (re->draw_lock) {
757         re->draw_lock(re->dlh, 1);
758       }
759
760       ViewLayer *view_layer = BLI_findstring(
761           &re->scene->view_layers, view_layer_iter->name, offsetof(ViewLayer, name));
762       engine_depsgraph_init(engine, view_layer);
763
764       if (type->update) {
765         type->update(engine, re->main, engine->depsgraph);
766       }
767
768       if (re->draw_lock) {
769         re->draw_lock(re->dlh, 0);
770       }
771
772       type->render(engine, engine->depsgraph);
773
774       /* Grease pencil render over previous render result.
775        *
776        * NOTE: External engine might have been requested to free its
777        * dependency graph, which is only allowed if there is no grease
778        * pencil (pipeline is taking care of that).
779        */
780       if (!RE_engine_test_break(engine) && engine->depsgraph != NULL) {
781         DRW_render_gpencil(engine, engine->depsgraph);
782       }
783
784       engine_depsgraph_free(engine);
785
786       if (RE_engine_test_break(engine)) {
787         break;
788       }
789     }
790     FOREACH_VIEW_LAYER_TO_RENDER_END;
791   }
792
793   engine->tile_x = 0;
794   engine->tile_y = 0;
795   engine->flag &= ~RE_ENGINE_RENDERING;
796
797   render_result_free_list(&engine->fullresult, engine->fullresult.first);
798
799   BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
800
801   if (re->result->do_exr_tile) {
802     render_result_exr_file_end(re, engine);
803   }
804
805   /* re->engine becomes zero if user changed active render engine during render */
806   if (!persistent_data || !re->engine) {
807     RE_engine_free(engine);
808     re->engine = NULL;
809   }
810
811   if (re->r.scemode & R_EXR_CACHE_FILE) {
812     BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
813     render_result_exr_file_cache_write(re);
814     BLI_rw_mutex_unlock(&re->resultmutex);
815   }
816
817   RE_parts_free(re);
818   BLI_rw_mutex_unlock(&re->partsmutex);
819
820   if (BKE_reports_contain(re->reports, RPT_ERROR)) {
821     G.is_break = true;
822   }
823
824 #ifdef WITH_FREESTYLE
825   if (re->r.mode & R_EDGE_FRS) {
826     RE_RenderFreestyleExternal(re);
827   }
828 #endif
829
830   return 1;
831 }
832
833 void RE_engine_update_render_passes(struct RenderEngine *engine,
834                                     struct Scene *scene,
835                                     struct ViewLayer *view_layer,
836                                     update_render_passes_cb_t callback,
837                                     void *callback_data)
838 {
839   if (!(scene && view_layer && engine && callback && engine->type->update_render_passes)) {
840     return;
841   }
842
843   BLI_mutex_lock(&engine->update_render_passes_mutex);
844
845   engine->update_render_passes_cb = callback;
846   engine->update_render_passes_data = callback_data;
847   engine->type->update_render_passes(engine, scene, view_layer);
848   engine->update_render_passes_cb = NULL;
849   engine->update_render_passes_data = NULL;
850
851   BLI_mutex_unlock(&engine->update_render_passes_mutex);
852 }
853
854 void RE_engine_register_pass(struct RenderEngine *engine,
855                              struct Scene *scene,
856                              struct ViewLayer *view_layer,
857                              const char *name,
858                              int channels,
859                              const char *chanid,
860                              int type)
861 {
862   if (!(scene && view_layer && engine && engine->update_render_passes_cb)) {
863     return;
864   }
865
866   engine->update_render_passes_cb(
867       engine->update_render_passes_data, scene, view_layer, name, channels, chanid, type);
868 }
869
870 void RE_engine_free_blender_memory(RenderEngine *engine)
871 {
872   /* Weak way to save memory, but not crash grease pencil.
873    *
874    * TODO(sergey): Find better solution for this.
875    * TODO(sergey): Try to find solution which does not involve looping over
876    * all the objects.
877    */
878   if (DRW_render_check_grease_pencil(engine->depsgraph)) {
879     return;
880   }
881   DEG_graph_free(engine->depsgraph);
882   engine->depsgraph = NULL;
883 }