From 02633498fde745615e069daee82c201338fde6d3 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 16 Jan 2024 19:37:50 +0100 Subject: [PATCH 1/2] Fix incorrect number of planes for ImBuf used for render passes Set the number of planes based on the number of pass channels. If the pass contains 2 passes or more than 4 passes set the number of planes to the previously used value of 32. This is needed because quite some areas check for the number of planes for various optimizations. For example, this is one of the factors which make IMB_create_gpu_texture() to choose the texture format. If the number of planes for the depth pass is set to the previously used this function will never consider using single channel GPU texture. Unfortunately, this change is not enough to make the GPU texture to use single channel format as the color space of the image buffer is also checked, and that is nullptr which means scene linear. --- source/blender/render/intern/render_result.cc | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/source/blender/render/intern/render_result.cc b/source/blender/render/intern/render_result.cc index 5e70e2a4186..0b78213ee02 100644 --- a/source/blender/render/intern/render_result.cc +++ b/source/blender/render/intern/render_result.cc @@ -167,6 +167,21 @@ void render_result_views_shallowdelete(RenderResult *rr) /** \name New * \{ */ +static int get_num_planes_for_pass_ibuf(const RenderPass &render_pass) +{ + switch (render_pass.channels) { + case 1: + return R_IMF_PLANES_BW; + case 3: + return R_IMF_PLANES_RGB; + case 4: + return R_IMF_PLANES_RGBA; + } + + /* Fallback to a commonly used default value of planes for odd-ball number of channel. */ + return R_IMF_PLANES_RGBA; +} + static void render_layer_allocate_pass(RenderResult *rr, RenderPass *rp) { if (rp->ibuf && rp->ibuf->float_buffer.data) { @@ -179,7 +194,7 @@ static void render_layer_allocate_pass(RenderResult *rr, RenderPass *rp) const size_t rectsize = size_t(rr->rectx) * rr->recty * rp->channels; float *buffer_data = MEM_cnew_array(rectsize, rp->name); - rp->ibuf = IMB_allocImBuf(rr->rectx, rr->recty, 32, 0); + rp->ibuf = IMB_allocImBuf(rr->rectx, rr->recty, get_num_planes_for_pass_ibuf(*rp), 0); rp->ibuf->channels = rp->channels; IMB_assign_float_buffer(rp->ibuf, buffer_data, IB_TAKE_OWNERSHIP); @@ -1302,7 +1317,8 @@ RenderResult *RE_DuplicateRenderResult(RenderResult *rr) ImBuf *RE_RenderPassEnsureImBuf(RenderPass *render_pass) { if (!render_pass->ibuf) { - render_pass->ibuf = IMB_allocImBuf(render_pass->rectx, render_pass->recty, 32, 0); + render_pass->ibuf = IMB_allocImBuf( + render_pass->rectx, render_pass->recty, get_num_planes_for_pass_ibuf(*render_pass), 0); render_pass->ibuf->channels = render_pass->channels; } -- 2.30.2 From 3208a1818a3c8b927e2245a8a94f744255528391 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 16 Jan 2024 20:24:12 +0100 Subject: [PATCH 2/2] Render: Set non-color colorspace for ImBuf of data passes This allows code outside of the render pipeline to make proper decisions about how the imbuf of render passes are to be handled. For example, IMB_create_gpu_texture() will now properly select single channel grayscale texture format for depth pass coming from multilayer EXR, additionally solving assert in the GPU compositor code which verifies expected and actual imbuf texture format. --- .../blender/blenkernel/intern/image_save.cc | 2 +- source/blender/render/RE_pipeline.h | 3 +++ source/blender/render/intern/render_result.cc | 23 ++++++++++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index fa07199c356..115e8386629 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -813,7 +813,7 @@ bool BKE_image_render_write_exr(ReportList *reports, /* We only store RGBA passes as half float, for * others precision loss can be problematic. */ - const bool pass_RGBA = STR_ELEM(rp->chan_id, "RGB", "RGBA", "R", "G", "B", "A"); + const bool pass_RGBA = RE_RenderPassIsColor(rp); const bool pass_half_float = half_float && pass_RGBA; /* Color-space conversion only happens on RGBA passes. */ diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h index b07f8868db5..88af53e3ab2 100644 --- a/source/blender/render/RE_pipeline.h +++ b/source/blender/render/RE_pipeline.h @@ -502,6 +502,9 @@ RenderResult *RE_DuplicateRenderResult(RenderResult *rr); struct ImBuf *RE_RenderPassEnsureImBuf(RenderPass *render_pass); struct ImBuf *RE_RenderViewEnsureImBuf(const RenderResult *render_result, RenderView *render_view); +/* Returns true if the pass is a color (as opposite of data) and needs to be color managed. */ +bool RE_RenderPassIsColor(const RenderPass *render_pass); + #ifdef __cplusplus } #endif diff --git a/source/blender/render/intern/render_result.cc b/source/blender/render/intern/render_result.cc index 0b78213ee02..a14957a3bdd 100644 --- a/source/blender/render/intern/render_result.cc +++ b/source/blender/render/intern/render_result.cc @@ -182,6 +182,16 @@ static int get_num_planes_for_pass_ibuf(const RenderPass &render_pass) return R_IMF_PLANES_RGBA; } +static void assign_render_pass_ibuf_colorspace(RenderPass &render_pass) +{ + if (RE_RenderPassIsColor(&render_pass)) { + return; + } + + const char *data_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DATA); + IMB_colormanagement_assign_float_colorspace(render_pass.ibuf, data_colorspace); +} + static void render_layer_allocate_pass(RenderResult *rr, RenderPass *rp) { if (rp->ibuf && rp->ibuf->float_buffer.data) { @@ -197,6 +207,7 @@ static void render_layer_allocate_pass(RenderResult *rr, RenderPass *rp) rp->ibuf = IMB_allocImBuf(rr->rectx, rr->recty, get_num_planes_for_pass_ibuf(*rp), 0); rp->ibuf->channels = rp->channels; IMB_assign_float_buffer(rp->ibuf, buffer_data, IB_TAKE_OWNERSHIP); + assign_render_pass_ibuf_colorspace(*rp); if (STREQ(rp->name, RE_PASSNAME_VECTOR)) { /* initialize to max speed */ @@ -695,6 +706,7 @@ RenderResult *render_result_new_from_exr( RenderResult *rr = MEM_cnew(__func__); const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get( COLOR_ROLE_SCENE_LINEAR); + const char *data_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DATA); rr->rectx = rectx; rr->recty = recty; @@ -711,7 +723,7 @@ RenderResult *render_result_new_from_exr( rpass->rectx = rectx; rpass->recty = recty; - if (rpass->channels >= 3) { + if (RE_RenderPassIsColor(rpass)) { IMB_colormanagement_transform(rpass->ibuf->float_buffer.data, rpass->rectx, rpass->recty, @@ -720,6 +732,9 @@ RenderResult *render_result_new_from_exr( to_colorspace, predivide); } + else { + IMB_colormanagement_assign_float_colorspace(rpass->ibuf, data_colorspace); + } } } @@ -1320,6 +1335,7 @@ ImBuf *RE_RenderPassEnsureImBuf(RenderPass *render_pass) render_pass->ibuf = IMB_allocImBuf( render_pass->rectx, render_pass->recty, get_num_planes_for_pass_ibuf(*render_pass), 0); render_pass->ibuf->channels = render_pass->channels; + assign_render_pass_ibuf_colorspace(*render_pass); } return render_pass->ibuf; @@ -1334,4 +1350,9 @@ ImBuf *RE_RenderViewEnsureImBuf(const RenderResult *render_result, RenderView *r return render_view->ibuf; } +bool RE_RenderPassIsColor(const RenderPass *render_pass) +{ + return STR_ELEM(render_pass->chan_id, "RGB", "RGBA", "R", "G", "B", "A"); +} + /** \} */ -- 2.30.2