Blender V5.0
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#include <memory>
17
18#include "DNA_anim_types.h"
19#include "DNA_image_types.h"
20#include "DNA_node_types.h"
21#include "DNA_object_types.h"
22#include "DNA_scene_types.h"
23#include "DNA_sequence_types.h"
24#include "DNA_space_types.h"
26
27#include "MEM_guardedalloc.h"
28
29#include "BLI_fileops.h"
30#include "BLI_listbase.h"
31#include "BLI_map.hh"
32#include "BLI_mutex.hh"
33#include "BLI_rect.h"
34#include "BLI_set.hh"
35#include "BLI_string_utf8.h"
36#include "BLI_threads.h"
37#include "BLI_time.h"
38#include "BLI_timecode.h"
39#include "BLI_vector.hh"
40
41#include "BKE_anim_data.hh"
42#include "BKE_animsys.h" /* <------ should this be here?, needed for sequencer update */
43#include "BKE_callbacks.hh"
44#include "BKE_camera.h"
45#include "BKE_colortools.hh"
46#include "BKE_global.hh"
47#include "BKE_image.hh"
48#include "BKE_image_format.hh"
49#include "BKE_image_save.hh"
50#include "BKE_layer.hh"
51#include "BKE_lib_id.hh"
52#include "BKE_lib_remap.hh"
53#include "BKE_main.hh"
54#include "BKE_mask.h"
55#include "BKE_modifier.hh"
57#include "BKE_node_runtime.hh"
58#include "BKE_pointcache.h"
59#include "BKE_report.hh"
60#include "BKE_scene.hh"
61#include "BKE_sound.h"
62
63#include "NOD_composite.hh"
64
65#include "COM_compositor.hh"
66#include "COM_context.hh"
67#include "COM_render_context.hh"
68
69#include "DEG_depsgraph.hh"
73
75#include "IMB_imbuf.hh"
76#include "IMB_imbuf_types.hh"
77#include "IMB_metadata.hh"
78
79#include "MOV_write.hh"
80
81#include "RE_engine.h"
82#include "RE_pipeline.h"
83#include "RE_texture.h"
84
85#include "SEQ_relations.hh"
86#include "SEQ_render.hh"
87
88#include "GPU_capabilities.hh"
89#include "GPU_context.hh"
90#include "WM_api.hh"
91#include "wm_window.hh"
92
93#ifdef WITH_FREESTYLE
94# include "FRS_freestyle.h"
95#endif
96
97/* internal */
98#include "pipeline.hh"
99#include "render_result.h"
100#include "render_types.h"
101
102#include "CLG_log.h"
103
104static CLG_LogRef LOG = {"render"};
105
107
108/* render flow
109 *
110 * 1) Initialize state
111 * - state data, tables
112 * - movie/image file init
113 * - everything that doesn't change during animation
114 *
115 * 2) Initialize data
116 * - camera, world, matrices
117 * - make render verts, faces, halos, strands
118 * - everything can change per frame/field
119 *
120 * 3) Render Processor
121 * - multiple layers
122 * - tiles, rect, baking
123 * - layers/tiles optionally to disk or directly in Render Result
124 *
125 * 4) Composite Render Result
126 * - also read external files etc
127 *
128 * 5) Image Files
129 * - save file or append in movie
130 */
131
132/* -------------------------------------------------------------------- */
135
136/* here we store all renders */
137static struct {
138 std::forward_list<Render *> render_list;
148
150
151/* -------------------------------------------------------------------- */
154
155static void render_callback_exec_string(Render *re, Main *bmain, eCbEvent evt, const char *str)
156{
157 if (re->r.scemode & R_BUTS_PREVIEW) {
158 return;
159 }
160 BKE_callback_exec_string(bmain, evt, str);
161}
162
163static void render_callback_exec_id(Render *re, Main *bmain, ID *id, eCbEvent evt)
164{
165 if (re->r.scemode & R_BUTS_PREVIEW) {
166 return;
167 }
168 BKE_callback_exec_id(bmain, id, evt);
169}
170
172
173/* -------------------------------------------------------------------- */
176
177static bool do_write_image_or_movie(
178 Render *re, Main *bmain, Scene *scene, const int totvideos, const char *filepath_override);
179
180/* default callbacks, set in each new render */
181static void result_rcti_nothing(void * /*arg*/, RenderResult * /*rr*/, rcti * /*rect*/) {}
182static void current_scene_nothing(void * /*arg*/, Scene * /*scene*/) {}
183static void stats_nothing(void * /*arg*/, RenderStats * /*rs*/) {}
184static void float_nothing(void * /*arg*/, float /*val*/) {}
185static bool default_break(void * /*arg*/)
186{
187 return G.is_break == true;
188}
189
190static void stats_background(void * /*arg*/, RenderStats *rs)
191{
192 if (rs->infostr == nullptr) {
193 return;
194 }
195
196 /* Compositor calls this from multiple threads, mutex lock to ensure we don't
197 * get garbled output. */
198 static blender::Mutex mutex;
199 std::scoped_lock lock(mutex);
200
201 const bool show_info = CLOG_CHECK(&LOG, CLG_LEVEL_INFO);
202 if (show_info) {
204 /* Flush stdout to be sure python callbacks are printing stuff after blender. */
205 fflush(stdout);
206 }
207
208 /* NOTE: using G_MAIN seems valid here???
209 * Not sure it's actually even used anyway, we could as well pass nullptr? */
211
212 if (show_info) {
213 fflush(stdout);
214 }
215}
216
218{
219 /* There is no need to lock as the user-counted render results are protected by mutex at the
220 * higher call stack level. */
221 ++rr->user_counter;
222}
223
228
229ImBuf *RE_RenderLayerGetPassImBuf(RenderLayer *rl, const char *name, const char *viewname)
230{
231 RenderPass *rpass = RE_pass_find_by_name(rl, name, viewname);
232 return rpass ? rpass->ibuf : nullptr;
233}
234
235float *RE_RenderLayerGetPass(RenderLayer *rl, const char *name, const char *viewname)
236{
237 const ImBuf *ibuf = RE_RenderLayerGetPassImBuf(rl, name, viewname);
238 return ibuf ? ibuf->float_buffer.data : nullptr;
239}
240
242{
243 if (rr == nullptr) {
244 return nullptr;
245 }
246
247 return static_cast<RenderLayer *>(
249}
250
252{
253 return (re->r.scemode & R_SINGLE_LAYER);
254}
255
257 ExrHandle *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
258{
259 return render_result_new_from_exr(exrhandle, colorspace, predivide, rectx, recty);
260}
261
263{
264 if (re->single_view_layer[0]) {
266
267 if (rl) {
268 return rl;
269 }
270 }
271
272 return static_cast<RenderLayer *>(rr->layers.first);
273}
274
275static bool render_scene_has_layers_to_render(Scene *scene, ViewLayer *single_layer)
276{
277 if (single_layer) {
278 return true;
279 }
280
281 LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
282 if (view_layer->flag & VIEW_LAYER_RENDER) {
283 return true;
284 }
285 }
286 return false;
287}
288
290
291/* -------------------------------------------------------------------- */
294
295Render *RE_GetRender(const void *owner)
296{
297 /* search for existing renders */
298 for (Render *re : RenderGlobal.render_list) {
299 if (re->owner == owner) {
300 return re;
301 }
302 }
303
304 return nullptr;
305}
306
308{
309 if (re) {
311 return re->result;
312 }
313
314 return nullptr;
315}
316
318{
319 if (re) {
322 return re->result;
323 }
324
325 return nullptr;
326}
327
329{
330 if (re) {
332 re->result = nullptr;
334 }
335}
336
338{
339 /* for keeping render buffers */
340 if (re) {
341 std::swap(re->result, *rr);
342 }
343}
344
346{
347 if (re) {
349 }
350}
351
353{
354 if (re) {
355 return re->scene;
356 }
357 return nullptr;
358}
359
360void RE_SetScene(Render *re, Scene *sce)
361{
362 if (re) {
363 re->scene = sce;
364 }
365}
366
368{
369 memset(rr, 0, sizeof(RenderResult));
370
371 if (re) {
373
374 if (re->result) {
375 rr->rectx = re->result->rectx;
376 rr->recty = re->result->recty;
377
378 copy_v2_v2_db(rr->ppm, re->result->ppm);
379
380 /* creates a temporary duplication of views */
382
383 RenderView *rv = static_cast<RenderView *>(rr->views.first);
384 rr->have_combined = (rv->ibuf != nullptr);
385
386 /* single layer */
388
389 /* The render result uses shallow initialization, and the caller is not expected to
390 * explicitly free it. So simply assign the buffers as a shallow copy here as well. */
391
392 if (rl) {
393 if (rv->ibuf == nullptr) {
394 LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
395 rview->ibuf = RE_RenderLayerGetPassImBuf(rl, RE_PASSNAME_COMBINED, rview->name);
396 }
397 }
398 }
399
400 rr->layers = re->result->layers;
401 rr->xof = re->disprect.xmin;
402 rr->yof = re->disprect.ymin;
403 rr->stamp_data = re->result->stamp_data;
404 }
405 }
406}
407
409{
410 if (re) {
411 if (rr) {
413 }
415 }
416}
417
418void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
419{
420 memset(rr, 0, sizeof(RenderResult));
421
422 if (re) {
424
425 if (re->result) {
426 RenderLayer *rl;
427 RenderView *rv;
428
429 rr->rectx = re->result->rectx;
430 rr->recty = re->result->recty;
431
432 copy_v2_v2_db(rr->ppm, re->result->ppm);
433
434 /* `scene.rd.actview` view. */
435 rv = RE_RenderViewGetById(re->result, view_id);
436 rr->have_combined = (rv->ibuf != nullptr);
437
438 /* The render result uses shallow initialization, and the caller is not expected to
439 * explicitly free it. So simply assign the buffers as a shallow copy here as well.
440 *
441 * The thread safety is ensured via the `re->resultmutex`. */
442 rr->ibuf = rv->ibuf;
443
444 /* active layer */
445 rl = render_get_single_layer(re, re->result);
446
447 if (rl) {
448 if (rv->ibuf == nullptr) {
450 }
451 }
452
453 rr->layers = re->result->layers;
454 rr->views = re->result->views;
455
456 rr->xof = re->disprect.xmin;
457 rr->yof = re->disprect.ymin;
458
459 rr->stamp_data = re->result->stamp_data;
460 }
461 }
462}
463
465{
466 if (re) {
468 }
469}
470
471void RE_ResultGet32(Render *re, uint *rect)
472{
473 RenderResult rres;
474 const int view_id = BKE_scene_multiview_view_id_get(&re->r, re->viewname);
475
478 rect,
479 re->rectx,
480 re->recty,
481 &re->scene->view_settings,
483 view_id);
485}
486
488{
489 RenderView *view = static_cast<RenderView *>(rr->views.first);
490 return (view && (view->next || view->name[0]));
491}
492
494{
495 return &re->i;
496}
497
498Render *RE_NewRender(const void *owner)
499{
500 Render *re;
501
502 /* only one render per name exists */
503 re = RE_GetRender(owner);
504 if (re == nullptr) {
505
506 /* new render data struct */
507 re = MEM_new<Render>("new render");
508 RenderGlobal.render_list.push_front(re);
509 re->owner = owner;
510 }
511
512 RE_display_init(re);
513
514 return re;
515}
516
518{
519 ViewRender *view_render = MEM_new<ViewRender>("new view render");
520 view_render->engine = RE_engine_create(engine_type);
521 return view_render;
522}
523
525{
526 return RE_GetRender(DEG_get_original_id(&scene->id));
527}
528
530{
531 return RE_NewRender(DEG_get_original_id(&scene->id));
532}
533
535{
536 const void *owner = DEG_get_original_id(&scene->id);
537
538 return RenderGlobal.interactive_compositor_renders.lookup_or_add_cb(owner, [&]() {
539 Render *render = MEM_new<Render>("New Interactive Compositor Render");
540 render->owner = owner;
541 return render;
542 });
543}
544
546{
547 RenderGlobal.render_list.remove(re);
548
549 MEM_delete(re);
550}
551
553{
554 MEM_delete(view_render);
555}
556
558{
559 while (!RenderGlobal.render_list.empty()) {
560 RE_FreeRender(static_cast<Render *>(RenderGlobal.render_list.front()));
561 }
562
564
565#ifdef WITH_FREESTYLE
566 /* finalize Freestyle */
567 FRS_exit();
568#endif
569}
570
572{
573 for (Render *render : RenderGlobal.interactive_compositor_renders.values()) {
574 RE_FreeRender(render);
575 }
576 RenderGlobal.interactive_compositor_renders.clear();
577}
578
580{
581 for (Render *re : RenderGlobal.render_list) {
584
585 re->result = nullptr;
586 re->pushedresult = nullptr;
588 }
589}
590
592{
593 for (Render *re : RenderGlobal.render_list) {
594 if (re->engine != nullptr) {
597 re->engine = nullptr;
598 }
599 }
600}
601
603{
604 /* Free persistent compositor that may be using these textures. */
605 if (re->compositor) {
607 }
608
609 /* Free textures. */
612 if (result != nullptr) {
614 }
617 }
618}
619
621{
622 for (Render *re : RenderGlobal.render_list) {
624 }
625}
626
628{
630
631 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
632
633 for (Render *re : RenderGlobal.render_list) {
634 bool do_free = true;
635
636 /* Don't free scenes being rendered or composited. Note there is no
637 * race condition here because we are on the main thread and new jobs can only
638 * be started from the main thread. */
639 if (WM_jobs_test(wm, re->owner, WM_JOB_TYPE_RENDER) ||
641 {
642 do_free = false;
643 }
644
645 LISTBASE_FOREACH (const wmWindow *, win, &wm->windows) {
646 if (!do_free) {
647 /* No need to do further checks. */
648 break;
649 }
650
651 const Scene *scene = WM_window_get_active_scene(win);
652 if (scene != re->owner) {
653 continue;
654 }
655
656 /* Detect if scene is using GPU compositing, and if either a node editor is
657 * showing the nodes, or an image editor is showing the render result or viewer. */
658 if (!(scene->compositing_node_group &&
660 {
661 continue;
662 }
663
664 const bScreen *screen = WM_window_get_active_screen(win);
665 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
666 const SpaceLink &space = *static_cast<const SpaceLink *>(area->spacedata.first);
667
668 if (space.spacetype == SPACE_NODE) {
669 const SpaceNode &snode = reinterpret_cast<const SpaceNode &>(space);
670 if (snode.nodetree == scene->compositing_node_group) {
671 do_free = false;
672 }
673 }
674 else if (space.spacetype == SPACE_IMAGE) {
675 const SpaceImage &sima = reinterpret_cast<const SpaceImage &>(space);
676 if (sima.image && sima.image->source == IMA_SRC_VIEWER) {
677 do_free = false;
678 }
679 }
680 }
681 }
682
683 if (do_free) {
685 if (!re->display_shared) {
686 RE_display_free(re);
687 }
688
689 /* We also free the resources from the interactive compositor render of the scene if one
690 * exists. */
691 Render *interactive_compositor_render =
692 RenderGlobal.interactive_compositor_renders.lookup_default(re->owner, nullptr);
693 if (interactive_compositor_render) {
694 re_gpu_texture_caches_free(interactive_compositor_render);
695 if (!interactive_compositor_render->display_shared) {
696 RE_display_free(interactive_compositor_render);
697 }
698 }
699 }
700 }
701}
702
704{
705 /* If engine is currently rendering, just wait for it to be freed when it finishes rendering.
706 */
707 if (re->engine && !(re->engine->flag & RE_ENGINE_RENDERING)) {
709 re->engine = nullptr;
710 }
711}
712
713void RE_FreePersistentData(const Scene *scene)
714{
715 /* Render engines can be kept around for quick re-render, this clears all or one scene. */
716 if (scene) {
717 Render *re = RE_GetSceneRender(scene);
718 if (re) {
720 }
721 }
722 else {
723 for (Render *re : RenderGlobal.render_list) {
725 }
726 }
727}
728
730
731/* -------------------------------------------------------------------- */
734
736 Render *re, Render *source, int winx, int winy, const rcti *disprect)
737{
738 re->winx = winx;
739 re->winy = winy;
740 if (source && (source->r.mode & R_BORDER)) {
741 /* NOTE(@sergey): doesn't seem original bordered `disprect` is storing anywhere
742 * after insertion on black happening in #do_render_engine(),
743 * so for now simply re-calculate `disprect` using border from source renderer. */
744
745 re->disprect.xmin = source->r.border.xmin * winx;
746 re->disprect.xmax = source->r.border.xmax * winx;
747
748 re->disprect.ymin = source->r.border.ymin * winy;
749 re->disprect.ymax = source->r.border.ymax * winy;
750
751 re->rectx = BLI_rcti_size_x(&re->disprect);
752 re->recty = BLI_rcti_size_y(&re->disprect);
753
754 /* copy border itself, since it could be used by external engines */
755 re->r.border = source->r.border;
756 }
757 else if (disprect) {
758 re->disprect = *disprect;
759 re->rectx = BLI_rcti_size_x(&re->disprect);
760 re->recty = BLI_rcti_size_y(&re->disprect);
761 }
762 else {
763 re->disprect.xmin = re->disprect.ymin = 0;
764 re->disprect.xmax = winx;
765 re->disprect.ymax = winy;
766 re->rectx = winx;
767 re->recty = winy;
768 }
769}
770
772{
773 /* Mostly shallow copy referencing pointers in scene renderdata. */
775
776 memcpy(to, from, sizeof(*to));
777
779}
780
782 Render *source,
783 RenderData *rd,
784 ListBase * /*render_layers*/,
785 ViewLayer *single_layer,
786 int winx,
787 int winy,
788 const rcti *disprect)
789{
790 bool had_freestyle = (re->r.mode & R_EDGE_FRS) != 0;
791
792 re->ok = true; /* maybe flag */
793
795
796 /* copy render data and render layers for thread safety */
797 render_copy_renderdata(&re->r, rd);
798 re->single_view_layer[0] = '\0';
799
800 if (source) {
801 /* reuse border flags from source renderer */
802 re->r.mode &= ~(R_BORDER | R_CROP);
803 re->r.mode |= source->r.mode & (R_BORDER | R_CROP);
804
805 /* dimensions shall be shared between all renderers */
806 re->r.xsch = source->r.xsch;
807 re->r.ysch = source->r.ysch;
808 re->r.size = source->r.size;
809 }
810
811 re_init_resolution(re, source, winx, winy, disprect);
812
813 /* disable border if it's a full render anyway */
814 if (re->r.border.xmin == 0.0f && re->r.border.xmax == 1.0f && re->r.border.ymin == 0.0f &&
815 re->r.border.ymax == 1.0f)
816 {
817 re->r.mode &= ~R_BORDER;
818 }
819
820 if (re->rectx < 1 || re->recty < 1 ||
821 (BKE_imtype_is_movie(rd->im_format.imtype) && (re->rectx < 16 || re->recty < 16)))
822 {
823 BKE_report(re->reports, RPT_ERROR, "Image too small");
824 re->ok = false;
825 return;
826 }
827
828 if (single_layer) {
829 STRNCPY_UTF8(re->single_view_layer, single_layer->name);
830 re->r.scemode |= R_SINGLE_LAYER;
831 }
832 else {
834 }
835
836 /* if preview render, we try to keep old result */
838
839 if (re->r.scemode & R_BUTS_PREVIEW) {
840 if (had_freestyle || (re->r.mode & R_EDGE_FRS)) {
841 /* freestyle manipulates render layers so always have to free */
843 re->result = nullptr;
844 }
845 else if (re->result) {
846 bool have_layer = false;
847
848 if (re->single_view_layer[0] == '\0' && re->result->layers.first) {
849 have_layer = true;
850 }
851 else {
853 if (STREQ(rl->name, re->single_view_layer)) {
854 have_layer = true;
855 }
856 }
857 }
858
859 if (re->result->rectx == re->rectx && re->result->recty == re->recty && have_layer) {
860 /* keep render result, this avoids flickering black tiles
861 * when the preview changes */
862 }
863 else {
864 /* free because resolution changed */
866 re->result = nullptr;
867 }
868 }
869 }
870 else {
871
872 /* make empty render result, so display callbacks can initialize */
874 re->result = MEM_callocN<RenderResult>("new render result");
875 re->result->rectx = re->rectx;
876 re->result->recty = re->recty;
877 BKE_scene_ppm_get(&re->r, re->result->ppm);
879 }
880
882
884}
885
887 void *handle,
888 void (*f)(void *handle, RenderResult *rr, rcti *rect))
889{
890 re->display->display_update_cb = f;
891 re->display->duh = handle;
892}
893void RE_current_scene_update_cb(Render *re, void *handle, void (*f)(void *handle, Scene *scene))
894{
895 re->display->current_scene_update_cb = f;
896 re->display->suh = handle;
897}
898void RE_stats_draw_cb(Render *re, void *handle, void (*f)(void *handle, RenderStats *rs))
899{
900 re->display->stats_draw_cb = f;
901 re->display->sdh = handle;
902}
903void RE_progress_cb(Render *re, void *handle, void (*f)(void *handle, float))
904{
905 re->display->progress_cb = f;
906 re->display->prh = handle;
907}
908
909void RE_draw_lock_cb(Render *re, void *handle, void (*f)(void *handle, bool lock))
910{
911 re->display->draw_lock_cb = f;
912 re->display->dlh = handle;
913}
914
915void RE_test_break_cb(Render *re, void *handle, bool (*f)(void *handle))
916{
917 re->display->test_break_cb = f;
918 re->display->tbh = handle;
919}
920
922 void *handle,
923 bool (*f)(void *handle, ViewLayer *vl, Depsgraph *depsgraph))
924{
925 re->prepare_viewlayer_cb = f;
926 re->prepare_vl_handle = handle;
927}
928
930
931/* -------------------------------------------------------------------- */
934
936{
937 re->display_shared = false;
938 re->display = std::make_shared<RenderDisplay>();
939
940 re->display->display_update_cb = result_rcti_nothing;
941 re->display->current_scene_update_cb = current_scene_nothing;
942 re->display->progress_cb = float_nothing;
943 re->display->test_break_cb = default_break;
944 if (G.background) {
945 re->display->stats_draw_cb = stats_background;
946 }
947 else {
948 re->display->stats_draw_cb = stats_nothing;
949 }
950}
951
953{
954 re->display->ensure_system_gpu_context();
955}
956
957void RE_display_share(Render *re, const Render *parent_re)
958{
959 /* Use for compositor and sequencer, which can render scenes recursively.
960 * It more efficient, and we can only create this context on the main thread. */
961 if (parent_re == nullptr || re == parent_re) {
962 return;
963 }
964
965 re->display_shared = true;
966 re->display = parent_re->display;
967}
968
970{
971 /* Re-initializing with a new RenderDisplay will free the GPU contexts. */
972 RE_display_init(re);
973}
974
976{
977 RenderDisplay *display = re->display.get();
978 return display->system_gpu_context;
979}
980
982{
983 RenderDisplay *display = re->display.get();
984 return display->ensure_blender_gpu_context();
985}
986
988
989/* -------------------------------------------------------------------- */
996
997/* ************ This part uses API, for rendering Blender scenes ********** */
998
999/* make sure disprect is not affected by the render border */
1001{
1002 re->disprect.xmin = re->disprect.ymin = 0;
1003 re->disprect.xmax = re->winx;
1004 re->disprect.ymax = re->winy;
1005 re->rectx = re->winx;
1006 re->recty = re->winy;
1007}
1008
1010{
1011 /* when using border render with crop disabled, insert render result into
1012 * full size with black pixels outside */
1013 if (re->result && (re->r.mode & R_BORDER)) {
1014 if ((re->r.mode & R_CROP) == 0) {
1015 RenderResult *rres;
1016
1017 /* backup */
1018 const rcti orig_disprect = re->disprect;
1019 const int orig_rectx = re->rectx, orig_recty = re->recty;
1020
1022
1023 /* sub-rect for merge call later on */
1024 re->result->tilerect = re->disprect;
1025
1026 /* weak is: it chances disprect from border */
1028
1031
1032 render_result_clone_passes(re, rres, nullptr);
1034
1035 render_result_merge(rres, re->result);
1037 re->result = rres;
1038
1039 /* Weak, the display callback wants an active render-layer pointer. */
1041
1043
1044 re->display->display_update(re->result, nullptr);
1045
1046 /* restore the disprect from border */
1047 re->disprect = orig_disprect;
1048 re->rectx = orig_rectx;
1049 re->recty = orig_recty;
1050 }
1051 else {
1052 /* set offset (again) for use in compositor, disprect was manipulated. */
1053 re->result->xof = 0;
1054 re->result->yof = 0;
1055 }
1056 }
1057}
1058
1059/* Render scene into render result, with a render engine. */
1060static void do_render_engine(Render *re)
1061{
1062 Object *camera = RE_GetCamera(re);
1063 /* also check for camera here */
1064 if (camera == nullptr) {
1065 BKE_report(re->reports, RPT_ERROR, "Cannot render, no camera");
1066 G.is_break = true;
1067 return;
1068 }
1069
1070 /* now use renderdata and camera to set viewplane */
1071 RE_SetCamera(re, camera);
1072
1073 re->display->current_scene_update(re->scene);
1074 RE_engine_render(re, false);
1075
1076 /* when border render, check if we have to insert it in black */
1078}
1079
1080/* Render scene into render result, within a compositor node tree.
1081 * Uses the same image dimensions, does not recursively perform compositing. */
1082static void do_render_compositor_scene(Render *re, Scene *sce, int cfra)
1083{
1084 Render *resc = RE_NewSceneRender(sce);
1085 int winx = re->winx, winy = re->winy;
1086
1087 sce->r.cfra = cfra;
1088
1090
1091 /* exception: scene uses its own size (unfinished code) */
1092 if (false) {
1093 BKE_render_resolution(&sce->r, false, &winx, &winy);
1094 }
1095
1096 /* initial setup */
1097 RE_InitState(resc, re, &sce->r, &sce->view_layers, nullptr, winx, winy, &re->disprect);
1098
1099 /* We still want to use "Render Cache" setting from the original (main) scene. */
1100 resc->r.scemode = (resc->r.scemode & ~R_EXR_CACHE_FILE) | (re->r.scemode & R_EXR_CACHE_FILE);
1101
1102 /* still unsure entity this... */
1103 resc->main = re->main;
1104 resc->scene = sce;
1105
1106 RE_display_share(resc, re);
1107
1108 do_render_engine(resc);
1109
1110 RE_display_free(resc);
1111}
1112
1113/* Get the scene referenced by the given node if the node uses its render. Returns nullptr
1114 * otherwise. */
1116{
1117 if (node->is_muted()) {
1118 return nullptr;
1119 }
1120
1121 if (node->type_legacy == CMP_NODE_R_LAYERS) {
1122 return reinterpret_cast<Scene *>(node->id);
1123 }
1124 if (node->type_legacy == CMP_NODE_CRYPTOMATTE &&
1126 {
1127 return reinterpret_cast<Scene *>(node->id);
1128 }
1129
1130 return nullptr;
1131}
1132
1133/* Returns true if the given scene needs a render, either because it doesn't use the compositor
1134 * pipeline and thus needs a simple render, or that its compositor node tree requires the scene to
1135 * be rendered. */
1137{
1138 bNodeTree *ntree = scene->compositing_node_group;
1139
1140 if (ntree == nullptr) {
1141 return true;
1142 }
1143 if ((scene->r.scemode & R_DOCOMP) == 0) {
1144 return true;
1145 }
1146
1147 for (const bNode *node : ntree->all_nodes()) {
1148 Scene *node_scene = get_scene_referenced_by_node(node);
1149 if (node_scene && node_scene == scene) {
1150 return true;
1151 }
1152 }
1153
1154 return false;
1155}
1156
1158static bool node_tree_has_group_output(const bNodeTree *node_tree)
1159{
1160 if (node_tree == nullptr) {
1161 return false;
1162 }
1163
1164 node_tree->ensure_topology_cache();
1165 for (const bNode *node : node_tree->nodes_by_type("NodeGroupOutput")) {
1166 if (node->flag & NODE_DO_OUTPUT && !node->is_muted()) {
1167 return true;
1168 }
1169 }
1170
1171 return false;
1172}
1173
1174/* Render all scenes references by the compositor of the given render's scene. */
1176{
1177 if (re->scene->compositing_node_group == nullptr) {
1178 return;
1179 }
1180
1181 /* For each node that requires a scene we do a full render. Results are stored in a way
1182 * compositor will find it. */
1183 blender::Set<Scene *> scenes_rendered;
1184 for (bNode *node : re->scene->compositing_node_group->all_nodes()) {
1185 Scene *node_scene = get_scene_referenced_by_node(node);
1186 if (!node_scene) {
1187 continue;
1188 }
1189
1190 /* References the current scene, which was already rendered. */
1191 if (node_scene == re->scene) {
1192 continue;
1193 }
1194
1195 /* Scene already rendered as required by another node. */
1196 if (scenes_rendered.contains(node_scene)) {
1197 continue;
1198 }
1199
1200 if (!render_scene_has_layers_to_render(node_scene, nullptr)) {
1201 continue;
1202 }
1203
1204 scenes_rendered.add_new(node_scene);
1205 do_render_compositor_scene(re, node_scene, re->scene->r.cfra);
1206 node->typeinfo->updatefunc(re->scene->compositing_node_group, node);
1207 }
1208
1209 /* If another scene was rendered, switch back to the current scene. */
1210 if (!scenes_rendered.is_empty()) {
1211 re->display->current_scene_update(re->scene);
1212 }
1213}
1214
1215/* bad call... need to think over proper method still */
1216static void render_compositor_stats(void *arg, const char *str)
1217{
1218 Render *re = (Render *)arg;
1219
1220 RenderStats i;
1221 memcpy(&i, &re->i, sizeof(i));
1222 i.infostr = str;
1223 re->display->stats_draw(&i);
1224}
1225
1226/* Render compositor nodes, along with any scenes required for them.
1227 * The result will be output into a compositing render layer in the render result. */
1229{
1231 bool update_newframe = false;
1232
1234 /* render the frames
1235 * it could be optimized to render only the needed view
1236 * but what if a scene has a different number of views
1237 * than the main scene? */
1238 do_render_engine(re);
1239 }
1240 else {
1241 re->i.cfra = re->r.cfra;
1242
1243 /* ensure new result gets added, like for regular renders */
1245
1247 if ((re->r.mode & R_CROP) == 0) {
1249 }
1251
1253
1254 /* Scene render process already updates animsys. */
1255 update_newframe = true;
1256
1257 /* The compositor does not have a group output, skip writing the render result. See
1258 * R_SKIP_WRITE for more information. */
1260 re->flag |= R_SKIP_WRITE;
1261 }
1262 }
1263
1264 /* swap render result */
1265 if (re->r.scemode & R_SINGLE_LAYER) {
1269 }
1270
1271 if (!re->display->test_break()) {
1272 if (ntree && re->r.scemode & R_DOCOMP) {
1273 /* checks if there are render-result nodes that need scene */
1274 if ((re->r.scemode & R_SINGLE_LAYER) == 0) {
1276 }
1277
1278 if (!re->display->test_break()) {
1279 ntree->runtime->stats_draw = render_compositor_stats;
1280 ntree->runtime->test_break = re->display->test_break_cb;
1281 ntree->runtime->progress = re->display->progress_cb;
1282 ntree->runtime->sdh = re;
1283 ntree->runtime->tbh = re->display->tbh;
1284 ntree->runtime->prh = re->display->prh;
1285
1286 if (update_newframe) {
1287 /* If we have consistent depsgraph now would be a time to update them. */
1288 }
1289
1290 blender::compositor::OutputTypes needed_outputs =
1293 if (!G.background) {
1296 }
1297
1298 CLOG_STR_INFO(&LOG, "Executing compositor");
1299 blender::compositor::RenderContext compositor_render_context;
1300 compositor_render_context.is_animation_render = re->flag & R_ANIMATION;
1301 LISTBASE_FOREACH (RenderView *, rv, &re->result->views) {
1302 COM_execute(re,
1303 &re->r,
1305 ntree,
1306 rv->name,
1307 &compositor_render_context,
1308 nullptr,
1309 needed_outputs);
1310 }
1311 compositor_render_context.save_file_outputs(re->pipeline_scene_eval);
1312
1313 ntree->runtime->stats_draw = nullptr;
1314 ntree->runtime->test_break = nullptr;
1315 ntree->runtime->progress = nullptr;
1316 ntree->runtime->tbh = ntree->runtime->sdh = ntree->runtime->prh = nullptr;
1317 }
1318 }
1319 }
1320
1321 /* Weak: the display callback wants an active render-layer pointer. */
1322 if (re->result != nullptr) {
1324 re->display->display_update(re->result, nullptr);
1325 }
1326}
1327
1329{
1330 RenderResult *render_result = re->result;
1331
1333
1334 LISTBASE_FOREACH (RenderLayer *, render_layer, &render_result->layers) {
1335 LISTBASE_FOREACH_BACKWARD (RenderPass *, render_pass, &render_layer->passes) {
1336 if (render_pass->ibuf) {
1337 BKE_imbuf_stamp_info(render_result, render_pass->ibuf);
1338 }
1339 }
1340 }
1341
1343}
1344
1346{
1347 RenderResult rres;
1348 int nr = 0;
1349
1350 /* this is the basic trick to get the displayed float or char rect from render result */
1351 LISTBASE_FOREACH (RenderView *, rv, &re->result->views) {
1352 RE_SetActiveRenderView(re, rv->name);
1353 RE_AcquireResultImage(re, &rres, nr);
1354
1355 if (rres.ibuf != nullptr) {
1356 Object *ob_camera_eval = DEG_get_evaluated(re->pipeline_depsgraph, RE_GetCamera(re));
1358 ob_camera_eval,
1359 (re->scene->r.stamp & R_STAMP_STRIPMETA) ? rres.stamp_data : nullptr,
1360 rres.ibuf);
1361 }
1362
1364 nr++;
1365 }
1366}
1367
1369{
1370 Editing *ed = scene->ed;
1371
1372 if (!(rd->scemode & R_DOSEQ) || !ed || !ed->seqbase.first) {
1373 return false;
1374 }
1375
1376 LISTBASE_FOREACH (Strip *, strip, &ed->seqbase) {
1377 if (strip->type != STRIP_TYPE_SOUND_RAM &&
1379 {
1380 return true;
1381 }
1382 }
1383
1384 return false;
1385}
1386
1387static bool seq_result_needs_float(const ImageFormatData &im_format)
1388{
1390}
1391
1393 const ImageFormatData &im_format,
1394 const Scene *scene)
1395{
1396 if (src == nullptr) {
1397 return nullptr;
1398 }
1399
1400 ImBuf *dst = nullptr;
1401 if (seq_result_needs_float(im_format) && src->float_buffer.data == nullptr) {
1402 /* If render output needs >8-BPP input and we only have 8-BPP, convert to float. */
1403 dst = IMB_allocImBuf(src->x, src->y, src->planes, 0);
1404 IMB_alloc_float_pixels(dst, src->channels, false);
1405 /* Transform from sequencer space to scene linear. */
1406 const char *from_colorspace = IMB_colormanagement_get_rect_colorspace(src);
1407 const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(
1410 src->byte_buffer.data,
1411 src->x,
1412 src->y,
1413 src->channels,
1414 from_colorspace,
1415 to_colorspace);
1416 }
1417 else {
1418 /* Duplicate sequencer output and ensure it is in needed color space. */
1419 dst = IMB_dupImBuf(src);
1421 }
1422 IMB_metadata_copy(dst, src);
1423 IMB_freeImBuf(src);
1424
1425 return dst;
1426}
1427
1428/* Render sequencer strips into render result. */
1430{
1431 static int recurs_depth = 0;
1432 ImBuf *out;
1433 RenderResult *rr; /* don't assign re->result here as it might change during give_ibuf_seq */
1434 int cfra = re->r.cfra;
1436 int view_id, tot_views;
1437 int re_x, re_y;
1438
1439 CLOG_STR_INFO(&LOG, "Executing sequencer");
1440
1441 re->i.cfra = cfra;
1442
1443 recurs_depth++;
1444
1445 if ((re->r.mode & R_BORDER) && (re->r.mode & R_CROP) == 0) {
1446 /* if border rendering is used and cropping is disabled, final buffer should
1447 * be as large as the whole frame */
1448 re_x = re->winx;
1449 re_y = re->winy;
1450 }
1451 else {
1452 re_x = re->result->rectx;
1453 re_y = re->result->recty;
1454 }
1455
1456 tot_views = BKE_scene_multiview_num_views_get(&re->r);
1457 blender::Vector<ImBuf *> ibuf_arr(tot_views);
1458
1459 render_new_render_data(re->main,
1461 re->scene,
1462 re_x,
1463 re_y,
1465 re,
1466 &context);
1467
1468 /* The render-result gets destroyed during the rendering, so we first collect all ibufs
1469 * and then we populate the final render-result. */
1470
1471 for (view_id = 0; view_id < tot_views; view_id++) {
1472 context.view_id = view_id;
1473 out = render_give_ibuf(&context, cfra, 0);
1474 ibuf_arr[view_id] = seq_process_render_image(out, re->r.im_format, re->pipeline_scene_eval);
1475 }
1476
1477 rr = re->result;
1478
1480 render_result_views_new(rr, &re->r);
1482
1483 for (view_id = 0; view_id < tot_views; view_id++) {
1484 RenderView *rv = RE_RenderViewGetById(rr, view_id);
1486
1487 if (ibuf_arr[view_id]) {
1488 /* copy ibuf into combined pixel rect */
1489 RE_render_result_rect_from_ibuf(rr, ibuf_arr[view_id], view_id);
1490
1491 if (ibuf_arr[view_id]->metadata && (re->scene->r.stamp & R_STAMP_STRIPMETA)) {
1492 /* ensure render stamp info first */
1493 BKE_render_result_stamp_info(nullptr, nullptr, rr, true);
1494 BKE_stamp_info_from_imbuf(rr, ibuf_arr[view_id]);
1495 }
1496
1497 if (recurs_depth == 0) { /* With nested scenes, only free on top-level. */
1498 Editing *ed = re->pipeline_scene_eval->ed;
1499 if (ed) {
1501 }
1502 }
1503 IMB_freeImBuf(ibuf_arr[view_id]);
1504 }
1505 else {
1506 /* render result is delivered empty in most cases, nevertheless we handle all cases */
1507 render_result_rect_fill_zero(rr, view_id);
1508 }
1509
1511
1512 /* would mark display buffers as invalid */
1514 re->display->display_update(re->result, nullptr);
1515 }
1516
1517 recurs_depth--;
1518
1519 /* just in case this flag went missing at some point */
1520 re->r.scemode |= R_DOSEQ;
1521
1522 /* set overall progress of sequence rendering */
1523 if (re->r.efra != re->r.sfra) {
1524 re->display->progress(float(cfra - re->r.sfra) / (re->r.efra - re->r.sfra));
1525 }
1526 else {
1527 re->display->progress(1.0f);
1528 }
1529}
1530
1531/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
1532
1533/* Render full pipeline, using render engine, sequencer and compositing nodes. */
1535{
1536 bool render_seq = false;
1537
1538 re->display->current_scene_update_cb(re->display->suh, re->scene);
1539
1541
1543
1544 /* ensure no images are in memory from previous animated sequences */
1547
1548 if (RE_engine_render(re, true)) {
1549 /* in this case external render overrides all */
1550 }
1551 else if (RE_seq_render_active(re->scene, &re->r)) {
1552 /* NOTE: do_render_sequencer() frees rect32 when sequencer returns float images. */
1553 if (!re->display->test_break()) {
1555 render_seq = true;
1556 }
1557
1558 re->display->stats_draw(&re->i);
1559 re->display->display_update(re->result, nullptr);
1560 }
1561 else {
1563 }
1564
1566
1567 re->display->stats_draw(&re->i);
1568
1569 /* save render result stamp if needed */
1570 if (re->result != nullptr) {
1571 /* sequence rendering should have taken care of that already */
1572 if (!(render_seq && (re->scene->r.stamp & R_STAMP_STRIPMETA))) {
1573 Object *ob_camera_eval = DEG_get_evaluated(re->pipeline_depsgraph, RE_GetCamera(re));
1574 BKE_render_result_stamp_info(re->scene, ob_camera_eval, re->result, false);
1575 }
1576
1578
1579 /* stamp image info here */
1580 if ((re->scene->r.stamp & R_STAMP_ALL) && (re->scene->r.stamp & R_STAMP_DRAW)) {
1582 re->display->display_update(re->result, nullptr);
1583 }
1584 }
1585}
1586
1588 Object *camera_override,
1589 ReportList *reports)
1590{
1591 if (scene->r.scemode & R_DOCOMP && scene->compositing_node_group) {
1592 for (bNode *node : scene->compositing_node_group->all_nodes()) {
1593 if (node->type_legacy == CMP_NODE_R_LAYERS && !node->is_muted()) {
1594 Scene *sce = node->id ? (Scene *)node->id : scene;
1595 if (sce->camera == nullptr) {
1597 }
1598 if (sce->camera == nullptr) {
1599 /* all render layers nodes need camera */
1600 BKE_reportf(reports,
1601 RPT_ERROR,
1602 "No camera found in scene \"%s\" (used in compositing of scene \"%s\")",
1603 sce->id.name + 2,
1604 scene->id.name + 2);
1605 return false;
1606 }
1607 }
1608 }
1609
1610 return true;
1611 }
1612
1613 const bool ok = (camera_override != nullptr || scene->camera != nullptr);
1614 if (!ok) {
1615 BKE_reportf(reports, RPT_ERROR, "No camera found in scene \"%s\"", scene->id.name + 2);
1616 }
1617
1618 return ok;
1619}
1620
1621static bool check_valid_camera_multiview(Scene *scene, Object *camera, ReportList *reports)
1622{
1623 bool active_view = false;
1624
1625 if (camera == nullptr || (scene->r.scemode & R_MULTIVIEW) == 0) {
1626 return true;
1627 }
1628
1629 LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
1630 if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
1631 active_view = true;
1632
1634 Object *view_camera;
1635 view_camera = BKE_camera_multiview_render(scene, camera, srv->name);
1636
1637 if (view_camera == camera) {
1638 /* if the suffix is not in the camera, means we are using the fallback camera */
1639 if (!BLI_str_endswith(view_camera->id.name + 2, srv->suffix)) {
1640 BKE_reportf(reports,
1641 RPT_ERROR,
1642 "Camera \"%s\" is not a multi-view camera",
1643 camera->id.name + 2);
1644 return false;
1645 }
1646 }
1647 }
1648 }
1649 }
1650
1651 if (!active_view) {
1652 BKE_reportf(reports, RPT_ERROR, "No active view found in scene \"%s\"", scene->id.name + 2);
1653 return false;
1654 }
1655
1656 return true;
1657}
1658
1659static int check_valid_camera(Scene *scene, Object *camera_override, ReportList *reports)
1660{
1661 if (camera_override == nullptr && scene->camera == nullptr) {
1663 }
1664
1665 if (!check_valid_camera_multiview(scene, scene->camera, reports)) {
1666 return false;
1667 }
1668
1669 if (RE_seq_render_active(scene, &scene->r)) {
1670 if (scene->ed) {
1671 LISTBASE_FOREACH (Strip *, strip, &scene->ed->seqbase) {
1672 if ((strip->type == STRIP_TYPE_SCENE) && ((strip->flag & SEQ_SCENE_STRIPS) == 0) &&
1673 (strip->scene != nullptr))
1674 {
1675 if (!strip->scene_camera) {
1676 if (!strip->scene->camera &&
1677 !BKE_view_layer_camera_find(strip->scene,
1678 BKE_view_layer_default_render(strip->scene)))
1679 {
1680 /* camera could be unneeded due to composite nodes */
1681 Object *override = (strip->scene == scene) ? camera_override : nullptr;
1682
1683 if (!check_valid_compositing_camera(strip->scene, override, reports)) {
1684 return false;
1685 }
1686 }
1687 }
1688 else if (!check_valid_camera_multiview(strip->scene, strip->scene_camera, reports)) {
1689 return false;
1690 }
1691 }
1692 }
1693 }
1694 }
1695 else if (!check_valid_compositing_camera(scene, camera_override, reports)) {
1696 return false;
1697 }
1698
1699 return true;
1700}
1701
1702static bool node_tree_has_file_output(const bNodeTree *node_tree)
1703{
1704 node_tree->ensure_topology_cache();
1705 for (const bNode *node : node_tree->nodes_by_type("CompositorNodeOutputFile")) {
1706 if (!node->is_muted()) {
1707 return true;
1708 }
1709 }
1710
1711 for (const bNode *node : node_tree->group_nodes()) {
1712 if (node->is_muted() || !node->id) {
1713 continue;
1714 }
1715
1716 if (node_tree_has_file_output(reinterpret_cast<const bNodeTree *>(node->id))) {
1717 return true;
1718 }
1719 }
1720
1721 return false;
1722}
1723
1725{
1727 return true;
1728 }
1730}
1731
1732/* Identify if the compositor can run on the GPU. Currently, this only checks if the compositor is
1733 * set to GPU and the render size exceeds what can be allocated as a texture in it. */
1735{
1736 /* CPU compositor can always run. */
1738 return true;
1739 }
1740
1741 int width, height;
1742 BKE_render_resolution(&scene->r, false, &width, &height);
1743 if (!GPU_is_safe_texture_size(width, height)) {
1744 BKE_report(reports, RPT_ERROR, "Render size too large for GPU, use CPU compositor instead");
1745 return false;
1746 }
1747
1748 return true;
1749}
1750
1752 ViewLayer *single_layer,
1753 Object *camera_override,
1754 ReportList *reports)
1755{
1756 const int scemode = scene->r.scemode;
1757
1758 if (scene->r.mode & R_BORDER) {
1759 if (scene->r.border.xmax <= scene->r.border.xmin ||
1760 scene->r.border.ymax <= scene->r.border.ymin)
1761 {
1762 BKE_report(reports, RPT_ERROR, "No border area selected");
1763 return false;
1764 }
1765 }
1766
1767 if (RE_seq_render_active(scene, &scene->r)) {
1768 /* Sequencer */
1769 if (scene->r.mode & R_BORDER) {
1770 BKE_report(reports, RPT_ERROR, "Border rendering is not supported by sequencer");
1771 return false;
1772 }
1773 }
1774 else if (scemode & R_DOCOMP && scene->compositing_node_group) {
1775 /* Compositor */
1776 if (!scene_has_compositor_output(scene)) {
1777 BKE_report(reports, RPT_ERROR, "No Group Output or File Output nodes in scene");
1778 return false;
1779 }
1780
1781 if (!is_compositing_possible_on_gpu(scene, reports)) {
1782 return false;
1783 }
1784 }
1785 else {
1786 /* Regular Render */
1787 if (!render_scene_has_layers_to_render(scene, single_layer)) {
1788 BKE_report(reports, RPT_ERROR, "All render layers are disabled");
1789 return false;
1790 }
1791 }
1792
1793 /* check valid camera, without camera render is OK (compo, seq) */
1794 if (!check_valid_camera(scene, camera_override, reports)) {
1795 return false;
1796 }
1797
1798 return true;
1799}
1800
1802 Scene *scene,
1803 ViewLayer *view_layer,
1804 const bool /*anim_init*/)
1805{
1806 PTCacheBaker baker;
1807
1808 memset(&baker, 0, sizeof(baker));
1809 baker.bmain = re->main;
1810 baker.scene = scene;
1811 baker.view_layer = view_layer;
1812 baker.depsgraph = BKE_scene_ensure_depsgraph(re->main, scene, view_layer);
1813 baker.bake = false;
1814 baker.render = true;
1815 baker.anim_init = true;
1816 baker.quick_step = 1;
1817
1818 BKE_ptcache_bake(&baker);
1819}
1820
1821void RE_SetActiveRenderView(Render *re, const char *viewname)
1822{
1823 STRNCPY(re->viewname, viewname);
1824}
1825
1827{
1828 return re->viewname;
1829}
1830
1833 const RenderData *rd,
1834 Main *bmain,
1835 Scene *scene,
1836 ViewLayer *single_layer,
1837 Object *camera_override,
1838 const bool anim,
1839 const bool anim_init)
1840{
1841 int winx, winy;
1842 rcti disprect;
1843
1844 /* Reset the runtime flags before rendering, but only if this init is not an inter-animation
1845 * init, since some flags needs to be kept across the entire animation. */
1846 if (!anim) {
1847 re->flag = 0;
1848 }
1849
1850 /* r.xsch and r.ysch has the actual view window size
1851 * r.border is the clipping rect */
1852
1853 /* calculate actual render result and display size */
1854 BKE_render_resolution(rd, false, &winx, &winy);
1855
1856 /* We always render smaller part, inserting it in larger image is compositor business,
1857 * it uses 'disprect' for it. */
1858 if (scene->r.mode & R_BORDER) {
1859 disprect.xmin = rd->border.xmin * winx;
1860 disprect.xmax = rd->border.xmax * winx;
1861
1862 disprect.ymin = rd->border.ymin * winy;
1863 disprect.ymax = rd->border.ymax * winy;
1864 }
1865 else {
1866 disprect.xmin = disprect.ymin = 0;
1867 disprect.xmax = winx;
1868 disprect.ymax = winy;
1869 }
1870
1871 re->main = bmain;
1872 re->scene = scene;
1873 re->camera_override = camera_override;
1874 re->viewname[0] = '\0';
1875
1876 /* not too nice, but it survives anim-border render */
1877 if (anim) {
1878 re->disprect = disprect;
1879 return true;
1880 }
1881
1882 /*
1883 * Disabled completely for now,
1884 * can be later set as render profile option
1885 * and default for background render.
1886 */
1887 if (false) {
1888 /* make sure dynamics are up to date */
1890 update_physics_cache(re, scene, view_layer, anim_init);
1891 }
1892
1893 if (single_layer || scene->r.scemode & R_SINGLE_LAYER) {
1897 }
1898
1899 RE_InitState(re, nullptr, &scene->r, &scene->view_layers, single_layer, winx, winy, &disprect);
1900 if (!re->ok) { /* if an error was printed, abort */
1901 return false;
1902 }
1903
1904 return true;
1905}
1906
1908{
1909 re->reports = reports;
1910}
1911
1918
1920{
1921 Scene *scene = re->scene;
1923
1924 re->pipeline_depsgraph = DEG_graph_new(re->main, scene, view_layer, DAG_EVAL_RENDER);
1925 DEG_debug_name_set(re->pipeline_depsgraph, "RENDER PIPELINE");
1926
1927 /* Make sure there is a correct evaluated scene pointer. */
1929
1930 /* Update immediately so we have proper evaluated scene. */
1932
1934}
1935
1936/* Free data only needed during rendering operation. */
1938{
1939 if (re->engine && !RE_engine_use_persistent_data(re->engine)) {
1941 re->engine = nullptr;
1942 }
1943
1944 /* Destroy compositor that was using pipeline depsgraph. */
1945 RE_compositor_free(*re);
1946
1947 /* Destroy pipeline depsgraph. */
1948 if (re->pipeline_depsgraph != nullptr) {
1950 re->pipeline_depsgraph = nullptr;
1951 re->pipeline_scene_eval = nullptr;
1952 }
1953
1954 /* Destroy the opengl context in the correct thread. */
1955 RE_display_free(re);
1956}
1957
1959 Main *bmain,
1960 Scene *scene,
1961 ViewLayer *single_layer,
1962 Object *camera_override,
1963 const int frame,
1964 const float subframe,
1965 const bool write_still)
1966{
1968
1969 /* Ugly global still...
1970 * is to prevent preview events and signal subdivision-surface etc to make full resolution. */
1971 G.is_rendering = true;
1972
1973 scene->r.cfra = frame;
1974 scene->r.subframe = subframe;
1975
1977 re, &scene->r, bmain, scene, single_layer, camera_override, false, false))
1978 {
1979 RenderData rd;
1980 memcpy(&rd, &scene->r, sizeof(rd));
1982
1984
1985 /* Reduce GPU memory usage so renderer has more space. */
1987
1989
1991
1992 const bool should_write = write_still && !(re->flag & R_SKIP_WRITE);
1993 if (should_write && !G.is_break) {
1995 /* operator checks this but in case its called from elsewhere */
1996 printf("Error: cannot write single images with a movie format!\n");
1997 }
1998 else {
1999 char filepath_override[FILE_MAX];
2000 const char *relbase = BKE_main_blendfile_path(bmain);
2001 path_templates::VariableMap template_variables;
2002 BKE_add_template_variables_general(template_variables, &scene->id);
2003 BKE_add_template_variables_for_render_path(template_variables, *scene);
2004
2006 filepath_override,
2007 rd.pic,
2008 relbase,
2009 &template_variables,
2010 scene->r.cfra,
2011 &rd.im_format,
2012 (rd.scemode & R_EXTENSION) != 0,
2013 false,
2014 nullptr);
2015
2016 if (errors.is_empty()) {
2017 do_write_image_or_movie(re, bmain, scene, 0, filepath_override);
2018 }
2019 else {
2021 }
2022 }
2023 }
2024
2025 /* keep after file save */
2027 if (should_write) {
2029 }
2030 }
2031
2033 re->main,
2034 &scene->id,
2036
2038
2039 /* UGLY WARNING */
2040 G.is_rendering = false;
2041}
2042
2043#ifdef WITH_FREESTYLE
2044
2045/* Not freestyle specific, currently only used by free-style. */
2046static void change_renderdata_engine(Render *re, const char *new_engine)
2047{
2048 if (!STREQ(re->r.engine, new_engine)) {
2049 if (re->engine) {
2051 re->engine = nullptr;
2052 }
2053 STRNCPY(re->r.engine, new_engine);
2054 }
2055}
2056
2057static bool use_eevee_for_freestyle_render(Render *re)
2058{
2060 return !(type->flag & RE_USE_CUSTOM_FREESTYLE);
2061}
2062
2063void RE_RenderFreestyleStrokes(Render *re, Main *bmain, Scene *scene, const bool render)
2064{
2065 if (render_init_from_main(re, &scene->r, bmain, scene, nullptr, nullptr, false, false)) {
2066 if (render) {
2067 char scene_engine[32];
2068 STRNCPY(scene_engine, re->r.engine);
2069 if (use_eevee_for_freestyle_render(re)) {
2070 change_renderdata_engine(re, RE_engine_id_BLENDER_EEVEE);
2071 }
2072
2073 RE_engine_render(re, false);
2074
2075 change_renderdata_engine(re, scene_engine);
2076 }
2077 }
2078}
2079
2080void RE_RenderFreestyleExternal(Render *re)
2081{
2082 if (re->display->test_break()) {
2083 return;
2084 }
2085
2087
2088 LISTBASE_FOREACH (RenderView *, rv, &re->result->views) {
2089 RE_SetActiveRenderView(re, rv->name);
2090
2092
2093 LISTBASE_FOREACH (ViewLayer *, view_layer, &re->scene->view_layers) {
2094 if ((re->r.scemode & R_SINGLE_LAYER) && !STREQ(view_layer->name, re->single_view_layer)) {
2095 continue;
2096 }
2097
2098 if (FRS_is_freestyle_enabled(view_layer)) {
2099 FRS_do_stroke_rendering(re, view_layer);
2100 }
2101 }
2102
2104 }
2105}
2106#endif
2107
2109
2110/* -------------------------------------------------------------------- */
2113
2115 RenderResult *rr,
2116 Scene *scene,
2117 RenderData *rd,
2118 MovieWriter **movie_writers,
2119 const int totvideos,
2120 bool preview)
2121{
2122 bool ok = true;
2123
2124 if (!rr) {
2125 return false;
2126 }
2127
2128 ImageFormatData image_format;
2129 BKE_image_format_init_for_write(&image_format, scene, nullptr, true);
2130
2131 const bool is_mono = !RE_ResultIsMultiView(rr);
2132 const float dither = scene->r.dither_intensity;
2133
2134 if (is_mono || (image_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
2135 int view_id;
2136 for (view_id = 0; view_id < totvideos; view_id++) {
2137 const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
2138 ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id);
2139
2140 IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format);
2141
2142 BLI_assert(movie_writers[view_id] != nullptr);
2143 if (!MOV_write_append(movie_writers[view_id],
2144 scene,
2145 rd,
2146 &image_format,
2147 preview ? scene->r.psfra : scene->r.sfra,
2148 scene->r.cfra,
2149 ibuf,
2150 suffix,
2151 reports))
2152 {
2153 ok = false;
2154 }
2155
2156 /* imbuf knows which rects are not part of ibuf */
2157 IMB_freeImBuf(ibuf);
2158 }
2159 CLOG_INFO(&LOG, "Video append frame %d", scene->r.cfra);
2160 }
2161 else { /* R_IMF_VIEWS_STEREO_3D */
2162 const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
2163 ImBuf *ibuf_arr[3] = {nullptr};
2164 int i;
2165
2166 BLI_assert((totvideos == 1) && (image_format.views_format == R_IMF_VIEWS_STEREO_3D));
2167
2168 for (i = 0; i < 2; i++) {
2169 int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
2170 ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id);
2171
2172 IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &image_format);
2173 }
2174
2175 ibuf_arr[2] = IMB_stereo3d_ImBuf(&image_format, ibuf_arr[0], ibuf_arr[1]);
2176
2177 if (ibuf_arr[2]) {
2178 BLI_assert(movie_writers[0] != nullptr);
2179 if (!MOV_write_append(movie_writers[0],
2180 scene,
2181 rd,
2182 &image_format,
2183 preview ? scene->r.psfra : scene->r.sfra,
2184 scene->r.cfra,
2185 ibuf_arr[2],
2186 "",
2187 reports))
2188 {
2189 ok = false;
2190 }
2191 }
2192 else {
2193 BKE_report(reports, RPT_ERROR, "Failed to create stereo image buffer");
2194 ok = false;
2195 }
2196
2197 for (i = 0; i < 3; i++) {
2198 /* imbuf knows which rects are not part of ibuf */
2199 if (ibuf_arr[i]) {
2200 IMB_freeImBuf(ibuf_arr[i]);
2201 }
2202 }
2203 }
2204
2205 BKE_image_format_free(&image_format);
2206
2207 return ok;
2208}
2209
2211 Render *re, Main *bmain, Scene *scene, const int totvideos, const char *filepath_override)
2212{
2213 char filepath[FILE_MAX];
2214 RenderResult rres;
2215 double render_time;
2216 bool ok = true;
2217 RenderEngineType *re_type = RE_engines_find(re->r.engine);
2218
2219 /* Only disable file writing if postprocessing is also disabled. */
2220 const bool do_write_file = !(re_type->flag & RE_USE_NO_IMAGE_SAVE) ||
2221 (re_type->flag & RE_USE_POSTPROCESS);
2222
2223 if (do_write_file) {
2224 RE_AcquireResultImageViews(re, &rres);
2225
2226 /* write movie or image */
2227 if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
2229 re->reports, &rres, scene, &re->r, re->movie_writers.data(), totvideos, false);
2230 }
2231 else {
2232 if (filepath_override) {
2233 STRNCPY(filepath, filepath_override);
2234 }
2235 else {
2236 const char *relbase = BKE_main_blendfile_path(bmain);
2237 path_templates::VariableMap template_variables;
2238 BKE_add_template_variables_general(template_variables, &scene->id);
2239 BKE_add_template_variables_for_render_path(template_variables, *scene);
2240
2242 filepath,
2243 scene->r.pic,
2244 relbase,
2245 &template_variables,
2246 scene->r.cfra,
2247 &scene->r.im_format,
2248 (scene->r.scemode & R_EXTENSION) != 0,
2249 true,
2250 nullptr);
2251 if (!errors.is_empty()) {
2253 ok = false;
2254 }
2255 }
2256
2257 /* write images as individual images or stereo */
2258 if (ok) {
2259 ok = BKE_image_render_write(re->reports, &rres, scene, true, filepath);
2260 }
2261 }
2262
2263 RE_ReleaseResultImageViews(re, &rres);
2264 }
2265
2266 render_time = re->i.lastframetime;
2268
2269 BLI_timecode_string_from_time_simple(filepath, sizeof(filepath), re->i.lastframetime);
2270 std::string message = fmt::format("Time: {}", filepath);
2271
2272 if (do_write_file && ok) {
2274 filepath, sizeof(filepath), re->i.lastframetime - render_time);
2275 message = fmt::format("{} (Saving: {})", message, filepath);
2276 }
2277
2278 const bool show_info = CLOG_CHECK(&LOG, CLG_LEVEL_INFO);
2279 if (show_info) {
2280 CLOG_STR_INFO(&LOG, message.c_str());
2281 /* Flush stdout to be sure python callbacks are printing stuff after blender. */
2282 fflush(stdout);
2283 }
2284
2285 /* NOTE: using G_MAIN seems valid here???
2286 * Not sure it's actually even used anyway, we could as well pass nullptr? */
2288
2289 if (show_info) {
2290 fflush(stdout);
2291 }
2292
2293 return ok;
2294}
2295
2296static void get_videos_dimensions(const Render *re,
2297 const RenderData *rd,
2298 const ImageFormatData *imf,
2299 size_t *r_width,
2300 size_t *r_height)
2301{
2302 size_t width, height;
2303 if (re->r.mode & R_BORDER) {
2304 if ((re->r.mode & R_CROP) == 0) {
2305 width = re->winx;
2306 height = re->winy;
2307 }
2308 else {
2309 width = re->rectx;
2310 height = re->recty;
2311 }
2312 }
2313 else {
2314 width = re->rectx;
2315 height = re->recty;
2316 }
2317
2318 BKE_scene_multiview_videos_dimensions_get(rd, imf, width, height, r_width, r_height);
2319}
2320
2322{
2323 for (MovieWriter *writer : re->movie_writers) {
2324 MOV_write_end(writer);
2325 }
2327}
2328
2329static void touch_file(const char *filepath)
2330{
2331 if (BLI_exists(filepath)) {
2332 return;
2333 }
2334
2335 if (!BLI_file_ensure_parent_dir_exists(filepath)) {
2336 CLOG_ERROR(&LOG, "Couldn't create directory for file %s: %s", filepath, std::strerror(errno));
2337 return;
2338 }
2339 if (!BLI_file_touch(filepath)) {
2340 CLOG_ERROR(&LOG, "Couldn't touch file %s: %s", filepath, std::strerror(errno));
2341 return;
2342 }
2343}
2344
2346 Main *bmain,
2347 Scene *scene,
2348 ViewLayer *single_layer,
2349 Object *camera_override,
2350 int sfra,
2351 int efra,
2352 int tfra)
2353{
2354 if (sfra == efra) {
2355 CLOG_INFO(&LOG, "Rendering single frame (frame %d)", sfra);
2356 }
2357 else {
2358 CLOG_INFO(&LOG, "Rendering animation (frames %d..%d)", sfra, efra);
2359 }
2360
2361 /* Call hooks before taking a copy of scene->r, so user can alter the render settings prior to
2362 * copying (e.g. alter the output path). */
2364
2365 RenderData rd;
2366 memcpy(&rd, &scene->r, sizeof(rd));
2367 const int cfra_old = rd.cfra;
2368 const float subframe_old = rd.subframe;
2369 int nfra, totrendered = 0, totskipped = 0;
2370
2371 /* do not fully call for each frame, it initializes & pops output window */
2372 if (!render_init_from_main(re, &rd, bmain, scene, single_layer, camera_override, false, true)) {
2373 return;
2374 }
2375
2376 RenderEngineType *re_type = RE_engines_find(re->r.engine);
2377
2378 /* Image format for writing. */
2379 ImageFormatData image_format;
2380 BKE_image_format_init_for_write(&image_format, scene, nullptr, true);
2381
2382 const int totvideos = BKE_scene_multiview_num_videos_get(&rd, &image_format);
2383 const bool is_movie = BKE_imtype_is_movie(image_format.imtype);
2384 const bool is_multiview_name = ((rd.scemode & R_MULTIVIEW) != 0 &&
2385 (image_format.views_format == R_IMF_VIEWS_INDIVIDUAL));
2386
2387 /* Only disable file writing if postprocessing is also disabled. */
2388 const bool do_write_file = !(re_type->flag & RE_USE_NO_IMAGE_SAVE) ||
2389 (re_type->flag & RE_USE_POSTPROCESS);
2390
2392
2393 if (is_movie && do_write_file) {
2394 size_t width, height;
2395 get_videos_dimensions(re, &rd, &image_format, &width, &height);
2396
2397 bool is_error = false;
2398 re->movie_writers.reserve(totvideos);
2399 for (int i = 0; i < totvideos; i++) {
2400 const char *suffix = BKE_scene_multiview_view_id_suffix_get(&re->r, i);
2401 MovieWriter *writer = MOV_write_begin(re->pipeline_scene_eval,
2402 &re->r,
2403 &image_format,
2404 width,
2405 height,
2406 re->reports,
2407 false,
2408 suffix);
2409 if (writer == nullptr) {
2410 is_error = true;
2411 break;
2412 }
2413 re->movie_writers.append(writer);
2414 }
2415
2416 if (is_error) {
2418 BKE_image_format_free(&image_format);
2420 return;
2421 }
2422 }
2423
2424 /* Ugly global still... is to prevent renderwin events and signal subdivision-surface etc
2425 * to make full resolution is also set by caller renderwin.c */
2426 G.is_rendering = true;
2427
2428 re->flag |= R_ANIMATION;
2430
2431 scene->r.subframe = 0.0f;
2432 for (nfra = sfra, scene->r.cfra = sfra; scene->r.cfra <= efra; scene->r.cfra++) {
2433 char filepath[FILE_MAX];
2434
2435 /* Reduce GPU memory usage so renderer has more space. */
2437
2438 /* A feedback loop exists here -- render initialization requires updated
2439 * render layers settings which could be animated, but scene evaluation for
2440 * the frame happens later because it depends on what layers are visible to
2441 * render engine.
2442 *
2443 * The idea here is to only evaluate animation data associated with the scene,
2444 * which will make sure render layer settings are up-to-date, initialize the
2445 * render database itself and then perform full scene update with only needed
2446 * layers.
2447 * -sergey-
2448 */
2449 {
2450 float ctime = BKE_scene_ctime_get(scene);
2451 AnimData *adt = BKE_animdata_from_id(&scene->id);
2453 re->pipeline_depsgraph, ctime);
2454 BKE_animsys_evaluate_animdata(&scene->id, adt, &anim_eval_context, ADT_RECALC_ALL, false);
2455 }
2456
2458
2459 /* Only border now, TODO(ton): camera lens. */
2460 render_init_from_main(re, &rd, bmain, scene, single_layer, camera_override, true, false);
2461
2462 if (nfra != scene->r.cfra) {
2463 /* Skip this frame, but could update for physics and particles system. */
2464 continue;
2465 }
2466
2467 nfra += tfra;
2468
2469 /* Touch/NoOverwrite options are only valid for image's */
2470 if (is_movie == false && do_write_file) {
2471 path_templates::VariableMap template_variables;
2472 BKE_add_template_variables_general(template_variables, &scene->id);
2473 BKE_add_template_variables_for_render_path(template_variables, *scene);
2474
2476 filepath,
2477 rd.pic,
2479 &template_variables,
2480 scene->r.cfra,
2481 &image_format,
2482 (rd.scemode & R_EXTENSION) != 0,
2483 true,
2484 nullptr);
2485
2486 /* The filepath cannot be parsed, so we can't save the renders anywhere.
2487 * So we just cancel. */
2488 if (!errors.is_empty()) {
2490 /* We have to set the `is_break` flag here so that final cleanup code
2491 * recognizes that the render has failed. */
2492 G.is_break = true;
2493 break;
2494 }
2495
2496 if (rd.mode & R_NO_OVERWRITE) {
2497 if (!is_multiview_name) {
2498 if (BLI_exists(filepath)) {
2499 CLOG_INFO(&LOG, "Skipping existing frame \"%s\"", filepath);
2500 totskipped++;
2501 continue;
2502 }
2503 }
2504 else {
2505 bool is_skip = false;
2506 char filepath_view[FILE_MAX];
2507
2508 LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
2509 if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
2510 continue;
2511 }
2512
2513 BKE_scene_multiview_filepath_get(srv, filepath, filepath_view);
2514 if (BLI_exists(filepath_view)) {
2515 is_skip = true;
2516 CLOG_INFO(&LOG,
2517 "Skipping existing frame \"%s\" for view \"%s\"",
2518 filepath_view,
2519 srv->name);
2520 }
2521 }
2522
2523 if (is_skip) {
2524 totskipped++;
2525 continue;
2526 }
2527 }
2528 }
2529
2530 if (rd.mode & R_TOUCH) {
2531 if (!is_multiview_name) {
2532 touch_file(filepath);
2533 }
2534 else {
2535 char filepath_view[FILE_MAX];
2536
2537 LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
2538 if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
2539 continue;
2540 }
2541
2542 BKE_scene_multiview_filepath_get(srv, filepath, filepath_view);
2543
2544 touch_file(filepath);
2545 }
2546 }
2547 }
2548 }
2549
2550 re->r.cfra = scene->r.cfra; /* weak.... */
2551 re->r.subframe = scene->r.subframe;
2552
2553 /* run callbacks before rendering, before the scene is updated */
2555
2557 totrendered++;
2558
2559 const bool should_write = !(re->flag & R_SKIP_WRITE);
2560 if (re->display->test_break() == 0) {
2561 if (!G.is_break && should_write) {
2562 if (!do_write_image_or_movie(re, bmain, scene, totvideos, nullptr)) {
2563 G.is_break = true;
2564 }
2565 }
2566 }
2567 else {
2568 G.is_break = true;
2569 }
2570
2571 if (G.is_break == true) {
2572 /* remove touched file */
2573 if (is_movie == false && do_write_file) {
2574 if (rd.mode & R_TOUCH) {
2575 if (!is_multiview_name) {
2576 if (BLI_file_size(filepath) == 0) {
2577 /* BLI_exists(filepath) is implicit */
2578 BLI_delete(filepath, false, false);
2579 }
2580 }
2581 else {
2582 char filepath_view[FILE_MAX];
2583
2584 LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
2585 if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
2586 continue;
2587 }
2588
2589 BKE_scene_multiview_filepath_get(srv, filepath, filepath_view);
2590
2591 if (BLI_file_size(filepath_view) == 0) {
2592 /* BLI_exists(filepath_view) is implicit */
2593 BLI_delete(filepath_view, false, false);
2594 }
2595 }
2596 }
2597 }
2598 }
2599
2600 break;
2601 }
2602
2603 if (G.is_break == false) {
2604 /* keep after file save */
2606 if (should_write) {
2608 }
2609 }
2610 }
2611
2612 /* end movie */
2613 if (is_movie && do_write_file) {
2615 }
2616
2617 BKE_image_format_free(&image_format);
2618
2619 if (totskipped && totrendered == 0) {
2620 BKE_report(re->reports, RPT_INFO, "No frames rendered, skipped to not overwrite");
2621 }
2622
2623 scene->r.cfra = cfra_old;
2624 scene->r.subframe = subframe_old;
2625
2627 re->main,
2628 &scene->id,
2631
2633
2634 /* UGLY WARNING */
2635 G.is_rendering = false;
2636}
2637
2638void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
2639{
2640 /* Ensure within GPU render boundary. */
2641 const bool use_gpu = GPU_backend_get_type() != GPU_BACKEND_NONE;
2642 if (use_gpu) {
2644 }
2645
2646 Object *camera;
2647 int winx, winy;
2648
2649 BKE_render_resolution(&sce->r, false, &winx, &winy);
2650
2651 RE_InitState(re, nullptr, &sce->r, &sce->view_layers, nullptr, winx, winy, nullptr);
2652
2653 re->main = bmain;
2654 re->scene = sce;
2655
2656 camera = RE_GetCamera(re);
2657 RE_SetCamera(re, camera);
2658
2659 RE_engine_render(re, false);
2660
2661 /* No persistent data for preview render. */
2662 if (re->engine) {
2664 re->engine = nullptr;
2665 }
2666
2667 /* Close GPU render boundary. */
2668 if (use_gpu) {
2670 }
2671}
2672
2673/* NOTE: repeated win/disprect calc... solve that nicer, also in compo. */
2674
2675bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
2676{
2677 Render *re;
2678 int winx, winy;
2679 bool success;
2680 rcti disprect;
2681
2682 /* calculate actual render result and display size */
2683 BKE_render_resolution(&scene->r, false, &winx, &winy);
2684
2685 /* only in movie case we render smaller part */
2686 if (scene->r.mode & R_BORDER) {
2687 disprect.xmin = scene->r.border.xmin * winx;
2688 disprect.xmax = scene->r.border.xmax * winx;
2689
2690 disprect.ymin = scene->r.border.ymin * winy;
2691 disprect.ymax = scene->r.border.ymax * winy;
2692 }
2693 else {
2694 disprect.xmin = disprect.ymin = 0;
2695 disprect.xmax = winx;
2696 disprect.ymax = winy;
2697 }
2698
2699 if (scenode) {
2700 scene = scenode;
2701 }
2702
2703 /* get render: it can be called from UI with draw callbacks */
2704 re = RE_GetSceneRender(scene);
2705 if (re == nullptr) {
2706 re = RE_NewSceneRender(scene);
2707 }
2708 RE_InitState(re, nullptr, &scene->r, &scene->view_layers, nullptr, winx, winy, &disprect);
2709 re->scene = scene;
2710
2714
2716
2717 return success;
2718}
2719
2721 RenderLayer *layer, ReportList *reports, const char *filepath, int x, int y)
2722{
2723 /* First try loading multi-layer EXR. */
2724 if (render_result_exr_file_read_path(nullptr, layer, reports, filepath)) {
2725 return;
2726 }
2727
2728 /* OCIO_TODO: assume layer was saved in default color space */
2730 RenderPass *rpass = nullptr;
2731
2732 /* multi-view: since the API takes no 'view', we use the first combined pass found */
2733 for (rpass = static_cast<RenderPass *>(layer->passes.first); rpass; rpass = rpass->next) {
2734 if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
2735 break;
2736 }
2737 }
2738
2739 if (rpass == nullptr) {
2740 BKE_reportf(reports,
2741 RPT_ERROR,
2742 "%s: no Combined pass found in the render layer '%s'",
2743 __func__,
2744 filepath);
2745 }
2746
2747 if (ibuf && (ibuf->byte_buffer.data || ibuf->float_buffer.data)) {
2748 if (ibuf->x == layer->rectx && ibuf->y == layer->recty) {
2749 if (ibuf->float_buffer.data == nullptr) {
2750 IMB_float_from_byte(ibuf);
2751 }
2752
2753 memcpy(rpass->ibuf->float_buffer.data,
2754 ibuf->float_buffer.data,
2755 sizeof(float[4]) * layer->rectx * layer->recty);
2756 }
2757 else {
2758 if ((ibuf->x - x >= layer->rectx) && (ibuf->y - y >= layer->recty)) {
2759 ImBuf *ibuf_clip;
2760
2761 if (ibuf->float_buffer.data == nullptr) {
2762 IMB_float_from_byte(ibuf);
2763 }
2764
2765 ibuf_clip = IMB_allocImBuf(layer->rectx, layer->recty, 32, IB_float_data);
2766 if (ibuf_clip) {
2767 IMB_rectcpy(ibuf_clip, ibuf, 0, 0, x, y, layer->rectx, layer->recty);
2768
2769 memcpy(rpass->ibuf->float_buffer.data,
2770 ibuf_clip->float_buffer.data,
2771 sizeof(float[4]) * layer->rectx * layer->recty);
2772 IMB_freeImBuf(ibuf_clip);
2773 }
2774 else {
2776 reports, RPT_ERROR, "%s: failed to allocate clip buffer '%s'", __func__, filepath);
2777 }
2778 }
2779 else {
2780 BKE_reportf(reports,
2781 RPT_ERROR,
2782 "%s: incorrect dimensions for partial copy '%s'",
2783 __func__,
2784 filepath);
2785 }
2786 }
2787
2788 IMB_freeImBuf(ibuf);
2789 }
2790 else {
2791 BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filepath);
2792 }
2793}
2794
2795void RE_result_load_from_file(RenderResult *result, ReportList *reports, const char *filepath)
2796{
2797 if (!render_result_exr_file_read_path(result, nullptr, reports, filepath)) {
2798 BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filepath);
2799 return;
2800 }
2801}
2802
2804{
2805 switch (BLI_listbase_count_at_most(&result->layers, 2)) {
2806 case 0:
2807 return false;
2808 case 1:
2809 return (((RenderLayer *)result->layers.first)->name[0] != '\0');
2810 default:
2811 return true;
2812 }
2813}
2814
2816{
2817 LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) {
2818 if (!STREQ(rp->name, "Combined")) {
2819 return true;
2820 }
2821 }
2822
2823 return false;
2824}
2825
2826RenderPass *RE_pass_find_by_name(RenderLayer *rl, const char *name, const char *viewname)
2827{
2829 if (STREQ(rp->name, name)) {
2830 if (viewname == nullptr || viewname[0] == '\0') {
2831 return rp;
2832 }
2833 if (STREQ(rp->view, viewname)) {
2834 return rp;
2835 }
2836 }
2837 }
2838 return nullptr;
2839}
2840
2841RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const char *viewname)
2842{
2843 RenderLayer *rl = RE_GetRenderLayer(rr, layername);
2844 /* only create render layer if not exist */
2845 if (!rl) {
2846 rl = MEM_callocN<RenderLayer>(layername);
2847 BLI_addtail(&rr->layers, rl);
2848 STRNCPY(rl->name, layername);
2849 rl->layflag = SCE_LAY_SOLID;
2851 rl->rectx = rr->rectx;
2852 rl->recty = rr->recty;
2853 }
2854
2855 /* Clear previous pass if exist or the new image will be over previous one. */
2857 if (rp) {
2858 IMB_freeImBuf(rp->ibuf);
2859 BLI_freelinkN(&rl->passes, rp);
2860 }
2861 /* create a totally new pass */
2862 return render_layer_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, viewname, "RGBA", true);
2863}
2864
2866
2867/* -------------------------------------------------------------------- */
2870
2872{
2873 /* override not showing object when duplis are used with particles */
2874 if (ob->transflag & OB_DUPLIPARTS) {
2875 /* pass */ /* let particle system(s) handle showing vs. not showing */
2876 }
2877 else if (ob->transflag & OB_DUPLI) {
2878 return false;
2879 }
2880 return true;
2881}
2882
2884{
2885 re->r.threads = BKE_render_num_threads(&re->r);
2886}
2887
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:83
AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, float eval_time) ATTR_WARN_UNUSED_RESULT
Definition anim_sys.cc:738
@ 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, ImBuf *ibuf)
void BKE_image_format_free(ImageFormatData *imf)
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)
void BKE_image_format_init_for_write(ImageFormatData *imf, const Scene *scene_src, const ImageFormatData *imf_src, const bool allow_video=false)
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:887
#define CMP_NODE_CRYPTOMATTE
#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)
void BKE_add_template_variables_for_render_path(blender::bke::path_templates::VariableMap &variables, const Scene &scene)
void BKE_add_template_variables_general(blender::bke::path_templates::VariableMap &variables, const ID *path_owner_id)
void BKE_ptcache_bake(struct PTCacheBaker *baker)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2915
void BKE_scene_multiview_videos_dimensions_get(const RenderData *rd, const ImageFormatData *imf, size_t width, size_t height, size_t *r_width, size_t *r_height)
Definition scene.cc:3195
float BKE_scene_ctime_get(const Scene *scene)
Definition scene.cc:2370
int BKE_scene_multiview_num_views_get(const RenderData *rd)
Definition scene.cc:2940
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
Definition scene.cc:2988
const char * BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, int view_id)
Definition scene.cc:3154
int BKE_render_num_threads(const RenderData *r)
Definition scene.cc:2888
bool BKE_scene_camera_switch_update(Scene *scene)
Definition scene.cc:2265
Depsgraph * BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3416
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2384
int BKE_scene_multiview_num_videos_get(const RenderData *rd, const ImageFormatData *imf)
Definition scene.cc:3216
void BKE_scene_update_sound(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2511
void BKE_scene_multiview_filepath_get(const SceneRenderView *srv, const char *filepath, char *r_filepath)
Definition scene.cc:3108
int BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
Definition scene.cc:3082
void BKE_scene_ppm_get(const RenderData *rd, double r_ppm[2])
Definition scene.cc:3234
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:360
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:226
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
Definition fileops_c.cc:452
#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 * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
int bool bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
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:113
size_t BLI_timecode_string_from_time_simple(char *str, size_t maxncpy, double time_seconds) ATTR_NONNULL()
Definition timecode.cc:170
#define ELEM(...)
#define STREQ(a, b)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
#define CLOG_CHECK(clg_ref, verbose_level,...)
Definition CLG_log.h:147
@ CLG_LEVEL_INFO
Definition CLG_log.h:60
#define CLOG_STR_INFO(clg_ref, str)
Definition CLG_log.h:198
#define CLOG_INFO(clg_ref,...)
Definition CLG_log.h:190
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)
ID * DEG_get_original_id(ID *id)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_AUDIO_MUTE
Definition DNA_ID.h:1129
@ IMA_SRC_VIEWER
@ VIEW_LAYER_RENDER
@ CMP_NODE_CRYPTOMATTE_SOURCE_RENDER
@ NODE_DO_OUTPUT
Object is a sort of wrapper for general info.
@ OB_DUPLI
@ OB_DUPLIPARTS
#define R_STAMP_ALL
@ R_STAMP_DRAW
@ R_STAMP_STRIPMETA
#define RE_PASSNAME_COMBINED
#define STEREO_LEFT_NAME
@ SCE_LAY_SOLID
@ R_TOUCH
@ R_CROP
@ R_NO_OVERWRITE
@ R_EDGE_FRS
@ R_BORDER
@ R_IMF_CHAN_DEPTH_12
@ R_IMF_CHAN_DEPTH_10
@ R_IMF_VIEWS_STEREO_3D
@ R_IMF_VIEWS_INDIVIDUAL
#define STEREO_RIGHT_NAME
@ SCE_VIEWS_FORMAT_MULTIVIEW
@ SCE_COMPOSITOR_DEVICE_GPU
@ SCE_PASS_COMBINED
@ R_MULTIVIEW
@ R_SINGLE_LAYER
@ R_DOSEQ
@ R_EXR_CACHE_FILE
@ R_DOCOMP
@ R_EXTENSION
@ R_BUTS_PREVIEW
@ 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)
bool GPU_is_safe_texture_size(int width, int height)
void GPU_render_end()
void GPU_render_begin()
GPUBackendType GPU_backend_get_type()
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)
const char * IMB_colormanagement_get_rect_colorspace(const ImBuf *ibuf)
@ COLOR_ROLE_SCENE_LINEAR
ImBuf * IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, bool allocate_result, const ImageFormatData *image_format)
const char * IMB_colormanagement_role_colorspace_name_get(int role)
ImBuf * IMB_load_image_from_filepath(const char *filepath, const int flags, char r_colorspace[IM_MAX_SPACE]=nullptr)
Definition readimage.cc:189
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:444
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:62
@ WM_JOB_TYPE_COMPOSITE
Definition WM_api.hh:1777
@ WM_JOB_TYPE_RENDER
Definition WM_api.hh:1778
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(...)
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)
#define LOG(level)
Definition log.h:97
void(* MEM_reset_peak_memory)(void)
Definition mallocn.cc:72
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
#define G(x, y, z)
void MOV_write_end(MovieWriter *writer)
MovieWriter * MOV_write_begin(const Scene *scene, const RenderData *rd, const ImageFormatData *imf, int rectx, int recty, ReportList *reports, bool preview, const char *suffix)
bool MOV_write_append(MovieWriter *writer, const Scene *scene, const RenderData *rd, const ImageFormatData *imf, 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:2110
void cache_cleanup(Scene *scene)
void render_imbuf_from_sequencer_space(const Scene *scene, ImBuf *ibuf)
Definition render.cc:167
void relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
std::mutex Mutex
Definition BLI_mutex.hh:47
const char * name
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)
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)
RenderResult * render_result_new_from_exr(ExrHandle *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
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
Definition scene.cc:1580
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 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 bool node_tree_has_group_output(const bNodeTree *node_tree)
static void do_render_engine(Render *re)
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)
RenderResult * RE_MultilayerConvert(ExrHandle *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
void RE_test_break_cb(Render *re, void *handle, bool(*f)(void *handle))
static void get_videos_dimensions(const Render *re, const RenderData *rd, const ImageFormatData *imf, size_t *r_width, size_t *r_height)
void * RE_system_gpu_context_get(Render *re)
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)
static bool node_tree_has_file_output(const bNodeTree *node_tree)
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 void *owner)
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)
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)
static bool scene_has_compositor_output(Scene *scene)
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 render_result_uncrop(Render *re)
void RE_ReferenceRenderResult(RenderResult *rr)
void RE_display_free(Render *re)
Render * RE_NewSceneRender(const Scene *scene)
Scene * RE_GetScene(Render *re)
static bool is_compositing_possible_on_gpu(Scene *scene, ReportList *reports)
void RE_display_ensure_gpu_context(Render *re)
blender::Map< const void *, Render * > interactive_compositor_renders
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_display_init(Render *re)
void RE_ReleaseResult(Render *re)
static struct @370044371030232304352252035216052377043321026353 RenderGlobal
const char * RE_GetActiveRenderView(Render *re)
static void touch_file(const char *filepath)
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)
bool RE_ResultIsMultiView(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))
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)
void RE_display_share(Render *re, const Render *parent_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)
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)
Render * RE_GetRender(const void *owner)
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 void re_gpu_texture_caches_free(Render *re)
bool display_shared
struct RenderEngine * engine
ThreadRWMutex resultmutex
std::shared_ptr< RenderDisplay > display
RenderResult * result
ListBase seqbase
ListBase channels
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
unsigned char planes
short source
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
void * system_gpu_context
void * ensure_blender_gpu_context()
ListBase passes
Definition RE_pipeline.h:94
char name[RE_MAXNAME]
Definition RE_pipeline.h:89
struct ImBuf * ibuf
Definition RE_pipeline.h:67
char name[64]
Definition RE_pipeline.h:55
struct RenderPass * next
Definition RE_pipeline.h:53
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:49
char name[64]
Definition RE_pipeline.h:42
Scene * pipeline_scene_eval
bool(* prepare_viewlayer_cb)(void *handle, struct ViewLayer *vl, struct Depsgraph *depsgraph)
bool result_has_gpu_texture_caches
RenderResult * pushedresult
RenderData r
blender::render::Compositor * compositor
struct Main * main
const void * owner
Scene * scene
struct Depsgraph * pipeline_depsgraph
void * prepare_vl_handle
short flag
char single_view_layer[MAX_NAME]
char viewname[MAX_NAME]
RenderStats i
struct ReportList * reports
rcti disprect
struct Object * camera_override
blender::Vector< MovieWriter * > movie_writers
ColorManagedViewSettings view_settings
struct Editing * ed
struct bNodeTree * compositing_node_group
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
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:247
Scene * WM_window_get_active_scene(const wmWindow *win)
bScreen * WM_window_get_active_screen(const wmWindow *win)