From 1520d9148fb66b7c683e1a4628984f70224de7f5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 1 May 2023 14:24:00 +0200 Subject: [PATCH 1/4] Refactor Render Result to allow implicit buffer sharing Allows to share buffer data between the render result and image buffers. The storage of the passes and buffers in the render result have been wrapped into utility structures, with functions to operate on them. Currently only image buffers which are sharing buffers with the render results are using the implicit sharing. This allows proper decoupling of the image buffers from the lifetime of the underlying render result. Fixes #107248: Compositor ACCESS VIOLATION when updating datablocks from handlers Additionally, this lowers the memory usage of multi-layer EXR sequences by avoiding having two copies of render passes in memory. It is possible to use implicit sharing in more places, but needs some API to ensure the render result is the only owner of data before writing to its pixels. --- source/blender/blenkernel/intern/image.cc | 63 ++-- .../blender/blenkernel/intern/image_save.cc | 20 +- .../operations/COM_CompositorOperation.cc | 11 +- .../draw/engines/eevee/eevee_cryptomatte.c | 13 +- .../blender/draw/engines/eevee/eevee_render.c | 2 +- .../draw/engines/eevee_next/eevee_instance.cc | 5 +- .../draw/engines/gpencil/gpencil_render.c | 23 +- .../engines/workbench/workbench_engine.cc | 8 +- .../draw/engines/workbench/workbench_render.c | 19 +- .../interface/eyedroppers/eyedropper_color.cc | 2 +- .../blender/editors/render/render_internal.cc | 6 +- .../blender/editors/render/render_opengl.cc | 28 +- .../blender/editors/render/render_preview.cc | 9 +- .../editors/space_image/image_buttons.c | 4 +- .../blender_interface/FRS_freestyle.cpp | 5 +- source/blender/imbuf/IMB_imbuf.h | 15 + source/blender/imbuf/IMB_imbuf_types.h | 13 +- source/blender/imbuf/intern/allocimbuf.cc | 75 ++++- source/blender/makesdna/intern/makesdna.c | 2 +- source/blender/makesrna/intern/rna_render.c | 6 +- source/blender/render/RE_pipeline.h | 86 ++++- source/blender/render/intern/engine.cc | 6 +- source/blender/render/intern/pipeline.cc | 73 +++-- source/blender/render/intern/render_result.cc | 301 +++++++++++++----- source/blender/sequencer/intern/render.c | 23 +- 25 files changed, 581 insertions(+), 237 deletions(-) diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index 19a00ac977c..3348b1443e4 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -3989,12 +3989,11 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int e if (rpass) { // printf("load from pass %s\n", rpass->name); - /* since we free render results, we copy the rect */ ibuf = IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0); - IMB_assign_float_buffer( - ibuf, static_cast(MEM_dupallocN(rpass->rect)), IB_TAKE_OWNERSHIP); ibuf->channels = rpass->channels; + IMB_assign_shared_float_buffer(ibuf, rpass->buffer.data, rpass->buffer.sharing_info); + BKE_imbuf_stamp_info(ima->rr, ibuf); image_init_after_load(ima, iuser, ibuf); @@ -4301,7 +4300,8 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser) image_init_after_load(ima, iuser, ibuf); - IMB_assign_float_buffer(ibuf, rpass->rect, IB_DO_NOT_TAKE_OWNERSHIP); + IMB_assign_shared_float_buffer(ibuf, rpass->buffer.data, rpass->buffer.sharing_info); + ibuf->channels = rpass->channels; BKE_imbuf_stamp_info(ima->rr, ibuf); @@ -4320,8 +4320,8 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc { Render *re; RenderView *rv; - float *rectf, *rectz; - uint *rect; + RenderBuffer *combined_buffer, *z_buffer; + RenderByteBuffer *byte_buffer; float dither; int channels, layer, pass; ImBuf *ibuf; @@ -4355,7 +4355,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc } else if ((slot = BKE_image_get_renderslot(ima, ima->render_slot))->render) { rres = *(slot->render); - rres.have_combined = ((RenderView *)rres.views.first)->rectf != nullptr; + rres.have_combined = ((RenderView *)rres.views.first)->combined_buffer.data != nullptr; } if (!(rres.rectx > 0 && rres.recty > 0)) { @@ -4380,14 +4380,14 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc /* this gives active layer, composite or sequence result */ if (rv == nullptr) { - rect = (uint *)rres.rect32; - rectf = rres.rectf; - rectz = rres.rectz; + byte_buffer = &rres.byte_buffer; + combined_buffer = &rres.combined_buffer; + z_buffer = &rres.z_buffer; } else { - rect = (uint *)rv->rect32; - rectf = rv->rectf; - rectz = rv->rectz; + byte_buffer = &rv->byte_buffer; + combined_buffer = &rv->combined_buffer; + z_buffer = &rv->z_buffer; } dither = iuser->scene->r.dither_intensity; @@ -4396,13 +4396,13 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc if (rres.have_combined && layer == 0) { /* pass */ } - else if (rect && layer == 0) { + else if (byte_buffer && byte_buffer->data && layer == 0) { /* rect32 is set when there's a Sequence pass, this pass seems * to have layer=0 (this is from image_buttons.c) * in this case we ignore float buffer, because it could have * hung from previous pass which was float */ - rectf = nullptr; + combined_buffer = nullptr; } else if (rres.layers.first) { RenderLayer *rl = static_cast( @@ -4410,7 +4410,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc if (rl) { RenderPass *rpass = image_render_pass_get(rl, pass, actview, nullptr); if (rpass) { - rectf = rpass->rect; + combined_buffer = &rpass->buffer; if (pass != 0) { channels = rpass->channels; dither = 0.0f; /* don't dither passes */ @@ -4419,7 +4419,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc for (rpass = static_cast(rl->passes.first); rpass; rpass = rpass->next) { if (STREQ(rpass->name, RE_PASSNAME_Z) && rpass->view_id == actview) { - rectz = rpass->rect; + z_buffer = &rpass->buffer; } } } @@ -4441,14 +4441,16 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc * * For other cases we need to be sure it stays to default byte buffer space. */ - if (ibuf->byte_buffer.data != (uint8_t *)rect) { + if (ibuf->byte_buffer.data != byte_buffer->data) { const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE); IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace); } /* invalidate color managed buffers if render result changed */ BLI_thread_lock(LOCK_COLORMANAGE); - if (ibuf->x != rres.rectx || ibuf->y != rres.recty || ibuf->float_buffer.data != rectf) { + if (combined_buffer && (ibuf->x != rres.rectx || ibuf->y != rres.recty || + ibuf->float_buffer.data != combined_buffer->data)) + { ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; } @@ -4458,9 +4460,26 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc imb_freerectImBuf(ibuf); - IMB_assign_byte_buffer(ibuf, (uint8_t *)rect, IB_DO_NOT_TAKE_OWNERSHIP); - IMB_assign_float_buffer(ibuf, rectf, IB_DO_NOT_TAKE_OWNERSHIP); - IMB_assign_float_z_buffer(ibuf, rectz, IB_DO_NOT_TAKE_OWNERSHIP); + if (byte_buffer) { + IMB_assign_shared_byte_buffer(ibuf, byte_buffer->data, byte_buffer->sharing_info); + } + else { + IMB_assign_byte_buffer(ibuf, nullptr, IB_DO_NOT_TAKE_OWNERSHIP); + } + + if (combined_buffer) { + IMB_assign_shared_float_buffer(ibuf, combined_buffer->data, combined_buffer->sharing_info); + } + else { + IMB_assign_float_buffer(ibuf, nullptr, IB_DO_NOT_TAKE_OWNERSHIP); + } + + if (z_buffer) { + IMB_assign_shared_float_z_buffer(ibuf, z_buffer->data, z_buffer->sharing_info); + } + else { + IMB_assign_float_z_buffer(ibuf, nullptr, IB_DO_NOT_TAKE_OWNERSHIP); + } /* TODO(sergey): Make this faster by either simply referencing the stamp * or by changing both ImBuf and RenderResult to use same data type to diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index b0ee3f729a8..c9dcca9b86d 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -738,7 +738,7 @@ bool BKE_image_render_write_exr(ReportList *reports, /* Compositing result. */ if (rr->have_combined) { LISTBASE_FOREACH (RenderView *, rview, &rr->views) { - if (!rview->rectf) { + if (!rview->combined_buffer.data) { continue; } @@ -756,10 +756,11 @@ bool BKE_image_render_write_exr(ReportList *reports, continue; } - float *output_rect = (save_as_render) ? - image_exr_from_scene_linear_to_output( - rview->rectf, rr->rectx, rr->recty, 4, imf, tmp_output_rects) : - rview->rectf; + float *output_rect = + (save_as_render) ? + image_exr_from_scene_linear_to_output( + rview->combined_buffer.data, rr->rectx, rr->recty, 4, imf, tmp_output_rects) : + rview->combined_buffer.data; for (int a = 0; a < channels; a++) { char passname[EXR_PASS_MAXNAME]; @@ -781,9 +782,10 @@ bool BKE_image_render_write_exr(ReportList *reports, exrhandle, layname, passname, viewname, 4, 4 * rr->rectx, output_rect + a, half_float); } - if (write_z && rview->rectz) { + if (write_z && rview->z_buffer.data) { const char *layname = (multi_layer) ? "Composite" : ""; - IMB_exr_add_channel(exrhandle, layname, "Z", viewname, 1, rr->rectx, rview->rectz, false); + IMB_exr_add_channel( + exrhandle, layname, "Z", viewname, 1, rr->rectx, rview->z_buffer.data, false); } } } @@ -825,8 +827,8 @@ bool BKE_image_render_write_exr(ReportList *reports, float *output_rect = (save_as_render && pass_RGBA) ? image_exr_from_scene_linear_to_output( - rp->rect, rr->rectx, rr->recty, rp->channels, imf, tmp_output_rects) : - rp->rect; + rp->buffer.data, rr->rectx, rr->recty, rp->channels, imf, tmp_output_rects) : + rp->buffer.data; for (int a = 0; a < std::min(channels, rp->channels); a++) { /* Save Combined as RGBA or RGB if single layer save. */ diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cc b/source/blender/compositor/operations/COM_CompositorOperation.cc index 587f661646a..e8338c642ed 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.cc +++ b/source/blender/compositor/operations/COM_CompositorOperation.cc @@ -67,14 +67,9 @@ void CompositorOperation::deinit_execution() if (rr) { RenderView *rv = RE_RenderViewGetByName(rr, view_name_); - if (rv->rectf != nullptr) { - MEM_freeN(rv->rectf); - } - rv->rectf = output_buffer_; - if (rv->rectz != nullptr) { - MEM_freeN(rv->rectz); - } - rv->rectz = depth_buffer_; + RE_RenderBuffer_assign_data(&rv->combined_buffer, output_buffer_); + RE_RenderBuffer_assign_data(&rv->z_buffer, depth_buffer_); + rr->have_combined = true; } else { diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c index 003f36d18f5..1a0d112cd84 100644 --- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c +++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c @@ -582,6 +582,7 @@ static void eevee_cryptomatte_extract_render_passes( const int pass_offset = pass * 2; SNPRINTF_RLEN(cryptomatte_pass_name, render_pass_name_format, pass); RenderPass *rp_object = RE_pass_find_by_name(rl, cryptomatte_pass_name, viewname); + float *rp_buffer_data = rp_object->buffer.data; for (int y = 0; y < rect_height; y++) { for (int x = 0; x < rect_width; x++) { const int accum_buffer_offset = (rect_offset_x + x + @@ -589,15 +590,15 @@ static void eevee_cryptomatte_extract_render_passes( accum_pixel_stride + layer_index * layer_stride + pass_offset; const int render_pass_offset = (y * rect_width + x) * 4; - rp_object->rect[render_pass_offset] = accum_buffer[accum_buffer_offset].hash; - rp_object->rect[render_pass_offset + 1] = accum_buffer[accum_buffer_offset].weight; + rp_buffer_data[render_pass_offset] = accum_buffer[accum_buffer_offset].hash; + rp_buffer_data[render_pass_offset + 1] = accum_buffer[accum_buffer_offset].weight; if (levels_done + 1 < num_cryptomatte_levels) { - rp_object->rect[render_pass_offset + 2] = accum_buffer[accum_buffer_offset + 1].hash; - rp_object->rect[render_pass_offset + 3] = accum_buffer[accum_buffer_offset + 1].weight; + rp_buffer_data[render_pass_offset + 2] = accum_buffer[accum_buffer_offset + 1].hash; + rp_buffer_data[render_pass_offset + 3] = accum_buffer[accum_buffer_offset + 1].weight; } else { - rp_object->rect[render_pass_offset + 2] = 0.0f; - rp_object->rect[render_pass_offset + 3] = 0.0f; + rp_buffer_data[render_pass_offset + 2] = 0.0f; + rp_buffer_data[render_pass_offset + 3] = 0.0f; } } } diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 8a79d80c2e9..16f9be3f7c5 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -271,7 +271,7 @@ static void eevee_render_color_result(RenderLayer *rl, num_channels, 0, GPU_DATA_FLOAT, - rp->rect); + rp->buffer.data); } static void eevee_render_result_combined(RenderLayer *rl, diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 95bcf92d32c..575ef7a086d 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -276,8 +276,7 @@ void Instance::render_read_result(RenderLayer *render_layer, const char *view_na * However, on some implementation, we need a buffer with a few extra bytes for the read to * happen correctly (see GLTexture::read()). So we need a custom memory allocation. */ /* Avoid memcpy(), replace the pointer directly. */ - MEM_SAFE_FREE(rp->rect); - rp->rect = result; + RE_pass_set_buffer_data(rp, result); BLI_mutex_unlock(&render->update_render_passes_mutex); } } @@ -291,7 +290,7 @@ void Instance::render_read_result(RenderLayer *render_layer, const char *view_na RenderPass *vector_rp = RE_pass_find_by_name( render_layer, vector_pass_name.c_str(), view_name); if (vector_rp) { - memset(vector_rp->rect, 0, sizeof(float) * 4 * vector_rp->rectx * vector_rp->recty); + memset(vector_rp->buffer.data, 0, sizeof(float) * 4 * vector_rp->rectx * vector_rp->recty); } } } diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c index 869462adc6f..9e945bdbad2 100644 --- a/source/blender/draw/engines/gpencil/gpencil_render.c +++ b/source/blender/draw/engines/gpencil/gpencil_render.c @@ -49,8 +49,8 @@ void GPENCIL_render_init(GPENCIL_Data *vedata, RenderPass *rpass_z_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname); RenderPass *rpass_col_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname); - float *pix_z = (rpass_z_src) ? rpass_z_src->rect : NULL; - float *pix_col = (rpass_col_src) ? rpass_col_src->rect : NULL; + float *pix_z = (rpass_z_src) ? rpass_z_src->buffer.data : NULL; + float *pix_col = (rpass_col_src) ? rpass_col_src->buffer.data : NULL; if (!pix_z || !pix_col) { RE_engine_set_error_message(engine, @@ -160,6 +160,7 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl, if ((view_layer->passflag & SCE_PASS_Z) != 0) { RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname); + float *ro_buffer_data = rp->buffer.data; GPU_framebuffer_read_depth(vedata->fbl->render_fb, rect->xmin, @@ -167,7 +168,7 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), GPU_DATA_FLOAT, - rp->rect); + ro_buffer_data); float winmat[4][4]; DRW_view_winmat_get(NULL, winmat, false); @@ -177,12 +178,12 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl, /* Convert GPU depth [0..1] to view Z [near..far] */ if (DRW_view_is_persp_get(NULL)) { for (int i = 0; i < pix_num; i++) { - if (rp->rect[i] == 1.0f) { - rp->rect[i] = 1e10f; /* Background */ + if (ro_buffer_data[i] == 1.0f) { + ro_buffer_data[i] = 1e10f; /* Background */ } else { - rp->rect[i] = rp->rect[i] * 2.0f - 1.0f; - rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]); + ro_buffer_data[i] = ro_buffer_data[i] * 2.0f - 1.0f; + ro_buffer_data[i] = winmat[3][2] / (ro_buffer_data[i] + winmat[2][2]); } } } @@ -193,11 +194,11 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl, float range = fabsf(far - near); for (int i = 0; i < pix_num; i++) { - if (rp->rect[i] == 1.0f) { - rp->rect[i] = 1e10f; /* Background */ + if (ro_buffer_data[i] == 1.0f) { + ro_buffer_data[i] = 1e10f; /* Background */ } else { - rp->rect[i] = rp->rect[i] * range - near; + ro_buffer_data[i] = ro_buffer_data[i] * range - near; } } } @@ -221,7 +222,7 @@ static void GPENCIL_render_result_combined(struct RenderLayer *rl, 4, 0, GPU_DATA_FLOAT, - rp->rect); + rp->buffer.data); } void GPENCIL_render_to_image(void *ved, diff --git a/source/blender/draw/engines/workbench/workbench_engine.cc b/source/blender/draw/engines/workbench/workbench_engine.cc index 6bf78addd65..e9cf0604300 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.cc +++ b/source/blender/draw/engines/workbench/workbench_engine.cc @@ -552,7 +552,7 @@ static void write_render_color_output(struct RenderLayer *layer, 4, 0, GPU_DATA_FLOAT, - rp->rect); + rp->buffer.data); } } @@ -571,13 +571,13 @@ static void write_render_z_output(struct RenderLayer *layer, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), GPU_DATA_FLOAT, - rp->rect); + rp->buffer.data); int pix_num = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect); /* Convert GPU depth [0..1] to view Z [near..far] */ if (DRW_view_is_persp_get(nullptr)) { - for (float &z : MutableSpan(rp->rect, pix_num)) { + for (float &z : MutableSpan(rp->buffer.data, pix_num)) { if (z == 1.0f) { z = 1e10f; /* Background */ } @@ -593,7 +593,7 @@ static void write_render_z_output(struct RenderLayer *layer, float far = DRW_view_far_distance_get(nullptr); float range = fabsf(far - near); - for (float &z : MutableSpan(rp->rect, pix_num)) { + for (float &z : MutableSpan(rp->buffer.data, pix_num)) { if (z == 1.0f) { z = 1e10f; /* Background */ } diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c index 92daa35476d..8774a8c60e0 100644 --- a/source/blender/draw/engines/workbench/workbench_render.c +++ b/source/blender/draw/engines/workbench/workbench_render.c @@ -105,6 +105,7 @@ static void workbench_render_result_z(struct RenderLayer *rl, if ((view_layer->passflag & SCE_PASS_Z) != 0) { RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname); + float *rp_buffer_data = rp->buffer.data; GPU_framebuffer_bind(dfbl->default_fb); GPU_framebuffer_read_depth(dfbl->default_fb, @@ -113,7 +114,7 @@ static void workbench_render_result_z(struct RenderLayer *rl, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), GPU_DATA_FLOAT, - rp->rect); + rp_buffer_data); float winmat[4][4]; DRW_view_winmat_get(NULL, winmat, false); @@ -123,12 +124,12 @@ static void workbench_render_result_z(struct RenderLayer *rl, /* Convert GPU depth [0..1] to view Z [near..far] */ if (DRW_view_is_persp_get(NULL)) { for (int i = 0; i < pix_num; i++) { - if (rp->rect[i] == 1.0f) { - rp->rect[i] = 1e10f; /* Background */ + if (rp_buffer_data[i] == 1.0f) { + rp_buffer_data[i] = 1e10f; /* Background */ } else { - rp->rect[i] = rp->rect[i] * 2.0f - 1.0f; - rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]); + rp_buffer_data[i] = rp_buffer_data[i] * 2.0f - 1.0f; + rp_buffer_data[i] = winmat[3][2] / (rp_buffer_data[i] + winmat[2][2]); } } } @@ -139,11 +140,11 @@ static void workbench_render_result_z(struct RenderLayer *rl, float range = fabsf(far - near); for (int i = 0; i < pix_num; i++) { - if (rp->rect[i] == 1.0f) { - rp->rect[i] = 1e10f; /* Background */ + if (rp_buffer_data[i] == 1.0f) { + rp_buffer_data[i] = 1e10f; /* Background */ } else { - rp->rect[i] = rp->rect[i] * range - near; + rp_buffer_data[i] = rp_buffer_data[i] * range - near; } } } @@ -208,7 +209,7 @@ void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer 4, 0, GPU_DATA_FLOAT, - rp->rect); + rp->buffer.data); workbench_render_result_z(render_layer, viewname, rect); } diff --git a/source/blender/editors/interface/eyedroppers/eyedropper_color.cc b/source/blender/editors/interface/eyedroppers/eyedropper_color.cc index a9b4db328ee..a5e09d4166c 100644 --- a/source/blender/editors/interface/eyedroppers/eyedropper_color.cc +++ b/source/blender/editors/interface/eyedroppers/eyedropper_color.cc @@ -181,7 +181,7 @@ static bool eyedropper_cryptomatte_sample_renderlayer_fl(RenderLayer *render_lay const int y = int(fpos[1] * render_pass->recty); const int offset = 4 * (y * render_pass->rectx + x); zero_v3(r_col); - r_col[0] = render_pass->rect[offset]; + r_col[0] = render_pass->buffer.data[offset]; return true; } } diff --git a/source/blender/editors/render/render_internal.cc b/source/blender/editors/render/render_internal.cc index 63f52dcaec4..e29ee66eb57 100644 --- a/source/blender/editors/render/render_internal.cc +++ b/source/blender/editors/render/render_internal.cc @@ -207,11 +207,11 @@ static void image_buffer_rect_update(RenderJob *rj, rv = RE_RenderViewGetById(rr, view_id); /* find current float rect for display, first case is after composite... still weak */ - if (rv->rectf) { - rectf = rv->rectf; + if (rv->combined_buffer.data) { + rectf = rv->combined_buffer.data; } else { - if (rv->rect32) { + if (rv->byte_buffer.data) { /* special case, currently only happens with sequencer rendering, * which updates the whole frame, so we can only mark display buffer * as invalid here (sergey) diff --git a/source/blender/editors/render/render_opengl.cc b/source/blender/editors/render/render_opengl.cc index 702a78deec5..58f29fd5f82 100644 --- a/source/blender/editors/render/render_opengl.cc +++ b/source/blender/editors/render/render_opengl.cc @@ -193,17 +193,9 @@ static void screen_opengl_views_setup(OGLRender *oglrender) RenderView *rv_del = rv->next; BLI_remlink(&rr->views, rv_del); - if (rv_del->rectf) { - MEM_freeN(rv_del->rectf); - } - - if (rv_del->rectz) { - MEM_freeN(rv_del->rectz); - } - - if (rv_del->rect32) { - MEM_freeN(rv_del->rect32); - } + RE_RenderBuffer_data_free(&rv_del->combined_buffer); + RE_RenderBuffer_data_free(&rv_del->z_buffer); + RE_RenderByteBuffer_data_free(&rv_del->byte_buffer); MEM_freeN(rv_del); } @@ -227,17 +219,9 @@ static void screen_opengl_views_setup(OGLRender *oglrender) BLI_remlink(&rr->views, rv_del); - if (rv_del->rectf) { - MEM_freeN(rv_del->rectf); - } - - if (rv_del->rectz) { - MEM_freeN(rv_del->rectz); - } - - if (rv_del->rect32) { - MEM_freeN(rv_del->rect32); - } + RE_RenderBuffer_data_free(&rv_del->combined_buffer); + RE_RenderBuffer_data_free(&rv_del->z_buffer); + RE_RenderByteBuffer_data_free(&rv_del->byte_buffer); MEM_freeN(rv_del); } diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc index db1baf20804..9d1c4412243 100644 --- a/source/blender/editors/render/render_preview.cc +++ b/source/blender/editors/render/render_preview.cc @@ -666,7 +666,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect rv = nullptr; } - if (rv && rv->rectf) { + if (rv && rv->combined_buffer.data) { if (abs(rres.rectx - newx) < 2 && abs(rres.recty - newy) < 2) { @@ -1073,8 +1073,9 @@ static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Rend /* Create buffer in empty RenderView created in the init step. */ RenderResult *rr = RE_AcquireResultWrite(re); RenderView *rv = (RenderView *)rr->views.first; - rv->rectf = static_cast( - MEM_callocN(sizeof(float[4]) * width * height, "texture render result")); + RE_RenderBuffer_assign_data(&rv->combined_buffer, + static_cast(MEM_callocN(sizeof(float[4]) * width * height, + "texture render result"))); RE_ReleaseResult(re); /* Get texture image pool (if any) */ @@ -1082,7 +1083,7 @@ static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Rend BKE_texture_fetch_images_for_pool(tex, img_pool); /* Fill in image buffer. */ - float *rect_float = rv->rectf; + float *rect_float = rv->combined_buffer.data; float tex_coord[3] = {0.0f, 0.0f, 0.0f}; bool color_manage = true; diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 9ed30666676..2b502e0dafc 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -127,10 +127,10 @@ static bool ui_imageuser_slot_menu_step(bContext *C, int direction, void *image_ static const char *ui_imageuser_layer_fake_name(RenderResult *rr) { RenderView *rv = RE_RenderViewGetById(rr, 0); - if (rv->rectf) { + if (rv->combined_buffer.data) { return IFACE_("Composite"); } - if (rv->rect32) { + if (rv->byte_buffer.data) { return IFACE_("Sequence"); } return NULL; diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp index a547c201f58..f42a05b37fb 100644 --- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp +++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp @@ -445,12 +445,13 @@ static void prepare(Render *re, ViewLayer *view_layer, Depsgraph *depsgraph) RenderLayer *rl = RE_GetRenderLayer(re->result, view_layer->name); bool diffuse = false, z = false; for (RenderPass *rpass = (RenderPass *)rl->passes.first; rpass; rpass = rpass->next) { + float *rpass_buffer_data = rpass->buffer.data; if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE_COLOR)) { - controller->setPassDiffuse(rpass->rect, rpass->rectx, rpass->recty); + controller->setPassDiffuse(rpass_buffer_data, rpass->rectx, rpass->recty); diffuse = true; } if (STREQ(rpass->name, RE_PASSNAME_Z)) { - controller->setPassZ(rpass->rect, rpass->rectx, rpass->recty); + controller->setPassZ(rpass_buffer_data, rpass->rectx, rpass->recty); z = true; } } diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 272293f4198..98de8c615b1 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -43,6 +43,7 @@ #include "../blenlib/BLI_sys_types.h" #include "../gpu/GPU_texture.h" +#include "BLI_implicit_sharing.h" #include "IMB_imbuf_types.h" #ifdef __cplusplus @@ -148,6 +149,20 @@ struct ImBuf *IMB_allocFromBuffer(const uint8_t *byte_buffer, unsigned int h, unsigned int channels); +/* Assign the content of the corresponding buffer using an implicitly shareable data pointer. + * + * NOTE: Does not modify the the topology (width, height, number of channels) or the mipmaps in any + * way. */ +void IMB_assign_shared_byte_buffer(struct ImBuf *ibuf, + uint8_t *buffer_data, + const ImplicitSharingInfoHandle *implicit_sharing); +void IMB_assign_shared_float_buffer(struct ImBuf *ibuf, + float *buffer_data, + const ImplicitSharingInfoHandle *implicit_sharing); +void IMB_assign_shared_float_z_buffer(struct ImBuf *ibuf, + float *buffer_data, + const ImplicitSharingInfoHandle *implicit_sharing); + /* Assign the content of the corresponding buffer with the given data and ownership. * The current content of the buffer is released corresponding to its ownership configuration. * diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 5da3f9af3cb..2590f339510 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -3,6 +3,8 @@ #pragma once +#include "BLI_implicit_sharing.h" + #include "DNA_vec_types.h" /* for rcti */ #include "BLI_sys_types.h" @@ -169,22 +171,31 @@ typedef enum ImBufOwnership { IB_TAKE_OWNERSHIP = 1, } ImBufOwnership; -/* Different storage specialization. */ +/* Different storage specialization. + * + * Note on the implicit sharing + * ---------------------------- + * + * The buffer allows to implicitly share data with other users of such data. In this case the + * ownership is set to IB_DO_NOT_TAKE_OWNERSHIP. */ /* TODO(sergey): Once everything is C++ replace with a template. */ typedef struct ImBufIntBuffer { int *data; ImBufOwnership ownership; + const ImplicitSharingInfoHandle *implicit_sharing; } ImBufIntBuffer; typedef struct ImBufByteBuffer { uint8_t *data; ImBufOwnership ownership; + const ImplicitSharingInfoHandle *implicit_sharing; } ImBufByteBuffer; typedef struct ImBufFloatBuffer { float *data; ImBufOwnership ownership; + const ImplicitSharingInfoHandle *implicit_sharing; } ImBufFloatBuffer; /** \} */ diff --git a/source/blender/imbuf/intern/allocimbuf.cc b/source/blender/imbuf/intern/allocimbuf.cc index 4ddd3344293..81a367a237d 100644 --- a/source/blender/imbuf/intern/allocimbuf.cc +++ b/source/blender/imbuf/intern/allocimbuf.cc @@ -22,6 +22,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_implicit_sharing.hh" #include "BLI_threads.h" #include "BLI_utildefines.h" @@ -65,12 +66,16 @@ void imb_mmap_unlock(void) * buffer to its defaults. */ template static void imb_free_buffer(BufferType &buffer) { - if (buffer.data) { + if (buffer.implicit_sharing) { + buffer.implicit_sharing->remove_user_and_delete_if_last(); + } + else if (buffer.data) { switch (buffer.ownership) { case IB_DO_NOT_TAKE_OWNERSHIP: break; case IB_TAKE_OWNERSHIP: + BLI_assert(buffer.implicit_sharing == nullptr); MEM_freeN(buffer.data); break; } @@ -79,6 +84,7 @@ template static void imb_free_buffer(BufferType &buffer) /* Reset buffer to defaults. */ buffer.data = nullptr; buffer.ownership = IB_DO_NOT_TAKE_OWNERSHIP; + buffer.implicit_sharing = nullptr; } /* Allocate pixel storage of the given buffer. The buffer owns the allocated memory. @@ -110,6 +116,11 @@ template void imb_make_writeable_buffer(BufferType &buffer) case IB_DO_NOT_TAKE_OWNERSHIP: buffer.data = static_cast(MEM_dupallocN(buffer.data)); buffer.ownership = IB_TAKE_OWNERSHIP; + + if (buffer.implicit_sharing) { + buffer.implicit_sharing->remove_user_and_delete_if_last(); + buffer.implicit_sharing = nullptr; + } break; case IB_TAKE_OWNERSHIP: @@ -144,6 +155,29 @@ auto imb_steal_buffer_data(BufferType &buffer) -> decltype(BufferType::data) return nullptr; } +/* Assign the new data of the buffer which is implicitly shared via the given handle. + * The old content of the buffer is freed using imb_free_buffer. */ +template +void imb_assign_shared_buffer(BufferType &buffer, + decltype(BufferType::data) buffer_data, + const ImplicitSharingInfoHandle *implicit_sharing) +{ + imb_free_buffer(buffer); + + if (implicit_sharing) { + BLI_assert(buffer_data != nullptr); + + implicit_sharing->add_user(); + } + else { + BLI_assert(buffer_data == nullptr); + } + + buffer.data = buffer_data; + buffer.ownership = IB_DO_NOT_TAKE_OWNERSHIP; + buffer.implicit_sharing = implicit_sharing; +} + void imb_freemipmapImBuf(ImBuf *ibuf) { int a; @@ -483,6 +517,45 @@ void IMB_make_writable_float_buffer(ImBuf *ibuf) imb_make_writeable_buffer(ibuf->float_buffer); } +void IMB_assign_shared_byte_buffer(ImBuf *ibuf, + uint8_t *buffer_data, + const ImplicitSharingInfoHandle *implicit_sharing) +{ + imb_free_buffer(ibuf->byte_buffer); + ibuf->flags &= ~IB_rect; + + if (buffer_data) { + imb_assign_shared_buffer(ibuf->byte_buffer, buffer_data, implicit_sharing); + ibuf->flags |= IB_rect; + } +} + +void IMB_assign_shared_float_buffer(ImBuf *ibuf, + float *buffer_data, + const ImplicitSharingInfoHandle *implicit_sharing) +{ + imb_free_buffer(ibuf->float_buffer); + ibuf->flags &= ~IB_rectfloat; + + if (buffer_data) { + imb_assign_shared_buffer(ibuf->float_buffer, buffer_data, implicit_sharing); + ibuf->flags |= IB_rectfloat; + } +} + +void IMB_assign_shared_float_z_buffer(ImBuf *ibuf, + float *buffer_data, + const ImplicitSharingInfoHandle *implicit_sharing) +{ + imb_free_buffer(ibuf->float_z_buffer); + ibuf->flags &= ~IB_zbuffloat; + + if (buffer_data) { + imb_assign_shared_buffer(ibuf->float_z_buffer, buffer_data, implicit_sharing); + ibuf->flags |= IB_zbuffloat; + } +} + void IMB_assign_byte_buffer(ImBuf *ibuf, uint8_t *buffer_data, const ImBufOwnership ownership) { imb_free_buffer(ibuf->byte_buffer); diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 15eae50be51..95a2a8040ee 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -1299,7 +1299,7 @@ static int make_structDNA(const char *base_directory, /* NOTE(nzc): `str` contains filenames. * Since we now include paths, I stretched it a bit. Hope this is enough :). */ char str[SDNA_MAX_FILENAME_LENGTH]; - sprintf(str, "%s%s", base_directory, includefiles[i]); + snprintf(str, sizeof(str), "%s%s", base_directory, includefiles[i]); DEBUG_PRINTF(0, "\t|-- Converting %s\n", str); if (convert_include(str)) { return 1; diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index c384cdfb8e7..19d31187181 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -503,13 +503,15 @@ static int rna_RenderPass_rect_get_length(const PointerRNA *ptr, static void rna_RenderPass_rect_get(PointerRNA *ptr, float *values) { RenderPass *rpass = (RenderPass *)ptr->data; - memcpy(values, rpass->rect, sizeof(float) * rpass->rectx * rpass->recty * rpass->channels); + memcpy( + values, rpass->buffer.data, sizeof(float) * rpass->rectx * rpass->recty * rpass->channels); } void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values) { RenderPass *rpass = (RenderPass *)ptr->data; - memcpy(rpass->rect, values, sizeof(float) * rpass->rectx * rpass->recty * rpass->channels); + memcpy( + rpass->buffer.data, values, sizeof(float) * rpass->rectx * rpass->recty * rpass->channels); } static RenderPass *rna_RenderPass_find_by_type(RenderLayer *rl, int passtype, const char *view) diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h index 79a5918da89..f2a351cb64b 100644 --- a/source/blender/render/RE_pipeline.h +++ b/source/blender/render/RE_pipeline.h @@ -11,6 +11,8 @@ #include "DNA_listBase.h" #include "DNA_vec_types.h" +#include "BLI_implicit_sharing.h" + struct ImBuf; struct Image; struct ImageFormatData; @@ -38,6 +40,21 @@ extern "C" { /* only used as handle */ typedef struct Render Render; +/* Buffer of a floating point values which uses implicit sharing. + * + * The buffer is allocated by render passes creation, and then is shared with the render result + * and image buffer. */ +typedef struct RenderBuffer { + float *data; + const ImplicitSharingInfoHandle *sharing_info; +} RenderBuffer; + +/* Specialized render buffer to store 8bpp passes. */ +typedef struct RenderByteBuffer { + uint8_t *data; + const ImplicitSharingInfoHandle *sharing_info; +} RenderByteBuffer; + /* Render Result usage: * * - render engine allocates/frees and delivers raw floating point rects @@ -51,11 +68,11 @@ typedef struct RenderView { char name[64]; /* EXR_VIEW_MAXNAME */ /* if this exists, result of composited layers */ - float *rectf; - /* if this exists, result of composited layers */ - float *rectz; + RenderBuffer combined_buffer; + RenderBuffer z_buffer; + /* optional, 32 bits version of picture, used for sequencer, OpenGL render and image curves */ - int *rect32; + RenderByteBuffer byte_buffer; } RenderView; @@ -64,7 +81,9 @@ typedef struct RenderPass { int channels; char name[64]; /* amount defined in IMB_openexr.h */ char chan_id[8]; /* amount defined in IMB_openexr.h */ - float *rect; + + RenderBuffer buffer; + int rectx, recty; char fullname[64]; /* EXR_PASS_MAXNAME */ @@ -102,15 +121,15 @@ typedef struct RenderResult { /* target image size */ int rectx, recty; - /* The following rect32, rectf and rectz buffers are for temporary storage only, + /* The following byte, combined, and z buffers are for temporary storage only, * for RenderResult structs created in #RE_AcquireResultImage - which do not have RenderView */ /* Optional, 32 bits version of picture, used for OpenGL render and image curves. */ - int *rect32; + RenderByteBuffer byte_buffer; + /* if this exists, a copy of one of layers, or result of composited layers */ - float *rectf; - /* if this exists, a copy of one of layers, or result of composited layers */ - float *rectz; + RenderBuffer combined_buffer; + RenderBuffer z_buffer; /* coordinates within final image (after cropping) */ rcti tilerect; @@ -259,6 +278,9 @@ void RE_render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name); float *RE_RenderLayerGetPass(struct RenderLayer *rl, const char *name, const char *viewname); +RenderBuffer *RE_RenderLayerGetPassBuffer(struct RenderLayer *rl, + const char *name, + const char *viewname); bool RE_HasSingleLayer(struct Render *re); @@ -433,6 +455,13 @@ struct RenderPass *RE_pass_find_by_type(struct RenderLayer *rl, int passtype, const char *viewname); +/** + * Set the buffer data of the render pass. + * The pass takes ownership of the data, and creates an implicit sharing handle to allow its + * sharing with other users. + */ +void RE_pass_set_buffer_data(struct RenderPass *pass, float *data); + /* shaded view or baking options */ #define RE_BAKE_NORMALS 0 #define RE_BAKE_DISPLACEMENT 1 @@ -467,6 +496,43 @@ struct RenderView *RE_RenderViewGetByName(struct RenderResult *rr, const char *v RenderResult *RE_DuplicateRenderResult(RenderResult *rr); +/** + * Create new render buffer which takes ownership of the given data. + * Creates an implicit sharing handle for the data as well. */ +RenderBuffer RE_RenderBuffer_new(float *data); + +/** + * Assign the buffer data. + * + * The current buffer data is freed and the new one is assigned, and the implicit sharing for it. + */ +void RE_RenderBuffer_assign_data(RenderBuffer *render_buffer, float *data); + +/** + * Effectively `lhs = rhs`. The ths will share the same buffer as the ths (with an increased user + * counter). + * + * The current content of the lhs is freed. + * The rhs and its data is allowed to be nullptr, in which case the lhs's data will be nullptr + * after this call. + */ +void RE_RenderBuffer_assign_shared(RenderBuffer *lhs, const RenderBuffer *rhs); + +/** + * Free data of the given buffer. + * + * The data and implicit sharing information of the buffer is set to nullptr after this call. + * The buffer itself is not freed. + */ +void RE_RenderBuffer_data_free(RenderBuffer *render_buffer); + +/* Implementation of above, but for byte buffer. */ +/* TODO(sergey): Once everything is C++ we can remove the duplicated API. */ +RenderByteBuffer RE_RenderByteBuffer_new(uint8_t *data); +void RE_RenderByteBuffer_assign_data(RenderByteBuffer *render_buffer, uint8_t *data); +void RE_RenderByteBuffer_assign_shared(RenderByteBuffer *lhs, const RenderByteBuffer *rhs); +void RE_RenderByteBuffer_data_free(RenderByteBuffer *render_buffer); + #ifdef __cplusplus } #endif diff --git a/source/blender/render/intern/engine.cc b/source/blender/render/intern/engine.cc index a1a8fa98c74..aed5da7779e 100644 --- a/source/blender/render/intern/engine.cc +++ b/source/blender/render/intern/engine.cc @@ -222,8 +222,8 @@ static RenderResult *render_result_from_bake( /* Fill render passes from bake pixel array, to be read by the render engine. */ for (int ty = 0; ty < h; ty++) { size_t offset = ty * w * 4; - float *primitive = primitive_pass->rect + offset; - float *differential = differential_pass->rect + offset; + float *primitive = primitive_pass->buffer.data + offset; + float *differential = differential_pass->buffer.data + offset; size_t bake_offset = (y + ty) * image->width + x; const BakePixel *bake_pixel = pixels + bake_offset; @@ -290,7 +290,7 @@ static void render_result_to_bake(RenderEngine *engine, RenderResult *rr) const size_t offset = ty * w; const size_t bake_offset = (y + ty) * image->width + x; - const float *pass_rect = rpass->rect + offset * channels_num; + const float *pass_rect = rpass->buffer.data + offset * channels_num; const BakePixel *bake_pixel = pixels + bake_offset; float *bake_result = result + bake_offset * channels_num; diff --git a/source/blender/render/intern/pipeline.cc b/source/blender/render/intern/pipeline.cc index 833999cee2d..eb1381cf369 100644 --- a/source/blender/render/intern/pipeline.cc +++ b/source/blender/render/intern/pipeline.cc @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" #include "BLI_fileops.h" +#include "BLI_implicit_sharing.hh" #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_path_util.h" @@ -225,10 +226,18 @@ void RE_FreeRenderResult(RenderResult *rr) render_result_free(rr); } +RenderBuffer *RE_RenderLayerGetPassBuffer(struct RenderLayer *rl, + const char *name, + const char *viewname) +{ + RenderPass *rpass = RE_pass_find_by_name(rl, name, viewname); + return rpass ? &rpass->buffer : nullptr; +} + float *RE_RenderLayerGetPass(RenderLayer *rl, const char *name, const char *viewname) { RenderPass *rpass = RE_pass_find_by_name(rl, name, viewname); - return rpass ? rpass->rect : nullptr; + return rpass ? rpass->buffer.data : nullptr; } RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name) @@ -371,21 +380,31 @@ void RE_AcquireResultImageViews(Render *re, RenderResult *rr) render_result_views_shallowcopy(rr, re->result); RenderView *rv = static_cast(rr->views.first); - rr->have_combined = (rv->rectf != nullptr); + rr->have_combined = (rv->combined_buffer.data != nullptr); /* single layer */ RenderLayer *rl = render_get_single_layer(re, re->result); + /* The render result uses shallow initialization, and the caller is not expected to + * explicitly free it. So simply assign the buffers as a shallow copy here as well. */ + if (rl) { - if (rv->rectf == nullptr) { + if (rv->combined_buffer.data == nullptr) { LISTBASE_FOREACH (RenderView *, rview, &rr->views) { - rview->rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, rview->name); + RenderBuffer *buffer = RE_RenderLayerGetPassBuffer( + rl, RE_PASSNAME_COMBINED, rview->name); + if (buffer) { + rview->combined_buffer = *buffer; + } } } - if (rv->rectz == nullptr) { + if (rv->z_buffer.data == nullptr) { LISTBASE_FOREACH (RenderView *, rview, &rr->views) { - rview->rectz = RE_RenderLayerGetPass(rl, RE_PASSNAME_Z, rview->name); + RenderBuffer *buffer = RE_RenderLayerGetPassBuffer(rl, RE_PASSNAME_Z, rview->name); + if (buffer) { + rview->z_buffer = *buffer; + } } } } @@ -424,22 +443,32 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id) /* `scene.rd.actview` view. */ rv = RE_RenderViewGetById(re->result, view_id); - rr->have_combined = (rv->rectf != nullptr); + rr->have_combined = (rv->combined_buffer.data != nullptr); - rr->rectf = rv->rectf; - rr->rectz = rv->rectz; - rr->rect32 = rv->rect32; + /* The render result uses shallow initialization, and the caller is not expected to + * explicitly free it. So simply assign the buffers as a shallow copy here as well. + * + * The thread safety is ensured via the re->resultmutex. */ + rr->combined_buffer = rv->combined_buffer; + rr->z_buffer = rv->z_buffer; + rr->byte_buffer = rv->byte_buffer; /* active layer */ rl = render_get_single_layer(re, re->result); if (rl) { - if (rv->rectf == nullptr) { - rr->rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, rv->name); + if (rv->combined_buffer.data == nullptr) { + RenderBuffer *buffer = RE_RenderLayerGetPassBuffer(rl, RE_PASSNAME_COMBINED, rv->name); + if (buffer) { + rr->combined_buffer = *buffer; + } } - if (rv->rectz == nullptr) { - rr->rectz = RE_RenderLayerGetPass(rl, RE_PASSNAME_Z, rv->name); + if (rv->z_buffer.data == nullptr) { + RenderBuffer *buffer = RE_RenderLayerGetPassBuffer(rl, RE_PASSNAME_Z, rv->name); + if (buffer) { + rr->z_buffer = *buffer; + } } } @@ -1198,8 +1227,8 @@ static void renderresult_stampinfo(Render *re) BKE_image_stamp_buf(re->scene, ob_camera_eval, (re->r.stamp & R_STAMP_STRIPMETA) ? rres.stamp_data : nullptr, - (uchar *)rres.rect32, - rres.rectf, + rres.byte_buffer.data, + rres.combined_buffer.data, rres.rectx, rres.recty, 4); @@ -2464,7 +2493,9 @@ void RE_layer_load_from_file( IMB_float_from_rect(ibuf); } - memcpy(rpass->rect, ibuf->float_buffer.data, sizeof(float[4]) * layer->rectx * layer->recty); + memcpy(rpass->buffer.data, + ibuf->float_buffer.data, + sizeof(float[4]) * layer->rectx * layer->recty); } else { if ((ibuf->x - x >= layer->rectx) && (ibuf->y - y >= layer->recty)) { @@ -2478,7 +2509,7 @@ void RE_layer_load_from_file( if (ibuf_clip) { IMB_rectcpy(ibuf_clip, ibuf, 0, 0, x, y, layer->rectx, layer->recty); - memcpy(rpass->rect, + memcpy(rpass->buffer.data, ibuf_clip->float_buffer.data, sizeof(float[4]) * layer->rectx * layer->recty); IMB_freeImBuf(ibuf_clip); @@ -2605,9 +2636,9 @@ RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const cha /* Clear previous pass if exist or the new image will be over previous one. */ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname); if (rp) { - if (rp->rect) { - MEM_freeN(rp->rect); - } + rp->buffer.sharing_info->remove_user_and_delete_if_last(); + rp->buffer.sharing_info = nullptr; + BLI_freelinkN(&rl->passes, rp); } /* create a totally new pass */ diff --git a/source/blender/render/intern/render_result.cc b/source/blender/render/intern/render_result.cc index e8476277f64..eb4b58836a3 100644 --- a/source/blender/render/intern/render_result.cc +++ b/source/blender/render/intern/render_result.cc @@ -14,6 +14,7 @@ #include "BLI_ghash.h" #include "BLI_hash_md5.h" +#include "BLI_implicit_sharing.hh" #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_rect.h" @@ -50,17 +51,9 @@ static void render_result_views_free(RenderResult *rr) RenderView *rv = static_cast(rr->views.first); BLI_remlink(&rr->views, rv); - if (rv->rect32) { - MEM_freeN(rv->rect32); - } - - if (rv->rectz) { - MEM_freeN(rv->rectz); - } - - if (rv->rectf) { - MEM_freeN(rv->rectf); - } + RE_RenderByteBuffer_data_free(&rv->byte_buffer); + RE_RenderBuffer_data_free(&rv->combined_buffer); + RE_RenderBuffer_data_free(&rv->z_buffer); MEM_freeN(rv); } @@ -79,11 +72,10 @@ void render_result_free(RenderResult *rr) while (rl->passes.first) { RenderPass *rpass = static_cast(rl->passes.first); - if (rpass->rect) { - MEM_freeN(rpass->rect); - } - BLI_remlink(&rl->passes, rpass); - MEM_freeN(rpass); + + RE_RenderBuffer_data_free(&rpass->buffer); + + BLI_freelinkN(&rl->passes, rpass); } BLI_remlink(&rr->layers, rl); MEM_freeN(rl); @@ -91,15 +83,10 @@ void render_result_free(RenderResult *rr) render_result_views_free(rr); - if (rr->rect32) { - MEM_freeN(rr->rect32); - } - if (rr->rectz) { - MEM_freeN(rr->rectz); - } - if (rr->rectf) { - MEM_freeN(rr->rectf); - } + RE_RenderByteBuffer_data_free(&rr->byte_buffer); + RE_RenderBuffer_data_free(&rr->combined_buffer); + RE_RenderBuffer_data_free(&rr->z_buffer); + if (rr->text) { MEM_freeN(rr->text); } @@ -142,9 +129,10 @@ void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src) BLI_addtail(&dst->views, rv); STRNCPY(rv->name, rview->name); - rv->rectf = rview->rectf; - rv->rectz = rview->rectz; - rv->rect32 = rview->rect32; + + rv->combined_buffer = rview->combined_buffer; + rv->z_buffer = rview->z_buffer; + rv->byte_buffer = rview->byte_buffer; } } @@ -165,24 +153,24 @@ void render_result_views_shallowdelete(RenderResult *rr) static void render_layer_allocate_pass(RenderResult *rr, RenderPass *rp) { - if (rp->rect != nullptr) { + if (rp->buffer.data != nullptr) { return; } const size_t rectsize = size_t(rr->rectx) * rr->recty * rp->channels; - rp->rect = MEM_cnew_array(rectsize, rp->name); + float *buffer_data = MEM_cnew_array(rectsize, rp->name); + + rp->buffer = RE_RenderBuffer_new(buffer_data); if (STREQ(rp->name, RE_PASSNAME_VECTOR)) { /* initialize to max speed */ - float *rect = rp->rect; for (int x = rectsize - 1; x >= 0; x--) { - rect[x] = PASS_VECTOR_MAX; + buffer_data[x] = PASS_VECTOR_MAX; } } else if (STREQ(rp->name, RE_PASSNAME_Z)) { - float *rect = rp->rect; for (int x = rectsize - 1; x >= 0; x--) { - rect[x] = 10e10; + buffer_data[x] = 10e10; } } } @@ -413,6 +401,11 @@ void RE_create_render_pass(RenderResult *rr, } } +void RE_pass_set_buffer_data(struct RenderPass *pass, float *data) +{ + RE_RenderBuffer_assign_data(&pass->buffer, data); +} + void RE_render_result_full_channel_name(char *fullname, const char *layname, const char *passname, @@ -515,7 +508,8 @@ static void ml_addpass_cb(void *base, /* channel id chars */ STRNCPY(rpass->chan_id, chan_id); - rpass->rect = rect; + RE_pass_set_buffer_data(rpass, rect); + STRNCPY(rpass->name, name); STRNCPY(rpass->view, view); RE_render_result_full_channel_name(rpass->fullname, nullptr, name, view, rpass->chan_id, -1); @@ -638,7 +632,7 @@ RenderResult *render_result_new_from_exr( rpass->recty = recty; if (rpass->channels >= 3) { - IMB_colormanagement_transform(rpass->rect, + IMB_colormanagement_transform(rpass->buffer.data, rpass->rectx, rpass->recty, rpass->channels, @@ -718,7 +712,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart) rpass = rpass->next) { /* For save buffers, skip any passes that are only saved to disk. */ - if (rpass->rect == nullptr || rpassp->rect == nullptr) { + if (rpass->buffer.data == nullptr || rpassp->buffer.data == nullptr) { continue; } /* Render-result have all passes, render-part only the active view's passes. */ @@ -726,7 +720,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart) continue; } - do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels); + do_merge_tile(rr, rrpart, rpass->buffer.data, rpassp->buffer.data, rpass->channels); /* manually get next render pass */ rpassp = rpassp->next; @@ -825,7 +819,7 @@ int render_result_exr_file_read_path(RenderResult *rr, RE_render_result_full_channel_name( fullname, nullptr, rpass->name, rpass->view, rpass->chan_id, a); IMB_exr_set_channel( - exrhandle, rl->name, fullname, xstride, xstride * rectx, rpass->rect + a); + exrhandle, rl->name, fullname, xstride, xstride * rectx, rpass->buffer.data + a); } RE_render_result_full_channel_name( @@ -931,9 +925,9 @@ ImBuf *RE_render_result_rect_to_ibuf(RenderResult *rr, RenderView *rv = RE_RenderViewGetById(rr, view_id); /* if not exists, BKE_imbuf_write makes one */ - IMB_assign_byte_buffer(ibuf, reinterpret_cast(rv->rect32), IB_DO_NOT_TAKE_OWNERSHIP); - IMB_assign_float_buffer(ibuf, rv->rectf, IB_DO_NOT_TAKE_OWNERSHIP); - IMB_assign_float_z_buffer(ibuf, rv->rectz, IB_DO_NOT_TAKE_OWNERSHIP); + IMB_assign_shared_byte_buffer(ibuf, rv->byte_buffer.data, rv->byte_buffer.sharing_info); + IMB_assign_shared_float_buffer(ibuf, rv->combined_buffer.data, rv->combined_buffer.sharing_info); + IMB_assign_shared_float_z_buffer(ibuf, rv->z_buffer.data, rv->z_buffer.sharing_info); /* float factor for random dither, imbuf takes care of it */ ibuf->dither = dither; @@ -978,27 +972,31 @@ void RE_render_result_rect_from_ibuf(RenderResult *rr, const ImBuf *ibuf, const if (ibuf->float_buffer.data) { rr->have_combined = true; - if (!rv->rectf) { - rv->rectf = MEM_cnew_array(4 * rr->rectx * rr->recty, "render_seq rectf"); + if (!rv->combined_buffer.data) { + float *data = MEM_cnew_array(4 * rr->rectx * rr->recty, "render_seq rectf"); + RE_RenderBuffer_assign_data(&rv->combined_buffer, data); } - memcpy(rv->rectf, ibuf->float_buffer.data, sizeof(float[4]) * rr->rectx * rr->recty); + memcpy(rv->combined_buffer.data, + ibuf->float_buffer.data, + sizeof(float[4]) * rr->rectx * rr->recty); /* TSK! Since sequence render doesn't free the *rr render result, the old rect32 * can hang around when sequence render has rendered a 32 bits one before */ - MEM_SAFE_FREE(rv->rect32); + RE_RenderByteBuffer_data_free(&rv->byte_buffer); } else if (ibuf->byte_buffer.data) { rr->have_combined = true; - if (!rv->rect32) { - rv->rect32 = MEM_cnew_array(rr->rectx * rr->recty, "render_seq rect"); + if (!rv->byte_buffer.data) { + uint8_t *data = MEM_cnew_array(4 * rr->rectx * rr->recty, "render_seq rect"); + RE_RenderByteBuffer_assign_data(&rv->byte_buffer, data); } - memcpy(rv->rect32, ibuf->byte_buffer.data, sizeof(int) * rr->rectx * rr->recty); + memcpy(rv->byte_buffer.data, ibuf->byte_buffer.data, sizeof(int) * rr->rectx * rr->recty); /* Same things as above, old rectf can hang around from previous render. */ - MEM_SAFE_FREE(rv->rectf); + RE_RenderBuffer_data_free(&rv->combined_buffer); } } @@ -1006,14 +1004,15 @@ void render_result_rect_fill_zero(RenderResult *rr, const int view_id) { RenderView *rv = RE_RenderViewGetById(rr, view_id); - if (rv->rectf) { - memset(rv->rectf, 0, sizeof(float[4]) * rr->rectx * rr->recty); + if (rv->combined_buffer.data) { + memset(rv->combined_buffer.data, 0, sizeof(float[4]) * rr->rectx * rr->recty); } - else if (rv->rect32) { - memset(rv->rect32, 0, 4 * rr->rectx * rr->recty); + else if (rv->byte_buffer.data) { + memset(rv->byte_buffer.data, 0, 4 * rr->rectx * rr->recty); } else { - rv->rect32 = MEM_cnew_array(rr->rectx * rr->recty, "render_seq rect"); + uint8_t *data = MEM_cnew_array(rr->rectx * rr->recty, "render_seq rect"); + RE_RenderByteBuffer_assign_data(&rv->byte_buffer, data); } } @@ -1027,12 +1026,18 @@ void render_result_rect_get_pixels(RenderResult *rr, { RenderView *rv = RE_RenderViewGetById(rr, view_id); - if (rv && rv->rect32) { - memcpy(rect, rv->rect32, sizeof(int) * rr->rectx * rr->recty); + if (rv && rv->byte_buffer.data) { + memcpy(rect, rv->byte_buffer.data, sizeof(int) * rr->rectx * rr->recty); } - else if (rv && rv->rectf) { - IMB_display_buffer_transform_apply( - (uchar *)rect, rv->rectf, rr->rectx, rr->recty, 4, view_settings, display_settings, true); + else if (rv && rv->combined_buffer.data) { + IMB_display_buffer_transform_apply((uchar *)rect, + rv->combined_buffer.data, + rr->rectx, + rr->recty, + 4, + view_settings, + display_settings, + true); } else { /* else fill with black */ @@ -1053,13 +1058,13 @@ bool RE_HasCombinedLayer(const RenderResult *result) return false; } - return (rv->rect32 || rv->rectf); + return (rv->byte_buffer.data || rv->combined_buffer.data); } bool RE_HasFloatPixels(const RenderResult *result) { LISTBASE_FOREACH (const RenderView *, rview, &result->views) { - if (rview->rect32 && !rview->rectf) { + if (rview->byte_buffer.data && !rview->combined_buffer.data) { return false; } } @@ -1099,9 +1104,11 @@ static RenderPass *duplicate_render_pass(RenderPass *rpass) { RenderPass *new_rpass = MEM_cnew("new render pass", *rpass); new_rpass->next = new_rpass->prev = nullptr; - if (new_rpass->rect != nullptr) { - new_rpass->rect = static_cast(MEM_dupallocN(new_rpass->rect)); + + if (new_rpass->buffer.sharing_info != nullptr) { + new_rpass->buffer.sharing_info->add_user(); } + return new_rpass; } @@ -1121,15 +1128,22 @@ static RenderLayer *duplicate_render_layer(RenderLayer *rl) static RenderView *duplicate_render_view(RenderView *rview) { RenderView *new_rview = MEM_cnew("new render view", *rview); - if (new_rview->rectf != nullptr) { - new_rview->rectf = static_cast(MEM_dupallocN(new_rview->rectf)); + + if (rview->combined_buffer.data != nullptr) { + RE_RenderBuffer_assign_data(&new_rview->combined_buffer, + static_cast(MEM_dupallocN(rview->combined_buffer.data))); } - if (new_rview->rectz != nullptr) { - new_rview->rectz = static_cast(MEM_dupallocN(new_rview->rectz)); + + if (rview->z_buffer.data != nullptr) { + RE_RenderBuffer_assign_data(&new_rview->z_buffer, + static_cast(MEM_dupallocN(rview->z_buffer.data))); } - if (new_rview->rect32 != nullptr) { - new_rview->rect32 = static_cast(MEM_dupallocN(new_rview->rect32)); + + if (rview->byte_buffer.data != nullptr) { + RE_RenderByteBuffer_assign_data( + &new_rview->byte_buffer, static_cast(MEM_dupallocN(rview->byte_buffer.data))); } + return new_rview; } @@ -1147,15 +1161,144 @@ RenderResult *RE_DuplicateRenderResult(RenderResult *rr) RenderView *new_rview = duplicate_render_view(rview); BLI_addtail(&new_rr->views, new_rview); } - if (new_rr->rectf != nullptr) { - new_rr->rectf = static_cast(MEM_dupallocN(new_rr->rectf)); - } - if (new_rr->rectz != nullptr) { - new_rr->rectz = static_cast(MEM_dupallocN(new_rr->rectz)); - } - if (new_rr->rect32 != nullptr) { - new_rr->rect32 = static_cast(MEM_dupallocN(new_rr->rect32)); - } + + RE_RenderBuffer_assign_data(&new_rr->combined_buffer, + static_cast(MEM_dupallocN(rr->combined_buffer.data))); + RE_RenderBuffer_assign_data(&new_rr->z_buffer, + static_cast(MEM_dupallocN(rr->z_buffer.data))); + + RE_RenderByteBuffer_assign_data(&new_rr->byte_buffer, + static_cast(MEM_dupallocN(rr->byte_buffer.data))); + new_rr->stamp_data = BKE_stamp_data_copy(new_rr->stamp_data); return new_rr; } + +/* -------------------------------------------------------------------- + * Render buffer. + */ + +/* An #ImplicitSharingInfo that knows how to free the referenced render rpass data. */ +class PassImplicitSharing : public blender::ImplicitSharingInfo { + private: + const void *data_; + + public: + explicit PassImplicitSharing(const void *data) : ImplicitSharingInfo(), data_(data) {} + + private: + void delete_self_with_data() override + { + MEM_freeN(const_cast(data_)); + MEM_delete(this); + } + + void delete_data_only() override + { + MEM_freeN(const_cast(data_)); + data_ = nullptr; + } +}; + +static const blender::ImplicitSharingInfo *make_implicit_sharing_info_for_pass(const void *data) +{ + return MEM_new(__func__, data); +} + +template static BufferType render_buffer_new(decltype(BufferType::data) data) +{ + BufferType buffer; + + buffer.data = data; + buffer.sharing_info = make_implicit_sharing_info_for_pass(data); + + return buffer; +} + +template static void render_buffer_data_free(BufferType *render_buffer) +{ + if (!render_buffer->sharing_info) { + MEM_SAFE_FREE(render_buffer->data); + return; + } + + render_buffer->sharing_info->remove_user_and_delete_if_last(); + + render_buffer->data = nullptr; + render_buffer->sharing_info = nullptr; +} + +template +static void render_buffer_assign_data(BufferType *render_buffer, decltype(BufferType::data) data) +{ + render_buffer_data_free(render_buffer); + + if (!data) { + render_buffer->data = nullptr; + render_buffer->sharing_info = nullptr; + return; + } + + render_buffer->data = data; + render_buffer->sharing_info = make_implicit_sharing_info_for_pass(data); +} + +template +static void render_buffer_assign_shared(BufferType *lhs, const BufferType *rhs) +{ + if (lhs->sharing_info) { + lhs->sharing_info->remove_user_and_delete_if_last(); + lhs->sharing_info = nullptr; + } + + if (rhs) { + *lhs = *rhs; + } + else { + lhs->data = nullptr; + } + + if (lhs->sharing_info) { + lhs->sharing_info->add_user(); + } +} + +RenderBuffer RE_RenderBuffer_new(float *data) +{ + return render_buffer_new(data); +} + +void RE_RenderBuffer_assign_data(RenderBuffer *render_buffer, float *data) +{ + return render_buffer_assign_data(render_buffer, data); +} + +void RE_RenderBuffer_assign_shared(RenderBuffer *lhs, const RenderBuffer *rhs) +{ + render_buffer_assign_shared(lhs, rhs); +} + +void RE_RenderBuffer_data_free(RenderBuffer *render_buffer) +{ + render_buffer_data_free(render_buffer); +} + +RenderByteBuffer RE_RenderByteBuffer_new(uint8_t *data) +{ + return render_buffer_new(data); +} + +void RE_RenderByteBuffer_assign_data(RenderByteBuffer *render_buffer, uint8_t *data) +{ + return render_buffer_assign_data(render_buffer, data); +} + +void RE_RenderByteBuffer_assign_shared(RenderByteBuffer *lhs, const RenderByteBuffer *rhs) +{ + render_buffer_assign_shared(lhs, rhs); +} + +void RE_RenderByteBuffer_data_free(RenderByteBuffer *render_buffer) +{ + render_buffer_data_free(render_buffer); +} diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index e070b4f442a..25e45dcf083 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -1575,25 +1575,24 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, RE_AcquireResultImage(re, &rres, view_id); - if (rres.rectf) { - ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat); - memcpy(ibufs_arr[view_id]->float_buffer.data, - rres.rectf, - sizeof(float[4]) * rres.rectx * rres.recty); + if (rres.combined_buffer.data) { + ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, 0); + IMB_assign_shared_float_buffer( + ibufs_arr[view_id], rres.combined_buffer.data, rres.combined_buffer.sharing_info); - if (rres.rectz) { - addzbuffloatImBuf(ibufs_arr[view_id]); - memcpy(ibufs_arr[view_id]->float_z_buffer.data, - rres.rectz, - sizeof(float) * rres.rectx * rres.recty); + if (rres.z_buffer.data) { + IMB_assign_shared_float_z_buffer( + ibufs_arr[view_id], rres.z_buffer.data, rres.z_buffer.sharing_info); } /* float buffers in the sequencer are not linear */ seq_imbuf_to_sequencer_space(context->scene, ibufs_arr[view_id], false); } - else if (rres.rect32) { + else if (rres.byte_buffer.data) { ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect); - memcpy(ibufs_arr[view_id]->byte_buffer.data, rres.rect32, 4 * rres.rectx * rres.recty); + memcpy(ibufs_arr[view_id]->byte_buffer.data, + rres.byte_buffer.data, + 4 * rres.rectx * rres.recty); } if (view_id != context->view_id) { -- 2.30.2 From d200ef9268b722395174169968db0af1e3243ac5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 19 May 2023 09:23:23 +0200 Subject: [PATCH 2/4] Fix grammar according to Hans --- source/blender/imbuf/IMB_imbuf_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 2590f339510..a1de53149ee 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -176,7 +176,7 @@ typedef enum ImBufOwnership { * Note on the implicit sharing * ---------------------------- * - * The buffer allows to implicitly share data with other users of such data. In this case the + * The buffer allows implicitly sharing data with other users of such data. In this case the * ownership is set to IB_DO_NOT_TAKE_OWNERSHIP. */ /* TODO(sergey): Once everything is C++ replace with a template. */ -- 2.30.2 From 30c0c85971b2bd8f5610b46fe84e9284730f546b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 19 May 2023 09:45:25 +0200 Subject: [PATCH 3/4] Use utilities from blender::implicit_sharing --- source/blender/imbuf/intern/allocimbuf.cc | 9 ++-- source/blender/render/intern/render_result.cc | 51 +++---------------- 2 files changed, 11 insertions(+), 49 deletions(-) diff --git a/source/blender/imbuf/intern/allocimbuf.cc b/source/blender/imbuf/intern/allocimbuf.cc index 81a367a237d..b6e967f21f2 100644 --- a/source/blender/imbuf/intern/allocimbuf.cc +++ b/source/blender/imbuf/intern/allocimbuf.cc @@ -67,7 +67,7 @@ void imb_mmap_unlock(void) template static void imb_free_buffer(BufferType &buffer) { if (buffer.implicit_sharing) { - buffer.implicit_sharing->remove_user_and_delete_if_last(); + blender::implicit_sharing::free_shared_data(&buffer.data, &buffer.implicit_sharing); } else if (buffer.data) { switch (buffer.ownership) { @@ -167,15 +167,16 @@ void imb_assign_shared_buffer(BufferType &buffer, if (implicit_sharing) { BLI_assert(buffer_data != nullptr); - implicit_sharing->add_user(); + blender::implicit_sharing::copy_shared_pointer( + buffer_data, implicit_sharing, &buffer.data, &buffer.implicit_sharing); } else { BLI_assert(buffer_data == nullptr); + buffer.data = nullptr; + buffer.implicit_sharing = nullptr; } - buffer.data = buffer_data; buffer.ownership = IB_DO_NOT_TAKE_OWNERSHIP; - buffer.implicit_sharing = implicit_sharing; } void imb_freemipmapImBuf(ImBuf *ibuf) diff --git a/source/blender/render/intern/render_result.cc b/source/blender/render/intern/render_result.cc index eb4b58836a3..8747c5165e7 100644 --- a/source/blender/render/intern/render_result.cc +++ b/source/blender/render/intern/render_result.cc @@ -1178,39 +1178,12 @@ RenderResult *RE_DuplicateRenderResult(RenderResult *rr) * Render buffer. */ -/* An #ImplicitSharingInfo that knows how to free the referenced render rpass data. */ -class PassImplicitSharing : public blender::ImplicitSharingInfo { - private: - const void *data_; - - public: - explicit PassImplicitSharing(const void *data) : ImplicitSharingInfo(), data_(data) {} - - private: - void delete_self_with_data() override - { - MEM_freeN(const_cast(data_)); - MEM_delete(this); - } - - void delete_data_only() override - { - MEM_freeN(const_cast(data_)); - data_ = nullptr; - } -}; - -static const blender::ImplicitSharingInfo *make_implicit_sharing_info_for_pass(const void *data) -{ - return MEM_new(__func__, data); -} - template static BufferType render_buffer_new(decltype(BufferType::data) data) { BufferType buffer; buffer.data = data; - buffer.sharing_info = make_implicit_sharing_info_for_pass(data); + buffer.sharing_info = blender::implicit_sharing::info_for_mem_free(data); return buffer; } @@ -1222,10 +1195,7 @@ template static void render_buffer_data_free(BufferType *rende return; } - render_buffer->sharing_info->remove_user_and_delete_if_last(); - - render_buffer->data = nullptr; - render_buffer->sharing_info = nullptr; + blender::implicit_sharing::free_shared_data(&render_buffer->data, &render_buffer->sharing_info); } template @@ -1240,26 +1210,17 @@ static void render_buffer_assign_data(BufferType *render_buffer, decltype(Buffer } render_buffer->data = data; - render_buffer->sharing_info = make_implicit_sharing_info_for_pass(data); + render_buffer->sharing_info = blender::implicit_sharing::info_for_mem_free(data); } template static void render_buffer_assign_shared(BufferType *lhs, const BufferType *rhs) { - if (lhs->sharing_info) { - lhs->sharing_info->remove_user_and_delete_if_last(); - lhs->sharing_info = nullptr; - } + render_buffer_data_free(lhs); if (rhs) { - *lhs = *rhs; - } - else { - lhs->data = nullptr; - } - - if (lhs->sharing_info) { - lhs->sharing_info->add_user(); + blender::implicit_sharing::copy_shared_pointer( + rhs->data, rhs->sharing_info, &lhs->data, &lhs->sharing_info); } } -- 2.30.2 From 2927d2d7e2774116e9a4dbd9fe322f1a5a27256b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 19 May 2023 16:32:13 +0200 Subject: [PATCH 4/4] Remove unrelated change --- source/blender/makesdna/intern/makesdna.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 95a2a8040ee..15eae50be51 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -1299,7 +1299,7 @@ static int make_structDNA(const char *base_directory, /* NOTE(nzc): `str` contains filenames. * Since we now include paths, I stretched it a bit. Hope this is enough :). */ char str[SDNA_MAX_FILENAME_LENGTH]; - snprintf(str, sizeof(str), "%s%s", base_directory, includefiles[i]); + sprintf(str, "%s%s", base_directory, includefiles[i]); DEBUG_PRINTF(0, "\t|-- Converting %s\n", str); if (convert_include(str)) { return 1; -- 2.30.2