Blender V5.0
render_result.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 <cerrno>
10#include <cstdio>
11#include <cstdlib>
12#include <cstring>
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_hash_md5.hh"
17#include "BLI_listbase.h"
18#include "BLI_path_utils.hh"
19#include "BLI_rect.h"
20#include "BLI_string_utf8.h"
21#include "BLI_string_utils.hh"
22#include "BLI_utildefines.h"
23
24#include "DNA_userdef_types.h"
25
26#include "BKE_appdir.hh"
27#include "BKE_image.hh"
28#include "BKE_image_format.hh"
29#include "BKE_image_save.hh"
30#include "BKE_main.hh"
31#include "BKE_report.hh"
32#include "BKE_scene.hh"
33
35#include "IMB_imbuf.hh"
36#include "IMB_imbuf_types.hh"
37#include "IMB_openexr.hh"
38
39#include "GPU_texture.hh"
40
41#include "render_result.h"
42#include "render_types.h"
43
44/* -------------------------------------------------------------------- */
47
49{
50 while (rr->views.first) {
51 RenderView *rv = static_cast<RenderView *>(rr->views.first);
52 BLI_remlink(&rr->views, rv);
53
55
56 MEM_freeN(rv);
57 }
58
59 rr->have_combined = false;
60}
61
63{
64 if (rr == nullptr) {
65 return;
66 }
67
68 /* Only actually free when RenderResult when the render result has zero users which is its
69 * default state.
70 * There is no need to lock as the user-counted render results are protected by mutex at the
71 * higher call stack level. */
72 if (rr->user_counter > 0) {
73 --rr->user_counter;
74 return;
75 }
76
77 while (rr->layers.first) {
78 RenderLayer *rl = static_cast<RenderLayer *>(rr->layers.first);
79
80 while (rl->passes.first) {
81 RenderPass *rpass = static_cast<RenderPass *>(rl->passes.first);
82
83 IMB_freeImBuf(rpass->ibuf);
84
85 BLI_freelinkN(&rl->passes, rpass);
86 }
87 BLI_remlink(&rr->layers, rl);
88 MEM_freeN(rl);
89 }
90
92
94
95 if (rr->text) {
96 MEM_freeN(rr->text);
97 }
98 if (rr->error) {
99 MEM_freeN(rr->error);
100 }
101
103
104 MEM_freeN(rr);
105}
106
108{
109 RenderResult *rrnext;
110
111 for (; rr; rr = rrnext) {
112 rrnext = rr->next;
113
114 if (lb && lb->first) {
115 BLI_remlink(lb, rr);
116 }
117
119 }
120}
121
123{
124 LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
125 LISTBASE_FOREACH (RenderPass *, rpass, &rl->passes) {
126 IMB_free_gpu_textures(rpass->ibuf);
127 }
128 }
129}
130
132
133/* -------------------------------------------------------------------- */
136
138{
139 if (dst == nullptr || src == nullptr) {
140 return;
141 }
142
143 LISTBASE_FOREACH (RenderView *, rview, &src->views) {
144 RenderView *rv;
145
146 rv = MEM_callocN<RenderView>("new render view");
147 BLI_addtail(&dst->views, rv);
148
149 STRNCPY_UTF8(rv->name, rview->name);
150
151 rv->ibuf = rview->ibuf;
152 }
153}
154
156{
157 if (rr == nullptr) {
158 return;
159 }
160
161 while (rr->views.first) {
162 RenderView *rv = static_cast<RenderView *>(rr->views.first);
163 BLI_remlink(&rr->views, rv);
164 MEM_freeN(rv);
165 }
166}
167
169
170/* -------------------------------------------------------------------- */
173
174static int get_num_planes_for_pass_ibuf(const RenderPass &render_pass)
175{
176 switch (render_pass.channels) {
177 case 1:
178 return R_IMF_PLANES_BW;
179 case 3:
180 return R_IMF_PLANES_RGB;
181 case 4:
182 return R_IMF_PLANES_RGBA;
183 }
184
185 /* Fall back to a commonly used default value of planes for odd-ball number of channel. */
186 return R_IMF_PLANES_RGBA;
187}
188
190{
191 if (RE_RenderPassIsColor(&render_pass)) {
192 return;
193 }
194
196 IMB_colormanagement_assign_float_colorspace(render_pass.ibuf, data_colorspace);
197}
198
200{
201 if (rp->ibuf && rp->ibuf->float_buffer.data) {
202 return;
203 }
204
205 /* NOTE: In-lined manual allocation to support floating point buffers of an arbitrary number of
206 * channels. */
207
208 const size_t rectsize = size_t(rr->rectx) * rr->recty * rp->channels;
209 float *buffer_data = MEM_calloc_arrayN<float>(rectsize, rp->name);
210
212 rp->ibuf->channels = rp->channels;
213 copy_v2_v2_db(rp->ibuf->ppm, rr->ppm);
216
217 if (STREQ(rp->name, RE_PASSNAME_VECTOR)) {
218 /* initialize to max speed */
219 for (int x = rectsize - 1; x >= 0; x--) {
220 buffer_data[x] = PASS_VECTOR_MAX;
221 }
222 }
223 else if (STREQ(rp->name, RE_PASSNAME_DEPTH)) {
224 for (int x = rectsize - 1; x >= 0; x--) {
225 buffer_data[x] = 10e10;
226 }
227 }
228}
229
231 RenderLayer *rl,
232 int channels,
233 const char *name,
234 const char *viewname,
235 const char *chan_id,
236 const bool allocate)
237{
238 const int view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name));
240
241 rpass->channels = channels;
242 rpass->rectx = rl->rectx;
243 rpass->recty = rl->recty;
244 rpass->view_id = view_id;
245
246 STRNCPY(rpass->name, name);
247 STRNCPY(rpass->chan_id, chan_id);
248 STRNCPY(rpass->view, viewname);
250 rpass->fullname, nullptr, rpass->name, rpass->view, rpass->chan_id, -1);
251
252 BLI_addtail(&rl->passes, rpass);
253
254 if (allocate) {
256 }
257 else {
258 /* The result contains non-allocated pass now, so tag it as such. */
259 rr->passes_allocated = false;
260 }
261
262 return rpass;
263}
264
266 const rcti *partrct,
267 const char *layername,
268 const char *viewname)
269{
270 RenderResult *rr;
271 RenderLayer *rl;
272 int rectx, recty;
273
274 rectx = BLI_rcti_size_x(partrct);
275 recty = BLI_rcti_size_y(partrct);
276
277 if (rectx <= 0 || recty <= 0) {
278 return nullptr;
279 }
280
281 rr = MEM_callocN<RenderResult>("new render result");
282 rr->rectx = rectx;
283 rr->recty = recty;
284
285 BKE_scene_ppm_get(&re->r, rr->ppm);
286
287 /* tilerect is relative coordinates within render disprect. do not subtract crop yet */
288 rr->tilerect.xmin = partrct->xmin - re->disprect.xmin;
289 rr->tilerect.xmax = partrct->xmax - re->disprect.xmin;
290 rr->tilerect.ymin = partrct->ymin - re->disprect.ymin;
291 rr->tilerect.ymax = partrct->ymax - re->disprect.ymin;
292
293 rr->passes_allocated = false;
294
295 render_result_views_new(rr, &re->r);
296
297 /* Check render-data for amount of layers. */
298 FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer) {
299 if (layername && layername[0]) {
300 if (!STREQ(view_layer->name, layername)) {
301 continue;
302 }
303 }
304
305 rl = MEM_callocN<RenderLayer>("new render layer");
306 BLI_addtail(&rr->layers, rl);
307
308 STRNCPY_UTF8(rl->name, view_layer->name);
309 rl->layflag = view_layer->layflag;
310
311 rl->passflag = view_layer->passflag;
312
313 rl->rectx = rectx;
314 rl->recty = recty;
315
316 LISTBASE_FOREACH (RenderView *, rv, &rr->views) {
317 const char *view = rv->name;
318
319 if (viewname && viewname[0]) {
320 if (!STREQ(view, viewname)) {
321 continue;
322 }
323 }
324
325 /* A render-layer should always have a "Combined" pass. */
326 render_layer_add_pass(rr, rl, 4, "Combined", view, "RGBA", false);
327 }
328 }
330
331 /* Preview-render doesn't do layers, so we make a default one. */
332 if (BLI_listbase_is_empty(&rr->layers) && !(layername && layername[0])) {
333 rl = MEM_callocN<RenderLayer>("new render layer");
334 BLI_addtail(&rr->layers, rl);
335
336 rl->rectx = rectx;
337 rl->recty = recty;
338
339 LISTBASE_FOREACH (RenderView *, rv, &rr->views) {
340 const char *view = rv->name;
341
342 if (viewname && viewname[0]) {
343 if (!STREQ(view, viewname)) {
344 continue;
345 }
346 }
347
348 /* A render-layer should always have a "Combined" pass. */
349 render_layer_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, view, "RGBA", false);
350 }
351
352 /* NOTE: this has to be in sync with `scene.cc`. */
355
356 re->single_view_layer[0] = '\0';
357 }
358
359 /* Border render; calculate offset for use in compositor. compo is centralized coords. */
360 /* XXX(ton): obsolete? I now use it for drawing border render offset. */
361 rr->xof = re->disprect.xmin + BLI_rcti_cent_x(&re->disprect) - (re->winx / 2);
362 rr->yof = re->disprect.ymin + BLI_rcti_cent_y(&re->disprect) - (re->winy / 2);
363
364 return rr;
365}
366
368{
369 if (rr == nullptr) {
370 /* Happens when the result was not yet allocated for the current scene or slot configuration.
371 */
372 return;
373 }
374
375 LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
376 LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) {
378 }
379 }
380
381 rr->passes_allocated = true;
382}
383
384void render_result_clone_passes(Render *re, RenderResult *rr, const char *viewname)
385{
386 LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
387 RenderLayer *main_rl = RE_GetRenderLayer(re->result, rl->name);
388 if (!main_rl) {
389 continue;
390 }
391
392 LISTBASE_FOREACH (RenderPass *, main_rp, &main_rl->passes) {
393 if (viewname && viewname[0] && !STREQ(main_rp->view, viewname)) {
394 continue;
395 }
396
397 /* Compare `fullname` to make sure that the view also is equal. */
398 const RenderPass *rp = static_cast<const RenderPass *>(
399 BLI_findstring(&rl->passes, main_rp->fullname, offsetof(RenderPass, fullname)));
400 if (!rp) {
402 rr, rl, main_rp->channels, main_rp->name, main_rp->view, main_rp->chan_id, false);
403 }
404 }
405 }
406}
407
409 const char *name,
410 int channels,
411 const char *chan_id,
412 const char *layername,
413 const char *viewname,
414 const bool allocate)
415{
416 LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
417 if (layername && layername[0] && !STREQ(rl->name, layername)) {
418 continue;
419 }
420
421 LISTBASE_FOREACH (RenderView *, rv, &rr->views) {
422 const char *view = rv->name;
423
424 if (viewname && viewname[0] && !STREQ(view, viewname)) {
425 continue;
426 }
427
428 /* Ensure that the pass doesn't exist yet. */
429 bool pass_exists = false;
430 LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) {
431 if (STREQ(rp->name, name) && STREQ(rp->view, view)) {
432 pass_exists = true;
433 break;
434 }
435 }
436
437 if (!pass_exists) {
438 render_layer_add_pass(rr, rl, channels, name, view, chan_id, allocate);
439 }
440 }
441 }
442}
443
450
452{
453 ImBuf *ibuf = rpass->ibuf;
454
455 if (!ibuf) {
456 /* No existing GPU texture, but also no CPU side data to create it from. */
457 return nullptr;
458 }
459
460 if (ibuf->gpu.texture) {
461 /* Return existing GPU texture, regardless whether it also exists on CPU or not. */
462 return ibuf->gpu.texture;
463 }
464
465 if (ibuf->float_buffer.data == nullptr) {
466 /* No CPU side data to create the texture from. */
467 return nullptr;
468 }
469
470 const blender::gpu::TextureFormat format = (rpass->channels == 1) ?
471 blender::gpu::TextureFormat::SFLOAT_32 :
472 (rpass->channels == 3) ?
473 blender::gpu::TextureFormat::SFLOAT_32_32_32 :
474 blender::gpu::TextureFormat::SFLOAT_32_32_32_32;
475
476 /* TODO(sergey): Use utility to assign the texture. */
477 ibuf->gpu.texture = GPU_texture_create_2d("RenderBuffer.gpu_texture",
478 rpass->rectx,
479 rpass->recty,
480 1,
481 format,
483 nullptr);
484
485 if (ibuf->gpu.texture) {
488 }
489
490 return ibuf->gpu.texture;
491}
492
494 const char *layname,
495 const char *passname,
496 const char *viewname,
497 const char *chan_id,
498 const int channel)
499{
500 /* OpenEXR compatible full channel name. */
501 const char *strings[4];
502 int strings_len = 0;
503
504 if (layname && layname[0]) {
505 strings[strings_len++] = layname;
506 }
507 if (passname && passname[0]) {
508 strings[strings_len++] = passname;
509 }
510 if (viewname && viewname[0]) {
511 strings[strings_len++] = viewname;
512 }
513
514 char token[2];
515 if (channel >= 0) {
516 ARRAY_SET_ITEMS(token, chan_id[channel], '\0');
517 strings[strings_len++] = token;
518 }
519
520 BLI_string_join_array_by_sep_char(fullname, EXR_PASS_MAXNAME, '.', strings, strings_len);
521}
522
523static int passtype_from_name(const char *name)
524{
525 const char delim[] = {'.', '\0'};
526 const char *sep, *suf;
527 int len = BLI_str_partition(name, delim, &sep, &suf);
528
529#define CHECK_PASS(NAME) \
530 if (STREQLEN(name, RE_PASSNAME_##NAME, len)) { \
531 return SCE_PASS_##NAME; \
532 } \
533 ((void)0)
534
535 CHECK_PASS(COMBINED);
536 CHECK_PASS(DEPTH);
538 CHECK_PASS(NORMAL);
539 CHECK_PASS(UV);
540 CHECK_PASS(EMIT);
541 CHECK_PASS(SHADOW);
542 CHECK_PASS(AO);
543 CHECK_PASS(ENVIRONMENT);
544 CHECK_PASS(INDEXOB);
545 CHECK_PASS(INDEXMA);
546 CHECK_PASS(MIST);
547 CHECK_PASS(DIFFUSE_DIRECT);
548 CHECK_PASS(DIFFUSE_INDIRECT);
549 CHECK_PASS(DIFFUSE_COLOR);
550 CHECK_PASS(GLOSSY_DIRECT);
551 CHECK_PASS(GLOSSY_INDIRECT);
552 CHECK_PASS(GLOSSY_COLOR);
553 CHECK_PASS(TRANSM_DIRECT);
554 CHECK_PASS(TRANSM_INDIRECT);
555 CHECK_PASS(TRANSM_COLOR);
556 CHECK_PASS(SUBSURFACE_DIRECT);
557 CHECK_PASS(SUBSURFACE_INDIRECT);
558 CHECK_PASS(SUBSURFACE_COLOR);
559
560#undef CHECK_PASS
561 return 0;
562}
563
564/* callbacks for render_result_new_from_exr */
565static void *ml_addlayer_cb(void *base, const char *str)
566{
567 RenderResult *rr = static_cast<RenderResult *>(base);
568
569 RenderLayer *rl = MEM_callocN<RenderLayer>("new render layer");
570 BLI_addtail(&rr->layers, rl);
571
573 return rl;
574}
575
576static void ml_addpass_cb(void *base,
577 void *lay,
578 const char *name,
579 float *rect,
580 int totchan,
581 const char *chan_id,
582 const char *view)
583{
584 RenderResult *rr = static_cast<RenderResult *>(base);
585 RenderLayer *rl = static_cast<RenderLayer *>(lay);
586 RenderPass *rpass = MEM_callocN<RenderPass>("loaded pass");
587
588 BLI_addtail(&rl->passes, rpass);
589 rpass->rectx = rr->rectx;
590 rpass->recty = rr->recty;
591 rpass->channels = totchan;
593
594 /* channel id chars */
595 STRNCPY(rpass->chan_id, chan_id);
596
597 RE_pass_set_buffer_data(rpass, rect);
598
599 STRNCPY(rpass->name, name);
600 STRNCPY(rpass->view, view);
601 RE_render_result_full_channel_name(rpass->fullname, nullptr, name, view, rpass->chan_id, -1);
602
603 if (view[0] != '\0') {
605 }
606 else {
607 rpass->view_id = 0;
608 }
609}
610
611static void *ml_addview_cb(void *base, const char *str)
612{
613 RenderResult *rr = static_cast<RenderResult *>(base);
614
615 RenderView *rv = MEM_callocN<RenderView>("new render view");
616 STRNCPY_UTF8(rv->name, str);
617
618 /* For stereo drawing we need to ensure:
619 * STEREO_LEFT_NAME == STEREO_LEFT_ID and
620 * STEREO_RIGHT_NAME == STEREO_RIGHT_ID */
621
622 if (STREQ(str, STEREO_LEFT_NAME)) {
623 BLI_addhead(&rr->views, rv);
624 }
625 else if (STREQ(str, STEREO_RIGHT_NAME)) {
626 RenderView *left_rv = static_cast<RenderView *>(
628
629 if (left_rv == nullptr) {
630 BLI_addhead(&rr->views, rv);
631 }
632 else {
633 BLI_insertlinkafter(&rr->views, left_rv, rv);
634 }
635 }
636 else {
637 BLI_addtail(&rr->views, rv);
638 }
639
640 return rv;
641}
642
643static int order_render_passes(const void *a, const void *b)
644{
645 /* 1 if `a` is after `b`. */
646 const RenderPass *rpa = (const RenderPass *)a;
647 const RenderPass *rpb = (const RenderPass *)b;
648 uint passtype_a = passtype_from_name(rpa->name);
649 uint passtype_b = passtype_from_name(rpb->name);
650
651 /* Render passes with default type always go first. */
652 if (passtype_b && !passtype_a) {
653 return 1;
654 }
655 if (passtype_a && !passtype_b) {
656 return 0;
657 }
658
659 if (passtype_a && passtype_b) {
660 if (passtype_a > passtype_b) {
661 return 1;
662 }
663 if (passtype_a < passtype_b) {
664 return 0;
665 }
666 }
667 else {
668 int cmp = strncmp(rpa->name, rpb->name, EXR_PASS_MAXNAME);
669 if (cmp > 0) {
670 return 1;
671 }
672 if (cmp < 0) {
673 return 0;
674 }
675 }
676
677 /* they have the same type */
678 /* left first */
679 if (STREQ(rpa->view, STEREO_LEFT_NAME)) {
680 return 0;
681 }
682 if (STREQ(rpb->view, STEREO_LEFT_NAME)) {
683 return 1;
684 }
685
686 /* right second */
687 if (STREQ(rpa->view, STEREO_RIGHT_NAME)) {
688 return 0;
689 }
690 if (STREQ(rpb->view, STEREO_RIGHT_NAME)) {
691 return 1;
692 }
693
694 /* remaining in ascending id order */
695 return (rpa->view_id < rpb->view_id);
696}
697
699 ExrHandle *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
700{
702 const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(
705
706 rr->rectx = rectx;
707 rr->recty = recty;
708
709 IMB_exr_get_ppm(exrhandle, rr->ppm);
710
712
713 LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
714 rl->rectx = rectx;
715 rl->recty = recty;
716
718
719 LISTBASE_FOREACH (RenderPass *, rpass, &rl->passes) {
720 rpass->rectx = rectx;
721 rpass->recty = recty;
722
723 copy_v2_v2_db(rpass->ibuf->ppm, rr->ppm);
724
725 if (RE_RenderPassIsColor(rpass)) {
726 IMB_colormanagement_transform_float(rpass->ibuf->float_buffer.data,
727 rpass->rectx,
728 rpass->recty,
729 rpass->channels,
730 colorspace,
731 to_colorspace,
732 predivide);
733 }
734 else {
735 IMB_colormanagement_assign_float_colorspace(rpass->ibuf, data_colorspace);
736 }
737 }
738 }
739
740 return rr;
741}
742
743void render_result_view_new(RenderResult *rr, const char *viewname)
744{
745 RenderView *rv = MEM_callocN<RenderView>("new render view");
746 BLI_addtail(&rr->views, rv);
747 STRNCPY_UTF8(rv->name, viewname);
748}
749
751{
752 /* clear previously existing views - for sequencer */
754
755 /* check renderdata for amount of views */
756 if (rd->scemode & R_MULTIVIEW) {
757 LISTBASE_FOREACH (SceneRenderView *, srv, &rd->views) {
758 if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) {
759 continue;
760 }
761 render_result_view_new(rr, srv->name);
762 }
763 }
764
765 /* we always need at least one view */
766 if (BLI_listbase_is_empty(&rr->views)) {
768 }
769}
770
772
773/* -------------------------------------------------------------------- */
776
777static void do_merge_tile(
778 RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize)
779{
780 int y, tilex, tiley;
781 size_t ofs, copylen;
782
783 copylen = tilex = rrpart->rectx;
784 tiley = rrpart->recty;
785
786 ofs = (size_t(rrpart->tilerect.ymin) * rr->rectx + rrpart->tilerect.xmin);
787 target += pixsize * ofs;
788
789 copylen *= sizeof(float) * pixsize;
790 tilex *= pixsize;
791 ofs = pixsize * rr->rectx;
792
793 for (y = 0; y < tiley; y++) {
794 memcpy(target, tile, copylen);
795 target += ofs;
796 tile += tilex;
797 }
798}
799
801{
802 LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
803 RenderLayer *rlp = RE_GetRenderLayer(rrpart, rl->name);
804
805 if (rlp) {
806 /* Passes are allocated in sync. */
807 for (RenderPass *rpass = static_cast<RenderPass *>(rl->passes.first),
808 *rpassp = static_cast<RenderPass *>(rlp->passes.first);
809 rpass && rpassp;
810 rpass = rpass->next)
811 {
812 /* For save buffers, skip any passes that are only saved to disk. */
813 if (rpass->ibuf == nullptr || rpassp->ibuf == nullptr) {
814 continue;
815 }
816 if (rpass->ibuf->float_buffer.data == nullptr ||
817 rpassp->ibuf->float_buffer.data == nullptr)
818 {
819 continue;
820 }
821 /* Render-result have all passes, render-part only the active view's passes. */
822 if (!STREQ(rpassp->fullname, rpass->fullname)) {
823 continue;
824 }
825
826 do_merge_tile(rr,
827 rrpart,
828 rpass->ibuf->float_buffer.data,
829 rpassp->ibuf->float_buffer.data,
830 rpass->channels);
831
832 /* manually get next render pass */
833 rpassp = rpassp->next;
834 }
835 }
836 }
837}
838
840
841/* -------------------------------------------------------------------- */
844
846{
847 /* all layers except the active one get temporally pushed away */
848
849 /* officially pushed result should be nullptr... error can happen with do_seq */
851
852 re->pushedresult = re->result;
853 re->result = nullptr;
854}
855
857{
858 if (re->result == nullptr) {
859 printf("pop render result error; no current result!\n");
860 return;
861 }
862
863 if (!re->pushedresult) {
864 return;
865 }
866
867 if (re->pushedresult->rectx == re->result->rectx && re->pushedresult->recty == re->result->recty)
868 {
869 /* find which layer in re->pushedresult should be replaced */
870 RenderLayer *rl = static_cast<RenderLayer *>(re->result->layers.first);
871
872 /* render result should be empty after this */
873 BLI_remlink(&re->result->layers, rl);
874
875 /* reconstruct render result layers */
876 LISTBASE_FOREACH (ViewLayer *, view_layer, &re->scene->view_layers) {
877 if (STREQ(view_layer->name, re->single_view_layer)) {
878 BLI_addtail(&re->result->layers, rl);
879 }
880 else {
881 RenderLayer *rlpush = RE_GetRenderLayer(re->pushedresult, view_layer->name);
882 if (rlpush) {
883 BLI_remlink(&re->pushedresult->layers, rlpush);
884 BLI_addtail(&re->result->layers, rlpush);
885 }
886 }
887 }
888 }
889
891 re->pushedresult = nullptr;
892}
893
895 RenderLayer *rl_single,
896 ReportList *reports,
897 const char *filepath)
898{
899 ExrHandle *exrhandle = IMB_exr_get_handle();
900 int rectx, recty;
901
902 if (!IMB_exr_begin_read(exrhandle, filepath, &rectx, &recty, false)) {
903 IMB_exr_close(exrhandle);
904 return false;
905 }
906
907 ListBase layers = (rr) ? rr->layers : ListBase{rl_single, rl_single};
908 const int expected_rectx = (rr) ? rr->rectx : rl_single->rectx;
909 const int expected_recty = (rr) ? rr->recty : rl_single->recty;
910 bool found_channels = false;
911
912 if (rectx != expected_rectx || recty != expected_recty) {
913 BKE_reportf(reports,
914 RPT_ERROR,
915 "Reading render result: dimensions don't match, expected %dx%d",
916 expected_rectx,
917 expected_recty);
918 IMB_exr_close(exrhandle);
919 return true;
920 }
921
922 LISTBASE_FOREACH (RenderLayer *, rl, &layers) {
923 if (rl_single && rl_single != rl) {
924 continue;
925 }
926
927 /* passes are allocated in sync */
928 LISTBASE_FOREACH (RenderPass *, rpass, &rl->passes) {
929 const int xstride = rpass->channels;
930 const int ystride = xstride * rectx;
931 int a;
932 char fullname[EXR_PASS_MAXNAME];
933
934 for (a = 0; a < xstride; a++) {
935 /* First try with layer included. */
937 fullname, rl->name, rpass->name, rpass->view, rpass->chan_id, a);
939 exrhandle, fullname, xstride, ystride, rpass->ibuf->float_buffer.data + a))
940 {
941 found_channels = true;
942 }
943 else if (rl_single) {
944 /* Then try without layer name. */
946 fullname, nullptr, rpass->name, rpass->view, rpass->chan_id, a);
948 exrhandle, fullname, xstride, ystride, rpass->ibuf->float_buffer.data + a))
949 {
950 found_channels = true;
951 }
952 else {
953 BKE_reportf(nullptr,
955 "Reading render result: expected channel \"%s.%s\" or \"%s\" not found",
956 rl->name,
957 fullname,
958 fullname);
959 }
960 }
961 else {
962 BKE_reportf(nullptr,
964 "Reading render result: expected channel \"%s.%s\" not found",
965 rl->name,
966 fullname);
967 }
968 }
969
971 rpass->fullname, nullptr, rpass->name, rpass->view, rpass->chan_id, -1);
972 }
973 }
974
975 if (found_channels) {
976 IMB_exr_read_channels(exrhandle);
977 }
978
979 IMB_exr_close(exrhandle);
980
981 return true;
982}
983
984#define FILE_CACHE_MAX (FILE_MAXDIR + FILE_MAXFILE + MAX_ID_NAME + 100)
985
987 const char *root,
988 char r_path[FILE_CACHE_MAX])
989{
990 char filename_full[FILE_MAXFILE + MAX_ID_NAME + 100];
991 char filename[FILE_MAXFILE];
992 char dirname[FILE_MAXDIR];
993 char path_digest[16] = {0};
994 char path_hexdigest[33];
995
996 /* If root is relative, use either current .blend file dir, or temp one if not saved. */
997 const char *blendfile_path = BKE_main_blendfile_path_from_global();
998 if (blendfile_path[0] != '\0') {
999 BLI_path_split_dir_file(blendfile_path, dirname, sizeof(dirname), filename, sizeof(filename));
1000 BLI_path_extension_strip(filename); /* Strip `.blend`. */
1001 BLI_hash_md5_buffer(blendfile_path, strlen(blendfile_path), path_digest);
1002 }
1003 else {
1005 STRNCPY(filename, "UNSAVED");
1006 }
1007 BLI_hash_md5_to_hexdigest(path_digest, path_hexdigest);
1008
1009 /* Default to *non-volatile* temp dir. */
1010 char root_buf[FILE_MAX];
1011 if (*root == '\0') {
1012 root = BKE_tempdir_base();
1013 }
1014 else if (BLI_path_is_rel(root)) {
1015 STRNCPY(root_buf, root);
1016 BLI_path_abs(root_buf, dirname);
1017 root = root_buf;
1018 }
1019
1020 /* FIXME: MAX_ID_NAME & FILE_MAXFILE
1021 *
1022 * If #filename is already long (it is initialized from the blend-file name itself), adding the
1023 * scene name can cause the file name to be truncated.
1024 */
1025 SNPRINTF(filename_full, "cached_RR_%s_%s_%s.exr", filename, sce->id.name + 2, path_hexdigest);
1026
1027 BLI_path_join(r_path, FILE_CACHE_MAX, root, filename_full);
1028}
1029
1031{
1032 RenderResult *rr = re->result;
1033 char str[FILE_CACHE_MAX];
1034 const char *root = U.render_cachedir;
1035
1037
1039 printf("Caching exr file, %dx%d, %s\n", rr->rectx, rr->recty, str);
1040
1041 BKE_image_render_write_exr(nullptr, rr, str, nullptr, true, nullptr, -1);
1042}
1043
1045{
1046 /* File path to cache. */
1047 char filepath[FILE_CACHE_MAX] = "";
1048 const char *root = U.render_cachedir;
1049 render_result_exr_file_cache_path(re->scene, root, filepath);
1050
1051 printf("read exr cache file: %s\n", filepath);
1052
1053 /* Try opening the file. */
1054 ExrHandle *exrhandle = IMB_exr_get_handle();
1055 int rectx, recty;
1056
1057 if (!IMB_exr_begin_read(exrhandle, filepath, &rectx, &recty, true)) {
1058 printf("cannot read: %s\n", filepath);
1059 IMB_exr_close(exrhandle);
1060 return false;
1061 }
1062
1063 /* Read file contents into render result. */
1066
1067 IMB_exr_read_channels(exrhandle);
1068 re->result = render_result_new_from_exr(exrhandle, colorspace, false, rectx, recty);
1069
1070 IMB_exr_close(exrhandle);
1071
1072 return true;
1073}
1074
1076
1077/* -------------------------------------------------------------------- */
1080
1082 const ImageFormatData *imf,
1083 const float dither,
1084 const int view_id)
1085{
1086 ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, imf->planes, 0);
1087 RenderView *rv = RE_RenderViewGetById(rr, view_id);
1088
1089 /* if not exists, BKE_imbuf_write makes one */
1090 if (rv->ibuf) {
1093 ibuf->channels = rv->ibuf->channels;
1094 }
1095
1098
1099 /* float factor for random dither, imbuf takes care of it */
1100 ibuf->dither = dither;
1101
1102 copy_v2_v2_db(ibuf->ppm, rr->ppm);
1103
1104 /* prepare to gamma correct to sRGB color space
1105 * note that sequence editor can generate 8bpc render buffers
1106 */
1107 if (ibuf->byte_buffer.data) {
1110 {
1111 if (imf->depth == R_IMF_CHAN_DEPTH_8) {
1112 /* Higher depth bits are supported but not needed for current file output. */
1114 }
1115 else {
1116 IMB_float_from_byte(ibuf);
1117 }
1118 }
1119 else {
1120 /* ensure no float buffer remained from previous frame */
1122 }
1123 }
1124
1125 /* Color -> gray-scale. */
1126 /* editing directly would alter the render view */
1127 if (imf->planes == R_IMF_PLANES_BW && imf->imtype != R_IMF_IMTYPE_MULTILAYER &&
1128 !(ibuf->float_buffer.data && !ibuf->byte_buffer.data && ibuf->channels == 1))
1129 {
1130 ImBuf *ibuf_bw = IMB_dupImBuf(ibuf);
1131 IMB_color_to_bw(ibuf_bw);
1132 IMB_freeImBuf(ibuf);
1133 ibuf = ibuf_bw;
1134 }
1135
1136 return ibuf;
1137}
1138
1139void RE_render_result_rect_from_ibuf(RenderResult *rr, const ImBuf *ibuf, const int view_id)
1140{
1141 RenderView *rv = RE_RenderViewGetById(rr, view_id);
1142
1143 ImBuf *rv_ibuf = RE_RenderViewEnsureImBuf(rr, rv);
1144
1145 if (ibuf->float_buffer.data) {
1146 rr->have_combined = true;
1147
1148 if (!rv_ibuf->float_buffer.data) {
1149 float *data = MEM_malloc_arrayN<float>(4 * size_t(rr->rectx) * size_t(rr->recty),
1150 "render_seq float");
1152 }
1153
1154 memcpy(rv_ibuf->float_buffer.data,
1155 ibuf->float_buffer.data,
1156 sizeof(float[4]) * rr->rectx * rr->recty);
1157
1158 /* TSK! Since sequence render doesn't free the *rr render result, the old rect32
1159 * can hang around when sequence render has rendered a 32 bits one before */
1160 IMB_free_byte_pixels(rv_ibuf);
1161 }
1162 else if (ibuf->byte_buffer.data) {
1163 rr->have_combined = true;
1164
1165 if (!rv_ibuf->byte_buffer.data) {
1166 uint8_t *data = MEM_malloc_arrayN<uint8_t>(4 * size_t(rr->rectx) * size_t(rr->recty),
1167 "render_seq byte");
1169 }
1170
1171 memcpy(rv_ibuf->byte_buffer.data, ibuf->byte_buffer.data, sizeof(int) * rr->rectx * rr->recty);
1172
1173 /* Same things as above, old rectf can hang around from previous render. */
1174 IMB_free_float_pixels(rv_ibuf);
1175 }
1176}
1177
1178void render_result_rect_fill_zero(RenderResult *rr, const int view_id)
1179{
1180 RenderView *rv = RE_RenderViewGetById(rr, view_id);
1181
1182 ImBuf *ibuf = RE_RenderViewEnsureImBuf(rr, rv);
1183
1184 if (!ibuf->float_buffer.data && !ibuf->byte_buffer.data) {
1185 uint8_t *data = MEM_calloc_arrayN<uint8_t>(4 * size_t(rr->rectx) * size_t(rr->recty),
1186 "render_seq rect");
1188 return;
1189 }
1190
1191 if (ibuf->float_buffer.data) {
1192 memset(ibuf->float_buffer.data, 0, sizeof(float[4]) * rr->rectx * rr->recty);
1193 }
1194
1195 if (ibuf->byte_buffer.data) {
1196 memset(ibuf->byte_buffer.data, 0, 4 * rr->rectx * rr->recty);
1197 }
1198}
1199
1201 uint *rect,
1202 int rectx,
1203 int recty,
1204 const ColorManagedViewSettings *view_settings,
1205 const ColorManagedDisplaySettings *display_settings,
1206 const int view_id)
1207{
1208 RenderView *rv = RE_RenderViewGetById(rr, view_id);
1209 if (ImBuf *ibuf = rv ? rv->ibuf : nullptr) {
1210 if (ibuf->byte_buffer.data) {
1211 memcpy(rect, ibuf->byte_buffer.data, sizeof(int) * rr->rectx * rr->recty);
1212 return;
1213 }
1214 if (ibuf->float_buffer.data) {
1216 ibuf->float_buffer.data,
1217 rr->rectx,
1218 rr->recty,
1219 4,
1220 view_settings,
1221 display_settings,
1222 true);
1223 return;
1224 }
1225 }
1226
1227 /* Fill with black as a fallback. */
1228 memset(rect, 0, sizeof(int) * rectx * recty);
1229}
1230
1232
1233/* -------------------------------------------------------------------- */
1236
1238{
1239 if (result == nullptr) {
1240 return false;
1241 }
1242
1243 const RenderView *rv = static_cast<RenderView *>(result->views.first);
1244 if (rv == nullptr) {
1245 return false;
1246 }
1247
1248 return (rv->ibuf);
1249}
1250
1252{
1253 LISTBASE_FOREACH (const RenderView *, rview, &result->views) {
1254 ImBuf *ibuf = rview->ibuf;
1255 if (!ibuf) {
1256 continue;
1257 }
1258 if (ibuf->byte_buffer.data && !ibuf->float_buffer.data) {
1259 return false;
1260 }
1261 }
1262
1263 return true;
1264}
1265
1267{
1269 return false;
1270 }
1271
1273 return false;
1274 }
1275
1276 return true;
1277}
1278
1280{
1281 RenderView *rv = static_cast<RenderView *>(BLI_findlink(&rr->views, view_id));
1282 BLI_assert(rr->views.first);
1283 return rv ? rv : static_cast<RenderView *>(rr->views.first);
1284}
1285
1287{
1288 RenderView *rv = static_cast<RenderView *>(
1289 BLI_findstring(&rr->views, viewname, offsetof(RenderView, name)));
1290 BLI_assert(rr->views.first);
1291 return rv ? rv : static_cast<RenderView *>(rr->views.first);
1292}
1293
1295{
1296 RenderPass *new_rpass = MEM_dupallocN<RenderPass>("new render pass", *rpass);
1297 new_rpass->next = new_rpass->prev = nullptr;
1298
1299 new_rpass->ibuf = IMB_dupImBuf(rpass->ibuf);
1300
1301 return new_rpass;
1302}
1303
1305{
1306 RenderLayer *new_rl = MEM_dupallocN<RenderLayer>("new render layer", *rl);
1307 new_rl->next = new_rl->prev = nullptr;
1308 new_rl->passes.first = new_rl->passes.last = nullptr;
1309 LISTBASE_FOREACH (RenderPass *, rpass, &rl->passes) {
1310 RenderPass *new_rpass = duplicate_render_pass(rpass);
1311 BLI_addtail(&new_rl->passes, new_rpass);
1312 }
1313 return new_rl;
1314}
1315
1317{
1318 RenderView *new_rview = MEM_dupallocN<RenderView>("new render view", *rview);
1319
1320 new_rview->ibuf = IMB_dupImBuf(rview->ibuf);
1321
1322 return new_rview;
1323}
1324
1326{
1327 RenderResult *new_rr = MEM_dupallocN<RenderResult>("new duplicated render result", *rr);
1328 new_rr->next = new_rr->prev = nullptr;
1329 new_rr->layers.first = new_rr->layers.last = nullptr;
1330 new_rr->views.first = new_rr->views.last = nullptr;
1331 LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
1332 RenderLayer *new_rl = duplicate_render_layer(rl);
1333 BLI_addtail(&new_rr->layers, new_rl);
1334 }
1335 LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
1336 RenderView *new_rview = duplicate_render_view(rview);
1337 BLI_addtail(&new_rr->views, new_rview);
1338 }
1339
1340 new_rr->ibuf = IMB_dupImBuf(rr->ibuf);
1341
1342 new_rr->stamp_data = BKE_stamp_data_copy(new_rr->stamp_data);
1343
1344 copy_v2_v2_db(new_rr->ppm, rr->ppm);
1345
1346 return new_rr;
1347}
1348
1350{
1351 if (!render_pass->ibuf) {
1352 render_pass->ibuf = IMB_allocImBuf(
1353 render_pass->rectx, render_pass->recty, get_num_planes_for_pass_ibuf(*render_pass), 0);
1354 render_pass->ibuf->channels = render_pass->channels;
1356 }
1357
1358 return render_pass->ibuf;
1359}
1360
1361ImBuf *RE_RenderViewEnsureImBuf(const RenderResult *render_result, RenderView *render_view)
1362{
1363 if (!render_view->ibuf) {
1364 render_view->ibuf = IMB_allocImBuf(render_result->rectx, render_result->recty, 32, 0);
1365 }
1366
1367 return render_view->ibuf;
1368}
1369
1370bool RE_RenderPassIsColor(const RenderPass *render_pass)
1371{
1372 return STR_ELEM(render_pass->chan_id, "RGB", "RGBA", "R", "G", "B", "A");
1373}
1374
const char * BKE_tempdir_base() ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition appdir.cc:1243
StampData * BKE_stamp_data_copy(const StampData *stamp_data)
void BKE_stamp_data_free(StampData *stamp_data)
char BKE_imtype_valid_depths(char imtype)
bool BKE_image_render_write_exr(ReportList *reports, const RenderResult *rr, const char *filepath, const ImageFormatData *imf, const bool save_as_render, const char *view, int layer)
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:892
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
Definition scene.cc:2988
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
char * BLI_hash_md5_to_hexdigest(const void *resblock, char r_hex_digest[33])
Definition hash_md5.cc:379
void * BLI_hash_md5_buffer(const char *buffer, size_t len, void *resblock)
Definition hash_md5.cc:343
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_freelinkN(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:270
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:332
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
int BLI_findstringindex(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:780
void void BLI_listbase_sort(ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
MINLINE void copy_v2_v2_db(double r[2], const double a[2])
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
bool bool BLI_path_extension_strip(char *path) ATTR_NONNULL(1)
#define FILE_MAXFILE
#define FILE_MAX
#define BLI_path_join(...)
void BLI_path_split_dir_file(const char *filepath, char *dir, size_t dir_maxncpy, char *file, size_t file_maxncpy) ATTR_NONNULL(1
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILE_MAXDIR
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
BLI_INLINE int BLI_rcti_cent_y(const struct rcti *rct)
Definition BLI_rect.h:181
BLI_INLINE int BLI_rcti_cent_x(const struct rcti *rct)
Definition BLI_rect.h:177
#define STR_ELEM(...)
Definition BLI_string.h:661
int bool bool bool size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf) ATTR_NONNULL(1
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:604
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
size_t BLI_string_join_array_by_sep_char(char *result, size_t result_maxncpy, char sep, const char *strings[], uint strings_num) ATTR_NONNULL()
unsigned char uchar
unsigned int uint
#define ARRAY_SET_ITEMS(...)
#define STREQ(a, b)
const char * dirname(char *path)
#define MAX_ID_NAME
Definition DNA_ID.h:373
#define RE_PASSNAME_COMBINED
#define STEREO_LEFT_NAME
@ SCE_LAY_FLAG_DEFAULT
#define RE_PASSNAME_VECTOR
#define RE_PASSNAME_DEPTH
@ R_IMF_PLANES_RGB
@ R_IMF_PLANES_RGBA
@ R_IMF_PLANES_BW
@ R_IMF_CHAN_DEPTH_24
@ R_IMF_CHAN_DEPTH_8
@ R_IMF_CHAN_DEPTH_16
@ R_IMF_CHAN_DEPTH_12
@ R_IMF_CHAN_DEPTH_32
#define STEREO_RIGHT_NAME
@ R_IMF_IMTYPE_MULTILAYER
@ SCE_PASS_COMBINED
@ R_MULTIVIEW
static AppView * view
@ GPU_DATA_FLOAT
@ GPU_TEXTURE_USAGE_GENERAL
blender::gpu::Texture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_update(blender::gpu::Texture *texture, eGPUDataFormat data_format, const void *data)
void IMB_colormanagement_assign_float_colorspace(ImBuf *ibuf, const char *name)
void IMB_colormanagement_transform_float(float *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide)
@ COLOR_ROLE_DATA
@ COLOR_ROLE_SCENE_LINEAR
const char * IMB_colormanagement_role_colorspace_name_get(int role)
void IMB_display_buffer_transform_apply(unsigned char *display_buffer, float *linear_buffer, int width, int height, int channels, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, bool predivide)
void IMB_free_gpu_textures(ImBuf *ibuf)
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
void IMB_assign_float_buffer(ImBuf *ibuf, float *buffer_data, ImBufOwnership ownership)
void IMB_color_to_bw(ImBuf *ibuf)
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
void IMB_free_float_pixels(ImBuf *ibuf)
void IMB_free_byte_pixels(ImBuf *ibuf)
void IMB_assign_byte_buffer(ImBuf *ibuf, uint8_t *buffer_data, ImBufOwnership ownership)
void IMB_float_from_byte(ImBuf *ibuf)
@ IB_DO_NOT_TAKE_OWNERSHIP
@ IB_TAKE_OWNERSHIP
ExrHandle * IMB_exr_get_handle(bool write_multipart=false)
#define EXR_LAY_MAXNAME
void IMB_exr_close(ExrHandle *handle)
#define EXR_PASS_MAXNAME
void IMB_exr_multilayer_convert(ExrHandle *handle, void *base, void *(*addview)(void *base, const char *str), void *(*addlayer)(void *base, const char *str), void(*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id, const char *view))
bool IMB_exr_get_ppm(ExrHandle *handle, double ppm[2])
void IMB_exr_read_channels(ExrHandle *handle)
bool IMB_exr_set_channel(ExrHandle *handle, blender::StringRefNull full_name, int xstride, int ystride, float *rect)
bool IMB_exr_begin_read(ExrHandle *handle, const char *filepath, int *width, int *height, bool parse_channels)
Read Guarded memory(de)allocation.
#define U
BMesh const char void * data
nullptr float
#define offsetof(t, d)
#define str(s)
#define printf(...)
const ccl_global KernelWorkTile * tile
format
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
const char * name
static void render_result_exr_file_cache_path(Scene *sce, const char *root, char r_path[FILE_CACHE_MAX])
static int order_render_passes(const void *a, const void *b)
bool render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, ReportList *reports, const char *filepath)
static void render_result_views_free(RenderResult *rr)
ImBuf * RE_RenderPassEnsureImBuf(RenderPass *render_pass)
void RE_pass_set_buffer_data(RenderPass *pass, float *data)
RenderView * RE_RenderViewGetByName(RenderResult *rr, const char *viewname)
void render_result_single_layer_end(Render *re)
bool RE_HasCombinedLayer(const RenderResult *result)
void render_result_exr_file_cache_write(Render *re)
void render_result_free_gpu_texture_caches(RenderResult *rr)
ImBuf * RE_RenderViewEnsureImBuf(const RenderResult *render_result, RenderView *render_view)
bool RE_RenderPassIsColor(const RenderPass *render_pass)
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)
blender::gpu::Texture * RE_pass_ensure_gpu_texture_cache(Render *re, RenderPass *rpass)
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)
bool RE_HasFloatPixels(const RenderResult *result)
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)
static void render_layer_allocate_pass(RenderResult *rr, RenderPass *rp)
static void assign_render_pass_ibuf_colorspace(RenderPass &render_pass)
void render_result_free(RenderResult *rr)
static RenderLayer * duplicate_render_layer(RenderLayer *rl)
static void * ml_addlayer_cb(void *base, const char *str)
void render_result_clone_passes(Render *re, RenderResult *rr, const char *viewname)
void render_result_free_list(ListBase *lb, RenderResult *rr)
void RE_render_result_full_channel_name(char *fullname, const char *layname, const char *passname, const char *viewname, const char *chan_id, const int channel)
RenderView * RE_RenderViewGetById(RenderResult *rr, const int view_id)
RenderResult * RE_DuplicateRenderResult(RenderResult *rr)
#define FILE_CACHE_MAX
static int passtype_from_name(const char *name)
static RenderView * duplicate_render_view(RenderView *rview)
void render_result_single_layer_begin(Render *re)
static void * ml_addview_cb(void *base, const char *str)
static void ml_addpass_cb(void *base, void *lay, const char *name, float *rect, int totchan, const char *chan_id, const char *view)
#define CHECK_PASS(NAME)
static RenderPass * duplicate_render_pass(RenderPass *rpass)
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)
static int get_num_planes_for_pass_ibuf(const RenderPass &render_pass)
RenderResult * render_result_new(Render *re, const rcti *partrct, const char *layername, const char *viewname)
bool RE_RenderResult_is_stereo(const RenderResult *result)
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)
RenderResult * render_result_new_from_exr(ExrHandle *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize)
void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src)
#define FOREACH_VIEW_LAYER_TO_RENDER_END
#define PASS_VECTOR_MAX
#define FOREACH_VIEW_LAYER_TO_RENDER_BEGIN(re_, iter_)
void RE_FreeRenderResult(RenderResult *rr)
RenderLayer * RE_GetRenderLayer(RenderResult *rr, const char *name)
RenderResult * result
char name[258]
Definition DNA_ID.h:432
blender::gpu::Texture * texture
ImBufGPU gpu
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
double ppm[2]
void * last
void * first
ListBase passes
Definition RE_pipeline.h:94
char name[RE_MAXNAME]
Definition RE_pipeline.h:89
struct RenderLayer * next
Definition RE_pipeline.h:86
struct RenderLayer * prev
Definition RE_pipeline.h:86
char chan_id[24]
Definition RE_pipeline.h:56
struct ImBuf * ibuf
Definition RE_pipeline.h:67
char name[64]
Definition RE_pipeline.h:55
char fullname[64]
Definition RE_pipeline.h:71
char view[64]
Definition RE_pipeline.h:72
struct RenderPass * prev
Definition RE_pipeline.h:53
struct RenderPass * next
Definition RE_pipeline.h:53
struct RenderResult * next
Definition RE_pipeline.h:98
ListBase views
ListBase layers
struct RenderResult * prev
Definition RE_pipeline.h:98
struct StampData * stamp_data
bool passes_allocated
double ppm[2]
struct ImBuf * ibuf
struct ImBuf * ibuf
Definition RE_pipeline.h:49
char name[64]
Definition RE_pipeline.h:42
bool result_has_gpu_texture_caches
RenderResult * pushedresult
RenderData r
Scene * scene
char single_view_layer[MAX_NAME]
rcti disprect
ListBase view_layers
int ymin
int ymax
int xmin
int xmax
uint len