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..a1de53149ee 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 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. */ 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..b6e967f21f2 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) { + blender::implicit_sharing::free_shared_data(&buffer.data, &buffer.implicit_sharing); + } + 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,30 @@ 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); + + 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.ownership = IB_DO_NOT_TAKE_OWNERSHIP; +} + void imb_freemipmapImBuf(ImBuf *ibuf) { int a; @@ -483,6 +518,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/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..8747c5165e7 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,105 @@ 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. + */ + +template static BufferType render_buffer_new(decltype(BufferType::data) data) +{ + BufferType buffer; + + buffer.data = data; + buffer.sharing_info = blender::implicit_sharing::info_for_mem_free(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; + } + + blender::implicit_sharing::free_shared_data(&render_buffer->data, &render_buffer->sharing_info); +} + +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 = blender::implicit_sharing::info_for_mem_free(data); +} + +template +static void render_buffer_assign_shared(BufferType *lhs, const BufferType *rhs) +{ + render_buffer_data_free(lhs); + + if (rhs) { + blender::implicit_sharing::copy_shared_pointer( + rhs->data, rhs->sharing_info, &lhs->data, &lhs->sharing_info); + } +} + +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) {