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