Blender V5.0
intern/engine.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2006 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstddef>
10#include <cstdlib>
11#include <cstring>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_listbase.h"
16#include "BLI_math_bits.h"
17#include "BLI_string.h"
18#include "BLI_utildefines.h"
19
20#include "DNA_object_types.h"
21
22#include "BKE_camera.h"
23#include "BKE_global.hh"
24#include "BKE_node.hh"
25#include "BKE_report.hh"
26#include "BKE_scene.hh"
27
28#include "DEG_depsgraph.hh"
31
32#include "GPU_context.hh"
33
34#ifdef WITH_PYTHON
35# include "BPY_extern.hh"
36#endif
37
38#include "IMB_imbuf_types.hh"
39
40#include "RE_bake.h"
41#include "RE_engine.h"
42#include "RE_pipeline.h"
43
44#include "DRW_engine.hh"
45
46#include "WM_api.hh"
47
48#include "CLG_log.h"
49
50#include "pipeline.hh"
51#include "render_result.h"
52#include "render_types.h"
53
54/* Render Engine Types */
55
56ListBase R_engines = {nullptr, nullptr};
57
58static CLG_LogRef LOG = {"render"};
59
65
67{
68 RenderEngineType *type, *next;
69
71 /* Clean resources if the DRW context exists.
72 * We need a context bound even when dealing with non context dependent GPU resources,
73 * since GL functions may be null otherwise (See #141233). */
77 }
78
79 for (type = static_cast<RenderEngineType *>(R_engines.first); type; type = next) {
80 next = type->next;
81
82 BLI_remlink(&R_engines, type);
83
84 if (!(type->flag & RE_INTERNAL)) {
85 if (type->rna_ext.free) {
86 type->rna_ext.free(type->rna_ext.data);
87 }
88
89 MEM_freeN(type);
90 }
91 }
92}
93
95{
96 BLI_addtail(&R_engines, render_type);
97}
98
100{
101 RenderEngineType *type = static_cast<RenderEngineType *>(
103 if (!type) {
104 type = static_cast<RenderEngineType *>(
105 BLI_findstring(&R_engines, "BLENDER_EEVEE", offsetof(RenderEngineType, idname)));
106 }
107
108 return type;
109}
110
112{
113 return (re->engine && re->engine->type && re->engine->type->render);
114}
115
116/* Create, Free */
117
119{
120 RenderEngine *engine = MEM_callocN<RenderEngine>("RenderEngine");
121 engine->type = type;
122
125
126 return engine;
127}
128
130{
131 if (engine->depsgraph) {
132 /* Need GPU context since this might free GPU buffers. */
133 const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT);
134 if (use_gpu_context) {
135 /* This function can be called on the main thread before RenderEngine is destroyed.
136 * In this case, just bind the main draw context to gather the deleted GPU buffers.
137 * Binding the same GPU context as the render engine is not needed (see #129019). */
138 if (BLI_thread_is_main()) {
140 }
141 else {
143 }
144 }
145
146 DEG_graph_free(engine->depsgraph);
147 engine->depsgraph = nullptr;
148
149 if (use_gpu_context) {
150 if (BLI_thread_is_main()) {
152 }
153 else {
155 }
156 }
157 }
158}
159
161{
162#ifdef WITH_PYTHON
163 if (engine->py_instance) {
165 }
166#endif
167
168 engine_depsgraph_free(engine);
169
172
173 MEM_freeN(engine);
174}
175
176/* Bake Render Results */
177
179 RenderEngine *engine, int x, int y, int w, int h, const char *layername)
180{
181 BakeImage *image = &engine->bake.targets->images[engine->bake.image_id];
182 const BakePixel *pixels = engine->bake.pixels + image->offset;
183 const size_t channels_num = engine->bake.targets->channels_num;
184
185 /* Remember layer name for to match images in render_frame_finish. */
186 if (image->render_layer_name[0] == '\0') {
187 STRNCPY(image->render_layer_name, layername);
188 }
189
190 /* Create render result with specified size. */
192
193 rr->rectx = w;
194 rr->recty = h;
195 rr->tilerect.xmin = x;
196 rr->tilerect.ymin = y;
197 rr->tilerect.xmax = x + w;
198 rr->tilerect.ymax = y + h;
199
200 BKE_scene_ppm_get(&engine->re->r, rr->ppm);
201
202 /* Add single baking render layer. */
203 RenderLayer *rl = MEM_callocN<RenderLayer>("bake render layer");
204 STRNCPY(rl->name, layername);
205 rl->rectx = w;
206 rl->recty = h;
207 BLI_addtail(&rr->layers, rl);
208
209 /* Add render passes. */
210 render_layer_add_pass(rr, rl, channels_num, RE_PASSNAME_COMBINED, "", "RGBA", true);
211
212 RenderPass *primitive_pass = render_layer_add_pass(rr, rl, 3, "BakePrimitive", "", "RGB", true);
213 RenderPass *differential_pass = render_layer_add_pass(
214 rr, rl, 4, "BakeDifferential", "", "RGBA", true);
215
216 /* Per-pixel seeds are only needed for baking to vertex colors, see
217 * bake_targets_populate_pixels_color_attributes for more details. */
218 RenderPass *seed_pass = (image->image == nullptr) ?
219 render_layer_add_pass(rr, rl, 1, "BakeSeed", "", "X", true) :
220 nullptr;
221
222 /* Fill render passes from bake pixel array, to be read by the render engine. */
223 for (int ty = 0; ty < h; ty++) {
224 size_t offset = ty * w;
225 float *primitive = primitive_pass->ibuf->float_buffer.data + 3 * offset;
226 float *seed = (seed_pass != nullptr) ? (seed_pass->ibuf->float_buffer.data + offset) : nullptr;
227 float *differential = differential_pass->ibuf->float_buffer.data + 4 * offset;
228
229 size_t bake_offset = (y + ty) * image->width + x;
230 const BakePixel *bake_pixel = pixels + bake_offset;
231
232 for (int tx = 0; tx < w; tx++) {
233 if (bake_pixel->object_id != engine->bake.object_id) {
234 primitive[0] = int_as_float(-1);
235 primitive[1] = int_as_float(-1);
236 primitive[2] = int_as_float(-1);
237 }
238 else {
239 primitive[0] = bake_pixel->uv[0];
240 primitive[1] = bake_pixel->uv[1];
241 primitive[2] = int_as_float(bake_pixel->primitive_id);
242
243 differential[0] = bake_pixel->du_dx;
244 differential[1] = bake_pixel->du_dy;
245 differential[2] = bake_pixel->dv_dx;
246 differential[3] = bake_pixel->dv_dy;
247 }
248
249 if (seed_pass != nullptr) {
250 *seed = int_as_float(bake_pixel->seed);
251 seed += 1;
252 }
253
254 primitive += 3;
255 differential += 4;
256 bake_pixel++;
257 }
258 }
259
260 return rr;
261}
262
264{
265 RenderLayer *rl = static_cast<RenderLayer *>(rr->layers.first);
267 if (!rpass) {
268 return;
269 }
270
271 /* Find bake image corresponding to layer. */
272 int image_id = 0;
273 for (; image_id < engine->bake.targets->images_num; image_id++) {
274 if (STREQ(engine->bake.targets->images[image_id].render_layer_name, rl->name)) {
275 break;
276 }
277 }
278 if (image_id == engine->bake.targets->images_num) {
279 return;
280 }
281
282 const BakeImage *image = &engine->bake.targets->images[image_id];
283 const BakePixel *pixels = engine->bake.pixels + image->offset;
284 const size_t channels_num = engine->bake.targets->channels_num;
285 const size_t channels_size = channels_num * sizeof(float);
286 float *result = engine->bake.result + image->offset * channels_num;
287
288 /* Copy from tile render result to full image bake result. Just the pixels for the
289 * object currently being baked, to preserve other objects when baking multiple. */
290 const int x = rr->tilerect.xmin;
291 const int y = rr->tilerect.ymin;
292 const int w = rr->tilerect.xmax - rr->tilerect.xmin;
293 const int h = rr->tilerect.ymax - rr->tilerect.ymin;
294
295 for (int ty = 0; ty < h; ty++) {
296 const size_t offset = ty * w;
297 const size_t bake_offset = (y + ty) * image->width + x;
298
299 const float *pass_rect = rpass->ibuf->float_buffer.data + offset * channels_num;
300 const BakePixel *bake_pixel = pixels + bake_offset;
301 float *bake_result = result + bake_offset * channels_num;
302
303 for (int tx = 0; tx < w; tx++) {
304 if (bake_pixel->object_id == engine->bake.object_id) {
305 memcpy(bake_result, pass_rect, channels_size);
306 }
307 pass_rect += channels_num;
308 bake_result += channels_num;
309 bake_pixel++;
310 }
311 }
312}
313
314/* Render Results */
315
317 RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname)
318{
319 if (engine->bake.targets) {
320 RenderResult *result = render_result_from_bake(engine, x, y, w, h, layername);
321 BLI_addtail(&engine->fullresult, result);
322 return result;
323 }
324
325 Render *re = engine->re;
327 rcti disprect;
328
329 /* ensure the coordinates are within the right limits */
330 CLAMP(x, 0, re->result->rectx);
331 CLAMP(y, 0, re->result->recty);
332 CLAMP(w, 0, re->result->rectx);
333 CLAMP(h, 0, re->result->recty);
334
335 if (x + w > re->result->rectx) {
336 w = re->result->rectx - x;
337 }
338 if (y + h > re->result->recty) {
339 h = re->result->recty - y;
340 }
341
342 /* allocate a render result */
343 disprect.xmin = x;
344 disprect.xmax = x + w;
345 disprect.ymin = y;
346 disprect.ymax = y + h;
347
348 result = render_result_new(re, &disprect, layername, viewname);
349
350 /* TODO: make this thread safe. */
351
352 /* can be nullptr if we CLAMP the width or height to 0 */
353 if (result) {
354 render_result_clone_passes(re, result, viewname);
356
357 BLI_addtail(&engine->fullresult, result);
358
359 result->tilerect.xmin += re->disprect.xmin;
360 result->tilerect.xmax += re->disprect.xmin;
361 result->tilerect.ymin += re->disprect.ymin;
362 result->tilerect.ymax += re->disprect.ymin;
363 }
364
365 return result;
366}
367
378
380{
381 if (engine->bake.targets) {
382 /* No interactive baking updates for now. */
383 return;
384 }
385
386 Render *re = engine->re;
387
388 if (result) {
391 result->renlay = static_cast<RenderLayer *>(
392 result->layers.first); /* weak, draws first layer always */
393 re->display->display_update(result, nullptr);
394 }
395}
396
398 const char *name,
399 int channels,
400 const char *chan_id,
401 const char *layername)
402{
403 Render *re = engine->re;
404
405 if (!re || !re->result) {
406 return;
407 }
408
409 RE_create_render_pass(re->result, name, channels, chan_id, layername, nullptr, false);
410}
411
413 RenderEngine *engine, RenderResult *result, bool cancel, bool highlight, bool merge_results)
414{
415 Render *re = engine->re;
416
417 if (!result) {
418 return;
419 }
420
421 if (engine->bake.targets) {
422 if (!cancel || merge_results) {
424 }
425 BLI_remlink(&engine->fullresult, result);
427 return;
428 }
429
430 if (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES)) {
432
433 if (tile_highlight) {
434 if (highlight) {
435 tile_highlight->highlight_tile_for_result(result);
436 }
437 else {
438 tile_highlight->unhighlight_tile_for_result(result);
439 }
440 }
441 }
442
443 if (!cancel || merge_results) {
444 if (!(re->display->test_break() && (re->r.scemode & R_BUTS_PREVIEW))) {
447 }
448
449 /* draw */
450 if (!re->display->test_break()) {
451 result->renlay = static_cast<RenderLayer *>(
452 result->layers.first); /* weak, draws first layer always */
453 re->display->display_update(result, nullptr);
454 }
455 }
456
457 /* free */
458 BLI_remlink(&engine->fullresult, result);
460}
461
463{
464 return engine->re->result;
465}
466
467/* Cancel */
468
470{
471 Render *re = engine->re;
472
473 if (re) {
474 return re->display->test_break();
475 }
476
477 return false;
478}
479
480/* Statistics */
481
482void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info)
483{
484 Render *re = engine->re;
485
486 /* stats draw callback */
487 if (re) {
488 re->i.statstr = stats;
489 re->i.infostr = info;
490 re->display->stats_draw(&re->i);
491 re->i.infostr = nullptr;
492 re->i.statstr = nullptr;
493 }
494
495 /* set engine text */
496 engine->text[0] = '\0';
497
498 if (stats && stats[0] && info && info[0]) {
499 SNPRINTF(engine->text, "%s | %s", stats, info);
500 }
501 else if (info && info[0]) {
502 STRNCPY(engine->text, info);
503 }
504 else if (stats && stats[0]) {
505 STRNCPY(engine->text, stats);
506 }
507}
508
509void RE_engine_update_progress(RenderEngine *engine, float progress)
510{
511 Render *re = engine->re;
512
513 if (re) {
514 CLAMP(progress, 0.0f, 1.0f);
515 re->display->progress(progress);
516 }
517}
518
519void RE_engine_update_memory_stats(RenderEngine *engine, float mem_used, float mem_peak)
520{
521 Render *re = engine->re;
522
523 if (re) {
524 re->i.mem_used = int(ceilf(mem_used));
525 re->i.mem_peak = int(ceilf(mem_peak));
526 }
527}
528
529void RE_engine_report(RenderEngine *engine, int type, const char *msg)
530{
531 Render *re = engine->re;
532
533 if (re) {
534 BKE_report(engine->re->reports, (eReportType)type, msg);
535 }
536 else if (engine->reports) {
537 BKE_report(engine->reports, (eReportType)type, msg);
538 }
539}
540
541void RE_engine_set_error_message(RenderEngine *engine, const char *msg)
542{
543 Render *re = engine->re;
544 if (re != nullptr) {
546 if (rr) {
547 if (rr->error != nullptr) {
548 MEM_freeN(rr->error);
549 }
550 rr->error = BLI_strdup(msg);
551 }
553 }
554}
555
556RenderPass *RE_engine_pass_by_index_get(RenderEngine *engine, const char *layer_name, int index)
557{
558 Render *re = engine->re;
559 if (re == nullptr) {
560 return nullptr;
561 }
562
563 RenderPass *pass = nullptr;
564
566 if (rr != nullptr) {
567 const RenderLayer *layer = RE_GetRenderLayer(rr, layer_name);
568 if (layer != nullptr) {
569 pass = static_cast<RenderPass *>(BLI_findlink(&layer->passes, index));
570 }
571 }
573
574 return pass;
575}
576
578{
579 Render *re = engine->re;
580 return RE_GetActiveRenderView(re);
581}
582
583void RE_engine_active_view_set(RenderEngine *engine, const char *viewname)
584{
585 Render *re = engine->re;
586 RE_SetActiveRenderView(re, viewname);
587}
588
589float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera, bool use_spherical_stereo)
590{
591 /* When using spherical stereo, get camera shift without multiview,
592 * leaving stereo to be handled by the engine. */
593 Render *re = engine->re;
594 if (use_spherical_stereo || re == nullptr) {
595 return BKE_camera_multiview_shift_x(nullptr, camera, nullptr);
596 }
597
598 return BKE_camera_multiview_shift_x(&re->r, camera, re->viewname);
599}
600
602 Object *camera,
603 bool use_spherical_stereo,
604 float r_modelmat[16])
605{
606 /* When using spherical stereo, get model matrix without multiview,
607 * leaving stereo to be handled by the engine. */
608 Render *re = engine->re;
609 if (use_spherical_stereo || re == nullptr) {
610 BKE_camera_multiview_model_matrix(nullptr, camera, nullptr, (float (*)[4])r_modelmat);
611 }
612 else {
613 BKE_camera_multiview_model_matrix(&re->r, camera, re->viewname, (float (*)[4])r_modelmat);
614 }
615}
616
618{
619 Render *re = engine->re;
620 return BKE_camera_multiview_spherical_stereo(re ? &re->r : nullptr, camera) ? true : false;
621}
622
623const rcti *RE_engine_get_current_tiles(Render *re, int *r_total_tiles)
624{
626 if (!tiles_highlight) {
627 *r_total_tiles = 0;
628 return nullptr;
629 };
630
631 blender::Span<rcti> highlighted_tiles = tiles_highlight->get_all_highlighted_tiles();
632
633 *r_total_tiles = highlighted_tiles.size();
634 return highlighted_tiles.data();
635}
636
638{
639 return &re->r;
640}
641
643{
644 /* Re-rendering is not supported with GPU contexts, since the GPU context
645 * is destroyed when the render thread exists. */
646 return (engine->re->r.mode & R_PERSISTENT_DATA) && !(engine->type->flag & RE_USE_GPU_CONTEXT);
647}
648
650{
651 /* For persistent data or GPU engines like Eevee, reuse the depsgraph between
652 * view layers and animation frames. For renderers like Cycles that create
653 * their own copy of the scene, persistent data must be explicitly enabled to
654 * keep memory usage low by default. */
655 return (engine->re->r.mode & R_PERSISTENT_DATA) || (engine->type->flag & RE_USE_GPU_CONTEXT);
656}
657
658/* Depsgraph */
659static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer)
660{
661 Main *bmain = engine->re->main;
662 Scene *scene = engine->re->scene;
663 bool reuse_depsgraph = false;
664
665 /* Reuse depsgraph from persistent data if possible. */
666 if (engine->depsgraph) {
667 if (DEG_get_bmain(engine->depsgraph) != bmain ||
668 DEG_get_input_scene(engine->depsgraph) != scene)
669 {
670 /* If bmain or scene changes, we need a completely new graph. */
671 engine_depsgraph_free(engine);
672 }
673 else if (DEG_get_input_view_layer(engine->depsgraph) != view_layer) {
674 /* If only view layer changed, reuse depsgraph in the hope of reusing
675 * objects shared between view layers. */
676 DEG_graph_replace_owners(engine->depsgraph, bmain, scene, view_layer);
678 }
679
680 reuse_depsgraph = true;
681 }
682
683 if (!engine->depsgraph) {
684 /* Ensure we only use persistent data for one scene / view layer at a time,
685 * to avoid excessive memory usage. */
686 RE_FreePersistentData(nullptr);
687
688 /* Create new depsgraph if not cached with persistent data. */
689 engine->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
690 DEG_debug_name_set(engine->depsgraph, "RENDER");
691 }
692
693 if (engine->re->r.scemode & R_BUTS_PREVIEW) {
694 /* Update for preview render. */
695 Depsgraph *depsgraph = engine->depsgraph;
697
698 /* Need GPU context since this might free GPU buffers. */
699 const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT) && reuse_depsgraph;
700 if (use_gpu_context) {
702 }
703
705
706 if (use_gpu_context) {
708 }
709 }
710 else {
711 /* Go through update with full Python callbacks for regular render. */
713 }
714
716}
717
719{
720 if (engine->depsgraph) {
721 if (engine_keep_depsgraph(engine)) {
722 /* Clear recalc flags since the engine should have handled the updates for the currently
723 * rendered framed by now. */
724 DEG_ids_clear_recalc(engine->depsgraph, false);
725 }
726 else {
727 /* Free immediately to save memory. */
728 engine_depsgraph_free(engine);
729 }
730 }
731}
732
733void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
734{
735 if (!engine->depsgraph) {
736 return;
737 }
738
739 /* Clear recalc flags before update so engine can detect what changed. */
740 DEG_ids_clear_recalc(engine->depsgraph, false);
741
742 Render *re = engine->re;
743 double cfra = double(frame) + double(subframe);
744
745 CLAMP(cfra, MINAFRAME, MAXFRAME);
746 BKE_scene_frame_set(re->scene, cfra);
748
750}
751
752/* Bake */
753
755{
756 re->scene = scene;
757 re->main = bmain;
758 render_copy_renderdata(&re->r, &scene->r);
759}
760
762{
763 const RenderEngineType *type = RE_engines_find(re->r.engine);
764 return (type->bake != nullptr);
765}
766
768 Depsgraph *depsgraph,
769 Object *object,
770 const int object_id,
771 const BakePixel pixel_array[],
772 const BakeTargets *targets,
773 const eScenePassType pass_type,
774 const int pass_filter,
775 float result[])
776{
778 RenderEngine *engine;
779
780 /* set render info */
781 re->i.cfra = re->scene->r.cfra;
782 STRNCPY(re->i.scene_name, re->scene->id.name + 2);
783
784 /* render */
785 engine = re->engine;
786
787 if (!engine) {
788 engine = RE_engine_create(type);
789 re->engine = engine;
790 }
791
792 engine->flag |= RE_ENGINE_RENDERING;
793
794 /* TODO: actually link to a parent which shouldn't happen */
795 engine->re = re;
796
797 engine->resolution_x = re->winx;
798 engine->resolution_y = re->winy;
799
800 if (type->bake) {
801 engine->depsgraph = depsgraph;
802
803 /* update is only called so we create the engine.session */
804 if (type->update) {
805 type->update(engine, re->main, engine->depsgraph);
806 }
807
808 /* Bake all images. */
809 engine->bake.targets = targets;
810 engine->bake.pixels = pixel_array;
811 engine->bake.result = result;
812 engine->bake.object_id = object_id;
813
814 for (int i = 0; i < targets->images_num; i++) {
815 const BakeImage *image = &targets->images[i];
816 engine->bake.image_id = i;
817
818 type->bake(
819 engine, engine->depsgraph, object, pass_type, pass_filter, image->width, image->height);
820 }
821
822 /* Optionally let render images read bake images from disk delayed. */
823 if (type->render_frame_finish) {
824 engine->bake.image_id = 0;
825 type->render_frame_finish(engine);
826 }
827
828 memset(&engine->bake, 0, sizeof(engine->bake));
829
830 engine->depsgraph = nullptr;
831 }
832
833 engine->flag &= ~RE_ENGINE_RENDERING;
834
835 engine_depsgraph_free(engine);
836
837 RE_engine_free(engine);
838 re->engine = nullptr;
839
841 G.is_break = true;
842 }
843
844 return true;
845}
846
847/* Render */
848
850{
852 return false;
853 }
854
855 const Scene *scene = re->pipeline_scene_eval;
856 return (scene->compositing_node_group && (scene->r.scemode & R_DOCOMP));
857}
858
860 RenderEngine *engine,
861 ViewLayer *view_layer_iter,
862 const bool use_engine,
863 const bool use_grease_pencil)
864{
865 /* Lock UI so scene can't be edited while we read from it in this render thread. */
866 re->display->draw_lock();
867
868 /* Create depsgraph with scene evaluated at render resolution. */
869 ViewLayer *view_layer = static_cast<ViewLayer *>(
870 BLI_findstring(&re->scene->view_layers, view_layer_iter->name, offsetof(ViewLayer, name)));
871 if (!re->prepare_viewlayer(view_layer, engine->depsgraph)) {
872 re->display->draw_unlock();
873 return;
874 }
875 engine_depsgraph_init(engine, view_layer);
876
877 /* Sync data to engine, within draw lock so scene data can be accessed safely. */
878 if (use_engine) {
879 const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT);
880 if (use_gpu_context) {
882 }
883 else if (G.background && ((engine->has_grease_pencil && use_grease_pencil) ||
885 {
886 /* Workaround for specific NVidia drivers which crash on Linux when OptiX context is
887 * initialized prior to OpenGL context. This affects driver versions 545.29.06, 550.54.14,
888 * and 550.67 running on kernel 6.8.
889 *
890 * The idea here is to initialize GPU context before giving control to the render engine in
891 * cases when we know that the GPU context will definitely be needed later on.
892 *
893 * Only do it for background renders to avoid possible extra global locking during the
894 * context initialization. For the non-background renders the GPU context is already
895 * initialized for the Blender interface and no workaround is needed.
896 *
897 * Technically it is enough to only call WM_init_gpu() here, but it expects to only be called
898 * once, and from here it is not possible to know whether GPU sub-system is initialized or
899 * not. So instead temporarily enable the render context, which will take care of the GPU
900 * context initialization.
901 *
902 * For demo file and tracking progress of possible fixes on driver side refer to #120007. */
905 }
906
907 if (engine->type->update) {
908 engine->type->update(engine, re->main, engine->depsgraph);
909 }
910 if (use_gpu_context) {
912 }
913 }
914
915 re->display->draw_unlock();
916
917 /* Perform render with engine. */
918 if (use_engine) {
919 const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT);
920 if (use_gpu_context) {
922 }
923
927
928 engine->type->render(engine, engine->depsgraph);
929
933
934 if (use_gpu_context) {
936 }
937 }
938
939 /* Optionally composite grease pencil over render result.
940 * Only do it if the passes are allocated (and the engine will not override the grease pencil
941 * when reading its result from EXR file and writing to the Blender side. */
942 if (engine->has_grease_pencil && use_grease_pencil && re->result->passes_allocated) {
943 /* NOTE: External engine might have been requested to free its
944 * dependency graph, which is only allowed if there is no grease
945 * pencil (pipeline is taking care of that). */
946 if (!RE_engine_test_break(engine) && engine->depsgraph != nullptr) {
947 CLOG_INFO(&LOG, "Rendering grease pencil");
948 DRW_render_gpencil(engine, engine->depsgraph);
949 }
950 }
951
952 /* Free dependency graph, if engine has not done it already. */
953 engine_depsgraph_exit(engine);
954}
955
956/* Callback function for engine_render_create_result to add all render passes to the result. */
957static void engine_render_add_result_pass_cb(void *user_data,
958 Scene * /*scene*/,
959 ViewLayer *view_layer,
960 const char *name,
961 int channels,
962 const char *chanid,
963 eNodeSocketDatatype /*type*/)
964{
965 RenderResult *rr = (RenderResult *)user_data;
966 RE_create_render_pass(rr, name, channels, chanid, view_layer->name, RR_ALL_VIEWS, false);
967}
968
970{
972 if (rr == nullptr) {
973 return nullptr;
974 }
975
976 FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer) {
978 re->engine, re->scene, view_layer, engine_render_add_result_pass_cb, rr);
979 }
981
982 /* Preview does not support deferred render result allocation. */
983 if (re->r.scemode & R_BUTS_PREVIEW) {
985 }
986
987 return rr;
988}
989
990bool RE_engine_render(Render *re, bool do_all)
991{
993
994 /* verify if we can render */
995 if (!type->render) {
996 return false;
997 }
998 if ((re->r.scemode & R_BUTS_PREVIEW) && !(type->flag & RE_USE_PREVIEW)) {
999 return false;
1000 }
1001 if (do_all && !(type->flag & RE_USE_POSTPROCESS)) {
1002 return false;
1003 }
1004 if (!do_all && (type->flag & RE_USE_POSTPROCESS)) {
1005 return false;
1006 }
1007
1008 /* Lock drawing in UI during data phase. */
1009 re->display->draw_lock();
1010
1011 if ((type->flag & RE_USE_GPU_CONTEXT) && !GPU_backend_supported()) {
1012 /* Clear UI drawing locks. */
1013 re->display->draw_unlock();
1014 BKE_report(re->reports, RPT_ERROR, "Cannot initialize the GPU");
1015 G.is_break = true;
1016 return true;
1017 }
1018
1019 /* Create engine. */
1020 RenderEngine *engine = re->engine;
1021
1022 if (!engine) {
1023 engine = RE_engine_create(type);
1024 re->engine = engine;
1025 }
1026
1027 /* Create render result. Do this before acquiring lock, to avoid lock
1028 * inversion as this calls python to get the render passes, while python UI
1029 * code can also hold a lock on the render result. */
1030 const bool create_new_result = (re->result == nullptr || !(re->r.scemode & R_BUTS_PREVIEW));
1031 RenderResult *new_result = (create_new_result) ? engine_render_create_result(re) : nullptr;
1032
1034 if (create_new_result) {
1035 if (re->result) {
1037 }
1038
1039 re->result = new_result;
1040 }
1042
1043 if (re->result == nullptr) {
1044 /* Clear UI drawing locks. */
1045 re->display->draw_unlock();
1046 /* Free engine. */
1047 RE_engine_free(engine);
1048 re->engine = nullptr;
1049 /* Too small image is handled earlier, here it could only happen if
1050 * there was no sufficient memory to allocate all passes.
1051 */
1052 BKE_report(re->reports, RPT_ERROR, "Failed allocate render result, out of memory");
1053 G.is_break = true;
1054 return true;
1055 }
1056
1057 /* set render info */
1058 re->i.cfra = re->scene->r.cfra;
1059 STRNCPY(re->i.scene_name, re->scene->id.name + 2);
1060
1061 engine->flag |= RE_ENGINE_RENDERING;
1062
1063 /* TODO: actually link to a parent which shouldn't happen */
1064 engine->re = re;
1065
1066 if (re->flag & R_ANIMATION) {
1067 engine->flag |= RE_ENGINE_ANIMATION;
1068 }
1069 if (re->r.scemode & R_BUTS_PREVIEW) {
1070 engine->flag |= RE_ENGINE_PREVIEW;
1071 }
1072 engine->camera_override = re->camera_override;
1073
1074 engine->resolution_x = re->winx;
1075 engine->resolution_y = re->winy;
1076
1077 /* Clear UI drawing locks. */
1078 re->display->draw_unlock();
1079
1080 /* Render view layers. */
1081 bool delay_grease_pencil = false;
1082
1083 if (type->render) {
1084 FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer_iter) {
1085 CLOG_INFO(&LOG, "Start rendering: %s, %s", re->scene->id.name + 2, view_layer_iter->name);
1086 CLOG_INFO(&LOG, "Engine: %s", engine->type->name);
1087 const bool use_grease_pencil = (view_layer_iter->layflag & SCE_LAY_GREASE_PENCIL) != 0;
1088 engine_render_view_layer(re, engine, view_layer_iter, true, use_grease_pencil);
1089
1090 /* If render passes are not allocated the render engine deferred final pixels write for
1091 * later. Need to defer the grease pencil for until after the engine has written the
1092 * render result to Blender. */
1093 delay_grease_pencil = use_grease_pencil && engine->has_grease_pencil &&
1095
1096 if (RE_engine_test_break(engine)) {
1097 break;
1098 }
1099 }
1101 }
1102
1103 if (type->render_frame_finish) {
1104 type->render_frame_finish(engine);
1105 }
1106
1107 /* Perform delayed grease pencil rendering. */
1108 if (delay_grease_pencil) {
1109 FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer_iter) {
1110 const bool use_grease_pencil = (view_layer_iter->layflag & SCE_LAY_GREASE_PENCIL) != 0;
1111 if (!use_grease_pencil) {
1112 continue;
1113 }
1114 engine_render_view_layer(re, engine, view_layer_iter, false, true);
1115 if (RE_engine_test_break(engine)) {
1116 break;
1117 }
1118 }
1120 }
1121
1122 /* Clear tile data */
1123 engine->flag &= ~RE_ENGINE_RENDERING;
1124
1126 static_cast<RenderResult *>(engine->fullresult.first));
1127
1128 /* re->engine becomes zero if user changed active render engine during render */
1129 if (!engine_keep_depsgraph(engine) || !re->engine) {
1130 engine_depsgraph_free(engine);
1131
1132 RE_engine_free(engine);
1133 re->engine = nullptr;
1134 }
1135
1136 if (re->r.scemode & R_EXR_CACHE_FILE) {
1140 }
1141
1143 G.is_break = true;
1144 }
1145
1146#ifdef WITH_FREESTYLE
1147 if (re->r.mode & R_EDGE_FRS) {
1148 CLOG_INFO(&LOG, "Rendering freestyle");
1149 RE_RenderFreestyleExternal(re);
1150 }
1151#endif
1152
1153 return true;
1154}
1155
1157 Scene *scene,
1158 ViewLayer *view_layer,
1160 void *callback_data)
1161{
1162 if (!(scene && view_layer && engine && callback && engine->type->update_render_passes)) {
1163 return;
1164 }
1165
1167
1168 engine->update_render_passes_cb = callback;
1169 engine->update_render_passes_data = callback_data;
1170 engine->type->update_render_passes(engine, scene, view_layer);
1171 engine->update_render_passes_cb = nullptr;
1172 engine->update_render_passes_data = nullptr;
1173
1175}
1176
1178 Scene *scene,
1179 ViewLayer *view_layer,
1180 const char *name,
1181 int channels,
1182 const char *chanid,
1184{
1185 if (!(scene && view_layer && engine && engine->update_render_passes_cb)) {
1186 return;
1187 }
1188
1190 engine->update_render_passes_data, scene, view_layer, name, channels, chanid, type);
1191}
1192
1194{
1195 /* Weak way to save memory, but not crash grease pencil.
1196 *
1197 * TODO(sergey): Find better solution for this.
1198 */
1199 if (engine->has_grease_pencil || engine_keep_depsgraph(engine)) {
1200 return;
1201 }
1202 engine_depsgraph_free(engine);
1203}
1204
1206{
1207 return re->engine;
1208}
1209
1211{
1212 return view_render->engine;
1213}
1214
1216{
1217 RenderEngine *engine = re->engine;
1218
1219 if (!engine) {
1220 /* No engine-side drawing if the engine does not exist. */
1221 return false;
1222 }
1223
1224 if (!engine->type->draw) {
1225 /* Required callbacks are not implemented on the engine side. */
1226 return false;
1227 }
1228
1229 /* Lock before checking the flag, to avoid possible conflicts with the render thread. */
1231
1232 if ((engine->flag & RE_ENGINE_CAN_DRAW) == 0) {
1233 /* The rendering is not started yet, or has finished.
1234 *
1235 * In the former case there will nothing to be drawn, so can simply use RenderResult drawing
1236 * pipeline. In the latter case the engine has destroyed its display-only resources (textures,
1237 * graphics interops, etc..) so need to use the #RenderResult drawing pipeline. */
1239 return false;
1240 }
1241
1242 return true;
1243}
1244
1249
1251 RenderEngine *engine, int x, int y, int width, int height, bool highlight)
1252{
1253 if (!engine->re) {
1254 /* No render on the engine, so nowhere to store the highlighted tiles information. */
1255 return;
1256 }
1257 if ((engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) {
1258 /* Engine reported it does not support tiles highlight, but attempted to set the highlight.
1259 * Technically it is a logic error, but there is no good way to inform an external engine about
1260 * it. */
1261 return;
1262 }
1263
1264 blender::render::TilesHighlight *tile_highlight = engine->re->get_tile_highlight();
1265 if (!tile_highlight) {
1266 /* The renderer itself does not support tiles highlight. */
1267 return;
1268 }
1269
1270 if (highlight) {
1271 tile_highlight->highlight_tile(x, y, width, height);
1272 }
1273 else {
1274 tile_highlight->unhighlight_tile(x, y, width, height);
1275 }
1276}
1277
1279{
1280 if (!engine->re) {
1281 /* No render on the engine, so nowhere to store the highlighted tiles information. */
1282 return;
1283 }
1284 if ((engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) {
1285 /* Engine reported it does not support tiles highlight, but attempted to set the highlight.
1286 * Technically it is a logic error, but there is no good way to inform an external engine about
1287 * it. */
1288 return;
1289 }
1290
1291 blender::render::TilesHighlight *tile_highlight = engine->re->get_tile_highlight();
1292 if (!tile_highlight) {
1293 /* The renderer itself does not support tiles highlight. */
1294 return;
1295 }
1296
1297 tile_highlight->clear();
1298}
1299
1300/* -------------------------------------------------------------------- */
1308
1310{
1311 /* If there already is a draw manager render context available, reuse it. */
1312 engine->use_drw_render_context = (engine->re && RE_system_gpu_context_get(engine->re));
1313 if (engine->use_drw_render_context) {
1314 return true;
1315 }
1316
1317 /* Viewport render case where no render context is available. We are expected to be on
1318 * the main thread here to safely create a context. */
1320
1321 const bool drw_state = DRW_gpu_context_release();
1323
1324 if (engine->system_gpu_context) {
1325 /* Activate new GPU Context for GPUContext creation. */
1327 /* Requires GPUContext for usage of GPU Module for displaying results. */
1328 engine->blender_gpu_context = GPU_context_create(nullptr, engine->system_gpu_context);
1329 GPU_context_active_set(nullptr);
1330 /* Deactivate newly created GPU Context, as it is not needed until
1331 * `RE_engine_gpu_context_enable` is called. */
1333 }
1334 else {
1335 engine->blender_gpu_context = nullptr;
1336 }
1337
1338 DRW_gpu_context_activate(drw_state);
1339
1340 return engine->system_gpu_context != nullptr;
1341}
1342
1344{
1345 if (!engine->system_gpu_context) {
1346 return;
1347 }
1348
1349 const bool drw_state = DRW_gpu_context_release();
1350
1352 if (engine->blender_gpu_context) {
1353 GPUContext *restore_context = GPU_context_active_get();
1356 if (restore_context != engine->blender_gpu_context) {
1357 GPU_context_active_set(restore_context);
1358 }
1359 engine->blender_gpu_context = nullptr;
1360 }
1362 engine->system_gpu_context = nullptr;
1363
1364 DRW_gpu_context_activate(drw_state);
1365}
1366
1368{
1369 engine->gpu_restore_context = false;
1370 if (engine->use_drw_render_context) {
1372 return true;
1373 }
1374 if (engine->system_gpu_context) {
1376 /* If a previous GPU/GPUContext was active (DST.blender_gpu_context), we should later
1377 * restore this when disabling the RenderEngine context. */
1379
1380 /* Activate RenderEngine System and Blender GPU Context. */
1382 if (engine->blender_gpu_context) {
1385 }
1386 return true;
1387 }
1388 return false;
1389}
1390
1392{
1393 if (engine->use_drw_render_context) {
1395 }
1396 else {
1397 if (engine->system_gpu_context) {
1398 if (engine->blender_gpu_context) {
1399 GPU_context_active_set(nullptr);
1401 }
1403 /* Restore DRW state context if previously active. */
1406 }
1407 }
1408}
1409
1411{
1412 if (engine->use_drw_render_context) {
1413 /* Locking already handled by the draw manager. */
1414 }
1415 else {
1416 if (engine->system_gpu_context) {
1418 }
1419 }
1420}
1421
1423{
1424 if (engine->use_drw_render_context) {
1425 /* Locking already handled by the draw manager. */
1426 }
1427 else {
1428 if (engine->system_gpu_context) {
1430 }
1431 }
1432}
1433
Camera data-block and utility functions.
float BKE_camera_multiview_shift_x(const struct RenderData *rd, const struct Object *camera, const char *viewname)
void BKE_camera_multiview_model_matrix(const struct RenderData *rd, const struct Object *camera, const char *viewname, float r_modelmat[4][4])
bool BKE_camera_multiview_spherical_stereo(const struct RenderData *rd, const struct Object *camera)
bool BKE_reports_contain(ReportList *reports, eReportType level)
Definition report.cc:383
eReportType
Definition BKE_report.hh:33
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
void BKE_scene_graph_update_for_newframe_ex(Depsgraph *depsgraph, bool clear_recalc)
Definition scene.cc:2631
void BKE_scene_frame_set(Scene *scene, float frame)
Definition scene.cc:2389
bool BKE_scene_camera_switch_update(Scene *scene)
Definition scene.cc:2265
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2384
void BKE_scene_ppm_get(const RenderData *rd, double r_ppm[2])
Definition scene.cc:3234
#define BLI_assert(a)
Definition BLI_assert.h:46
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
MINLINE float int_as_float(int i)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:604
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
void BLI_mutex_end(ThreadMutex *mutex)
Definition threads.cc:360
void BLI_mutex_init(ThreadMutex *mutex)
Definition threads.cc:340
#define THREAD_LOCK_WRITE
void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode)
Definition threads.cc:467
int BLI_thread_is_main(void)
Definition threads.cc:179
void BLI_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
#define CLAMP(a, b, c)
#define STREQ(a, b)
void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr)
#define CLOG_INFO(clg_ref,...)
Definition CLG_log.h:190
void DEG_ids_clear_recalc(Depsgraph *depsgraph, bool backup)
@ DAG_EVAL_RENDER
Depsgraph * DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
Definition depsgraph.cc:278
void DEG_graph_replace_owners(Depsgraph *depsgraph, Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition depsgraph.cc:285
void DEG_graph_free(Depsgraph *graph)
Definition depsgraph.cc:306
void DEG_evaluate_on_framechange(Depsgraph *graph, float frame, DepsgraphEvaluateSyncWriteback sync_writeback=DEG_EVALUATE_SYNC_WRITEBACK_NO)
void DEG_graph_tag_relations_update(Depsgraph *graph)
void DEG_graph_relations_update(Depsgraph *graph)
void DEG_debug_name_set(Depsgraph *depsgraph, const char *name)
ViewLayer * DEG_get_input_view_layer(const Depsgraph *graph)
Main * DEG_get_bmain(const Depsgraph *graph)
Scene * DEG_get_input_scene(const Depsgraph *graph)
eNodeSocketDatatype
Object is a sort of wrapper for general info.
#define RE_PASSNAME_COMBINED
@ SCE_LAY_GREASE_PENCIL
#define MINAFRAME
@ R_PERSISTENT_DATA
@ R_EDGE_FRS
@ SCE_COMPOSITOR_DEVICE_GPU
eScenePassType
@ R_EXR_CACHE_FILE
@ R_DOCOMP
@ R_BUTS_PREVIEW
#define MAXFRAME
bool DRW_render_check_grease_pencil(Depsgraph *depsgraph)
void DRW_module_exit()
void DRW_gpu_context_disable()
void DRW_gpu_context_enable()
void DRW_engines_free()
void DRW_gpu_context_activate(bool drw_state)
void DRW_render_context_disable(Render *render)
bool DRW_gpu_context_try_enable()
void DRW_module_init()
void DRW_render_gpencil(RenderEngine *engine, Depsgraph *depsgraph)
bool DRW_gpu_context_release()
void DRW_engines_register()
void DRW_render_context_enable(Render *render)
void GPU_render_end()
GPUContext * GPU_context_create(void *ghost_window, void *ghost_context)
bool GPU_backend_supported()
void GPU_render_begin()
GPUContext * GPU_context_active_get()
void GPU_context_discard(GPUContext *)
void GPU_context_active_set(GPUContext *)
Read Guarded memory(de)allocation.
void(*)(void *userdata, struct Scene *scene, struct ViewLayer *view_layer, const char *name, int channels, const char *chanid, eNodeSocketDatatype type) update_render_passes_cb_t
Definition RE_engine.h:121
@ RE_INTERNAL
Definition RE_engine.h:43
@ RE_USE_PREVIEW
Definition RE_engine.h:44
@ RE_USE_POSTPROCESS
Definition RE_engine.h:45
@ RE_USE_GPU_CONTEXT
Definition RE_engine.h:50
@ RE_ENGINE_PREVIEW
Definition RE_engine.h:59
@ RE_ENGINE_HIGHLIGHT_TILES
Definition RE_engine.h:63
@ RE_ENGINE_RENDERING
Definition RE_engine.h:62
@ RE_ENGINE_CAN_DRAW
Definition RE_engine.h:64
@ RE_ENGINE_ANIMATION
Definition RE_engine.h:58
return true
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
static unsigned long seed
Definition btSoftBody.h:39
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr int64_t size() const
Definition BLI_span.hh:252
void highlight_tile_for_result(const RenderResult *result)
void unhighlight_tile(int x, int y, int width, int height)
void unhighlight_tile_for_result(const RenderResult *result)
Span< rcti > get_all_highlighted_tiles() const
void highlight_tile(int x, int y, int width, int height)
nullptr float
#define offsetof(t, d)
static void re_ensure_passes_allocated_thread_safe(Render *re)
void RE_engine_draw_release(Render *re)
bool RE_engine_is_external(const Render *re)
const char * RE_engine_active_view_get(RenderEngine *engine)
RenderEngine * RE_view_engine_get(const ViewRender *view_render)
static RenderResult * render_result_from_bake(RenderEngine *engine, int x, int y, int w, int h, const char *layername)
bool RE_bake_engine(Render *re, Depsgraph *depsgraph, Object *object, const int object_id, const BakePixel pixel_array[], const BakeTargets *targets, const eScenePassType pass_type, const int pass_filter, float result[])
void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
RenderResult * RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname)
RenderResult * RE_engine_get_result(RenderEngine *engine)
static void engine_depsgraph_exit(RenderEngine *engine)
void RE_engine_add_pass(RenderEngine *engine, const char *name, int channels, const char *chan_id, const char *layername)
static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer)
void RE_engine_report(RenderEngine *engine, int type, const char *msg)
bool RE_bake_has_engine(const Render *re)
void RE_engine_active_view_set(RenderEngine *engine, const char *viewname)
bool RE_engine_use_persistent_data(RenderEngine *engine)
float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera, bool use_spherical_stereo)
void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
static void engine_render_view_layer(Render *re, RenderEngine *engine, ViewLayer *view_layer_iter, const bool use_engine, const bool use_grease_pencil)
void RE_engines_exit()
const rcti * RE_engine_get_current_tiles(Render *re, int *r_total_tiles)
void RE_engine_update_memory_stats(RenderEngine *engine, float mem_used, float mem_peak)
void RE_engine_update_render_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer, update_render_passes_cb_t callback, void *callback_data)
RenderEngine * RE_engine_get(const Render *re)
RenderPass * RE_engine_pass_by_index_get(RenderEngine *engine, const char *layer_name, int index)
RenderEngineType * RE_engines_find(const char *idname)
void RE_engine_tile_highlight_set(RenderEngine *engine, int x, int y, int width, int height, bool highlight)
bool RE_engine_draw_acquire(Render *re)
bool RE_engine_get_spherical_stereo(RenderEngine *engine, Object *camera)
RenderEngine * RE_engine_create(RenderEngineType *type)
bool RE_engine_render(Render *re, bool do_all)
bool RE_engine_test_break(RenderEngine *engine)
void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info)
void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
void RE_engine_gpu_context_lock(RenderEngine *engine)
void RE_engine_gpu_context_unlock(RenderEngine *engine)
static void engine_depsgraph_free(RenderEngine *engine)
static RenderResult * engine_render_create_result(Render *re)
void RE_engines_register(RenderEngineType *render_type)
static void engine_render_add_result_pass_cb(void *user_data, Scene *, ViewLayer *view_layer, const char *name, int channels, const char *chanid, eNodeSocketDatatype)
void RE_engine_free(RenderEngine *engine)
RenderData * RE_engine_get_render_data(Render *re)
void RE_engine_free_blender_memory(RenderEngine *engine)
static bool possibly_using_gpu_compositor(const Render *re)
void RE_engine_set_error_message(RenderEngine *engine, const char *msg)
void RE_engine_register_pass(RenderEngine *engine, Scene *scene, ViewLayer *view_layer, const char *name, int channels, const char *chanid, eNodeSocketDatatype type)
void RE_engine_end_result(RenderEngine *engine, RenderResult *result, bool cancel, bool highlight, bool merge_results)
ListBase R_engines
void RE_engine_tile_highlight_clear_all(RenderEngine *engine)
static bool engine_keep_depsgraph(RenderEngine *engine)
void RE_engine_gpu_context_destroy(RenderEngine *engine)
static void render_result_to_bake(RenderEngine *engine, RenderResult *rr)
bool RE_engine_gpu_context_enable(RenderEngine *engine)
bool RE_engine_gpu_context_create(RenderEngine *engine)
void RE_engines_init()
void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, bool use_spherical_stereo, float r_modelmat[16])
void RE_engine_update_progress(RenderEngine *engine, float progress)
void RE_engine_gpu_context_disable(RenderEngine *engine)
#define LOG(level)
Definition log.h:97
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static ulong * next
#define G(x, y, z)
const char * name
#define ceilf
void render_result_exr_file_cache_write(Render *re)
void render_result_merge(RenderResult *rr, RenderResult *rrpart)
RenderPass * render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, const char *name, const char *viewname, const char *chan_id, const bool allocate)
void render_result_passes_allocated_ensure(RenderResult *rr)
void render_result_free(RenderResult *rr)
void render_result_clone_passes(Render *re, RenderResult *rr, const char *viewname)
void render_result_free_list(ListBase *lb, RenderResult *rr)
RenderResult * render_result_new(Render *re, const rcti *partrct, const char *layername, const char *viewname)
void RE_create_render_pass(RenderResult *rr, const char *name, int channels, const char *chan_id, const char *layername, const char *viewname, const bool allocate)
#define FOREACH_VIEW_LAYER_TO_RENDER_END
#define RR_ALL_VIEWS
#define RR_ALL_LAYERS
#define FOREACH_VIEW_LAYER_TO_RENDER_BEGIN(re_, iter_)
#define R_ANIMATION
void * RE_system_gpu_context_get(Render *re)
RenderPass * RE_pass_find_by_name(RenderLayer *rl, const char *name, const char *viewname)
void render_copy_renderdata(RenderData *to, RenderData *from)
void RE_FreePersistentData(const Scene *scene)
RenderResult * RE_AcquireResultRead(Render *re)
RenderLayer * RE_GetRenderLayer(RenderResult *rr, const char *name)
void RE_ReleaseResult(Render *re)
const char * RE_GetActiveRenderView(Render *re)
void RE_SetActiveRenderView(Render *re, const char *viewname)
int height
Definition RE_bake.h:27
char render_layer_name[RE_MAXNAME]
Definition RE_bake.h:31
size_t offset
Definition RE_bake.h:28
struct Image * image
Definition RE_bake.h:23
int width
Definition RE_bake.h:26
float dv_dx
Definition RE_bake.h:57
float du_dx
Definition RE_bake.h:56
int seed
Definition RE_bake.h:54
float du_dy
Definition RE_bake.h:56
float uv[2]
Definition RE_bake.h:55
float dv_dy
Definition RE_bake.h:57
int object_id
Definition RE_bake.h:53
int primitive_id
Definition RE_bake.h:53
int channels_num
Definition RE_bake.h:46
int images_num
Definition RE_bake.h:37
BakeImage * images
Definition RE_bake.h:36
ThreadMutex engine_draw_mutex
struct RenderEngine * engine
ThreadRWMutex resultmutex
std::shared_ptr< RenderDisplay > display
RenderResult * result
StructFreeFunc free
char name[258]
Definition DNA_ID.h:432
ImBufFloatBuffer float_buffer
void * first
char engine[32]
void(* render)(struct RenderEngine *engine, struct Depsgraph *depsgraph)
Definition RE_engine.h:79
void(* update)(struct RenderEngine *engine, struct Main *bmain, struct Depsgraph *depsgraph)
Definition RE_engine.h:77
ExtensionRNA rna_ext
Definition RE_engine.h:118
char name[64]
Definition RE_engine.h:74
struct RenderEngineType * next
Definition RE_engine.h:70
void(* draw)(struct RenderEngine *engine, const struct bContext *context, struct Depsgraph *depsgraph)
Definition RE_engine.h:88
void(* render_frame_finish)(struct RenderEngine *engine)
Definition RE_engine.h:86
void(* update_render_passes)(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer)
Definition RE_engine.h:110
void(* bake)(struct RenderEngine *engine, struct Depsgraph *depsgraph, struct Object *object, int pass_type, int pass_filter, int width, int height)
Definition RE_engine.h:92
struct RenderEngine::@041244022306172004244365003343277124227106040205 bake
struct ReportList * reports
Definition RE_engine.h:143
struct Depsgraph * depsgraph
Definition RE_engine.h:154
RenderEngineType * type
Definition RE_engine.h:130
const struct BakePixel * pixels
Definition RE_engine.h:147
ThreadMutex blender_gpu_context_mutex
Definition RE_engine.h:164
float * result
Definition RE_engine.h:148
char text[512]
Definition RE_engine.h:139
bool has_grease_pencil
Definition RE_engine.h:155
bool use_drw_render_context
Definition RE_engine.h:165
struct Render * re
Definition RE_engine.h:137
struct GPUContext * blender_gpu_context
Definition RE_engine.h:166
void * update_render_passes_data
Definition RE_engine.h:160
ListBase fullresult
Definition RE_engine.h:138
void * py_instance
Definition RE_engine.h:131
void * system_gpu_context
Definition RE_engine.h:163
update_render_passes_cb_t update_render_passes_cb
Definition RE_engine.h:159
bool gpu_restore_context
Definition RE_engine.h:168
ThreadMutex update_render_passes_mutex
Definition RE_engine.h:158
const struct BakeTargets * targets
Definition RE_engine.h:146
struct Object * camera_override
Definition RE_engine.h:134
ListBase passes
Definition RE_pipeline.h:94
char name[RE_MAXNAME]
Definition RE_pipeline.h:89
struct ImBuf * ibuf
Definition RE_pipeline.h:67
ListBase layers
bool passes_allocated
double ppm[2]
const char * statstr
char scene_name[MAX_ID_NAME - 2]
const char * infostr
Scene * pipeline_scene_eval
RenderData r
struct Main * main
bool prepare_viewlayer(struct ViewLayer *view_layer, struct Depsgraph *depsgraph) override
Scene * scene
blender::render::TilesHighlight * get_tile_highlight() override
short flag
char viewname[MAX_NAME]
RenderStats i
struct ReportList * reports
rcti disprect
struct Object * camera_override
struct bNodeTree * compositing_node_group
struct RenderData r
ListBase view_layers
char name[64]
int ymin
int ymax
int xmin
int xmax
i
Definition text_draw.cc:230
void * WM_system_gpu_context_create()
void WM_system_gpu_context_dispose(void *context)
void WM_system_gpu_context_activate(void *context)
void WM_system_gpu_context_release(void *context)