Blender V4.5
source/blender/render/intern/pipeline.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2006 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <fmt/format.h>
10
11#include <cerrno>
12#include <cstddef>
13#include <cstdlib>
14#include <cstring>
15#include <forward_list>
16
17#include "DNA_anim_types.h"
18#include "DNA_image_types.h"
19#include "DNA_node_types.h"
20#include "DNA_object_types.h"
21#include "DNA_scene_types.h"
22#include "DNA_sequence_types.h"
23#include "DNA_space_types.h"
25
26#include "MEM_guardedalloc.h"
27
28#include "BLI_fileops.h"
29#include "BLI_listbase.h"
30#include "BLI_map.hh"
31#include "BLI_mutex.hh"
32#include "BLI_rect.h"
33#include "BLI_set.hh"
34#include "BLI_string.h"
35#include "BLI_threads.h"
36#include "BLI_time.h"
37#include "BLI_timecode.h"
38#include "BLI_vector.hh"
39
40#include "BLT_translation.hh"
41
42#include "BKE_anim_data.hh"
43#include "BKE_animsys.h" /* <------ should this be here?, needed for sequencer update */
44#include "BKE_callbacks.hh"
45#include "BKE_camera.h"
46#include "BKE_colortools.hh"
47#include "BKE_global.hh"
48#include "BKE_image.hh"
49#include "BKE_image_format.hh"
50#include "BKE_image_save.hh"
51#include "BKE_layer.hh"
52#include "BKE_lib_id.hh"
53#include "BKE_lib_remap.hh"
54#include "BKE_main.hh"
55#include "BKE_mask.h"
56#include "BKE_modifier.hh"
58#include "BKE_node_runtime.hh"
59#include "BKE_pointcache.h"
60#include "BKE_report.hh"
61#include "BKE_scene.hh"
62#include "BKE_sound.h"
63
64#include "NOD_composite.hh"
65
66#include "COM_compositor.hh"
67#include "COM_context.hh"
68#include "COM_render_context.hh"
69
70#include "DEG_depsgraph.hh"
74
76#include "IMB_imbuf.hh"
77#include "IMB_imbuf_types.hh"
78#include "IMB_metadata.hh"
79
80#include "MOV_write.hh"
81
82#include "RE_engine.h"
83#include "RE_pipeline.h"
84#include "RE_texture.h"
85
86#include "SEQ_relations.hh"
87#include "SEQ_render.hh"
88
89#include "GPU_capabilities.hh"
90#include "GPU_context.hh"
91#include "WM_api.hh"
92#include "wm_window.hh"
93
94#ifdef WITH_FREESTYLE
95# include "FRS_freestyle.h"
96#endif
97
98/* internal */
99#include "pipeline.hh"
100#include "render_result.h"
101#include "render_types.h"
102
104
105/* render flow
106 *
107 * 1) Initialize state
108 * - state data, tables
109 * - movie/image file init
110 * - everything that doesn't change during animation
111 *
112 * 2) Initialize data
113 * - camera, world, matrices
114 * - make render verts, faces, halos, strands
115 * - everything can change per frame/field
116 *
117 * 3) Render Processor
118 * - multiple layers
119 * - tiles, rect, baking
120 * - layers/tiles optionally to disk or directly in Render Result
121 *
122 * 4) Composite Render Result
123 * - also read external files etc
124 *
125 * 5) Image Files
126 * - save file or append in movie
127 */
128
129/* -------------------------------------------------------------------- */
132
133/* here we store all renders */
134static struct {
135 std::forward_list<Render *> render_list;
136 /* Special renders that can be used for interactive compositing, each scene has its own render,
137 * keyed with the scene name returned from scene_render_name_get and matches the same name in
138 * render_list. Those renders are separate from standard renders because the GPU context can't be
139 * bound for compositing and rendering at the same time, so those renders are essentially used to
140 * get a persistent dedicated GPU context to interactive compositor execution. */
143
145
146/* -------------------------------------------------------------------- */
149
150static void render_callback_exec_string(Render *re, Main *bmain, eCbEvent evt, const char *str)
151{
152 if (re->r.scemode & R_BUTS_PREVIEW) {
153 return;
154 }
155 BKE_callback_exec_string(bmain, evt, str);
156}
157
158static void render_callback_exec_id(Render *re, Main *bmain, ID *id, eCbEvent evt)
159{
160 if (re->r.scemode & R_BUTS_PREVIEW) {
161 return;
162 }
163 BKE_callback_exec_id(bmain, id, evt);
164}
165
167
168/* -------------------------------------------------------------------- */
171
172static bool do_write_image_or_movie(
173 Render *re, Main *bmain, Scene *scene, const int totvideos, const char *filepath_override);
174
175/* default callbacks, set in each new render */
176static void result_nothing(void * /*arg*/, RenderResult * /*rr*/) {}
177static void result_rcti_nothing(void * /*arg*/, RenderResult * /*rr*/, rcti * /*rect*/) {}
178static void current_scene_nothing(void * /*arg*/, Scene * /*scene*/) {}
179static bool prepare_viewlayer_nothing(void * /*arg*/,
180 ViewLayer * /*vl*/,
181 Depsgraph * /*depsgraph*/)
182{
183 return true;
184}
185static void stats_nothing(void * /*arg*/, RenderStats * /*rs*/) {}
186static void float_nothing(void * /*arg*/, float /*val*/) {}
187static bool default_break(void * /*arg*/)
188{
189 return G.is_break == true;
190}
191
192static void stats_background(void * /*arg*/, RenderStats *rs)
193{
194 if (rs->infostr == nullptr) {
195 return;
196 }
197
198 uintptr_t mem_in_use, peak_memory;
199 float megs_used_memory, megs_peak_memory;
200 char info_time_str[32];
201
203 peak_memory = MEM_get_peak_memory();
204
205 megs_used_memory = (mem_in_use) / (1024.0 * 1024.0);
206 megs_peak_memory = (peak_memory) / (1024.0 * 1024.0);
207
209 info_time_str, sizeof(info_time_str), BLI_time_now_seconds() - rs->starttime);
210
211 /* Compositor calls this from multiple threads, mutex lock to ensure we don't
212 * get garbled output. */
213 static blender::Mutex mutex;
214 std::scoped_lock lock(mutex);
215
216 char *message = BLI_sprintfN(RPT_("Fra:%d Mem:%.2fM (Peak %.2fM) | Time:%s | %s"),
217 rs->cfra,
218 megs_used_memory,
219 megs_peak_memory,
220 info_time_str,
221 rs->infostr);
222
223 if (!G.quiet) {
224 fprintf(stdout, "%s\n", message);
225
226 /* Flush stdout to be sure python callbacks are printing stuff after blender. */
227 fflush(stdout);
228 }
229
230 /* NOTE: using G_MAIN seems valid here???
231 * Not sure it's actually even used anyway, we could as well pass nullptr? */
233
234 if (!G.quiet) {
235 fflush(stdout);
236 }
237
238 MEM_freeN(message);
239}
240
242{
243 /* There is no need to lock as the user-counted render results are protected by mutex at the
244 * higher call stack level. */
245 ++rr->user_counter;
246}
247
252
253ImBuf *RE_RenderLayerGetPassImBuf(RenderLayer *rl, const char *name, const char *viewname)
254{
255 RenderPass *rpass = RE_pass_find_by_name(rl, name, viewname);
256 return rpass ? rpass->ibuf : nullptr;
257}
258
259float *RE_RenderLayerGetPass(RenderLayer *rl, const char *name, const char *viewname)
260{
261 const ImBuf *ibuf = RE_RenderLayerGetPassImBuf(rl, name, viewname);
262 return ibuf ? ibuf->float_buffer.data : nullptr;
263}
264
266{
267 if (rr == nullptr) {
268 return nullptr;
269 }
270
271 return static_cast<RenderLayer *>(
272 BLI_findstring(&rr->layers, name, offsetof(RenderLayer, name)));
273}
274
276{
277 return (re->r.scemode & R_SINGLE_LAYER);
278}
279
281 void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
282{
283 return render_result_new_from_exr(exrhandle, colorspace, predivide, rectx, recty);
284}
285
287{
288 if (re->single_view_layer[0]) {
290
291 if (rl) {
292 return rl;
293 }
294 }
295
296 return static_cast<RenderLayer *>(rr->layers.first);
297}
298
299static bool render_scene_has_layers_to_render(Scene *scene, ViewLayer *single_layer)
300{
301 if (single_layer) {
302 return true;
303 }
304
305 LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
306 if (view_layer->flag & VIEW_LAYER_RENDER) {
307 return true;
308 }
309 }
310 return false;
311}
312
314
315/* -------------------------------------------------------------------- */
318
319Render *RE_GetRender(const char *name)
320{
321 /* search for existing renders */
322 for (Render *re : RenderGlobal.render_list) {
323 if (STREQLEN(re->name, name, RE_MAXNAME)) {
324 return re;
325 }
326 }
327
328 return nullptr;
329}
330
332{
333 if (re) {
335 return re->result;
336 }
337
338 return nullptr;
339}
340
342{
343 if (re) {
346 return re->result;
347 }
348
349 return nullptr;
350}
351
353{
354 if (re) {
356 re->result = nullptr;
358 }
359}
360
362{
363 /* for keeping render buffers */
364 if (re) {
365 std::swap(re->result, *rr);
366 }
367}
368
370{
371 if (re) {
373 }
374}
375
377{
378 if (re) {
379 return re->scene;
380 }
381 return nullptr;
382}
383
384void RE_SetScene(Render *re, Scene *sce)
385{
386 if (re) {
387 re->scene = sce;
388 }
389}
390
392{
393 memset(rr, 0, sizeof(RenderResult));
394
395 if (re) {
397
398 if (re->result) {
399 rr->rectx = re->result->rectx;
400 rr->recty = re->result->recty;
401
402 copy_v2_v2_db(rr->ppm, re->result->ppm);
403
404 /* creates a temporary duplication of views */
406
407 RenderView *rv = static_cast<RenderView *>(rr->views.first);
408 rr->have_combined = (rv->ibuf != nullptr);
409
410 /* single layer */
412
413 /* The render result uses shallow initialization, and the caller is not expected to
414 * explicitly free it. So simply assign the buffers as a shallow copy here as well. */
415
416 if (rl) {
417 if (rv->ibuf == nullptr) {
418 LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
419 rview->ibuf = RE_RenderLayerGetPassImBuf(rl, RE_PASSNAME_COMBINED, rview->name);
420 }
421 }
422 }
423
424 rr->layers = re->result->layers;
425 rr->xof = re->disprect.xmin;
426 rr->yof = re->disprect.ymin;
427 rr->stamp_data = re->result->stamp_data;
428 }
429 }
430}
431
433{
434 if (re) {
435 if (rr) {
437 }
439 }
440}
441
442void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
443{
444 memset(rr, 0, sizeof(RenderResult));
445
446 if (re) {
448
449 if (re->result) {
450 RenderLayer *rl;
451 RenderView *rv;
452
453 rr->rectx = re->result->rectx;
454 rr->recty = re->result->recty;
455
456 copy_v2_v2_db(rr->ppm, re->result->ppm);
457
458 /* `scene.rd.actview` view. */
459 rv = RE_RenderViewGetById(re->result, view_id);
460 rr->have_combined = (rv->ibuf != nullptr);
461
462 /* The render result uses shallow initialization, and the caller is not expected to
463 * explicitly free it. So simply assign the buffers as a shallow copy here as well.
464 *
465 * The thread safety is ensured via the `re->resultmutex`. */
466 rr->ibuf = rv->ibuf;
467
468 /* active layer */
469 rl = render_get_single_layer(re, re->result);
470
471 if (rl) {
472 if (rv->ibuf == nullptr) {
474 }
475 }
476
477 rr->layers = re->result->layers;
478 rr->views = re->result->views;
479
480 rr->xof = re->disprect.xmin;
481 rr->yof = re->disprect.ymin;
482
483 rr->stamp_data = re->result->stamp_data;
484 }
485 }
486}
487
489{
490 if (re) {
492 }
493}
494
495void RE_ResultGet32(Render *re, uint *rect)
496{
497 RenderResult rres;
498 const int view_id = BKE_scene_multiview_view_id_get(&re->r, re->viewname);
499
502 rect,
503 re->rectx,
504 re->recty,
505 &re->scene->view_settings,
507 view_id);
509}
510
512{
513 RenderView *view = static_cast<RenderView *>(rr->views.first);
514 return (view && (view->next || view->name[0]));
515}
516
518{
519 return &re->i;
520}
521
522Render *RE_NewRender(const char *name)
523{
524 Render *re;
525
526 /* only one render per name exists */
527 re = RE_GetRender(name);
528 if (re == nullptr) {
529
530 /* new render data struct */
531 re = MEM_new<Render>("new render");
532 RenderGlobal.render_list.push_front(re);
533 STRNCPY(re->name, name);
534 }
535
536 RE_InitRenderCB(re);
537
538 return re;
539}
540
542{
543 ViewRender *view_render = MEM_new<ViewRender>("new view render");
544 view_render->engine = RE_engine_create(engine_type);
545 return view_render;
546}
547
548/* MAX_ID_NAME + sizeof(Library->name) + space + null-terminator. */
549#define MAX_SCENE_RENDER_NAME (MAX_ID_NAME + 1024 + 2)
550
551static void scene_render_name_get(const Scene *scene, const size_t max_size, char *render_name)
552{
553 if (ID_IS_LINKED(scene)) {
554 BLI_snprintf(render_name, max_size, "%s %s", scene->id.lib->id.name, scene->id.name);
555 }
556 else {
557 BLI_snprintf(render_name, max_size, "%s", scene->id.name);
558 }
559}
560
562{
563 char render_name[MAX_SCENE_RENDER_NAME];
564 scene_render_name_get(scene, sizeof(render_name), render_name);
565 return RE_GetRender(render_name);
566}
567
569{
570 char render_name[MAX_SCENE_RENDER_NAME];
571 scene_render_name_get(scene, sizeof(render_name), render_name);
572 return RE_NewRender(render_name);
573}
574
576{
577 char render_name[MAX_SCENE_RENDER_NAME];
578 scene_render_name_get(scene, sizeof(render_name), render_name);
579
580 return RenderGlobal.interactive_compositor_renders.lookup_or_add_cb(render_name, [&]() {
581 Render *render = MEM_new<Render>("New Interactive Compositor Render");
582 STRNCPY(render->name, render_name);
583 RE_InitRenderCB(render);
584 return render;
585 });
586}
587
589{
590 /* set default empty callbacks */
598 if (G.background) {
600 }
601 else {
603 }
604 re->draw_lock_cb = nullptr;
605 /* clear callback handles */
606 re->dih = re->dch = re->duh = re->sdh = re->prh = re->tbh = re->dlh = nullptr;
607}
608
610{
611 RenderGlobal.render_list.remove(re);
612
613 MEM_delete(re);
614}
615
617{
618 MEM_delete(view_render);
619}
620
622{
623 while (!RenderGlobal.render_list.empty()) {
624 RE_FreeRender(static_cast<Render *>(RenderGlobal.render_list.front()));
625 }
626
628
629#ifdef WITH_FREESTYLE
630 /* finalize Freestyle */
631 FRS_exit();
632#endif
633}
634
636{
637 for (Render *render : RenderGlobal.interactive_compositor_renders.values()) {
638 RE_FreeRender(render);
639 }
640 RenderGlobal.interactive_compositor_renders.clear();
641}
642
644{
645 for (Render *re : RenderGlobal.render_list) {
648
649 re->result = nullptr;
650 re->pushedresult = nullptr;
652 }
653}
654
656{
657 for (Render *re : RenderGlobal.render_list) {
658 if (re->engine != nullptr) {
661 re->engine = nullptr;
662 }
663 }
664}
665
667{
668 /* Free persistent compositor that may be using these textures. */
669 if (re->compositor) {
671 }
672
673 /* Free textures. */
676 if (result != nullptr) {
678 }
681 }
682}
683
685{
686 for (Render *re : RenderGlobal.render_list) {
688 }
689}
690
692{
694
695 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
696
697 for (Render *re : RenderGlobal.render_list) {
698 bool do_free = true;
699
700 LISTBASE_FOREACH (const wmWindow *, win, &wm->windows) {
701 const Scene *scene = WM_window_get_active_scene(win);
702 if (re != RE_GetSceneRender(scene)) {
703 continue;
704 }
705
706 /* Don't free if this scene is being rendered or composited. Note there is no
707 * race condition here because we are on the main thread and new jobs can only
708 * be started from the main thread. */
709 if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER) ||
711 {
712 do_free = false;
713 break;
714 }
715
716 /* Detect if scene is using GPU compositing, and if either a node editor is
717 * showing the nodes, or an image editor is showing the render result or viewer. */
718 if (!(scene->use_nodes && scene->nodetree &&
720 {
721 continue;
722 }
723
724 const bScreen *screen = WM_window_get_active_screen(win);
725 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
726 const SpaceLink &space = *static_cast<const SpaceLink *>(area->spacedata.first);
727
728 if (space.spacetype == SPACE_NODE) {
729 const SpaceNode &snode = reinterpret_cast<const SpaceNode &>(space);
730 if (snode.nodetree == scene->nodetree) {
731 do_free = false;
732 }
733 }
734 else if (space.spacetype == SPACE_IMAGE) {
735 const SpaceImage &sima = reinterpret_cast<const SpaceImage &>(space);
736 if (sima.image && sima.image->source == IMA_SRC_VIEWER) {
737 do_free = false;
738 }
739 }
740 }
741 }
742
743 if (do_free) {
747
748 /* We also free the resources from the interactive compositor render of the scene if one
749 * exists. */
750 Render *interactive_compositor_render =
751 RenderGlobal.interactive_compositor_renders.lookup_default(re->name, nullptr);
752 if (interactive_compositor_render) {
753 re_gpu_texture_caches_free(interactive_compositor_render);
754 RE_blender_gpu_context_free(interactive_compositor_render);
755 RE_system_gpu_context_free(interactive_compositor_render);
756 }
757 }
758 }
759}
760
762{
763 /* If engine is currently rendering, just wait for it to be freed when it finishes rendering.
764 */
765 if (re->engine && !(re->engine->flag & RE_ENGINE_RENDERING)) {
767 re->engine = nullptr;
768 }
769}
770
771void RE_FreePersistentData(const Scene *scene)
772{
773 /* Render engines can be kept around for quick re-render, this clears all or one scene. */
774 if (scene) {
775 Render *re = RE_GetSceneRender(scene);
776 if (re) {
778 }
779 }
780 else {
781 for (Render *re : RenderGlobal.render_list) {
783 }
784 }
785}
786
788
789/* -------------------------------------------------------------------- */
792
794 Render *re, Render *source, int winx, int winy, const rcti *disprect)
795{
796 re->winx = winx;
797 re->winy = winy;
798 if (source && (source->r.mode & R_BORDER)) {
799 /* NOTE(@sergey): doesn't seem original bordered `disprect` is storing anywhere
800 * after insertion on black happening in #do_render_engine(),
801 * so for now simply re-calculate `disprect` using border from source renderer. */
802
803 re->disprect.xmin = source->r.border.xmin * winx;
804 re->disprect.xmax = source->r.border.xmax * winx;
805
806 re->disprect.ymin = source->r.border.ymin * winy;
807 re->disprect.ymax = source->r.border.ymax * winy;
808
809 re->rectx = BLI_rcti_size_x(&re->disprect);
810 re->recty = BLI_rcti_size_y(&re->disprect);
811
812 /* copy border itself, since it could be used by external engines */
813 re->r.border = source->r.border;
814 }
815 else if (disprect) {
816 re->disprect = *disprect;
817 re->rectx = BLI_rcti_size_x(&re->disprect);
818 re->recty = BLI_rcti_size_y(&re->disprect);
819 }
820 else {
821 re->disprect.xmin = re->disprect.ymin = 0;
822 re->disprect.xmax = winx;
823 re->disprect.ymax = winy;
824 re->rectx = winx;
825 re->recty = winy;
826 }
827}
828
830{
831 /* Mostly shallow copy referencing pointers in scene renderdata. */
833
834 memcpy(to, from, sizeof(*to));
835
837}
838
840 Render *source,
841 RenderData *rd,
842 ListBase * /*render_layers*/,
843 ViewLayer *single_layer,
844 int winx,
845 int winy,
846 const rcti *disprect)
847{
848 bool had_freestyle = (re->r.mode & R_EDGE_FRS) != 0;
849
850 re->ok = true; /* maybe flag */
851
853
854 /* copy render data and render layers for thread safety */
855 render_copy_renderdata(&re->r, rd);
856 re->single_view_layer[0] = '\0';
857
858 if (source) {
859 /* reuse border flags from source renderer */
860 re->r.mode &= ~(R_BORDER | R_CROP);
861 re->r.mode |= source->r.mode & (R_BORDER | R_CROP);
862
863 /* dimensions shall be shared between all renderers */
864 re->r.xsch = source->r.xsch;
865 re->r.ysch = source->r.ysch;
866 re->r.size = source->r.size;
867 }
868
869 re_init_resolution(re, source, winx, winy, disprect);
870
871 /* disable border if it's a full render anyway */
872 if (re->r.border.xmin == 0.0f && re->r.border.xmax == 1.0f && re->r.border.ymin == 0.0f &&
873 re->r.border.ymax == 1.0f)
874 {
875 re->r.mode &= ~R_BORDER;
876 }
877
878 if (re->rectx < 1 || re->recty < 1 ||
879 (BKE_imtype_is_movie(rd->im_format.imtype) && (re->rectx < 16 || re->recty < 16)))
880 {
881 BKE_report(re->reports, RPT_ERROR, "Image too small");
882 re->ok = false;
883 return;
884 }
885
886 if (single_layer) {
887 STRNCPY(re->single_view_layer, single_layer->name);
888 re->r.scemode |= R_SINGLE_LAYER;
889 }
890 else {
892 }
893
894 /* if preview render, we try to keep old result */
896
897 if (re->r.scemode & R_BUTS_PREVIEW) {
898 if (had_freestyle || (re->r.mode & R_EDGE_FRS)) {
899 /* freestyle manipulates render layers so always have to free */
901 re->result = nullptr;
902 }
903 else if (re->result) {
904 bool have_layer = false;
905
906 if (re->single_view_layer[0] == '\0' && re->result->layers.first) {
907 have_layer = true;
908 }
909 else {
911 if (STREQ(rl->name, re->single_view_layer)) {
912 have_layer = true;
913 }
914 }
915 }
916
917 if (re->result->rectx == re->rectx && re->result->recty == re->recty && have_layer) {
918 /* keep render result, this avoids flickering black tiles
919 * when the preview changes */
920 }
921 else {
922 /* free because resolution changed */
924 re->result = nullptr;
925 }
926 }
927 }
928 else {
929
930 /* make empty render result, so display callbacks can initialize */
932 re->result = MEM_callocN<RenderResult>("new render result");
933 re->result->rectx = re->rectx;
934 re->result->recty = re->recty;
935 BKE_scene_ppm_get(&re->r, re->result->ppm);
937 }
938
940
942
944}
945
946void RE_display_init_cb(Render *re, void *handle, void (*f)(void *handle, RenderResult *rr))
947{
948 re->display_init_cb = f;
949 re->dih = handle;
950}
951void RE_display_clear_cb(Render *re, void *handle, void (*f)(void *handle, RenderResult *rr))
952{
953 re->display_clear_cb = f;
954 re->dch = handle;
955}
957 void *handle,
958 void (*f)(void *handle, RenderResult *rr, rcti *rect))
959{
960 re->display_update_cb = f;
961 re->duh = handle;
962}
963void RE_current_scene_update_cb(Render *re, void *handle, void (*f)(void *handle, Scene *scene))
964{
966 re->suh = handle;
967}
968void RE_stats_draw_cb(Render *re, void *handle, void (*f)(void *handle, RenderStats *rs))
969{
970 re->stats_draw_cb = f;
971 re->sdh = handle;
972}
973void RE_progress_cb(Render *re, void *handle, void (*f)(void *handle, float))
974{
975 re->progress_cb = f;
976 re->prh = handle;
977}
978
979void RE_draw_lock_cb(Render *re, void *handle, void (*f)(void *handle, bool lock))
980{
981 re->draw_lock_cb = f;
982 re->dlh = handle;
983}
984
985void RE_test_break_cb(Render *re, void *handle, bool (*f)(void *handle))
986{
987 re->test_break_cb = f;
988 re->tbh = handle;
989}
990
992 void *handle,
993 bool (*f)(void *handle, ViewLayer *vl, Depsgraph *depsgraph))
994{
995 re->prepare_viewlayer_cb = f;
996 re->prepare_vl_handle = handle;
997}
998
1000
1001/* -------------------------------------------------------------------- */
1004
1006{
1008
1009 if (re->system_gpu_context == nullptr) {
1010 /* Needs to be created in the main thread. */
1012 /* The context is activated during creation, so release it here since the function should not
1013 * have context activation as a side effect. Then activate the drawable's context below. */
1014 if (re->system_gpu_context) {
1016 }
1018 }
1019}
1020
1022{
1023 if (re->system_gpu_context) {
1024 if (re->blender_gpu_context) {
1026 GPU_context_active_set(static_cast<GPUContext *>(re->blender_gpu_context));
1027 GPU_context_discard(static_cast<GPUContext *>(re->blender_gpu_context));
1028 re->blender_gpu_context = nullptr;
1029 }
1030
1032 re->system_gpu_context = nullptr;
1033
1034 /* If in main thread, reset window context. */
1035 if (BLI_thread_is_main()) {
1037 }
1038 }
1039}
1040
1042{
1043 return re->system_gpu_context;
1044}
1045
1047{
1048 if (re->blender_gpu_context == nullptr) {
1050 }
1051 return re->blender_gpu_context;
1052}
1053
1055{
1056 if (re->blender_gpu_context) {
1058 GPU_context_active_set(static_cast<GPUContext *>(re->blender_gpu_context));
1059 GPU_context_discard(static_cast<GPUContext *>(re->blender_gpu_context));
1060 re->blender_gpu_context = nullptr;
1061 }
1062}
1063
1065
1066/* -------------------------------------------------------------------- */
1073
1074/* ************ This part uses API, for rendering Blender scenes ********** */
1075
1076/* make sure disprect is not affected by the render border */
1078{
1079 re->disprect.xmin = re->disprect.ymin = 0;
1080 re->disprect.xmax = re->winx;
1081 re->disprect.ymax = re->winy;
1082 re->rectx = re->winx;
1083 re->recty = re->winy;
1084}
1085
1087{
1088 /* when using border render with crop disabled, insert render result into
1089 * full size with black pixels outside */
1090 if (re->result && (re->r.mode & R_BORDER)) {
1091 if ((re->r.mode & R_CROP) == 0) {
1092 RenderResult *rres;
1093
1094 /* backup */
1095 const rcti orig_disprect = re->disprect;
1096 const int orig_rectx = re->rectx, orig_recty = re->recty;
1097
1099
1100 /* sub-rect for merge call later on */
1101 re->result->tilerect = re->disprect;
1102
1103 /* weak is: it chances disprect from border */
1105
1108
1109 render_result_clone_passes(re, rres, nullptr);
1111
1112 render_result_merge(rres, re->result);
1114 re->result = rres;
1115
1116 /* Weak, the display callback wants an active render-layer pointer. */
1118
1120
1121 re->display_init(re->result);
1122 re->display_update(re->result, nullptr);
1123
1124 /* restore the disprect from border */
1125 re->disprect = orig_disprect;
1126 re->rectx = orig_rectx;
1127 re->recty = orig_recty;
1128 }
1129 else {
1130 /* set offset (again) for use in compositor, disprect was manipulated. */
1131 re->result->xof = 0;
1132 re->result->yof = 0;
1133 }
1134 }
1135}
1136
1137/* Render scene into render result, with a render engine. */
1138static void do_render_engine(Render *re)
1139{
1140 Object *camera = RE_GetCamera(re);
1141 /* also check for camera here */
1142 if (camera == nullptr) {
1143 BKE_report(re->reports, RPT_ERROR, "Cannot render, no camera");
1144 G.is_break = true;
1145 return;
1146 }
1147
1148 /* now use renderdata and camera to set viewplane */
1149 RE_SetCamera(re, camera);
1150
1151 re->current_scene_update(re->scene);
1152 RE_engine_render(re, false);
1153
1154 /* when border render, check if we have to insert it in black */
1156}
1157
1158/* Render scene into render result, within a compositor node tree.
1159 * Uses the same image dimensions, does not recursively perform compositing. */
1160static void do_render_compositor_scene(Render *re, Scene *sce, int cfra)
1161{
1162 Render *resc = RE_NewSceneRender(sce);
1163 int winx = re->winx, winy = re->winy;
1164
1165 sce->r.cfra = cfra;
1166
1168
1169 /* exception: scene uses its own size (unfinished code) */
1170 if (false) {
1171 BKE_render_resolution(&sce->r, false, &winx, &winy);
1172 }
1173
1174 /* initial setup */
1175 RE_InitState(resc, re, &sce->r, &sce->view_layers, nullptr, winx, winy, &re->disprect);
1176
1177 /* We still want to use "Render Cache" setting from the original (main) scene. */
1178 resc->r.scemode = (resc->r.scemode & ~R_EXR_CACHE_FILE) | (re->r.scemode & R_EXR_CACHE_FILE);
1179
1180 /* still unsure entity this... */
1181 resc->main = re->main;
1182 resc->scene = sce;
1183
1184 /* copy callbacks */
1186 resc->duh = re->duh;
1187 resc->test_break_cb = re->test_break_cb;
1188 resc->tbh = re->tbh;
1189 resc->stats_draw_cb = re->stats_draw_cb;
1190 resc->sdh = re->sdh;
1192 resc->suh = re->suh;
1193
1194 do_render_engine(resc);
1195}
1196
1197/* Get the scene referenced by the given node if the node uses its render. Returns nullptr
1198 * otherwise. */
1200{
1201 if (node->is_muted()) {
1202 return nullptr;
1203 }
1204
1205 if (node->type_legacy == CMP_NODE_R_LAYERS) {
1206 return reinterpret_cast<Scene *>(node->id);
1207 }
1208 if (node->type_legacy == CMP_NODE_CRYPTOMATTE &&
1210 {
1211 return reinterpret_cast<Scene *>(node->id);
1212 }
1213
1214 return nullptr;
1215}
1216
1217/* Returns true if the given scene needs a render, either because it doesn't use the compositor
1218 * pipeline and thus needs a simple render, or that its compositor node tree requires the scene to
1219 * be rendered. */
1221{
1222 bNodeTree *ntree = scene->nodetree;
1223
1224 if (ntree == nullptr) {
1225 return true;
1226 }
1227 if (scene->use_nodes == false) {
1228 return true;
1229 }
1230 if ((scene->r.scemode & R_DOCOMP) == 0) {
1231 return true;
1232 }
1233
1234 for (const bNode *node : ntree->all_nodes()) {
1235 Scene *node_scene = get_scene_referenced_by_node(node);
1236 if (node_scene && node_scene == scene) {
1237 return true;
1238 }
1239 }
1240
1241 return false;
1242}
1243
1245static bool node_tree_has_composite_output(const bNodeTree *node_tree)
1246{
1247 if (node_tree == nullptr) {
1248 return false;
1249 }
1250
1251 for (const bNode *node : node_tree->all_nodes()) {
1252 if (node->is_muted()) {
1253 continue;
1254 }
1255 if (node->type_legacy == CMP_NODE_COMPOSITE && node->flag & NODE_DO_OUTPUT) {
1256 return true;
1257 }
1258 if (node->is_group() && node->id) {
1259 if (node_tree_has_composite_output(reinterpret_cast<const bNodeTree *>(node->id))) {
1260 return true;
1261 }
1262 }
1263 }
1264 return false;
1265}
1266
1267/* Render all scenes references by the compositor of the given render's scene. */
1269{
1270 if (re->scene->nodetree == nullptr) {
1271 return;
1272 }
1273
1274 /* For each node that requires a scene we do a full render. Results are stored in a way
1275 * compositor will find it. */
1276 blender::Set<Scene *> scenes_rendered;
1277 for (bNode *node : re->scene->nodetree->all_nodes()) {
1278 Scene *node_scene = get_scene_referenced_by_node(node);
1279 if (!node_scene) {
1280 continue;
1281 }
1282
1283 /* References the current scene, which was already rendered. */
1284 if (node_scene == re->scene) {
1285 continue;
1286 }
1287
1288 /* Scene already rendered as required by another node. */
1289 if (scenes_rendered.contains(node_scene)) {
1290 continue;
1291 }
1292
1293 if (!render_scene_has_layers_to_render(node_scene, nullptr)) {
1294 continue;
1295 }
1296
1297 scenes_rendered.add_new(node_scene);
1298 do_render_compositor_scene(re, node_scene, re->scene->r.cfra);
1299 node->typeinfo->updatefunc(re->scene->nodetree, node);
1300 }
1301
1302 /* If another scene was rendered, switch back to the current scene. */
1303 if (!scenes_rendered.is_empty()) {
1304 re->current_scene_update(re->scene);
1305 }
1306}
1307
1308/* bad call... need to think over proper method still */
1309static void render_compositor_stats(void *arg, const char *str)
1310{
1311 Render *re = (Render *)arg;
1312
1313 RenderStats i;
1314 memcpy(&i, &re->i, sizeof(i));
1315 i.infostr = str;
1316 re->stats_draw(&i);
1317}
1318
1319/* Render compositor nodes, along with any scenes required for them.
1320 * The result will be output into a compositing render layer in the render result. */
1322{
1324 bool update_newframe = false;
1325
1327 /* render the frames
1328 * it could be optimized to render only the needed view
1329 * but what if a scene has a different number of views
1330 * than the main scene? */
1331 do_render_engine(re);
1332 }
1333 else {
1334 re->i.cfra = re->r.cfra;
1335
1336 /* ensure new result gets added, like for regular renders */
1338
1340 if ((re->r.mode & R_CROP) == 0) {
1342 }
1344
1346
1347 /* Scene render process already updates animsys. */
1348 update_newframe = true;
1349
1350 /* The compositor does not have an output, skip writing the render result. See R_SKIP_WRITE for
1351 * more information. */
1353 re->flag |= R_SKIP_WRITE;
1354 }
1355 }
1356
1357 /* swap render result */
1358 if (re->r.scemode & R_SINGLE_LAYER) {
1362 }
1363
1364 if (!re->test_break()) {
1365 if (ntree && re->scene->use_nodes && re->r.scemode & R_DOCOMP) {
1366 /* checks if there are render-result nodes that need scene */
1367 if ((re->r.scemode & R_SINGLE_LAYER) == 0) {
1369 }
1370
1371 if (!re->test_break()) {
1372 ntree->runtime->stats_draw = render_compositor_stats;
1373 ntree->runtime->test_break = re->test_break_cb;
1374 ntree->runtime->progress = re->progress_cb;
1375 ntree->runtime->sdh = re;
1376 ntree->runtime->tbh = re->tbh;
1377 ntree->runtime->prh = re->prh;
1378
1379 if (update_newframe) {
1380 /* If we have consistent depsgraph now would be a time to update them. */
1381 }
1382
1383 blender::compositor::OutputTypes needed_outputs =
1386 if (!G.background) {
1389 }
1390
1391 blender::compositor::RenderContext compositor_render_context;
1392 LISTBASE_FOREACH (RenderView *, rv, &re->result->views) {
1393 COM_execute(re,
1394 &re->r,
1396 ntree,
1397 rv->name,
1398 &compositor_render_context,
1399 nullptr,
1400 needed_outputs);
1401 }
1402 compositor_render_context.save_file_outputs(re->pipeline_scene_eval);
1403
1404 ntree->runtime->stats_draw = nullptr;
1405 ntree->runtime->test_break = nullptr;
1406 ntree->runtime->progress = nullptr;
1407 ntree->runtime->tbh = ntree->runtime->sdh = ntree->runtime->prh = nullptr;
1408 }
1409 }
1410 }
1411
1412 /* Weak: the display callback wants an active render-layer pointer. */
1413 if (re->result != nullptr) {
1415 re->display_update(re->result, nullptr);
1416 }
1417}
1418
1420{
1421 RenderResult *render_result = re->result;
1422
1424
1425 LISTBASE_FOREACH (RenderLayer *, render_layer, &render_result->layers) {
1426 LISTBASE_FOREACH_BACKWARD (RenderPass *, render_pass, &render_layer->passes) {
1427 if (render_pass->ibuf) {
1428 BKE_imbuf_stamp_info(render_result, render_pass->ibuf);
1429 }
1430 }
1431 }
1432
1434}
1435
1437{
1438 RenderResult rres;
1439 int nr = 0;
1440
1441 /* this is the basic trick to get the displayed float or char rect from render result */
1442 LISTBASE_FOREACH (RenderView *, rv, &re->result->views) {
1444 RE_AcquireResultImage(re, &rres, nr);
1445
1446 if (rres.ibuf != nullptr) {
1447 Object *ob_camera_eval = DEG_get_evaluated(re->pipeline_depsgraph, RE_GetCamera(re));
1449 ob_camera_eval,
1450 (re->scene->r.stamp & R_STAMP_STRIPMETA) ? rres.stamp_data : nullptr,
1451 rres.ibuf->byte_buffer.data,
1452 rres.ibuf->float_buffer.data,
1453 rres.rectx,
1454 rres.recty);
1455 }
1456
1458 nr++;
1459 }
1460}
1461
1463{
1464 Editing *ed = scene->ed;
1465
1466 if (!(rd->scemode & R_DOSEQ) || !ed || !ed->seqbase.first) {
1467 return false;
1468 }
1469
1470 LISTBASE_FOREACH (Strip *, strip, &ed->seqbase) {
1471 if (strip->type != STRIP_TYPE_SOUND_RAM &&
1473 {
1474 return true;
1475 }
1476 }
1477
1478 return false;
1479}
1480
1481static bool seq_result_needs_float(const ImageFormatData &im_format)
1482{
1484}
1485
1487 const ImageFormatData &im_format,
1488 const Scene *scene)
1489{
1490 if (src == nullptr) {
1491 return nullptr;
1492 }
1493
1494 ImBuf *dst = nullptr;
1495 if (seq_result_needs_float(im_format) && src->float_buffer.data == nullptr) {
1496 /* If render output needs >8-BPP input and we only have 8-BPP, convert to float. */
1497 dst = IMB_allocImBuf(src->x, src->y, src->planes, 0);
1498 IMB_alloc_float_pixels(dst, src->channels, false);
1499 /* Transform from sequencer space to scene linear. */
1500 const char *from_colorspace = IMB_colormanagement_get_rect_colorspace(src);
1501 const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(
1504 src->byte_buffer.data,
1505 src->x,
1506 src->y,
1507 src->channels,
1508 from_colorspace,
1509 to_colorspace);
1510 }
1511 else {
1512 /* Duplicate sequencer output and ensure it is in needed color space. */
1513 dst = IMB_dupImBuf(src);
1515 }
1516 IMB_metadata_copy(dst, src);
1517 IMB_freeImBuf(src);
1518
1519 return dst;
1520}
1521
1522/* Render sequencer strips into render result. */
1524{
1525 static int recurs_depth = 0;
1526 ImBuf *out;
1527 RenderResult *rr; /* don't assign re->result here as it might change during give_ibuf_seq */
1528 int cfra = re->r.cfra;
1530 int view_id, tot_views;
1531 int re_x, re_y;
1532
1533 re->i.cfra = cfra;
1534
1535 recurs_depth++;
1536
1537 if ((re->r.mode & R_BORDER) && (re->r.mode & R_CROP) == 0) {
1538 /* if border rendering is used and cropping is disabled, final buffer should
1539 * be as large as the whole frame */
1540 re_x = re->winx;
1541 re_y = re->winy;
1542 }
1543 else {
1544 re_x = re->result->rectx;
1545 re_y = re->result->recty;
1546 }
1547
1548 tot_views = BKE_scene_multiview_num_views_get(&re->r);
1549 blender::Vector<ImBuf *> ibuf_arr(tot_views);
1550
1551 render_new_render_data(re->main,
1553 re->scene,
1554 re_x,
1555 re_y,
1557 true,
1558 &context);
1559
1560 /* The render-result gets destroyed during the rendering, so we first collect all ibufs
1561 * and then we populate the final render-result. */
1562
1563 for (view_id = 0; view_id < tot_views; view_id++) {
1564 context.view_id = view_id;
1565 out = render_give_ibuf(&context, cfra, 0);
1566 ibuf_arr[view_id] = seq_process_render_image(out, re->r.im_format, re->pipeline_scene_eval);
1567 }
1568
1569 rr = re->result;
1570
1572 render_result_views_new(rr, &re->r);
1574
1575 for (view_id = 0; view_id < tot_views; view_id++) {
1576 RenderView *rv = RE_RenderViewGetById(rr, view_id);
1578
1579 if (ibuf_arr[view_id]) {
1580 /* copy ibuf into combined pixel rect */
1581 RE_render_result_rect_from_ibuf(rr, ibuf_arr[view_id], view_id);
1582
1583 if (ibuf_arr[view_id]->metadata && (re->scene->r.stamp & R_STAMP_STRIPMETA)) {
1584 /* ensure render stamp info first */
1585 BKE_render_result_stamp_info(nullptr, nullptr, rr, true);
1586 BKE_stamp_info_from_imbuf(rr, ibuf_arr[view_id]);
1587 }
1588
1589 if (recurs_depth == 0) { /* With nested scenes, only free on top-level. */
1590 Editing *ed = re->pipeline_scene_eval->ed;
1591 if (ed) {
1593 }
1594 }
1595 IMB_freeImBuf(ibuf_arr[view_id]);
1596 }
1597 else {
1598 /* render result is delivered empty in most cases, nevertheless we handle all cases */
1599 render_result_rect_fill_zero(rr, view_id);
1600 }
1601
1603
1604 /* would mark display buffers as invalid */
1606 re->display_update(re->result, nullptr);
1607 }
1608
1609 recurs_depth--;
1610
1611 /* just in case this flag went missing at some point */
1612 re->r.scemode |= R_DOSEQ;
1613
1614 /* set overall progress of sequence rendering */
1615 if (re->r.efra != re->r.sfra) {
1616 re->progress(float(cfra - re->r.sfra) / (re->r.efra - re->r.sfra));
1617 }
1618 else {
1619 re->progress(1.0f);
1620 }
1621}
1622
1623/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
1624
1625/* Render full pipeline, using render engine, sequencer and compositing nodes. */
1627{
1628 bool render_seq = false;
1629
1630 re->current_scene_update_cb(re->suh, re->scene);
1631
1633
1635
1636 /* ensure no images are in memory from previous animated sequences */
1639
1640 if (RE_engine_render(re, true)) {
1641 /* in this case external render overrides all */
1642 }
1643 else if (RE_seq_render_active(re->scene, &re->r)) {
1644 /* NOTE: do_render_sequencer() frees rect32 when sequencer returns float images. */
1645 if (!re->test_break()) {
1647 render_seq = true;
1648 }
1649
1650 re->stats_draw(&re->i);
1651 re->display_update(re->result, nullptr);
1652 }
1653 else {
1655 }
1656
1658
1659 re->stats_draw(&re->i);
1660
1661 /* save render result stamp if needed */
1662 if (re->result != nullptr) {
1663 /* sequence rendering should have taken care of that already */
1664 if (!(render_seq && (re->scene->r.stamp & R_STAMP_STRIPMETA))) {
1665 Object *ob_camera_eval = DEG_get_evaluated(re->pipeline_depsgraph, RE_GetCamera(re));
1666 BKE_render_result_stamp_info(re->scene, ob_camera_eval, re->result, false);
1667 }
1668
1670
1671 /* stamp image info here */
1672 if ((re->scene->r.stamp & R_STAMP_ALL) && (re->scene->r.stamp & R_STAMP_DRAW)) {
1674 re->display_update(re->result, nullptr);
1675 }
1676 }
1677}
1678
1680 Object *camera_override,
1682{
1683 if (scene->r.scemode & R_DOCOMP && scene->use_nodes) {
1684 for (bNode *node : scene->nodetree->all_nodes()) {
1685 if (node->type_legacy == CMP_NODE_R_LAYERS && !node->is_muted()) {
1686 Scene *sce = node->id ? (Scene *)node->id : scene;
1687 if (sce->camera == nullptr) {
1689 }
1690 if (sce->camera == nullptr) {
1691 /* all render layers nodes need camera */
1693 RPT_ERROR,
1694 "No camera found in scene \"%s\" (used in compositing of scene \"%s\")",
1695 sce->id.name + 2,
1696 scene->id.name + 2);
1697 return false;
1698 }
1699 }
1700 }
1701
1702 return true;
1703 }
1704
1705 const bool ok = (camera_override != nullptr || scene->camera != nullptr);
1706 if (!ok) {
1707 BKE_reportf(reports, RPT_ERROR, "No camera found in scene \"%s\"", scene->id.name + 2);
1708 }
1709
1710 return ok;
1711}
1712
1714{
1715 bool active_view = false;
1716
1717 if (camera == nullptr || (scene->r.scemode & R_MULTIVIEW) == 0) {
1718 return true;
1719 }
1720
1721 LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
1722 if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
1723 active_view = true;
1724
1726 Object *view_camera;
1727 view_camera = BKE_camera_multiview_render(scene, camera, srv->name);
1728
1729 if (view_camera == camera) {
1730 /* if the suffix is not in the camera, means we are using the fallback camera */
1731 if (!BLI_str_endswith(view_camera->id.name + 2, srv->suffix)) {
1733 RPT_ERROR,
1734 "Camera \"%s\" is not a multi-view camera",
1735 camera->id.name + 2);
1736 return false;
1737 }
1738 }
1739 }
1740 }
1741 }
1742
1743 if (!active_view) {
1744 BKE_reportf(reports, RPT_ERROR, "No active view found in scene \"%s\"", scene->id.name + 2);
1745 return false;
1746 }
1747
1748 return true;
1749}
1750
1751static int check_valid_camera(Scene *scene, Object *camera_override, ReportList *reports)
1752{
1753 if (camera_override == nullptr && scene->camera == nullptr) {
1755 }
1756
1757 if (!check_valid_camera_multiview(scene, scene->camera, reports)) {
1758 return false;
1759 }
1760
1761 if (RE_seq_render_active(scene, &scene->r)) {
1762 if (scene->ed) {
1763 LISTBASE_FOREACH (Strip *, strip, &scene->ed->seqbase) {
1764 if ((strip->type == STRIP_TYPE_SCENE) && ((strip->flag & SEQ_SCENE_STRIPS) == 0) &&
1765 (strip->scene != nullptr))
1766 {
1767 if (!strip->scene_camera) {
1768 if (!strip->scene->camera &&
1769 !BKE_view_layer_camera_find(strip->scene,
1770 BKE_view_layer_default_render(strip->scene)))
1771 {
1772 /* camera could be unneeded due to composite nodes */
1773 Object *override = (strip->scene == scene) ? camera_override : nullptr;
1774
1775 if (!check_valid_compositing_camera(strip->scene, override, reports)) {
1776 return false;
1777 }
1778 }
1779 }
1780 else if (!check_valid_camera_multiview(strip->scene, strip->scene_camera, reports)) {
1781 return false;
1782 }
1783 }
1784 }
1785 }
1786 }
1787 else if (!check_valid_compositing_camera(scene, camera_override, reports)) {
1788 return false;
1789 }
1790
1791 return true;
1792}
1793
1795{
1796 for (const bNode *node : ntree->all_nodes()) {
1797 if (ELEM(node->type_legacy, CMP_NODE_COMPOSITE, CMP_NODE_OUTPUT_FILE)) {
1798 return true;
1799 }
1800 if (node->is_group()) {
1801 if (node->id) {
1802 if (node_tree_has_any_compositor_output((const bNodeTree *)node->id)) {
1803 return true;
1804 }
1805 }
1806 }
1807 }
1808
1809 return false;
1810}
1811
1813{
1815}
1816
1817/* Identify if the compositor can run on the GPU. Currently, this only checks if the compositor is
1818 * set to GPU and the render size exceeds what can be allocated as a texture in it. */
1820{
1821 /* CPU compositor can always run. */
1823 return true;
1824 }
1825
1826 int width, height;
1827 BKE_render_resolution(&scene->r, false, &width, &height);
1828 const int max_texture_size = GPU_max_texture_size();
1829
1830 /* There is no way to know if the render size is too large except if we actually allocate a test
1831 * texture, which we want to avoid due its cost. So we employ a heuristic that so far has worked
1832 * with all known GPU drivers. */
1833 if (size_t(width) * height > (size_t(max_texture_size) * max_texture_size) / 4) {
1834 BKE_report(reports, RPT_ERROR, "Render size too large for GPU, use CPU compositor instead");
1835 return false;
1836 }
1837
1838 return true;
1839}
1840
1842 ViewLayer *single_layer,
1843 Object *camera_override,
1845{
1846 const int scemode = scene->r.scemode;
1847
1848 if (scene->r.mode & R_BORDER) {
1849 if (scene->r.border.xmax <= scene->r.border.xmin ||
1850 scene->r.border.ymax <= scene->r.border.ymin)
1851 {
1852 BKE_report(reports, RPT_ERROR, "No border area selected");
1853 return false;
1854 }
1855 }
1856
1857 if (RE_seq_render_active(scene, &scene->r)) {
1858 /* Sequencer */
1859 if (scene->r.mode & R_BORDER) {
1860 BKE_report(reports, RPT_ERROR, "Border rendering is not supported by sequencer");
1861 return false;
1862 }
1863 }
1864 else if ((scemode & R_DOCOMP) && scene->use_nodes) {
1865 /* Compositor */
1866 if (!scene->nodetree) {
1867 BKE_report(reports, RPT_ERROR, "No node tree in scene");
1868 return false;
1869 }
1870
1871 if (!check_compositor_output(scene)) {
1872 BKE_report(reports, RPT_ERROR, "No render output node in scene");
1873 return false;
1874 }
1875
1877 return false;
1878 }
1879 }
1880 else {
1881 /* Regular Render */
1882 if (!render_scene_has_layers_to_render(scene, single_layer)) {
1883 BKE_report(reports, RPT_ERROR, "All render layers are disabled");
1884 return false;
1885 }
1886 }
1887
1888 /* check valid camera, without camera render is OK (compo, seq) */
1889 if (!check_valid_camera(scene, camera_override, reports)) {
1890 return false;
1891 }
1892
1893 return true;
1894}
1895
1897 Scene *scene,
1898 ViewLayer *view_layer,
1899 const bool /*anim_init*/)
1900{
1901 PTCacheBaker baker;
1902
1903 memset(&baker, 0, sizeof(baker));
1904 baker.bmain = re->main;
1905 baker.scene = scene;
1906 baker.view_layer = view_layer;
1907 baker.depsgraph = BKE_scene_ensure_depsgraph(re->main, scene, view_layer);
1908 baker.bake = false;
1909 baker.render = true;
1910 baker.anim_init = true;
1911 baker.quick_step = 1;
1912
1913 BKE_ptcache_bake(&baker);
1914}
1915
1916void RE_SetActiveRenderView(Render *re, const char *viewname)
1917{
1918 STRNCPY(re->viewname, viewname);
1919}
1920
1922{
1923 return re->viewname;
1924}
1925
1928 const RenderData *rd,
1929 Main *bmain,
1930 Scene *scene,
1931 ViewLayer *single_layer,
1932 Object *camera_override,
1933 const bool anim,
1934 const bool anim_init)
1935{
1936 int winx, winy;
1937 rcti disprect;
1938
1939 /* Reset the runtime flags before rendering, but only if this init is not an inter-animation
1940 * init, since some flags needs to be kept across the entire animation. */
1941 if (!anim) {
1942 re->flag = 0;
1943 }
1944
1945 /* r.xsch and r.ysch has the actual view window size
1946 * r.border is the clipping rect */
1947
1948 /* calculate actual render result and display size */
1949 BKE_render_resolution(rd, false, &winx, &winy);
1950
1951 /* We always render smaller part, inserting it in larger image is compositor business,
1952 * it uses 'disprect' for it. */
1953 if (scene->r.mode & R_BORDER) {
1954 disprect.xmin = rd->border.xmin * winx;
1955 disprect.xmax = rd->border.xmax * winx;
1956
1957 disprect.ymin = rd->border.ymin * winy;
1958 disprect.ymax = rd->border.ymax * winy;
1959 }
1960 else {
1961 disprect.xmin = disprect.ymin = 0;
1962 disprect.xmax = winx;
1963 disprect.ymax = winy;
1964 }
1965
1966 re->main = bmain;
1967 re->scene = scene;
1968 re->camera_override = camera_override;
1969 re->viewname[0] = '\0';
1970
1971 /* not too nice, but it survives anim-border render */
1972 if (anim) {
1973 re->disprect = disprect;
1974 return true;
1975 }
1976
1977 /*
1978 * Disabled completely for now,
1979 * can be later set as render profile option
1980 * and default for background render.
1981 */
1982 if (false) {
1983 /* make sure dynamics are up to date */
1985 update_physics_cache(re, scene, view_layer, anim_init);
1986 }
1987
1988 if (single_layer || scene->r.scemode & R_SINGLE_LAYER) {
1992 }
1993
1994 RE_InitState(re, nullptr, &scene->r, &scene->view_layers, single_layer, winx, winy, &disprect);
1995 if (!re->ok) { /* if an error was printed, abort */
1996 return false;
1997 }
1998
1999 re->display_init(re->result);
2000 re->display_clear(re->result);
2001
2002 return true;
2003}
2004
2006{
2007 re->reports = reports;
2008}
2009
2016
2018{
2019 Scene *scene = re->scene;
2021
2022 re->pipeline_depsgraph = DEG_graph_new(re->main, scene, view_layer, DAG_EVAL_RENDER);
2023 DEG_debug_name_set(re->pipeline_depsgraph, "RENDER PIPELINE");
2024
2025 /* Make sure there is a correct evaluated scene pointer. */
2027
2028 /* Update immediately so we have proper evaluated scene. */
2030
2032}
2033
2034/* Free data only needed during rendering operation. */
2036{
2037 if (re->engine && !RE_engine_use_persistent_data(re->engine)) {
2039 re->engine = nullptr;
2040 }
2041
2042 /* Destroy compositor that was using pipeline depsgraph. */
2043 RE_compositor_free(*re);
2044
2045 /* Destroy pipeline depsgraph. */
2046 if (re->pipeline_depsgraph != nullptr) {
2048 re->pipeline_depsgraph = nullptr;
2049 re->pipeline_scene_eval = nullptr;
2050 }
2051
2052 /* Destroy the opengl context in the correct thread. */
2055}
2056
2058 Main *bmain,
2059 Scene *scene,
2060 ViewLayer *single_layer,
2061 Object *camera_override,
2062 const int frame,
2063 const float subframe,
2064 const bool write_still)
2065{
2067
2068 /* Ugly global still...
2069 * is to prevent preview events and signal subdivision-surface etc to make full resolution. */
2070 G.is_rendering = true;
2071
2072 scene->r.cfra = frame;
2073 scene->r.subframe = subframe;
2074
2076 re, &scene->r, bmain, scene, single_layer, camera_override, false, false))
2077 {
2078 RenderData rd;
2079 memcpy(&rd, &scene->r, sizeof(rd));
2081
2083
2084 /* Reduce GPU memory usage so renderer has more space. */
2086
2088
2090
2091 const bool should_write = write_still && !(re->flag & R_SKIP_WRITE);
2092 if (should_write && !G.is_break) {
2094 /* operator checks this but in case its called from elsewhere */
2095 printf("Error: can't write single images with a movie format!\n");
2096 }
2097 else {
2098 char filepath_override[FILE_MAX];
2099 const char *relbase = BKE_main_blendfile_path(bmain);
2100 const path_templates::VariableMap template_variables =
2103 filepath_override,
2104 rd.pic,
2105 relbase,
2106 &template_variables,
2107 scene->r.cfra,
2108 &rd.im_format,
2109 (rd.scemode & R_EXTENSION) != 0,
2110 false,
2111 nullptr);
2112
2113 if (errors.is_empty()) {
2114 do_write_image_or_movie(re, bmain, scene, 0, filepath_override);
2115 }
2116 else {
2118 }
2119 }
2120 }
2121
2122 /* keep after file save */
2124 if (should_write) {
2126 }
2127 }
2128
2130 re->main,
2131 &scene->id,
2133
2135
2136 /* UGLY WARNING */
2137 G.is_rendering = false;
2138}
2139
2140#ifdef WITH_FREESTYLE
2141
2142/* Not freestyle specific, currently only used by free-style. */
2143static void change_renderdata_engine(Render *re, const char *new_engine)
2144{
2145 if (!STREQ(re->r.engine, new_engine)) {
2146 if (re->engine) {
2148 re->engine = nullptr;
2149 }
2150 STRNCPY(re->r.engine, new_engine);
2151 }
2152}
2153
2154static bool use_eevee_for_freestyle_render(Render *re)
2155{
2157 return !(type->flag & RE_USE_CUSTOM_FREESTYLE);
2158}
2159
2160void RE_RenderFreestyleStrokes(Render *re, Main *bmain, Scene *scene, const bool render)
2161{
2162 if (render_init_from_main(re, &scene->r, bmain, scene, nullptr, nullptr, false, false)) {
2163 if (render) {
2164 char scene_engine[32];
2165 STRNCPY(scene_engine, re->r.engine);
2166 if (use_eevee_for_freestyle_render(re)) {
2167 change_renderdata_engine(re, RE_engine_id_BLENDER_EEVEE_NEXT);
2168 }
2169
2170 RE_engine_render(re, false);
2171
2172 change_renderdata_engine(re, scene_engine);
2173 }
2174 }
2175}
2176
2177void RE_RenderFreestyleExternal(Render *re)
2178{
2179 if (re->test_break()) {
2180 return;
2181 }
2182
2184
2185 LISTBASE_FOREACH (RenderView *, rv, &re->result->views) {
2186 RE_SetActiveRenderView(re, rv->name);
2187
2189
2190 LISTBASE_FOREACH (ViewLayer *, view_layer, &re->scene->view_layers) {
2191 if ((re->r.scemode & R_SINGLE_LAYER) && !STREQ(view_layer->name, re->single_view_layer)) {
2192 continue;
2193 }
2194
2195 if (FRS_is_freestyle_enabled(view_layer)) {
2196 FRS_do_stroke_rendering(re, view_layer);
2197 }
2198 }
2199
2201 }
2202}
2203#endif
2204
2206
2207/* -------------------------------------------------------------------- */
2210
2212 RenderResult *rr,
2213 Scene *scene,
2214 RenderData *rd,
2215 MovieWriter **movie_writers,
2216 const int totvideos,
2217 bool preview)
2218{
2219 bool ok = true;
2220
2221 if (!rr) {
2222 return false;
2223 }
2224
2225 ImageFormatData image_format;
2226 BKE_image_format_init_for_write(&image_format, scene, nullptr);
2227
2228 const bool is_mono = !RE_ResultIsMultiView(rr);
2229 const float dither = scene->r.dither_intensity;
2230
2231 if (is_mono || (image_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
2232 int view_id;
2233 for (view_id = 0; view_id < totvideos; view_id++) {
2234 const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
2235 ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id);
2236
2237 IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format);
2238
2239 BLI_assert(movie_writers[view_id] != nullptr);
2240 if (!MOV_write_append(movie_writers[view_id],
2241 rd,
2242 preview ? scene->r.psfra : scene->r.sfra,
2243 scene->r.cfra,
2244 ibuf,
2245 suffix,
2246 reports))
2247 {
2248 ok = false;
2249 }
2250
2251 /* imbuf knows which rects are not part of ibuf */
2252 IMB_freeImBuf(ibuf);
2253 }
2254 if (!G.quiet) {
2255 printf("Append frame %d\n", scene->r.cfra);
2256 }
2257 }
2258 else { /* R_IMF_VIEWS_STEREO_3D */
2259 const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
2260 ImBuf *ibuf_arr[3] = {nullptr};
2261 int i;
2262
2263 BLI_assert((totvideos == 1) && (image_format.views_format == R_IMF_VIEWS_STEREO_3D));
2264
2265 for (i = 0; i < 2; i++) {
2266 int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
2267 ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id);
2268
2269 IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &image_format);
2270 }
2271
2272 ibuf_arr[2] = IMB_stereo3d_ImBuf(&image_format, ibuf_arr[0], ibuf_arr[1]);
2273
2274 if (ibuf_arr[2]) {
2275 BLI_assert(movie_writers[0] != nullptr);
2276 if (!MOV_write_append(movie_writers[0],
2277 rd,
2278 preview ? scene->r.psfra : scene->r.sfra,
2279 scene->r.cfra,
2280 ibuf_arr[2],
2281 "",
2282 reports))
2283 {
2284 ok = false;
2285 }
2286 }
2287 else {
2288 BKE_report(reports, RPT_ERROR, "Failed to create stereo image buffer");
2289 ok = false;
2290 }
2291
2292 for (i = 0; i < 3; i++) {
2293 /* imbuf knows which rects are not part of ibuf */
2294 if (ibuf_arr[i]) {
2295 IMB_freeImBuf(ibuf_arr[i]);
2296 }
2297 }
2298 }
2299
2300 BKE_image_format_free(&image_format);
2301
2302 return ok;
2303}
2304
2306 Render *re, Main *bmain, Scene *scene, const int totvideos, const char *filepath_override)
2307{
2308 char filepath[FILE_MAX];
2309 RenderResult rres;
2310 double render_time;
2311 bool ok = true;
2312 RenderEngineType *re_type = RE_engines_find(re->r.engine);
2313
2314 /* Only disable file writing if postprocessing is also disabled. */
2315 const bool do_write_file = !(re_type->flag & RE_USE_NO_IMAGE_SAVE) ||
2316 (re_type->flag & RE_USE_POSTPROCESS);
2317
2318 if (do_write_file) {
2319 RE_AcquireResultImageViews(re, &rres);
2320
2321 /* write movie or image */
2322 if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
2324 re->reports, &rres, scene, &re->r, re->movie_writers.data(), totvideos, false);
2325 }
2326 else {
2327 if (filepath_override) {
2328 STRNCPY(filepath, filepath_override);
2329 }
2330 else {
2331 const char *relbase = BKE_main_blendfile_path(bmain);
2332 const path_templates::VariableMap template_variables =
2335 filepath,
2336 scene->r.pic,
2337 relbase,
2338 &template_variables,
2339 scene->r.cfra,
2340 &scene->r.im_format,
2341 (scene->r.scemode & R_EXTENSION) != 0,
2342 true,
2343 nullptr);
2344 if (!errors.is_empty()) {
2346 ok = false;
2347 }
2348 }
2349
2350 /* write images as individual images or stereo */
2351 if (ok) {
2352 ok = BKE_image_render_write(re->reports, &rres, scene, true, filepath);
2353 }
2354 }
2355
2356 RE_ReleaseResultImageViews(re, &rres);
2357 }
2358
2359 render_time = re->i.lastframetime;
2361
2362 BLI_timecode_string_from_time_simple(filepath, sizeof(filepath), re->i.lastframetime);
2363 std::string message = fmt::format("Time: {}", filepath);
2364
2365 if (do_write_file && ok) {
2367 filepath, sizeof(filepath), re->i.lastframetime - render_time);
2368 message = fmt::format("{} (Saving: {})", message, filepath);
2369 }
2370
2371 if (!G.quiet) {
2372 printf("%s\n", message.c_str());
2373 /* Flush stdout to be sure python callbacks are printing stuff after blender. */
2374 fflush(stdout);
2375 }
2376
2377 /* NOTE: using G_MAIN seems valid here???
2378 * Not sure it's actually even used anyway, we could as well pass nullptr? */
2380
2381 if (!G.quiet) {
2382 fputc('\n', stdout);
2383 fflush(stdout);
2384 }
2385
2386 return ok;
2387}
2388
2389static void get_videos_dimensions(const Render *re,
2390 const RenderData *rd,
2391 size_t *r_width,
2392 size_t *r_height)
2393{
2394 size_t width, height;
2395 if (re->r.mode & R_BORDER) {
2396 if ((re->r.mode & R_CROP) == 0) {
2397 width = re->winx;
2398 height = re->winy;
2399 }
2400 else {
2401 width = re->rectx;
2402 height = re->recty;
2403 }
2404 }
2405 else {
2406 width = re->rectx;
2407 height = re->recty;
2408 }
2409
2410 BKE_scene_multiview_videos_dimensions_get(rd, width, height, r_width, r_height);
2411}
2412
2414{
2415 for (MovieWriter *writer : re->movie_writers) {
2416 MOV_write_end(writer);
2417 }
2419}
2420
2422 Main *bmain,
2423 Scene *scene,
2424 ViewLayer *single_layer,
2425 Object *camera_override,
2426 int sfra,
2427 int efra,
2428 int tfra)
2429{
2430 /* Call hooks before taking a copy of scene->r, so user can alter the render settings prior to
2431 * copying (e.g. alter the output path). */
2433
2434 RenderData rd;
2435 memcpy(&rd, &scene->r, sizeof(rd));
2436 const int cfra_old = rd.cfra;
2437 const float subframe_old = rd.subframe;
2438 int nfra, totrendered = 0, totskipped = 0;
2439 const int totvideos = BKE_scene_multiview_num_videos_get(&rd);
2440 const bool is_movie = BKE_imtype_is_movie(rd.im_format.imtype);
2441 const bool is_multiview_name = ((rd.scemode & R_MULTIVIEW) != 0 &&
2443
2444 /* do not fully call for each frame, it initializes & pops output window */
2445 if (!render_init_from_main(re, &rd, bmain, scene, single_layer, camera_override, false, true)) {
2446 return;
2447 }
2448
2449 RenderEngineType *re_type = RE_engines_find(re->r.engine);
2450
2451 /* Only disable file writing if postprocessing is also disabled. */
2452 const bool do_write_file = !(re_type->flag & RE_USE_NO_IMAGE_SAVE) ||
2453 (re_type->flag & RE_USE_POSTPROCESS);
2454
2456
2457 if (is_movie && do_write_file) {
2458 size_t width, height;
2459 get_videos_dimensions(re, &rd, &width, &height);
2460
2461 bool is_error = false;
2462 re->movie_writers.reserve(totvideos);
2463 for (int i = 0; i < totvideos; i++) {
2464 const char *suffix = BKE_scene_multiview_view_id_suffix_get(&re->r, i);
2465 MovieWriter *writer = MOV_write_begin(rd.im_format.imtype,
2467 &re->r,
2468 width,
2469 height,
2470 re->reports,
2471 false,
2472 suffix);
2473 if (writer == nullptr) {
2474 is_error = true;
2475 break;
2476 }
2477 re->movie_writers.append(writer);
2478 }
2479
2480 if (is_error) {
2483 return;
2484 }
2485 }
2486
2487 /* Ugly global still... is to prevent renderwin events and signal subdivision-surface etc
2488 * to make full resolution is also set by caller renderwin.c */
2489 G.is_rendering = true;
2490
2491 re->flag |= R_ANIMATION;
2493
2494 scene->r.subframe = 0.0f;
2495 for (nfra = sfra, scene->r.cfra = sfra; scene->r.cfra <= efra; scene->r.cfra++) {
2496 char filepath[FILE_MAX];
2497
2498 /* Reduce GPU memory usage so renderer has more space. */
2500
2501 /* A feedback loop exists here -- render initialization requires updated
2502 * render layers settings which could be animated, but scene evaluation for
2503 * the frame happens later because it depends on what layers are visible to
2504 * render engine.
2505 *
2506 * The idea here is to only evaluate animation data associated with the scene,
2507 * which will make sure render layer settings are up-to-date, initialize the
2508 * render database itself and then perform full scene update with only needed
2509 * layers.
2510 * -sergey-
2511 */
2512 {
2513 float ctime = BKE_scene_ctime_get(scene);
2514 AnimData *adt = BKE_animdata_from_id(&scene->id);
2516 re->pipeline_depsgraph, ctime);
2517 BKE_animsys_evaluate_animdata(&scene->id, adt, &anim_eval_context, ADT_RECALC_ALL, false);
2518 }
2519
2521
2522 /* Only border now, TODO(ton): camera lens. */
2523 render_init_from_main(re, &rd, bmain, scene, single_layer, camera_override, true, false);
2524
2525 if (nfra != scene->r.cfra) {
2526 /* Skip this frame, but could update for physics and particles system. */
2527 continue;
2528 }
2529
2530 nfra += tfra;
2531
2532 /* Touch/NoOverwrite options are only valid for image's */
2533 if (is_movie == false && do_write_file) {
2534 const path_templates::VariableMap template_variables =
2537 filepath,
2538 rd.pic,
2540 &template_variables,
2541 scene->r.cfra,
2542 &rd.im_format,
2543 (rd.scemode & R_EXTENSION) != 0,
2544 true,
2545 nullptr);
2546
2547 /* The filepath cannot be parsed, so we can't save the renders anywhere.
2548 * So we just cancel. */
2549 if (!errors.is_empty()) {
2551 /* We have to set the `is_break` flag here so that final cleanup code
2552 * recognizes that the render has failed. */
2553 G.is_break = true;
2554 break;
2555 }
2556
2557 if (rd.mode & R_NO_OVERWRITE) {
2558 if (!is_multiview_name) {
2559 if (BLI_exists(filepath)) {
2560 if (!G.quiet) {
2561 printf("skipping existing frame \"%s\"\n", filepath);
2562 }
2563 totskipped++;
2564 continue;
2565 }
2566 }
2567 else {
2568 bool is_skip = false;
2569 char filepath_view[FILE_MAX];
2570
2571 LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
2572 if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
2573 continue;
2574 }
2575
2576 BKE_scene_multiview_filepath_get(srv, filepath, filepath_view);
2577 if (BLI_exists(filepath_view)) {
2578 is_skip = true;
2579 if (!G.quiet) {
2580 printf(
2581 "skipping existing frame \"%s\" for view \"%s\"\n", filepath_view, srv->name);
2582 }
2583 }
2584 }
2585
2586 if (is_skip) {
2587 totskipped++;
2588 continue;
2589 }
2590 }
2591 }
2592
2593 if (rd.mode & R_TOUCH) {
2594 if (!is_multiview_name) {
2595 if (!BLI_exists(filepath)) {
2597 BLI_file_touch(filepath);
2598 }
2599 }
2600 else {
2601 char filepath_view[FILE_MAX];
2602
2603 LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
2604 if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
2605 continue;
2606 }
2607
2608 BKE_scene_multiview_filepath_get(srv, filepath, filepath_view);
2609
2610 if (!BLI_exists(filepath_view)) {
2611 BLI_file_ensure_parent_dir_exists(filepath_view);
2612 BLI_file_touch(filepath_view);
2613 }
2614 }
2615 }
2616 }
2617 }
2618
2619 re->r.cfra = scene->r.cfra; /* weak.... */
2620 re->r.subframe = scene->r.subframe;
2621
2622 /* run callbacks before rendering, before the scene is updated */
2624
2626 totrendered++;
2627
2628 const bool should_write = !(re->flag & R_SKIP_WRITE);
2629 if (re->test_break_cb(re->tbh) == 0) {
2630 if (!G.is_break && should_write) {
2631 if (!do_write_image_or_movie(re, bmain, scene, totvideos, nullptr)) {
2632 G.is_break = true;
2633 }
2634 }
2635 }
2636 else {
2637 G.is_break = true;
2638 }
2639
2640 if (G.is_break == true) {
2641 /* remove touched file */
2642 if (is_movie == false && do_write_file) {
2643 if (rd.mode & R_TOUCH) {
2644 if (!is_multiview_name) {
2645 if (BLI_file_size(filepath) == 0) {
2646 /* BLI_exists(filepath) is implicit */
2647 BLI_delete(filepath, false, false);
2648 }
2649 }
2650 else {
2651 char filepath_view[FILE_MAX];
2652
2653 LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
2654 if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
2655 continue;
2656 }
2657
2658 BKE_scene_multiview_filepath_get(srv, filepath, filepath_view);
2659
2660 if (BLI_file_size(filepath_view) == 0) {
2661 /* BLI_exists(filepath_view) is implicit */
2662 BLI_delete(filepath_view, false, false);
2663 }
2664 }
2665 }
2666 }
2667 }
2668
2669 break;
2670 }
2671
2672 if (G.is_break == false) {
2673 /* keep after file save */
2675 if (should_write) {
2677 }
2678 }
2679 }
2680
2681 /* end movie */
2682 if (is_movie && do_write_file) {
2684 }
2685
2686 if (totskipped && totrendered == 0) {
2687 BKE_report(re->reports, RPT_INFO, "No frames rendered, skipped to not overwrite");
2688 }
2689
2690 scene->r.cfra = cfra_old;
2691 scene->r.subframe = subframe_old;
2692
2694 re->main,
2695 &scene->id,
2698
2700
2701 /* UGLY WARNING */
2702 G.is_rendering = false;
2703}
2704
2705void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
2706{
2707 /* Ensure within GPU render boundary. */
2708 const bool use_gpu = GPU_backend_get_type() != GPU_BACKEND_NONE;
2709 if (use_gpu) {
2711 }
2712
2713 Object *camera;
2714 int winx, winy;
2715
2716 BKE_render_resolution(&sce->r, false, &winx, &winy);
2717
2718 RE_InitState(re, nullptr, &sce->r, &sce->view_layers, nullptr, winx, winy, nullptr);
2719
2720 re->main = bmain;
2721 re->scene = sce;
2722
2723 camera = RE_GetCamera(re);
2724 RE_SetCamera(re, camera);
2725
2726 RE_engine_render(re, false);
2727
2728 /* No persistent data for preview render. */
2729 if (re->engine) {
2731 re->engine = nullptr;
2732 }
2733
2734 /* Close GPU render boundary. */
2735 if (use_gpu) {
2737 }
2738}
2739
2740/* NOTE: repeated win/disprect calc... solve that nicer, also in compo. */
2741
2742bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
2743{
2744 Render *re;
2745 int winx, winy;
2746 bool success;
2747 rcti disprect;
2748
2749 /* calculate actual render result and display size */
2750 BKE_render_resolution(&scene->r, false, &winx, &winy);
2751
2752 /* only in movie case we render smaller part */
2753 if (scene->r.mode & R_BORDER) {
2754 disprect.xmin = scene->r.border.xmin * winx;
2755 disprect.xmax = scene->r.border.xmax * winx;
2756
2757 disprect.ymin = scene->r.border.ymin * winy;
2758 disprect.ymax = scene->r.border.ymax * winy;
2759 }
2760 else {
2761 disprect.xmin = disprect.ymin = 0;
2762 disprect.xmax = winx;
2763 disprect.ymax = winy;
2764 }
2765
2766 if (scenode) {
2767 scene = scenode;
2768 }
2769
2770 /* get render: it can be called from UI with draw callbacks */
2771 re = RE_GetSceneRender(scene);
2772 if (re == nullptr) {
2773 re = RE_NewSceneRender(scene);
2774 }
2775 RE_InitState(re, nullptr, &scene->r, &scene->view_layers, nullptr, winx, winy, &disprect);
2776 re->scene = scene;
2777
2781
2783
2784 return success;
2785}
2786
2788 RenderLayer *layer, ReportList *reports, const char *filepath, int x, int y)
2789{
2790 /* First try loading multi-layer EXR. */
2791 if (render_result_exr_file_read_path(nullptr, layer, reports, filepath)) {
2792 return;
2793 }
2794
2795 /* OCIO_TODO: assume layer was saved in default color space */
2797 RenderPass *rpass = nullptr;
2798
2799 /* multi-view: since the API takes no 'view', we use the first combined pass found */
2800 for (rpass = static_cast<RenderPass *>(layer->passes.first); rpass; rpass = rpass->next) {
2801 if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
2802 break;
2803 }
2804 }
2805
2806 if (rpass == nullptr) {
2808 RPT_ERROR,
2809 "%s: no Combined pass found in the render layer '%s'",
2810 __func__,
2811 filepath);
2812 }
2813
2814 if (ibuf && (ibuf->byte_buffer.data || ibuf->float_buffer.data)) {
2815 if (ibuf->x == layer->rectx && ibuf->y == layer->recty) {
2816 if (ibuf->float_buffer.data == nullptr) {
2817 IMB_float_from_byte(ibuf);
2818 }
2819
2820 memcpy(rpass->ibuf->float_buffer.data,
2821 ibuf->float_buffer.data,
2822 sizeof(float[4]) * layer->rectx * layer->recty);
2823 }
2824 else {
2825 if ((ibuf->x - x >= layer->rectx) && (ibuf->y - y >= layer->recty)) {
2826 ImBuf *ibuf_clip;
2827
2828 if (ibuf->float_buffer.data == nullptr) {
2829 IMB_float_from_byte(ibuf);
2830 }
2831
2832 ibuf_clip = IMB_allocImBuf(layer->rectx, layer->recty, 32, IB_float_data);
2833 if (ibuf_clip) {
2834 IMB_rectcpy(ibuf_clip, ibuf, 0, 0, x, y, layer->rectx, layer->recty);
2835
2836 memcpy(rpass->ibuf->float_buffer.data,
2837 ibuf_clip->float_buffer.data,
2838 sizeof(float[4]) * layer->rectx * layer->recty);
2839 IMB_freeImBuf(ibuf_clip);
2840 }
2841 else {
2843 reports, RPT_ERROR, "%s: failed to allocate clip buffer '%s'", __func__, filepath);
2844 }
2845 }
2846 else {
2848 RPT_ERROR,
2849 "%s: incorrect dimensions for partial copy '%s'",
2850 __func__,
2851 filepath);
2852 }
2853 }
2854
2855 IMB_freeImBuf(ibuf);
2856 }
2857 else {
2858 BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filepath);
2859 }
2860}
2861
2863{
2864 if (!render_result_exr_file_read_path(result, nullptr, reports, filepath)) {
2865 BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filepath);
2866 return;
2867 }
2868}
2869
2871{
2872 switch (BLI_listbase_count_at_most(&result->layers, 2)) {
2873 case 0:
2874 return false;
2875 case 1:
2876 return (((RenderLayer *)result->layers.first)->name[0] != '\0');
2877 default:
2878 return true;
2879 }
2880}
2881
2883{
2884 LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) {
2885 if (!STREQ(rp->name, "Combined")) {
2886 return true;
2887 }
2888 }
2889
2890 return false;
2891}
2892
2893RenderPass *RE_pass_find_by_name(RenderLayer *rl, const char *name, const char *viewname)
2894{
2896 if (STREQ(rp->name, name)) {
2897 if (viewname == nullptr || viewname[0] == '\0') {
2898 return rp;
2899 }
2900 if (STREQ(rp->view, viewname)) {
2901 return rp;
2902 }
2903 }
2904 }
2905 return nullptr;
2906}
2907
2908RenderPass *RE_pass_find_by_type(RenderLayer *rl, int passtype, const char *viewname)
2909{
2910#define CHECK_PASS(NAME) \
2911 if (passtype == SCE_PASS_##NAME) { \
2912 return RE_pass_find_by_name(rl, RE_PASSNAME_##NAME, viewname); \
2913 } \
2914 ((void)0)
2915
2916 CHECK_PASS(COMBINED);
2917 CHECK_PASS(Z);
2919 CHECK_PASS(NORMAL);
2920 CHECK_PASS(UV);
2921 CHECK_PASS(EMIT);
2922 CHECK_PASS(SHADOW);
2923 CHECK_PASS(AO);
2924 CHECK_PASS(ENVIRONMENT);
2925 CHECK_PASS(INDEXOB);
2926 CHECK_PASS(INDEXMA);
2927 CHECK_PASS(MIST);
2928 CHECK_PASS(DIFFUSE_DIRECT);
2929 CHECK_PASS(DIFFUSE_INDIRECT);
2930 CHECK_PASS(DIFFUSE_COLOR);
2931 CHECK_PASS(GLOSSY_DIRECT);
2932 CHECK_PASS(GLOSSY_INDIRECT);
2933 CHECK_PASS(GLOSSY_COLOR);
2934 CHECK_PASS(TRANSM_DIRECT);
2935 CHECK_PASS(TRANSM_INDIRECT);
2936 CHECK_PASS(TRANSM_COLOR);
2937 CHECK_PASS(SUBSURFACE_DIRECT);
2938 CHECK_PASS(SUBSURFACE_INDIRECT);
2939 CHECK_PASS(SUBSURFACE_COLOR);
2940
2941#undef CHECK_PASS
2942
2943 return nullptr;
2944}
2945
2946RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const char *viewname)
2947{
2948 RenderLayer *rl = RE_GetRenderLayer(rr, layername);
2949 /* only create render layer if not exist */
2950 if (!rl) {
2951 rl = MEM_callocN<RenderLayer>(layername);
2952 BLI_addtail(&rr->layers, rl);
2953 STRNCPY(rl->name, layername);
2954 rl->layflag = SCE_LAY_SOLID;
2956 rl->rectx = rr->rectx;
2957 rl->recty = rr->recty;
2958 }
2959
2960 /* Clear previous pass if exist or the new image will be over previous one. */
2962 if (rp) {
2963 IMB_freeImBuf(rp->ibuf);
2964 BLI_freelinkN(&rl->passes, rp);
2965 }
2966 /* create a totally new pass */
2967 return render_layer_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, viewname, "RGBA", true);
2968}
2969
2971
2972/* -------------------------------------------------------------------- */
2975
2977{
2978 /* override not showing object when duplis are used with particles */
2979 if (ob->transflag & OB_DUPLIPARTS) {
2980 /* pass */ /* let particle system(s) handle showing vs. not showing */
2981 }
2982 else if (ob->transflag & OB_DUPLI) {
2983 return false;
2984 }
2985 return true;
2986}
2987
2989{
2990 re->r.threads = BKE_render_num_threads(&re->r);
2991}
2992
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:82
AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, float eval_time) ATTR_WARN_UNUSED_RESULT
Definition anim_sys.cc:735
@ ADT_RECALC_ALL
void BKE_animsys_evaluate_animdata(struct ID *id, struct AnimData *adt, const struct AnimationEvalContext *anim_eval_context, eAnimData_Recalc recalc, bool flush_to_original)
void BKE_callback_exec_id(Main *bmain, ID *id, eCbEvent evt)
Definition callbacks.cc:43
void BKE_callback_exec_string(Main *bmain, eCbEvent evt, const char *str)
Definition callbacks.cc:63
eCbEvent
@ BKE_CB_EVT_RENDER_COMPLETE
@ BKE_CB_EVT_RENDER_POST
@ BKE_CB_EVT_RENDER_STATS
@ BKE_CB_EVT_RENDER_PRE
@ BKE_CB_EVT_RENDER_WRITE
@ BKE_CB_EVT_RENDER_INIT
@ BKE_CB_EVT_RENDER_CANCEL
Camera data-block and utility functions.
struct Object * BKE_camera_multiview_render(const struct Scene *scene, struct Object *camera, const char *viewname)
void BKE_curvemapping_free_data(CurveMapping *cumap)
void BKE_curvemapping_copy_data(CurveMapping *target, const CurveMapping *cumap)
#define G_MAIN
void BKE_imbuf_stamp_info(const RenderResult *rr, ImBuf *ibuf)
void BKE_stamp_info_from_imbuf(RenderResult *rr, ImBuf *ibuf)
StampData * BKE_stamp_data_copy(const StampData *stamp_data)
void BKE_render_result_stamp_info(Scene *scene, Object *camera, RenderResult *rr, bool allocate_only)
void BKE_image_all_free_anim_ibufs(Main *bmain, int cfra)
void BKE_image_stamp_buf(Scene *scene, Object *camera, const StampData *stamp_data_template, unsigned char *rect, float *rectf, int width, int height)
void BKE_image_format_free(ImageFormatData *imf)
void BKE_image_format_init_for_write(ImageFormatData *imf, const Scene *scene_src, const ImageFormatData *imf_src)
blender::Vector< blender::bke::path_templates::Error > BKE_image_path_from_imformat(char *filepath, const char *base, const char *relbase, const blender::bke::path_templates::VariableMap *template_variables, int frame, const ImageFormatData *im_format, bool use_ext, bool use_frames, const char *suffix)
bool BKE_imtype_is_movie(char imtype)
bool BKE_image_render_write(ReportList *reports, RenderResult *rr, const Scene *scene, const bool stamp, const char *filepath_basis, const ImageFormatData *format=nullptr, bool save_as_render=true)
Object * BKE_view_layer_camera_find(const Scene *scene, ViewLayer *view_layer)
ViewLayer * BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene)
ViewLayer * BKE_view_layer_default_render(const Scene *scene)
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:872
#define CMP_NODE_COMPOSITE
#define CMP_NODE_CRYPTOMATTE
#define CMP_NODE_OUTPUT_FILE
#define CMP_NODE_R_LAYERS
void BKE_report_path_template_errors(ReportList *reports, eReportType report_type, blender::StringRef path, blender::Span< blender::bke::path_templates::Error > errors)
blender::bke::path_templates::VariableMap BKE_build_template_variables_for_render_path(const RenderData *render_data)
void BKE_ptcache_bake(struct PTCacheBaker *baker)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2927
float BKE_scene_ctime_get(const Scene *scene)
Definition scene.cc:2367
int BKE_scene_multiview_num_views_get(const RenderData *rd)
Definition scene.cc:2952
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
Definition scene.cc:3000
const char * BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, int view_id)
Definition scene.cc:3166
int BKE_render_num_threads(const RenderData *r)
Definition scene.cc:2900
bool BKE_scene_camera_switch_update(Scene *scene)
Definition scene.cc:2267
Depsgraph * BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3427
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2381
void BKE_scene_multiview_videos_dimensions_get(const RenderData *rd, size_t width, size_t height, size_t *r_width, size_t *r_height)
Definition scene.cc:3207
void BKE_scene_update_sound(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2508
int BKE_scene_multiview_num_videos_get(const RenderData *rd)
Definition scene.cc:3227
void BKE_scene_multiview_filepath_get(const SceneRenderView *srv, const char *filepath, char *r_filepath)
Definition scene.cc:3120
int BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
Definition scene.cc:3094
void BKE_scene_ppm_get(const RenderData *rd, double r_ppm[2])
Definition scene.cc:3245
void BKE_sound_reset_scene_specs(struct Scene *scene)
#define BLI_assert(a)
Definition BLI_assert.h:46
File and directory operations.
bool BLI_file_touch(const char *filepath) ATTR_NONNULL(1)
Definition fileops_c.cc:316
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:373
int BLI_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL()
size_t BLI_file_size(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:239
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
Definition fileops_c.cc:429
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
void BLI_freelinkN(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:270
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
int BLI_listbase_count_at_most(const ListBase *listbase, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:511
int BLI_findstringindex(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:780
MINLINE void copy_v2_v2_db(double r[2], const double a[2])
#define FILE_MAX
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
int bool bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL(1
unsigned int uint
#define THREAD_LOCK_READ
#define THREAD_LOCK_WRITE
void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode)
Definition threads.cc:467
int BLI_thread_is_main(void)
Definition threads.cc:179
void BLI_rw_mutex_unlock(ThreadRWMutex *mutex)
Definition threads.cc:477
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:65
size_t BLI_timecode_string_from_time_simple(char *str, size_t maxncpy, double time_seconds) ATTR_NONNULL()
Definition timecode.cc:170
#define STREQLEN(a, b, n)
#define ELEM(...)
#define STREQ(a, b)
#define RPT_(msgid)
void COM_execute(Render *render, RenderData *render_data, Scene *scene, bNodeTree *node_tree, const char *view_name, blender::compositor::RenderContext *render_context, blender::compositor::Profiler *profiler, blender::compositor::OutputTypes needed_outputs)
The main method that is used to execute the compositor tree. It can be executed during editing (blenk...
@ DAG_EVAL_RENDER
Depsgraph * DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
Definition depsgraph.cc:278
void DEG_graph_id_tag_update(Main *bmain, Depsgraph *depsgraph, ID *id, unsigned int flags)
void DEG_graph_free(Depsgraph *graph)
Definition depsgraph.cc:306
void DEG_evaluate_on_framechange(Depsgraph *graph, float frame, DepsgraphEvaluateSyncWriteback sync_writeback=DEG_EVALUATE_SYNC_WRITEBACK_NO)
void DEG_graph_build_for_render_pipeline(Depsgraph *graph)
void DEG_debug_name_set(Depsgraph *depsgraph, const char *name)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_AUDIO_MUTE
Definition DNA_ID.h:1037
@ IMA_SRC_VIEWER
@ VIEW_LAYER_RENDER
@ NODE_DO_OUTPUT
@ CMP_NODE_CRYPTOMATTE_SOURCE_RENDER
Object is a sort of wrapper for general info.
@ OB_DUPLI
@ OB_DUPLIPARTS
#define R_STAMP_ALL
#define RE_PASSNAME_COMBINED
#define STEREO_LEFT_NAME
@ SCE_VIEWS_FORMAT_MULTIVIEW
@ SCE_LAY_SOLID
@ R_IMF_CHAN_DEPTH_12
@ R_IMF_CHAN_DEPTH_10
@ R_TOUCH
@ R_CROP
@ R_NO_OVERWRITE
@ R_EDGE_FRS
@ R_BORDER
@ R_STAMP_DRAW
@ R_STAMP_STRIPMETA
@ R_IMF_VIEWS_STEREO_3D
@ R_IMF_VIEWS_INDIVIDUAL
#define STEREO_RIGHT_NAME
@ R_MULTIVIEW
@ R_SINGLE_LAYER
@ R_DOSEQ
@ R_EXR_CACHE_FILE
@ R_DOCOMP
@ R_EXTENSION
@ R_BUTS_PREVIEW
@ SCE_COMPOSITOR_DEVICE_GPU
@ SCE_PASS_COMBINED
@ STRIP_TYPE_SCENE
@ STRIP_TYPE_SOUND_RAM
@ SEQ_SCENE_STRIPS
@ SEQ_RENDER_SIZE_SCENE
@ SPACE_NODE
@ SPACE_IMAGE
static AppView * view
void FRS_init_stroke_renderer(struct Render *re)
void FRS_exit(void)
void FRS_end_stroke_rendering(struct Render *re)
void FRS_begin_stroke_rendering(struct Render *re)
int FRS_is_freestyle_enabled(struct ViewLayer *view_layer)
void FRS_do_stroke_rendering(struct Render *re, struct ViewLayer *view_layer)
int GPU_max_texture_size()
void GPU_render_end()
GPUContext * GPU_context_create(void *ghost_window, void *ghost_context)
void GPU_render_begin()
void GPU_context_discard(GPUContext *)
void GPU_context_active_set(GPUContext *)
eGPUBackendType GPU_backend_get_type()
#define Z
void IMB_colormanagement_transform_byte_to_float(float *float_buffer, unsigned char *byte_buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
ImBuf * IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, bool allocate_result, const ImageFormatData *image_format)
@ COLOR_ROLE_SCENE_LINEAR
const char * IMB_colormanagement_role_colorspace_name_get(int role)
const char * IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
ImBuf * IMB_load_image_from_filepath(const char *filepath, const int flags, char r_colorspace[IM_MAX_SPACE]=nullptr)
Definition readimage.cc:204
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_stereo3d_ImBuf(const ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
bool IMB_alloc_float_pixels(ImBuf *ibuf, const unsigned int channels, bool initialize_pixels=true)
void IMB_rectcpy(ImBuf *dbuf, const ImBuf *sbuf, int destx, int desty, int srcx, int srcy, int width, int height)
Definition rectop.cc:445
void IMB_float_from_byte(ImBuf *ibuf)
@ IB_float_data
@ IB_byte_data
void IMB_metadata_copy(ImBuf *ibuf_dst, const ImBuf *ibuf_src)
Definition metadata.cc:59
Read Guarded memory(de)allocation.
@ RE_USE_CUSTOM_FREESTYLE
Definition RE_engine.h:51
@ RE_USE_POSTPROCESS
Definition RE_engine.h:45
@ RE_USE_NO_IMAGE_SAVE
Definition RE_engine.h:52
@ RE_ENGINE_RENDERING
Definition RE_engine.h:63
#define RE_MAXNAME
Definition RE_pipeline.h:34
@ WM_JOB_TYPE_COMPOSITE
Definition WM_api.hh:1727
@ WM_JOB_TYPE_RENDER
Definition WM_api.hh:1728
ReportList * reports
Definition WM_types.hh:1025
volatile int lock
BPy_StructRNA * depsgraph
void append(const T &value)
T * data()
void reserve(const int64_t min_capacity)
void clear_and_shrink()
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool is_empty() const
Definition BLI_set.hh:595
void add_new(const Key &key)
Definition BLI_set.hh:233
bool is_empty() const
#define offsetof(t, d)
#define str(s)
ThreadMutex mutex
#define out
#define printf(...)
#define ID_IS_LINKED(_id)
void RE_SetCamera(Render *re, const Object *cam_ob)
Object * RE_GetCamera(Render *re)
bool RE_engine_use_persistent_data(RenderEngine *engine)
RenderEngineType * RE_engines_find(const char *idname)
RenderEngine * RE_engine_create(RenderEngineType *type)
bool RE_engine_render(Render *re, bool do_all)
void RE_engine_free(RenderEngine *engine)
size_t(* MEM_get_peak_memory)(void)
Definition mallocn.cc:73
void(* MEM_reset_peak_memory)(void)
Definition mallocn.cc:72
size_t(* MEM_get_memory_in_use)(void)
Definition mallocn.cc:70
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static size_t mem_in_use
#define G(x, y, z)
MovieWriter * MOV_write_begin(const char imtype, const Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview, const char *suffix)
void MOV_write_end(MovieWriter *writer)
bool MOV_write_append(MovieWriter *writer, RenderData *rd, int start_frame, int frame, const ImBuf *image, const char *suffix, ReportList *reports)
bool render_is_muted(const ListBase *channels, const Strip *strip)
Definition render.cc:2081
void cache_cleanup(Scene *scene)
void render_imbuf_from_sequencer_space(const Scene *scene, ImBuf *ibuf)
Definition render.cc:163
void relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
std::mutex Mutex
Definition BLI_mutex.hh:47
void RE_compositor_free(Render &render)
bool render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, ReportList *reports, const char *filepath)
void render_result_single_layer_end(Render *re)
void render_result_free_gpu_texture_caches(RenderResult *rr)
bool render_result_exr_file_cache_read(Render *re)
void RE_render_result_rect_from_ibuf(RenderResult *rr, const ImBuf *ibuf, const int view_id)
void render_result_rect_fill_zero(RenderResult *rr, const int view_id)
void render_result_views_shallowdelete(RenderResult *rr)
void render_result_views_new(RenderResult *rr, const RenderData *rd)
void render_result_merge(RenderResult *rr, RenderResult *rrpart)
void render_result_view_new(RenderResult *rr, const char *viewname)
RenderPass * render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, const char *name, const char *viewname, const char *chan_id, const bool allocate)
ImBuf * RE_render_result_rect_to_ibuf(RenderResult *rr, const ImageFormatData *imf, const float dither, const int view_id)
void render_result_passes_allocated_ensure(RenderResult *rr)
void render_result_free(RenderResult *rr)
RenderResult * render_result_new_from_exr(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
void render_result_clone_passes(Render *re, RenderResult *rr, const char *viewname)
RenderView * RE_RenderViewGetById(RenderResult *rr, const int view_id)
void render_result_single_layer_begin(Render *re)
void render_result_rect_get_pixels(RenderResult *rr, uint *rect, int rectx, int recty, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, const int view_id)
RenderResult * render_result_new(Render *re, const rcti *partrct, const char *layername, const char *viewname)
void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src)
#define RR_ALL_VIEWS
#define RR_ALL_LAYERS
#define R_SKIP_WRITE
#define R_ANIMATION
const char * RE_engine_id_BLENDER_EEVEE_NEXT
Definition scene.cc:1626
static void stats_background(void *, RenderStats *rs)
bool RE_HasSingleLayer(Render *re)
void RE_ReleaseResultImageViews(Render *re, RenderResult *rr)
void RE_stats_draw_cb(Render *re, void *handle, void(*f)(void *handle, RenderStats *rs))
static bool node_tree_has_composite_output(const bNodeTree *node_tree)
static void float_nothing(void *, float)
static void stats_nothing(void *, RenderStats *)
static void re_free_persistent_data(Render *re)
void RE_FreeRender(Render *re)
static void result_nothing(void *, RenderResult *)
static void do_render_engine(Render *re)
RenderResult * RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
void * RE_blender_gpu_context_ensure(Render *re)
void RE_ReleaseResultImage(Render *re)
void RE_progress_cb(Render *re, void *handle, void(*f)(void *handle, float))
void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
void RE_test_break_cb(Render *re, void *handle, bool(*f)(void *handle))
void * RE_system_gpu_context_get(Render *re)
static bool node_tree_has_any_compositor_output(const bNodeTree *ntree)
RenderPass * RE_pass_find_by_type(RenderLayer *rl, int passtype, const char *viewname)
static bool default_break(void *)
static ImBuf * seq_process_render_image(ImBuf *src, const ImageFormatData &im_format, const Scene *scene)
static void do_render_compositor_scenes(Render *re)
static void do_render_compositor_scene(Render *re, Scene *sce, int cfra)
void RE_current_scene_update_cb(Render *re, void *handle, void(*f)(void *handle, Scene *scene))
static bool seq_result_needs_float(const ImageFormatData &im_format)
RenderPass * RE_pass_find_by_name(RenderLayer *rl, const char *name, const char *viewname)
void RE_prepare_viewlayer_cb(Render *re, void *handle, bool(*f)(void *handle, ViewLayer *vl, Depsgraph *depsgraph))
void RE_InitState(Render *re, Render *source, RenderData *rd, ListBase *, ViewLayer *single_layer, int winx, int winy, const rcti *disprect)
void render_copy_renderdata(RenderData *to, RenderData *from)
void RE_ResultGet32(Render *re, uint *rect)
void RE_FreePersistentData(const Scene *scene)
static Scene * get_scene_referenced_by_node(const bNode *node)
static bool check_valid_camera_multiview(Scene *scene, Object *camera, ReportList *reports)
static void re_init_resolution(Render *re, Render *source, int winx, int winy, const rcti *disprect)
std::forward_list< Render * > render_list
static void render_update_depsgraph(Render *re)
void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
Render * RE_NewRender(const char *name)
static int check_compositor_output(Scene *scene)
void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char *filepath, int x, int y)
void RE_ClearResult(Render *re)
void RE_SwapResult(Render *re, RenderResult **rr)
static struct @352337042264365162330240020117156337303336276132 RenderGlobal
void RE_FreeRenderResult(RenderResult *rr)
ImBuf * RE_RenderLayerGetPassImBuf(RenderLayer *rl, const char *name, const char *viewname)
Render * RE_NewInteractiveCompositorRender(const Scene *scene)
RenderResult * RE_AcquireResultWrite(Render *re)
static void render_pipeline_free(Render *re)
void RE_InitRenderCB(Render *re)
static void current_scene_nothing(void *, Scene *)
void RE_RenderFrame(Render *re, Main *bmain, Scene *scene, ViewLayer *single_layer, Object *camera_override, const int frame, const float subframe, const bool write_still)
static int check_valid_camera(Scene *scene, Object *camera_override, ReportList *reports)
static void scene_render_name_get(const Scene *scene, const size_t max_size, char *render_name)
blender::Map< std::string, Render * > interactive_compositor_renders
static void render_result_uncrop(Render *re)
void RE_ReferenceRenderResult(RenderResult *rr)
Render * RE_NewSceneRender(const Scene *scene)
Scene * RE_GetScene(Render *re)
Render * RE_GetRender(const char *name)
static bool is_compositing_possible_on_gpu(Scene *scene, ReportList *reports)
void RE_blender_gpu_context_free(Render *re)
static void render_result_disprect_to_full_resolution(Render *re)
static void render_callback_exec_string(Render *re, Main *bmain, eCbEvent evt, const char *str)
bool RE_seq_render_active(Scene *scene, RenderData *rd)
bool RE_passes_have_name(RenderLayer *rl)
static void do_render_sequencer(Render *re)
RenderResult * RE_AcquireResultRead(Render *re)
void RE_FreeInteractiveCompositorRenders()
RenderLayer * RE_GetRenderLayer(RenderResult *rr, const char *name)
void RE_ReleaseResult(Render *re)
const char * RE_GetActiveRenderView(Render *re)
static void render_compositor_stats(void *arg, const char *str)
void RE_RenderAnim(Render *re, Main *bmain, Scene *scene, ViewLayer *single_layer, Object *camera_override, int sfra, int efra, int tfra)
static void do_render_full_pipeline(Render *re)
static bool render_init_from_main(Render *re, const RenderData *rd, Main *bmain, Scene *scene, ViewLayer *single_layer, Object *camera_override, const bool anim, const bool anim_init)
static void re_movie_free_all(Render *re)
static void do_render_compositor(Render *re)
void RE_system_gpu_context_ensure(Render *re)
bool RE_ResultIsMultiView(RenderResult *rr)
void RE_display_clear_cb(Render *re, void *handle, void(*f)(void *handle, RenderResult *rr))
bool RE_layers_have_name(RenderResult *result)
bool RE_allow_render_generic_object(Object *ob)
void RE_result_load_from_file(RenderResult *result, ReportList *reports, const char *filepath)
void RE_display_update_cb(Render *re, void *handle, void(*f)(void *handle, RenderResult *rr, rcti *rect))
static void get_videos_dimensions(const Render *re, const RenderData *rd, size_t *r_width, size_t *r_height)
bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scene, RenderData *rd, MovieWriter **movie_writers, const int totvideos, bool preview)
static bool compositor_needs_render(Scene *scene)
static void renderresult_stampinfo(Render *re)
static void render_init_depsgraph(Render *re)
static bool do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, const int totvideos, const char *filepath_override)
ViewRender * RE_NewViewRender(RenderEngineType *engine_type)
Render * RE_GetSceneRender(const Scene *scene)
bool RE_is_rendering_allowed(Scene *scene, ViewLayer *single_layer, Object *camera_override, ReportList *reports)
RenderStats * RE_GetStats(Render *re)
static void renderresult_set_passes_metadata(Render *re)
static void update_physics_cache(Render *re, Scene *scene, ViewLayer *view_layer, const bool)
void RE_draw_lock_cb(Render *re, void *handle, void(*f)(void *handle, bool lock))
void RE_SetReports(Render *re, ReportList *reports)
void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
static bool render_scene_has_layers_to_render(Scene *scene, ViewLayer *single_layer)
bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
void RE_SetScene(Render *re, Scene *sce)
float * RE_RenderLayerGetPass(RenderLayer *rl, const char *name, const char *viewname)
#define CHECK_PASS(NAME)
void RE_system_gpu_context_free(Render *re)
static void render_callback_exec_id(Render *re, Main *bmain, ID *id, eCbEvent evt)
void RE_FreeViewRender(ViewRender *view_render)
static bool check_valid_compositing_camera(Scene *scene, Object *camera_override, ReportList *reports)
static void result_rcti_nothing(void *, RenderResult *, rcti *)
void RE_SetActiveRenderView(Render *re, const char *viewname)
RenderLayer * render_get_single_layer(Render *re, RenderResult *rr)
RenderPass * RE_create_gp_pass(RenderResult *rr, const char *layername, const char *viewname)
void RE_init_threadcount(Render *re)
static bool prepare_viewlayer_nothing(void *, ViewLayer *, Depsgraph *)
static void re_gpu_texture_caches_free(Render *re)
void RE_display_init_cb(Render *re, void *handle, void(*f)(void *handle, RenderResult *rr))
struct RenderEngine * engine
ThreadRWMutex resultmutex
RenderResult * result
ListBase seqbase
ListBase channels
Definition DNA_ID.h:404
struct Library * lib
Definition DNA_ID.h:410
char name[66]
Definition DNA_ID.h:415
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
unsigned char planes
short source
ID id
Definition DNA_ID.h:505
void * first
ustring name
Definition graph/node.h:177
short transflag
struct Scene * scene
struct Main * bmain
struct Depsgraph * depsgraph
struct ViewLayer * view_layer
struct CurveMapping mblur_shutter_curve
char engine[32]
struct ImageFormatData im_format
char pic[1024]
float dither_intensity
ListBase passes
Definition RE_pipeline.h:89
char name[RE_MAXNAME]
Definition RE_pipeline.h:81
struct ImBuf * ibuf
Definition RE_pipeline.h:60
char name[64]
Definition RE_pipeline.h:50
struct RenderPass * next
Definition RE_pipeline.h:48
ListBase views
ListBase layers
struct StampData * stamp_data
double ppm[2]
struct ImBuf * ibuf
RenderLayer * renlay
double starttime
double lastframetime
const char * infostr
struct ImBuf * ibuf
Definition RE_pipeline.h:44
char name[64]
Definition RE_pipeline.h:39
void * blender_gpu_context
void * dch
void * sdh
Scene * pipeline_scene_eval
void * duh
void * prh
bool(* prepare_viewlayer_cb)(void *handle, struct ViewLayer *vl, struct Depsgraph *depsgraph)
void display_update(RenderResult *render_result, rcti *rect) override
bool test_break() override
bool result_has_gpu_texture_caches
RenderResult * pushedresult
RenderData r
blender::render::Compositor * compositor
struct Main * main
void * dih
void * system_gpu_context
void(* current_scene_update_cb)(void *handle, struct Scene *scene)
void * dlh
void(* progress_cb)(void *handle, float i)
Scene * scene
void display_init(RenderResult *render_result) override
void(* display_init_cb)(void *handle, RenderResult *rr)
struct Depsgraph * pipeline_depsgraph
void progress(float progress) override
void * prepare_vl_handle
void(* display_clear_cb)(void *handle, RenderResult *rr)
short flag
bool(* test_break_cb)(void *handle)
char single_view_layer[MAX_NAME]
char viewname[MAX_NAME]
void display_clear(RenderResult *render_result) override
RenderStats i
void current_scene_update(struct Scene *scene) override
void * tbh
void * suh
struct ReportList * reports
rcti disprect
struct Object * camera_override
void(* draw_lock_cb)(void *handle, bool lock)
void(* display_update_cb)(void *handle, RenderResult *rr, rcti *rect)
char name[RE_MAXNAME]
void(* stats_draw_cb)(void *handle, RenderStats *ri)
blender::Vector< MovieWriter * > movie_writers
void stats_draw(RenderStats *render_stats) override
struct bNodeTree * nodetree
ColorManagedViewSettings view_settings
struct Editing * ed
struct RenderData r
ListBase view_layers
struct Object * camera
ColorManagedDisplaySettings display_settings
struct Image * image
struct bNodeTree * nodetree
char name[64]
bNodeTreeRuntimeHandle * runtime
int16_t custom1
struct ID * id
int16_t type_legacy
ListBase areabase
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
i
Definition text_draw.cc:230
void RE_point_density_fix_linking()
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:224
void * WM_system_gpu_context_create()
void wm_window_reset_drawable()
void WM_system_gpu_context_dispose(void *context)
void WM_system_gpu_context_activate(void *context)
Scene * WM_window_get_active_scene(const wmWindow *win)
void WM_system_gpu_context_release(void *context)
bScreen * WM_window_get_active_screen(const wmWindow *win)