diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index 5d12e6815ad..3850c11b371 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -3987,12 +3987,9 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int e if (ima->rr) { RenderPass *rpass = BKE_image_multilayer_index(ima->rr, iuser); - if (rpass) { - // printf("load from pass %s\n", rpass->name); - ibuf = IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0); - ibuf->channels = rpass->channels; - - IMB_assign_shared_float_buffer(ibuf, rpass->buffer.data, rpass->buffer.sharing_info); + if (rpass && rpass->ibuf) { + ibuf = rpass->ibuf; + IMB_refImBuf(ibuf); BKE_imbuf_stamp_info(ima->rr, ibuf); @@ -4295,15 +4292,12 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser) if (ima->rr) { RenderPass *rpass = BKE_image_multilayer_index(ima->rr, iuser); - if (rpass) { - ibuf = IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0); + if (rpass && rpass->ibuf) { + ibuf = rpass->ibuf; + IMB_refImBuf(ibuf); image_init_after_load(ima, iuser, ibuf); - IMB_assign_shared_float_buffer(ibuf, rpass->buffer.data, rpass->buffer.sharing_info); - - ibuf->channels = rpass->channels; - BKE_imbuf_stamp_info(ima->rr, ibuf); image_assign_ibuf(ima, ibuf, iuser ? iuser->multi_index : IMA_NO_INDEX, 0); @@ -4318,15 +4312,10 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser) /* always returns a single ibuf, also during render progress */ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_lock) { - Render *re; RenderView *rv; - RenderBuffer *combined_buffer; - RenderByteBuffer *byte_buffer; + ImBuf *pass_ibuf = nullptr; float dither; - int channels, layer, pass; - ImBuf *ibuf; - int from_render = (ima->render_slot == ima->last_render_slot); - int actview; + const int from_render = (ima->render_slot == ima->last_render_slot); if (!(iuser && iuser->scene)) { return nullptr; @@ -4337,12 +4326,11 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc return nullptr; } - re = RE_GetSceneRender(iuser->scene); + Render *re = RE_GetSceneRender(iuser->scene); - channels = 4; - layer = iuser->layer; - pass = iuser->pass; - actview = iuser->view; + const int layer = iuser->layer; + const int pass = iuser->pass; + int actview = iuser->view; if (BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO)) { actview = iuser->multiview_eye; @@ -4355,7 +4343,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)->combined_buffer.data != nullptr; + rres.have_combined = ((RenderView *)rres.views.first)->ibuf != nullptr; } if (!(rres.rectx > 0 && rres.recty > 0)) { @@ -4380,12 +4368,10 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc /* this gives active layer, composite or sequence result */ if (rv == nullptr) { - byte_buffer = &rres.byte_buffer; - combined_buffer = &rres.combined_buffer; + pass_ibuf = rres.ibuf; } else { - byte_buffer = &rv->byte_buffer; - combined_buffer = &rv->combined_buffer; + pass_ibuf = rv->ibuf; } dither = iuser->scene->r.dither_intensity; @@ -4394,13 +4380,8 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc if (rres.have_combined && layer == 0) { /* pass */ } - 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 - */ - combined_buffer = nullptr; + else if (pass_ibuf && pass_ibuf->byte_buffer.data && layer == 0) { + /* pass */ } else if (rres.layers.first) { RenderLayer *rl = static_cast( @@ -4408,78 +4389,24 @@ 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) { - combined_buffer = &rpass->buffer; + pass_ibuf = rpass->ibuf; if (pass != 0) { - channels = rpass->channels; dither = 0.0f; /* don't dither passes */ } } } } - ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0, nullptr); + if (pass_ibuf) { + /* TODO(sergey): Perhaps its better to assign dither when ImBuf is allocated for the render + * result. It will avoid modification here, and allow comparing render results with different + * dither applied to them. */ + pass_ibuf->dither = dither; - /* make ibuf if needed, and initialize it */ - if (ibuf == nullptr) { - ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 32, 0); - image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + IMB_refImBuf(pass_ibuf); } - /* Set color space settings for a byte buffer. - * - * This is mainly to make it so color management treats byte buffer - * from render result with Save Buffers enabled as final display buffer - * and doesn't apply any color management on it. - * - * For other cases we need to be sure it stays to default byte buffer space. - */ - if (ibuf->byte_buffer.data != byte_buffer->data) { - const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE); - IMB_colormanagement_assign_byte_colorspace(ibuf, colorspace); - } - - /* invalidate color managed buffers if render result changed */ - BLI_thread_lock(LOCK_COLORMANAGE); - if (combined_buffer && (ibuf->x != rres.rectx || ibuf->y != rres.recty || - ibuf->float_buffer.data != combined_buffer->data)) - { - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - } - - ibuf->x = rres.rectx; - ibuf->y = rres.recty; - ibuf->channels = channels; - - imb_freerectImBuf(ibuf); - - 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); - } - - /* TODO(sergey): Make this faster by either simply referencing the stamp - * or by changing both ImBuf and RenderResult to use same data type to - * store metadata. */ - if (ibuf->metadata != nullptr) { - IMB_metadata_free(ibuf->metadata); - ibuf->metadata = nullptr; - } - BKE_imbuf_stamp_info(&rres, ibuf); - - BLI_thread_unlock(LOCK_COLORMANAGE); - - ibuf->dither = dither; - - return ibuf; + return pass_ibuf; } static int image_get_multiview_index(Image *ima, ImageUser *iuser) diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index 4629dba5852..438fa729a4a 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -736,7 +736,7 @@ bool BKE_image_render_write_exr(ReportList *reports, /* Compositing result. */ if (rr->have_combined) { LISTBASE_FOREACH (RenderView *, rview, &rr->views) { - if (!rview->combined_buffer.data) { + if (!rview->ibuf || !rview->ibuf->float_buffer.data) { continue; } @@ -757,8 +757,8 @@ bool BKE_image_render_write_exr(ReportList *reports, 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; + rview->ibuf->float_buffer.data, rr->rectx, rr->recty, 4, imf, tmp_output_rects) : + rview->ibuf->float_buffer.data; for (int a = 0; a < channels; a++) { char passname[EXR_PASS_MAXNAME]; @@ -814,11 +814,14 @@ bool BKE_image_render_write_exr(ReportList *reports, const bool pass_half_float = half_float && pass_RGBA; /* Color-space conversion only happens on RGBA passes. */ - float *output_rect = - (save_as_render && pass_RGBA) ? - image_exr_from_scene_linear_to_output( - rp->buffer.data, rr->rectx, rr->recty, rp->channels, imf, tmp_output_rects) : - rp->buffer.data; + float *output_rect = (save_as_render && pass_RGBA) ? + image_exr_from_scene_linear_to_output(rp->ibuf->float_buffer.data, + rr->rectx, + rr->recty, + rp->channels, + imf, + tmp_output_rects) : + rp->ibuf->float_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 d941e54893e..5f73e9c5631 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.cc +++ b/source/blender/compositor/operations/COM_CompositorOperation.cc @@ -59,8 +59,9 @@ void CompositorOperation::deinit_execution() if (rr) { RenderView *rv = RE_RenderViewGetByName(rr, view_name_); + ImBuf *ibuf = RE_RenderViewEnsureImBuf(rr, rv); - RE_RenderBuffer_assign_data(&rv->combined_buffer, output_buffer_); + IMB_assign_float_buffer(ibuf, output_buffer_, IB_TAKE_OWNERSHIP); rr->have_combined = true; } diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c index f9754d366ab..fcc02164439 100644 --- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c +++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c @@ -46,6 +46,8 @@ #include "DNA_modifier_types.h" #include "DNA_particle_types.h" +#include "IMB_imbuf_types.h" + #include "eevee_private.h" /* -------------------------------------------------------------------- */ @@ -582,7 +584,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; + float *rp_buffer_data = rp_object->ibuf->float_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 + diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 446fd25731b..981ae178f64 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -31,6 +31,8 @@ #include "RE_pipeline.h" +#include "IMB_imbuf_types.h" + #include "eevee_private.h" bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, Depsgraph *depsgraph) @@ -267,7 +269,7 @@ static void eevee_render_color_result(RenderLayer *rl, num_channels, 0, GPU_DATA_FLOAT, - rp->buffer.data); + rp->ibuf->float_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 7d95631a127..44450299725 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -17,6 +17,7 @@ #include "DNA_ID.h" #include "DNA_lightprobe_types.h" #include "DNA_modifier_types.h" +#include "IMB_imbuf_types.h" #include "RE_pipeline.h" #include "eevee_engine.h" @@ -362,7 +363,9 @@ 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->buffer.data, 0, sizeof(float) * 4 * vector_rp->rectx * vector_rp->recty); + memset(vector_rp->ibuf->float_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 a63ffef377c..d110a97fddb 100644 --- a/source/blender/draw/engines/gpencil/gpencil_render.c +++ b/source/blender/draw/engines/gpencil/gpencil_render.c @@ -17,6 +17,8 @@ #include "RE_pipeline.h" +#include "IMB_imbuf_types.h" + #include "gpencil_engine.h" void GPENCIL_render_init(GPENCIL_Data *vedata, @@ -50,8 +52,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->buffer.data : NULL; - float *pix_col = (rpass_col_src) ? rpass_col_src->buffer.data : NULL; + float *pix_z = (rpass_z_src) ? rpass_z_src->ibuf->float_buffer.data : NULL; + float *pix_col = (rpass_col_src) ? rpass_col_src->ibuf->float_buffer.data : NULL; if (!pix_z || !pix_col) { RE_engine_set_error_message(engine, @@ -161,7 +163,7 @@ static void GPENCIL_render_result_z(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; + float *ro_buffer_data = rp->ibuf->float_buffer.data; GPU_framebuffer_read_depth(vedata->fbl->render_fb, rect->xmin, @@ -223,7 +225,7 @@ static void GPENCIL_render_result_combined(RenderLayer *rl, 4, 0, GPU_DATA_FLOAT, - rp->buffer.data); + rp->ibuf->float_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 81509ad5f0f..9c70b8ac514 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.cc +++ b/source/blender/draw/engines/workbench/workbench_engine.cc @@ -14,6 +14,7 @@ #include "ED_paint.h" #include "ED_view3d.h" #include "GPU_capabilities.h" +#include "IMB_imbuf_types.h" #include "draw_common.hh" #include "draw_sculpt.hh" @@ -656,7 +657,7 @@ static void write_render_color_output(RenderLayer *layer, 4, 0, GPU_DATA_FLOAT, - rp->buffer.data); + rp->ibuf->float_buffer.data); } } @@ -675,13 +676,13 @@ static void write_render_z_output(RenderLayer *layer, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), GPU_DATA_FLOAT, - rp->buffer.data); + rp->ibuf->float_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->buffer.data, pix_num)) { + for (float &z : MutableSpan(rp->ibuf->float_buffer.data, pix_num)) { if (z == 1.0f) { z = 1e10f; /* Background */ } @@ -697,7 +698,7 @@ static void write_render_z_output(RenderLayer *layer, float far = DRW_view_far_distance_get(nullptr); float range = fabsf(far - near); - for (float &z : MutableSpan(rp->buffer.data, pix_num)) { + for (float &z : MutableSpan(rp->ibuf->float_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 a965e888b88..d8ef38108ff 100644 --- a/source/blender/draw/engines/workbench/workbench_render.c +++ b/source/blender/draw/engines/workbench/workbench_render.c @@ -24,6 +24,8 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +#include "IMB_imbuf_types.h" + #include "RE_pipeline.h" #include "workbench_private.h" @@ -104,7 +106,7 @@ static void workbench_render_result_z(RenderLayer *rl, const char *viewname, con 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; + float *rp_buffer_data = rp->ibuf->float_buffer.data; GPU_framebuffer_bind(dfbl->default_fb); GPU_framebuffer_read_depth(dfbl->default_fb, @@ -208,7 +210,7 @@ void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer 4, 0, GPU_DATA_FLOAT, - rp->buffer.data); + rp->ibuf->float_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 7ad8ddbe1b9..5709fd098f5 100644 --- a/source/blender/editors/interface/eyedroppers/eyedropper_color.cc +++ b/source/blender/editors/interface/eyedroppers/eyedropper_color.cc @@ -182,7 +182,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->buffer.data[offset]; + r_col[0] = render_pass->ibuf->float_buffer.data[offset]; return true; } } diff --git a/source/blender/editors/render/render_internal.cc b/source/blender/editors/render/render_internal.cc index 5b0102fbd10..4a022bca06b 100644 --- a/source/blender/editors/render/render_internal.cc +++ b/source/blender/editors/render/render_internal.cc @@ -204,16 +204,19 @@ static void image_buffer_rect_update(RenderJob *rj, */ /* TODO(sergey): Need to check has_combined here? */ if (iuser->pass == 0) { - RenderView *rv; const int view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname); - rv = RE_RenderViewGetById(rr, view_id); + const RenderView *rv = RE_RenderViewGetById(rr, view_id); + + if (rv->ibuf == nullptr) { + return; + } /* find current float rect for display, first case is after composite... still weak */ - if (rv->combined_buffer.data) { - rectf = rv->combined_buffer.data; + if (rv->ibuf->float_buffer.data) { + rectf = rv->ibuf->float_buffer.data; } else { - if (rv->byte_buffer.data) { + if (rv->ibuf->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 0da07b2da9f..578559cf792 100644 --- a/source/blender/editors/render/render_opengl.cc +++ b/source/blender/editors/render/render_opengl.cc @@ -194,8 +194,7 @@ static void screen_opengl_views_setup(OGLRender *oglrender) RenderView *rv_del = rv->next; BLI_remlink(&rr->views, rv_del); - RE_RenderBuffer_data_free(&rv_del->combined_buffer); - RE_RenderByteBuffer_data_free(&rv_del->byte_buffer); + IMB_freeImBuf(rv_del->ibuf); MEM_freeN(rv_del); } @@ -219,8 +218,7 @@ static void screen_opengl_views_setup(OGLRender *oglrender) BLI_remlink(&rr->views, rv_del); - RE_RenderBuffer_data_free(&rv_del->combined_buffer); - RE_RenderByteBuffer_data_free(&rv_del->byte_buffer); + IMB_freeImBuf(rv_del->ibuf); MEM_freeN(rv_del); } diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc index 8f02729c11e..eafbc3e11c8 100644 --- a/source/blender/editors/render/render_preview.cc +++ b/source/blender/editors/render/render_preview.cc @@ -668,7 +668,7 @@ static bool ed_preview_draw_rect( rv = nullptr; } - if (rv && rv->combined_buffer.data) { + if (rv && rv->ibuf) { if (abs(rres.rectx - newx) < 2 && abs(rres.recty - newy) < 2) { newrect->xmax = max_ii(newrect->xmax, rect->xmin + rres.rectx + offx); newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty); @@ -677,13 +677,8 @@ static bool ed_preview_draw_rect( float fx = rect->xmin + offx; float fy = rect->ymin; - ImBuf *ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 0, 0); - IMB_assign_float_buffer(ibuf, rv->combined_buffer.data, IB_DO_NOT_TAKE_OWNERSHIP); - ED_draw_imbuf( - ibuf, fx, fy, false, &scene->view_settings, &scene->display_settings, 1.0f, 1.0f); - - IMB_freeImBuf(ibuf); + rv->ibuf, fx, fy, false, &scene->view_settings, &scene->display_settings, 1.0f, 1.0f); ok = true; } @@ -1062,9 +1057,11 @@ 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; - RE_RenderBuffer_assign_data(&rv->combined_buffer, - static_cast(MEM_callocN(sizeof(float[4]) * width * height, - "texture render result"))); + ImBuf *rv_ibuf = RE_RenderViewEnsureImBuf(rr, rv); + IMB_assign_float_buffer(rv_ibuf, + static_cast(MEM_callocN(sizeof(float[4]) * width * height, + "texture render result")), + IB_TAKE_OWNERSHIP); RE_ReleaseResult(re); /* Get texture image pool (if any) */ @@ -1072,7 +1069,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->combined_buffer.data; + float *rect_float = rv_ibuf->float_buffer.data; float tex_coord[3] = {0.0f, 0.0f, 0.0f}; bool color_manage = BKE_scene_check_color_management_enabled(sce); diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index f06b08e0279..a511d7b9e6e 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -128,10 +128,14 @@ 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->combined_buffer.data) { + ImBuf *ibuf = rv->ibuf; + if (!ibuf) { + return NULL; + } + if (ibuf->float_buffer.data) { return IFACE_("Composite"); } - if (rv->byte_buffer.data) { + if (ibuf->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 068724027f2..304c486f7eb 100644 --- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp +++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp @@ -47,6 +47,8 @@ using namespace Freestyle; #include "DEG_depsgraph_query.h" +#include "IMB_imbuf.h" + #include "pipeline.hh" #include "FRS_freestyle.h" @@ -447,7 +449,7 @@ 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; + float *rpass_buffer_data = rpass->ibuf->float_buffer.data; if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE_COLOR)) { controller->setPassDiffuse(rpass_buffer_data, rpass->rectx, rpass->recty); diffuse = true; diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 616dc8db181..49128a6ec08 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -44,7 +44,6 @@ #include "../blenlib/BLI_sys_types.h" #include "../gpu/GPU_texture.h" -#include "BLI_implicit_sharing.h" #include "BLI_utildefines.h" #include "IMB_imbuf_types.h" @@ -152,19 +151,6 @@ 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 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); - /** * 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. @@ -847,9 +833,13 @@ bool imb_addrectfloatImBuf(struct ImBuf *ibuf, const unsigned int channels); void imb_freerectfloatImBuf(struct ImBuf *ibuf); void imb_freemipmapImBuf(struct ImBuf *ibuf); -/** Free all pixel data (associated with image size). */ +/** Free all CPU pixel data (associated with image size). */ void imb_freerectImbuf_all(struct ImBuf *ibuf); +/* Free the GPU textures of the given image buffer, leaving the CPU buffers unchanged. + * The ibuf can be nullptr, in which case the function does nothing. */ +void IMB_free_gpu_textures(struct ImBuf *ibuf); + /** * Threaded processors. */ diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index c8d3879235d..ad628b605d4 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -4,12 +4,12 @@ #pragma once -#include "BLI_implicit_sharing.h" - #include "DNA_vec_types.h" /* for rcti */ #include "BLI_sys_types.h" +struct GPUTexture; + #ifdef __cplusplus extern "C" { #endif @@ -172,17 +172,14 @@ typedef enum ImBufOwnership { /* Different storage specialization. * - * Note on the implicit sharing - * ---------------------------- + * NOTE: Avoid direct assignments and allocations, use the buffer utilities from the IMB_imbuf.h + * instead. * - * 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. */ + * Accessing the data pointer directly is fine and is an expected way of accessing it. */ typedef struct ImBufByteBuffer { uint8_t *data; ImBufOwnership ownership; - const ImplicitSharingInfoHandle *implicit_sharing; struct ColorSpace *colorspace; } ImBufByteBuffer; @@ -190,11 +187,20 @@ typedef struct ImBufByteBuffer { typedef struct ImBufFloatBuffer { float *data; ImBufOwnership ownership; - const ImplicitSharingInfoHandle *implicit_sharing; struct ColorSpace *colorspace; } ImBufFloatBuffer; +typedef struct ImBufGPU { + /* Texture which corresponds to the state of the ImBug on the GPU. + * + * Allocation is supposed to happen outside of the ImBug module from a proper GPU context. + * De-referencing the ImBuf or its GPU texture can happen from any state. */ + /* TODO(sergey): This should become a list of textures, to support having high-res ImBuf on GPU + * without hitting hardware limitations. */ + struct GPUTexture *texture; +} ImBufGPU; + /** \} */ /* -------------------------------------------------------------------- */ @@ -236,6 +242,9 @@ typedef struct ImBuf { */ ImBufFloatBuffer float_buffer; + /* Image buffer on the GPU. */ + ImBufGPU gpu; + /** Resolution in pixels per meter. Multiply by `0.0254` for DPI. */ double ppm[2]; diff --git a/source/blender/imbuf/intern/allocimbuf.cc b/source/blender/imbuf/intern/allocimbuf.cc index 745c932efd7..ac09242ec6c 100644 --- a/source/blender/imbuf/intern/allocimbuf.cc +++ b/source/blender/imbuf/intern/allocimbuf.cc @@ -23,10 +23,11 @@ #include "MEM_guardedalloc.h" -#include "BLI_implicit_sharing.hh" #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "GPU_texture.h" + static SpinLock refcounter_spin; void imb_refcounter_lock_init() @@ -67,16 +68,12 @@ void imb_mmap_unlock() * buffer to its defaults. */ template static void imb_free_buffer(BufferType &buffer) { - if (buffer.implicit_sharing) { - blender::implicit_sharing::free_shared_data(&buffer.data, &buffer.implicit_sharing); - } - else if (buffer.data) { + 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; } @@ -85,7 +82,6 @@ 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. @@ -101,7 +97,6 @@ bool imb_alloc_buffer( } buffer.ownership = IB_TAKE_OWNERSHIP; - buffer.implicit_sharing = nullptr; return true; } @@ -119,12 +114,6 @@ template void imb_make_writeable_buffer(BufferType &buffer) 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: break; } @@ -157,30 +146,6 @@ 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; @@ -244,6 +209,16 @@ void imb_freerectImbuf_all(ImBuf *ibuf) freeencodedbufferImBuf(ibuf); } +void IMB_free_gpu_textures(ImBuf *ibuf) +{ + if (!ibuf || !ibuf->gpu.texture) { + return; + } + + GPU_texture_free(ibuf->gpu.texture); + ibuf->gpu.texture = nullptr; +} + void IMB_freeImBuf(ImBuf *ibuf) { if (ibuf == nullptr) { @@ -267,6 +242,7 @@ void IMB_freeImBuf(ImBuf *ibuf) "'.blend' relative \"//\" must not be used in ImBuf!"); imb_freerectImbuf_all(ibuf); + IMB_free_gpu_textures(ibuf); IMB_metadata_free(ibuf->metadata); colormanage_cache_free(ibuf); @@ -459,32 +435,6 @@ 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_byte_buffer(ImBuf *ibuf, uint8_t *buffer_data, const ImBufOwnership ownership) { imb_free_buffer(ibuf->byte_buffer); @@ -626,8 +576,6 @@ ImBuf *IMB_dupImBuf(const ImBuf *ibuf1) return nullptr; } - /* TODO(sergey): Use implicit sharing. */ - if (ibuf1->byte_buffer.data) { flags |= IB_rect; } diff --git a/source/blender/makesrna/intern/rna_render.cc b/source/blender/makesrna/intern/rna_render.cc index f964866a920..80df76fcc61 100644 --- a/source/blender/makesrna/intern/rna_render.cc +++ b/source/blender/makesrna/intern/rna_render.cc @@ -93,6 +93,7 @@ const EnumPropertyItem rna_enum_bake_pass_type_items[] = { # include "GPU_capabilities.h" # include "GPU_shader.h" # include "IMB_colormanagement.h" +# include "IMB_imbuf_types.h" # include "DEG_depsgraph_query.h" @@ -499,15 +500,30 @@ 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->buffer.data, sizeof(float) * rpass->rectx * rpass->recty * rpass->channels); + const size_t size_in_bytes = sizeof(float) * rpass->rectx * rpass->recty * rpass->channels; + const float *buffer = rpass->ibuf ? rpass->ibuf->float_buffer.data : nullptr; + + if (!buffer) { + /* No float buffer to read from, initialize to all zeroes. */ + memset(values, 0, size_in_bytes); + return; + } + + memcpy(values, buffer, size_in_bytes); } void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values) { RenderPass *rpass = (RenderPass *)ptr->data; - memcpy( - rpass->buffer.data, values, sizeof(float) * rpass->rectx * rpass->recty * rpass->channels); + float *buffer = rpass->ibuf ? rpass->ibuf->float_buffer.data : nullptr; + + if (!buffer) { + /* Only writing to an already existing buffer is supported. */ + return; + } + + const size_t size_in_bytes = sizeof(float) * rpass->rectx * rpass->recty * rpass->channels; + memcpy(buffer, values, size_in_bytes); } 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 6e93d84597e..f30be7d2e60 100644 --- a/source/blender/render/RE_pipeline.h +++ b/source/blender/render/RE_pipeline.h @@ -42,43 +42,14 @@ 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. - * - * The GPU texture is an optional read-only copy of the render buffer in GPU memory. */ -typedef struct RenderBuffer { - float *data; - const ImplicitSharingInfoHandle *sharing_info; - struct GPUTexture *gpu_texture; -} RenderBuffer; - -/* Specialized render buffer to store 8bpp passes. */ -typedef struct RenderByteBuffer { - uint8_t *data; - const ImplicitSharingInfoHandle *sharing_info; - struct GPUTexture *gpu_texture; -} RenderByteBuffer; - -/* Render Result usage: - * - * - render engine allocates/frees and delivers raw floating point rects - * - right now it's full rects, but might become tiles or file - * - the display client has to allocate display rects, sort out what to display, - * and how it's converted - */ - typedef struct RenderView { struct RenderView *next, *prev; char name[64]; /* EXR_VIEW_MAXNAME */ - /* if this exists, result of composited layers */ - RenderBuffer combined_buffer; - - /* optional, 32 bits version of picture, used for sequencer, OpenGL render and image curves */ - RenderByteBuffer byte_buffer; - + /* Image buffer of a composited layer or a sequencer output. + * The ibuf is only allocated if it has an actual data in one of its buffers (float, byte, or + * GPU). */ + struct ImBuf *ibuf; } RenderView; typedef struct RenderPass { @@ -87,7 +58,14 @@ typedef struct RenderPass { char name[64]; /* amount defined in IMB_openexr.h */ char chan_id[8]; /* amount defined in IMB_openexr.h */ - RenderBuffer buffer; + /* Image buffer which contains data of this pass. + * + * The data can be either CPU side stored in ibuf->float_buffer, or a GPU-side stored in + * ibuf->gpu (during rendering, i.e.). + * + * The pass data storage is lazily allocated, and until data is actually provided (via either CPU + * buffer of GPU texture) the ibuf is not allocated. */ + struct ImBuf *ibuf; int rectx, recty; @@ -126,14 +104,10 @@ typedef struct RenderResult { /* target image size */ int rectx, recty; - /* 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. */ - RenderByteBuffer byte_buffer; - - /* if this exists, a copy of one of layers, or result of composited layers */ - RenderBuffer combined_buffer; + /* The temporary storage to pass image data from #RE_AcquireResultImage. + * Is null pointer when the RenderResult is not coming from the #RE_AcquireResultImage, and is + * a pointer to an existing ibuf in either RenderView or a RenderPass otherwise. */ + struct ImBuf *ibuf; /* coordinates within final image (after cropping) */ rcti tilerect; @@ -285,9 +259,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); +struct ImBuf *RE_RenderLayerGetPassImBuf(struct RenderLayer *rl, + const char *name, + const char *viewname); bool RE_HasSingleLayer(struct Render *re); @@ -510,42 +484,8 @@ 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 lhs will share the same buffer as the rhs (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); +struct ImBuf *RE_RenderPassEnsureImBuf(RenderPass *render_pass); +struct ImBuf *RE_RenderViewEnsureImBuf(const RenderResult *render_result, RenderView *render_view); #ifdef __cplusplus } diff --git a/source/blender/render/intern/compositor.cc b/source/blender/render/intern/compositor.cc index bbb2932cb23..82e1242bad5 100644 --- a/source/blender/render/intern/compositor.cc +++ b/source/blender/render/intern/compositor.cc @@ -226,7 +226,7 @@ class Context : public realtime_compositor::Context { RenderPass *rpass = (RenderPass *)BLI_findstring( &rl->passes, pass_name, offsetof(RenderPass, name)); - if (rpass && rpass->buffer.data) { + if (rpass && rpass->ibuf && rpass->ibuf->float_buffer.data) { input_texture = RE_pass_ensure_gpu_texture_cache(re, rpass); if (input_texture) { @@ -283,7 +283,8 @@ class Context : public realtime_compositor::Context { float *output_buffer = (float *)GPU_texture_read(output_texture_, GPU_DATA_FLOAT, 0); if (output_buffer) { - RE_RenderBuffer_assign_data(&rv->combined_buffer, output_buffer); + ImBuf *ibuf = RE_RenderViewEnsureImBuf(rr, rv); + IMB_assign_float_buffer(ibuf, output_buffer, IB_TAKE_OWNERSHIP); } /* TODO: z-buffer output. */ diff --git a/source/blender/render/intern/engine.cc b/source/blender/render/intern/engine.cc index 7b154b46bda..03cfb2fe908 100644 --- a/source/blender/render/intern/engine.cc +++ b/source/blender/render/intern/engine.cc @@ -43,6 +43,8 @@ # include "BPY_extern.h" #endif +#include "IMB_imbuf_types.h" + #include "RE_bake.h" #include "RE_engine.h" #include "RE_pipeline.h" @@ -216,8 +218,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->buffer.data + offset; - float *differential = differential_pass->buffer.data + offset; + float *primitive = primitive_pass->ibuf->float_buffer.data + offset; + float *differential = differential_pass->ibuf->float_buffer.data + offset; size_t bake_offset = (y + ty) * image->width + x; const BakePixel *bake_pixel = pixels + bake_offset; @@ -284,7 +286,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->buffer.data + offset * channels_num; + const float *pass_rect = rpass->ibuf->float_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 047573ebc33..c40159136c0 100644 --- a/source/blender/render/intern/pipeline.cc +++ b/source/blender/render/intern/pipeline.cc @@ -228,16 +228,16 @@ void RE_FreeRenderResult(RenderResult *rr) render_result_free(rr); } -RenderBuffer *RE_RenderLayerGetPassBuffer(RenderLayer *rl, const char *name, const char *viewname) +ImBuf *RE_RenderLayerGetPassImBuf(RenderLayer *rl, const char *name, const char *viewname) { RenderPass *rpass = RE_pass_find_by_name(rl, name, viewname); - return rpass ? &rpass->buffer : nullptr; + return rpass ? rpass->ibuf : 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->buffer.data : nullptr; + const ImBuf *ibuf = RE_RenderLayerGetPassImBuf(rl, name, viewname); + return ibuf ? ibuf->float_buffer.data : nullptr; } RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name) @@ -381,7 +381,7 @@ 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->combined_buffer.data != nullptr); + rr->have_combined = (rv->ibuf != nullptr); /* single layer */ RenderLayer *rl = render_get_single_layer(re, re->result); @@ -390,13 +390,9 @@ void RE_AcquireResultImageViews(Render *re, RenderResult *rr) * explicitly free it. So simply assign the buffers as a shallow copy here as well. */ if (rl) { - if (rv->combined_buffer.data == nullptr) { + if (rv->ibuf == nullptr) { LISTBASE_FOREACH (RenderView *, rview, &rr->views) { - RenderBuffer *buffer = RE_RenderLayerGetPassBuffer( - rl, RE_PASSNAME_COMBINED, rview->name); - if (buffer) { - rview->combined_buffer = *buffer; - } + rview->ibuf = RE_RenderLayerGetPassImBuf(rl, RE_PASSNAME_COMBINED, rview->name); } } } @@ -435,24 +431,20 @@ 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->combined_buffer.data != nullptr); + rr->have_combined = (rv->ibuf != nullptr); /* 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->byte_buffer = rv->byte_buffer; + rr->ibuf = rv->ibuf; /* active layer */ rl = render_get_single_layer(re, re->result); if (rl) { - if (rv->combined_buffer.data == nullptr) { - RenderBuffer *buffer = RE_RenderLayerGetPassBuffer(rl, RE_PASSNAME_COMBINED, rv->name); - if (buffer) { - rr->combined_buffer = *buffer; - } + if (rv->ibuf == nullptr) { + rr->ibuf = RE_RenderLayerGetPassImBuf(rl, RE_PASSNAME_COMBINED, rv->name); } } @@ -1311,8 +1303,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, - rres.byte_buffer.data, - rres.combined_buffer.data, + rres.ibuf->byte_buffer.data, + rres.ibuf->float_buffer.data, rres.rectx, rres.recty, 4); @@ -2594,7 +2586,7 @@ void RE_layer_load_from_file( IMB_float_from_rect(ibuf); } - memcpy(rpass->buffer.data, + memcpy(rpass->ibuf->float_buffer.data, ibuf->float_buffer.data, sizeof(float[4]) * layer->rectx * layer->recty); } @@ -2610,7 +2602,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->buffer.data, + memcpy(rpass->ibuf->float_buffer.data, ibuf_clip->float_buffer.data, sizeof(float[4]) * layer->rectx * layer->recty); IMB_freeImBuf(ibuf_clip); @@ -2737,9 +2729,7 @@ 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) { - rp->buffer.sharing_info->remove_user_and_delete_if_last(); - rp->buffer.sharing_info = nullptr; - + IMB_freeImBuf(rp->ibuf); 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 96c2789d9c4..ccc061ee62a 100644 --- a/source/blender/render/intern/render_result.cc +++ b/source/blender/render/intern/render_result.cc @@ -54,8 +54,7 @@ static void render_result_views_free(RenderResult *rr) RenderView *rv = static_cast(rr->views.first); BLI_remlink(&rr->views, rv); - RE_RenderByteBuffer_data_free(&rv->byte_buffer); - RE_RenderBuffer_data_free(&rv->combined_buffer); + IMB_freeImBuf(rv->ibuf); MEM_freeN(rv); } @@ -75,7 +74,7 @@ void render_result_free(RenderResult *rr) while (rl->passes.first) { RenderPass *rpass = static_cast(rl->passes.first); - RE_RenderBuffer_data_free(&rpass->buffer); + IMB_freeImBuf(rpass->ibuf); BLI_freelinkN(&rl->passes, rpass); } @@ -85,8 +84,7 @@ void render_result_free(RenderResult *rr) render_result_views_free(rr); - RE_RenderByteBuffer_data_free(&rr->byte_buffer); - RE_RenderBuffer_data_free(&rr->combined_buffer); + IMB_freeImBuf(rr->ibuf); if (rr->text) { MEM_freeN(rr->text); @@ -119,10 +117,7 @@ void render_result_free_gpu_texture_caches(RenderResult *rr) { LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) { LISTBASE_FOREACH (RenderPass *, rpass, &rl->passes) { - if (rpass->buffer.gpu_texture) { - GPU_texture_free(rpass->buffer.gpu_texture); - rpass->buffer.gpu_texture = nullptr; - } + IMB_free_gpu_textures(rpass->ibuf); } } } @@ -143,8 +138,7 @@ void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src) STRNCPY(rv->name, rview->name); - rv->combined_buffer = rview->combined_buffer; - rv->byte_buffer = rview->byte_buffer; + rv->ibuf = rview->ibuf; } } @@ -165,14 +159,19 @@ void render_result_views_shallowdelete(RenderResult *rr) static void render_layer_allocate_pass(RenderResult *rr, RenderPass *rp) { - if (rp->buffer.data != nullptr) { + if (rp->ibuf && rp->ibuf->float_buffer.data) { return; } + /* NOTE: In-lined manual allocation to support floating point buffers of an arbitrary number of + * channels. */ + const size_t rectsize = size_t(rr->rectx) * rr->recty * rp->channels; float *buffer_data = MEM_cnew_array(rectsize, rp->name); - rp->buffer = RE_RenderBuffer_new(buffer_data); + rp->ibuf = IMB_allocImBuf(rr->rectx, rr->recty, 32, 0); + rp->ibuf->channels = rp->channels; + IMB_assign_float_buffer(rp->ibuf, buffer_data, IB_TAKE_OWNERSHIP); if (STREQ(rp->name, RE_PASSNAME_VECTOR)) { /* initialize to max speed */ @@ -415,15 +414,27 @@ void RE_create_render_pass(RenderResult *rr, void RE_pass_set_buffer_data(RenderPass *pass, float *data) { - RE_RenderBuffer_assign_data(&pass->buffer, data); + ImBuf *ibuf = RE_RenderPassEnsureImBuf(pass); + + IMB_assign_float_buffer(ibuf, data, IB_TAKE_OWNERSHIP); } GPUTexture *RE_pass_ensure_gpu_texture_cache(Render *re, RenderPass *rpass) { - if (rpass->buffer.gpu_texture) { - return rpass->buffer.gpu_texture; + ImBuf *ibuf = rpass->ibuf; + + if (!ibuf) { + /* No existing GPU texture, but also no CPU side data to create it from. */ + return nullptr; } - if (rpass->buffer.data == nullptr) { + + if (ibuf->gpu.texture) { + /* Return existing GPU texture, regardless whether it also exists on CPU or not. */ + return ibuf->gpu.texture; + } + + if (ibuf->float_buffer.data == nullptr) { + /* No CPU side data to create the texture from. */ return nullptr; } @@ -431,20 +442,21 @@ GPUTexture *RE_pass_ensure_gpu_texture_cache(Render *re, RenderPass *rpass) (rpass->channels == 3) ? GPU_RGB16F : GPU_RGBA16F; - rpass->buffer.gpu_texture = GPU_texture_create_2d("RenderBuffer.gpu_texture", - rpass->rectx, - rpass->recty, - 1, - format, - GPU_TEXTURE_USAGE_GENERAL, - nullptr); + /* TODO(sergey): Use utility to assign the texture. */ + ibuf->gpu.texture = GPU_texture_create_2d("RenderBuffer.gpu_texture", + rpass->rectx, + rpass->recty, + 1, + format, + GPU_TEXTURE_USAGE_GENERAL, + nullptr); - if (rpass->buffer.gpu_texture) { - GPU_texture_update(rpass->buffer.gpu_texture, GPU_DATA_FLOAT, rpass->buffer.data); + if (ibuf->gpu.texture) { + GPU_texture_update(ibuf->gpu.texture, GPU_DATA_FLOAT, ibuf->float_buffer.data); re->result_has_gpu_texture_caches = true; } - return rpass->buffer.gpu_texture; + return ibuf->gpu.texture; } void RE_render_result_full_channel_name(char *fullname, @@ -543,6 +555,8 @@ static void ml_addpass_cb(void *base, RenderPass *rpass = MEM_cnew("loaded pass"); BLI_addtail(&rl->passes, rpass); + rpass->rectx = rr->rectx; + rpass->recty = rr->recty; rpass->channels = totchan; rl->passflag |= passtype_from_name(name); @@ -673,7 +687,7 @@ RenderResult *render_result_new_from_exr( rpass->recty = recty; if (rpass->channels >= 3) { - IMB_colormanagement_transform(rpass->buffer.data, + IMB_colormanagement_transform(rpass->ibuf->float_buffer.data, rpass->rectx, rpass->recty, rpass->channels, @@ -753,7 +767,11 @@ 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->buffer.data == nullptr || rpassp->buffer.data == nullptr) { + if (rpass->ibuf == nullptr || rpassp->ibuf == nullptr) { + continue; + } + if (rpass->ibuf->float_buffer.data == nullptr || + rpassp->ibuf->float_buffer.data == nullptr) { continue; } /* Render-result have all passes, render-part only the active view's passes. */ @@ -761,7 +779,11 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart) continue; } - do_merge_tile(rr, rrpart, rpass->buffer.data, rpassp->buffer.data, rpass->channels); + do_merge_tile(rr, + rrpart, + rpass->ibuf->float_buffer.data, + rpassp->ibuf->float_buffer.data, + rpass->channels); /* manually get next render pass */ rpassp = rpassp->next; @@ -865,13 +887,23 @@ bool render_result_exr_file_read_path(RenderResult *rr, RE_render_result_full_channel_name( fullname, nullptr, rpass->name, rpass->view, rpass->chan_id, a); - if (IMB_exr_set_channel( - exrhandle, rl->name, fullname, xstride, ystride, rpass->buffer.data + a)) { + if (IMB_exr_set_channel(exrhandle, + rl->name, + fullname, + xstride, + ystride, + rpass->ibuf->float_buffer.data + a)) + { found_channels = true; } else if (rl_single) { - if (IMB_exr_set_channel( - exrhandle, nullptr, fullname, xstride, ystride, rpass->buffer.data + a)) { + if (IMB_exr_set_channel(exrhandle, + nullptr, + fullname, + xstride, + ystride, + rpass->ibuf->float_buffer.data + a)) + { found_channels = true; } else { @@ -998,8 +1030,10 @@ 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_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); + if (rv->ibuf) { + IMB_assign_byte_buffer(ibuf, rv->ibuf->byte_buffer.data, IB_DO_NOT_TAKE_OWNERSHIP); + IMB_assign_float_buffer(ibuf, rv->ibuf->float_buffer.data, IB_DO_NOT_TAKE_OWNERSHIP); + } /* float factor for random dither, imbuf takes care of it */ ibuf->dither = dither; @@ -1041,34 +1075,36 @@ void RE_render_result_rect_from_ibuf(RenderResult *rr, const ImBuf *ibuf, const { RenderView *rv = RE_RenderViewGetById(rr, view_id); + ImBuf *rv_ibuf = RE_RenderViewEnsureImBuf(rr, rv); + if (ibuf->float_buffer.data) { rr->have_combined = true; - if (!rv->combined_buffer.data) { + if (!rv_ibuf->float_buffer.data) { float *data = MEM_cnew_array(4 * rr->rectx * rr->recty, "render_seq rectf"); - RE_RenderBuffer_assign_data(&rv->combined_buffer, data); + IMB_assign_float_buffer(rv_ibuf, data, IB_TAKE_OWNERSHIP); } - memcpy(rv->combined_buffer.data, + memcpy(rv_ibuf->float_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 */ - RE_RenderByteBuffer_data_free(&rv->byte_buffer); + imb_freerectImBuf(rv_ibuf); } else if (ibuf->byte_buffer.data) { rr->have_combined = true; - if (!rv->byte_buffer.data) { + if (!rv_ibuf->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); + IMB_assign_byte_buffer(rv_ibuf, data, IB_TAKE_OWNERSHIP); } - memcpy(rv->byte_buffer.data, ibuf->byte_buffer.data, sizeof(int) * rr->rectx * rr->recty); + memcpy(rv_ibuf->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. */ - RE_RenderBuffer_data_free(&rv->combined_buffer); + imb_freerectfloatImBuf(rv_ibuf); } } @@ -1076,15 +1112,20 @@ void render_result_rect_fill_zero(RenderResult *rr, const int view_id) { RenderView *rv = RE_RenderViewGetById(rr, view_id); - if (rv->combined_buffer.data) { - memset(rv->combined_buffer.data, 0, sizeof(float[4]) * rr->rectx * rr->recty); - } - else if (rv->byte_buffer.data) { - memset(rv->byte_buffer.data, 0, 4 * rr->rectx * rr->recty); - } - else { + ImBuf *ibuf = RE_RenderViewEnsureImBuf(rr, rv); + + if (!ibuf->float_buffer.data && !ibuf->byte_buffer.data) { uint8_t *data = MEM_cnew_array(rr->rectx * rr->recty, "render_seq rect"); - RE_RenderByteBuffer_assign_data(&rv->byte_buffer, data); + IMB_assign_byte_buffer(ibuf, data, IB_TAKE_OWNERSHIP); + return; + } + + if (ibuf->float_buffer.data) { + memset(ibuf->float_buffer.data, 0, sizeof(float[4]) * rr->rectx * rr->recty); + } + + if (ibuf->byte_buffer.data) { + memset(ibuf->byte_buffer.data, 0, 4 * rr->rectx * rr->recty); } } @@ -1097,13 +1138,14 @@ void render_result_rect_get_pixels(RenderResult *rr, const int view_id) { RenderView *rv = RE_RenderViewGetById(rr, view_id); + ImBuf *ibuf = rv ? rv->ibuf : nullptr; - if (rv && rv->byte_buffer.data) { - memcpy(rect, rv->byte_buffer.data, sizeof(int) * rr->rectx * rr->recty); + if (ibuf->byte_buffer.data) { + memcpy(rect, ibuf->byte_buffer.data, sizeof(int) * rr->rectx * rr->recty); } - else if (rv && rv->combined_buffer.data) { + else if (ibuf->float_buffer.data) { IMB_display_buffer_transform_apply((uchar *)rect, - rv->combined_buffer.data, + ibuf->float_buffer.data, rr->rectx, rr->recty, 4, @@ -1130,13 +1172,17 @@ bool RE_HasCombinedLayer(const RenderResult *result) return false; } - return (rv->byte_buffer.data || rv->combined_buffer.data); + return (rv->ibuf); } bool RE_HasFloatPixels(const RenderResult *result) { LISTBASE_FOREACH (const RenderView *, rview, &result->views) { - if (rview->byte_buffer.data && !rview->combined_buffer.data) { + ImBuf *ibuf = rview->ibuf; + if (!ibuf) { + continue; + } + if (ibuf->byte_buffer.data && !ibuf->float_buffer.data) { return false; } } @@ -1177,9 +1223,7 @@ 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->buffer.sharing_info != nullptr) { - new_rpass->buffer.sharing_info->add_user(); - } + new_rpass->ibuf = IMB_dupImBuf(rpass->ibuf); return new_rpass; } @@ -1201,19 +1245,7 @@ static RenderView *duplicate_render_view(RenderView *rview) { RenderView *new_rview = MEM_cnew("new render view", *rview); - /* Reset buffers, they are not supposed to be shallow-coped. */ - new_rview->combined_buffer = {}; - new_rview->byte_buffer = {}; - - if (rview->combined_buffer.data != nullptr) { - RE_RenderBuffer_assign_data(&new_rview->combined_buffer, - static_cast(MEM_dupallocN(rview->combined_buffer.data))); - } - - if (rview->byte_buffer.data != nullptr) { - RE_RenderByteBuffer_assign_data( - &new_rview->byte_buffer, static_cast(MEM_dupallocN(rview->byte_buffer.data))); - } + new_rview->ibuf = IMB_dupImBuf(rview->ibuf); return new_rview; } @@ -1233,115 +1265,27 @@ RenderResult *RE_DuplicateRenderResult(RenderResult *rr) BLI_addtail(&new_rr->views, new_rview); } - /* Reset buffers, they are not supposed to be shallow-coped. */ - new_rr->combined_buffer = {}; - new_rr->byte_buffer = {}; - - if (rr->combined_buffer.data) { - RE_RenderBuffer_assign_data(&new_rr->combined_buffer, - static_cast(MEM_dupallocN(rr->combined_buffer.data))); - } - if (rr->byte_buffer.data) { - RE_RenderByteBuffer_assign_data(&new_rr->byte_buffer, - static_cast(MEM_dupallocN(rr->byte_buffer.data))); - } + new_rr->ibuf = IMB_dupImBuf(rr->ibuf); 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) +ImBuf *RE_RenderPassEnsureImBuf(RenderPass *render_pass) { - BufferType buffer; - - buffer.data = data; - buffer.sharing_info = blender::implicit_sharing::info_for_mem_free(data); - buffer.gpu_texture = nullptr; - - return buffer; -} - -template static void render_buffer_data_free(BufferType *render_buffer) -{ - if (!render_buffer->sharing_info) { - MEM_SAFE_FREE(render_buffer->data); - return; + if (!render_pass->ibuf) { + render_pass->ibuf = IMB_allocImBuf(render_pass->rectx, render_pass->recty, 32, 0); + render_pass->ibuf->channels = render_pass->channels; } - blender::implicit_sharing::free_shared_data(&render_buffer->data, &render_buffer->sharing_info); - - if (render_buffer->gpu_texture) { - GPU_texture_free(render_buffer->gpu_texture); - render_buffer->gpu_texture = nullptr; - } + return render_pass->ibuf; } -template -static void render_buffer_assign_data(BufferType *render_buffer, decltype(BufferType::data) data) +ImBuf *RE_RenderViewEnsureImBuf(const RenderResult *render_result, RenderView *render_view) { - render_buffer_data_free(render_buffer); - - if (!data) { - render_buffer->data = nullptr; - render_buffer->sharing_info = nullptr; - return; + if (!render_view->ibuf) { + render_view->ibuf = IMB_allocImBuf(render_result->rectx, render_result->recty, 32, 0); } - 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); -} + return render_view->ibuf; +} \ No newline at end of file diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index dd967f8a904..8cefc79769d 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -1577,18 +1577,18 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, RE_AcquireResultImage(re, &rres, view_id); - if (rres.combined_buffer.data) { + if (rres.ibuf && rres.ibuf->float_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); + IMB_assign_float_buffer( + ibufs_arr[view_id], rres.ibuf->float_buffer.data, IB_DO_NOT_TAKE_OWNERSHIP); /* float buffers in the sequencer are not linear */ seq_imbuf_to_sequencer_space(context->scene, ibufs_arr[view_id], false); } - else if (rres.byte_buffer.data) { + else if (rres.ibuf->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.byte_buffer.data, + rres.ibuf->byte_buffer.data, 4 * rres.rectx * rres.recty); }