Refactor: Use ImBuf to store passes in RenderResult

Doing so avoids having duplicated logic for working with pixel
data which is being passed throughout the render pipeline.

Notable changes:

- ImBug can now store GPU texture.
  This is not very finished part of the API, which will be
  worked further to support tiling for very-high-res images.

- Implicit sharing is removed from the image buffer, as it is
  no longer needed.

There should be no functional changes on user level with this
change.

Ref #108618

Pull Request: https://projects.blender.org/blender/blender/pulls/109788
This commit is contained in:
Sergey Sharybin
2023-07-10 16:33:32 +02:00
committed by Sergey Sharybin
parent baf1c79668
commit d579ac2b3f
25 changed files with 315 additions and 528 deletions

View File

@@ -3987,12 +3987,9 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int e
if (ima->rr) { if (ima->rr) {
RenderPass *rpass = BKE_image_multilayer_index(ima->rr, iuser); RenderPass *rpass = BKE_image_multilayer_index(ima->rr, iuser);
if (rpass) { if (rpass && rpass->ibuf) {
// printf("load from pass %s\n", rpass->name); ibuf = rpass->ibuf;
ibuf = IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0); IMB_refImBuf(ibuf);
ibuf->channels = rpass->channels;
IMB_assign_shared_float_buffer(ibuf, rpass->buffer.data, rpass->buffer.sharing_info);
BKE_imbuf_stamp_info(ima->rr, 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) { if (ima->rr) {
RenderPass *rpass = BKE_image_multilayer_index(ima->rr, iuser); RenderPass *rpass = BKE_image_multilayer_index(ima->rr, iuser);
if (rpass) { if (rpass && rpass->ibuf) {
ibuf = IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0); ibuf = rpass->ibuf;
IMB_refImBuf(ibuf);
image_init_after_load(ima, iuser, 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); BKE_imbuf_stamp_info(ima->rr, ibuf);
image_assign_ibuf(ima, ibuf, iuser ? iuser->multi_index : IMA_NO_INDEX, 0); 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 */ /* always returns a single ibuf, also during render progress */
static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_lock) static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_lock)
{ {
Render *re;
RenderView *rv; RenderView *rv;
RenderBuffer *combined_buffer; ImBuf *pass_ibuf = nullptr;
RenderByteBuffer *byte_buffer;
float dither; float dither;
int channels, layer, pass; const int from_render = (ima->render_slot == ima->last_render_slot);
ImBuf *ibuf;
int from_render = (ima->render_slot == ima->last_render_slot);
int actview;
if (!(iuser && iuser->scene)) { if (!(iuser && iuser->scene)) {
return nullptr; return nullptr;
@@ -4337,12 +4326,11 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
return nullptr; return nullptr;
} }
re = RE_GetSceneRender(iuser->scene); Render *re = RE_GetSceneRender(iuser->scene);
channels = 4; const int layer = iuser->layer;
layer = iuser->layer; const int pass = iuser->pass;
pass = iuser->pass; int actview = iuser->view;
actview = iuser->view;
if (BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO)) { if (BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO)) {
actview = iuser->multiview_eye; 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) { else if ((slot = BKE_image_get_renderslot(ima, ima->render_slot))->render) {
rres = *(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)) { 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 */ /* this gives active layer, composite or sequence result */
if (rv == nullptr) { if (rv == nullptr) {
byte_buffer = &rres.byte_buffer; pass_ibuf = rres.ibuf;
combined_buffer = &rres.combined_buffer;
} }
else { else {
byte_buffer = &rv->byte_buffer; pass_ibuf = rv->ibuf;
combined_buffer = &rv->combined_buffer;
} }
dither = iuser->scene->r.dither_intensity; 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) { if (rres.have_combined && layer == 0) {
/* pass */ /* pass */
} }
else if (byte_buffer && byte_buffer->data && layer == 0) { else if (pass_ibuf && pass_ibuf->byte_buffer.data && layer == 0) {
/* rect32 is set when there's a Sequence pass, this pass seems /* pass */
* 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 (rres.layers.first) { else if (rres.layers.first) {
RenderLayer *rl = static_cast<RenderLayer *>( RenderLayer *rl = static_cast<RenderLayer *>(
@@ -4408,78 +4389,24 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
if (rl) { if (rl) {
RenderPass *rpass = image_render_pass_get(rl, pass, actview, nullptr); RenderPass *rpass = image_render_pass_get(rl, pass, actview, nullptr);
if (rpass) { if (rpass) {
combined_buffer = &rpass->buffer; pass_ibuf = rpass->ibuf;
if (pass != 0) { if (pass != 0) {
channels = rpass->channels;
dither = 0.0f; /* don't dither passes */ 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 */ IMB_refImBuf(pass_ibuf);
if (ibuf == nullptr) {
ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 32, 0);
image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
} }
/* Set color space settings for a byte buffer. return pass_ibuf;
*
* 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;
} }
static int image_get_multiview_index(Image *ima, ImageUser *iuser) static int image_get_multiview_index(Image *ima, ImageUser *iuser)

View File

@@ -736,7 +736,7 @@ bool BKE_image_render_write_exr(ReportList *reports,
/* Compositing result. */ /* Compositing result. */
if (rr->have_combined) { if (rr->have_combined) {
LISTBASE_FOREACH (RenderView *, rview, &rr->views) { LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
if (!rview->combined_buffer.data) { if (!rview->ibuf || !rview->ibuf->float_buffer.data) {
continue; continue;
} }
@@ -757,8 +757,8 @@ bool BKE_image_render_write_exr(ReportList *reports,
float *output_rect = float *output_rect =
(save_as_render) ? (save_as_render) ?
image_exr_from_scene_linear_to_output( image_exr_from_scene_linear_to_output(
rview->combined_buffer.data, rr->rectx, rr->recty, 4, imf, tmp_output_rects) : rview->ibuf->float_buffer.data, rr->rectx, rr->recty, 4, imf, tmp_output_rects) :
rview->combined_buffer.data; rview->ibuf->float_buffer.data;
for (int a = 0; a < channels; a++) { for (int a = 0; a < channels; a++) {
char passname[EXR_PASS_MAXNAME]; 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; const bool pass_half_float = half_float && pass_RGBA;
/* Color-space conversion only happens on RGBA passes. */ /* Color-space conversion only happens on RGBA passes. */
float *output_rect = float *output_rect = (save_as_render && pass_RGBA) ?
(save_as_render && pass_RGBA) ? image_exr_from_scene_linear_to_output(rp->ibuf->float_buffer.data,
image_exr_from_scene_linear_to_output( rr->rectx,
rp->buffer.data, rr->rectx, rr->recty, rp->channels, imf, tmp_output_rects) : rr->recty,
rp->buffer.data; rp->channels,
imf,
tmp_output_rects) :
rp->ibuf->float_buffer.data;
for (int a = 0; a < std::min(channels, rp->channels); a++) { for (int a = 0; a < std::min(channels, rp->channels); a++) {
/* Save Combined as RGBA or RGB if single layer save. */ /* Save Combined as RGBA or RGB if single layer save. */

View File

@@ -59,8 +59,9 @@ void CompositorOperation::deinit_execution()
if (rr) { if (rr) {
RenderView *rv = RE_RenderViewGetByName(rr, view_name_); 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; rr->have_combined = true;
} }

View File

@@ -46,6 +46,8 @@
#include "DNA_modifier_types.h" #include "DNA_modifier_types.h"
#include "DNA_particle_types.h" #include "DNA_particle_types.h"
#include "IMB_imbuf_types.h"
#include "eevee_private.h" #include "eevee_private.h"
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
@@ -582,7 +584,7 @@ static void eevee_cryptomatte_extract_render_passes(
const int pass_offset = pass * 2; const int pass_offset = pass * 2;
SNPRINTF_RLEN(cryptomatte_pass_name, render_pass_name_format, pass); SNPRINTF_RLEN(cryptomatte_pass_name, render_pass_name_format, pass);
RenderPass *rp_object = RE_pass_find_by_name(rl, cryptomatte_pass_name, viewname); 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 y = 0; y < rect_height; y++) {
for (int x = 0; x < rect_width; x++) { for (int x = 0; x < rect_width; x++) {
const int accum_buffer_offset = (rect_offset_x + x + const int accum_buffer_offset = (rect_offset_x + x +

View File

@@ -31,6 +31,8 @@
#include "RE_pipeline.h" #include "RE_pipeline.h"
#include "IMB_imbuf_types.h"
#include "eevee_private.h" #include "eevee_private.h"
bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, Depsgraph *depsgraph) 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, num_channels,
0, 0,
GPU_DATA_FLOAT, GPU_DATA_FLOAT,
rp->buffer.data); rp->ibuf->float_buffer.data);
} }
static void eevee_render_result_combined(RenderLayer *rl, static void eevee_render_result_combined(RenderLayer *rl,

View File

@@ -17,6 +17,7 @@
#include "DNA_ID.h" #include "DNA_ID.h"
#include "DNA_lightprobe_types.h" #include "DNA_lightprobe_types.h"
#include "DNA_modifier_types.h" #include "DNA_modifier_types.h"
#include "IMB_imbuf_types.h"
#include "RE_pipeline.h" #include "RE_pipeline.h"
#include "eevee_engine.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( RenderPass *vector_rp = RE_pass_find_by_name(
render_layer, vector_pass_name.c_str(), view_name); render_layer, vector_pass_name.c_str(), view_name);
if (vector_rp) { 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);
} }
} }
} }

View File

@@ -17,6 +17,8 @@
#include "RE_pipeline.h" #include "RE_pipeline.h"
#include "IMB_imbuf_types.h"
#include "gpencil_engine.h" #include "gpencil_engine.h"
void GPENCIL_render_init(GPENCIL_Data *vedata, 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_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); 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_z = (rpass_z_src) ? rpass_z_src->ibuf->float_buffer.data : NULL;
float *pix_col = (rpass_col_src) ? rpass_col_src->buffer.data : NULL; float *pix_col = (rpass_col_src) ? rpass_col_src->ibuf->float_buffer.data : NULL;
if (!pix_z || !pix_col) { if (!pix_z || !pix_col) {
RE_engine_set_error_message(engine, 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) { if ((view_layer->passflag & SCE_PASS_Z) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname); 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, GPU_framebuffer_read_depth(vedata->fbl->render_fb,
rect->xmin, rect->xmin,
@@ -223,7 +225,7 @@ static void GPENCIL_render_result_combined(RenderLayer *rl,
4, 4,
0, 0,
GPU_DATA_FLOAT, GPU_DATA_FLOAT,
rp->buffer.data); rp->ibuf->float_buffer.data);
} }
void GPENCIL_render_to_image(void *ved, void GPENCIL_render_to_image(void *ved,

View File

@@ -14,6 +14,7 @@
#include "ED_paint.h" #include "ED_paint.h"
#include "ED_view3d.h" #include "ED_view3d.h"
#include "GPU_capabilities.h" #include "GPU_capabilities.h"
#include "IMB_imbuf_types.h"
#include "draw_common.hh" #include "draw_common.hh"
#include "draw_sculpt.hh" #include "draw_sculpt.hh"
@@ -656,7 +657,7 @@ static void write_render_color_output(RenderLayer *layer,
4, 4,
0, 0,
GPU_DATA_FLOAT, 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_x(rect),
BLI_rcti_size_y(rect), BLI_rcti_size_y(rect),
GPU_DATA_FLOAT, GPU_DATA_FLOAT,
rp->buffer.data); rp->ibuf->float_buffer.data);
int pix_num = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect); int pix_num = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
/* Convert GPU depth [0..1] to view Z [near..far] */ /* Convert GPU depth [0..1] to view Z [near..far] */
if (DRW_view_is_persp_get(nullptr)) { 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) { if (z == 1.0f) {
z = 1e10f; /* Background */ z = 1e10f; /* Background */
} }
@@ -697,7 +698,7 @@ static void write_render_z_output(RenderLayer *layer,
float far = DRW_view_far_distance_get(nullptr); float far = DRW_view_far_distance_get(nullptr);
float range = fabsf(far - near); 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) { if (z == 1.0f) {
z = 1e10f; /* Background */ z = 1e10f; /* Background */
} }

View File

@@ -24,6 +24,8 @@
#include "DEG_depsgraph.h" #include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h" #include "DEG_depsgraph_query.h"
#include "IMB_imbuf_types.h"
#include "RE_pipeline.h" #include "RE_pipeline.h"
#include "workbench_private.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) { if ((view_layer->passflag & SCE_PASS_Z) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname); 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_bind(dfbl->default_fb);
GPU_framebuffer_read_depth(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, 4,
0, 0,
GPU_DATA_FLOAT, GPU_DATA_FLOAT,
rp->buffer.data); rp->ibuf->float_buffer.data);
workbench_render_result_z(render_layer, viewname, rect); workbench_render_result_z(render_layer, viewname, rect);
} }

View File

@@ -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 y = int(fpos[1] * render_pass->recty);
const int offset = 4 * (y * render_pass->rectx + x); const int offset = 4 * (y * render_pass->rectx + x);
zero_v3(r_col); zero_v3(r_col);
r_col[0] = render_pass->buffer.data[offset]; r_col[0] = render_pass->ibuf->float_buffer.data[offset];
return true; return true;
} }
} }

View File

@@ -204,16 +204,19 @@ static void image_buffer_rect_update(RenderJob *rj,
*/ */
/* TODO(sergey): Need to check has_combined here? */ /* TODO(sergey): Need to check has_combined here? */
if (iuser->pass == 0) { if (iuser->pass == 0) {
RenderView *rv;
const int view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname); 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 */ /* find current float rect for display, first case is after composite... still weak */
if (rv->combined_buffer.data) { if (rv->ibuf->float_buffer.data) {
rectf = rv->combined_buffer.data; rectf = rv->ibuf->float_buffer.data;
} }
else { else {
if (rv->byte_buffer.data) { if (rv->ibuf->byte_buffer.data) {
/* special case, currently only happens with sequencer rendering, /* special case, currently only happens with sequencer rendering,
* which updates the whole frame, so we can only mark display buffer * which updates the whole frame, so we can only mark display buffer
* as invalid here (sergey) * as invalid here (sergey)

View File

@@ -194,8 +194,7 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
RenderView *rv_del = rv->next; RenderView *rv_del = rv->next;
BLI_remlink(&rr->views, rv_del); BLI_remlink(&rr->views, rv_del);
RE_RenderBuffer_data_free(&rv_del->combined_buffer); IMB_freeImBuf(rv_del->ibuf);
RE_RenderByteBuffer_data_free(&rv_del->byte_buffer);
MEM_freeN(rv_del); MEM_freeN(rv_del);
} }
@@ -219,8 +218,7 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
BLI_remlink(&rr->views, rv_del); BLI_remlink(&rr->views, rv_del);
RE_RenderBuffer_data_free(&rv_del->combined_buffer); IMB_freeImBuf(rv_del->ibuf);
RE_RenderByteBuffer_data_free(&rv_del->byte_buffer);
MEM_freeN(rv_del); MEM_freeN(rv_del);
} }

View File

@@ -668,7 +668,7 @@ static bool ed_preview_draw_rect(
rv = nullptr; rv = nullptr;
} }
if (rv && rv->combined_buffer.data) { if (rv && rv->ibuf) {
if (abs(rres.rectx - newx) < 2 && abs(rres.recty - newy) < 2) { if (abs(rres.rectx - newx) < 2 && abs(rres.recty - newy) < 2) {
newrect->xmax = max_ii(newrect->xmax, rect->xmin + rres.rectx + offx); newrect->xmax = max_ii(newrect->xmax, rect->xmin + rres.rectx + offx);
newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty); 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 fx = rect->xmin + offx;
float fy = rect->ymin; 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( ED_draw_imbuf(
ibuf, fx, fy, false, &scene->view_settings, &scene->display_settings, 1.0f, 1.0f); rv->ibuf, fx, fy, false, &scene->view_settings, &scene->display_settings, 1.0f, 1.0f);
IMB_freeImBuf(ibuf);
ok = true; 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. */ /* Create buffer in empty RenderView created in the init step. */
RenderResult *rr = RE_AcquireResultWrite(re); RenderResult *rr = RE_AcquireResultWrite(re);
RenderView *rv = (RenderView *)rr->views.first; RenderView *rv = (RenderView *)rr->views.first;
RE_RenderBuffer_assign_data(&rv->combined_buffer, ImBuf *rv_ibuf = RE_RenderViewEnsureImBuf(rr, rv);
static_cast<float *>(MEM_callocN(sizeof(float[4]) * width * height, IMB_assign_float_buffer(rv_ibuf,
"texture render result"))); static_cast<float *>(MEM_callocN(sizeof(float[4]) * width * height,
"texture render result")),
IB_TAKE_OWNERSHIP);
RE_ReleaseResult(re); RE_ReleaseResult(re);
/* Get texture image pool (if any) */ /* 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); BKE_texture_fetch_images_for_pool(tex, img_pool);
/* Fill in image buffer. */ /* 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}; float tex_coord[3] = {0.0f, 0.0f, 0.0f};
bool color_manage = BKE_scene_check_color_management_enabled(sce); bool color_manage = BKE_scene_check_color_management_enabled(sce);

View File

@@ -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) static const char *ui_imageuser_layer_fake_name(RenderResult *rr)
{ {
RenderView *rv = RE_RenderViewGetById(rr, 0); 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"); return IFACE_("Composite");
} }
if (rv->byte_buffer.data) { if (ibuf->byte_buffer.data) {
return IFACE_("Sequence"); return IFACE_("Sequence");
} }
return NULL; return NULL;

View File

@@ -47,6 +47,8 @@ using namespace Freestyle;
#include "DEG_depsgraph_query.h" #include "DEG_depsgraph_query.h"
#include "IMB_imbuf.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "FRS_freestyle.h" #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); RenderLayer *rl = RE_GetRenderLayer(re->result, view_layer->name);
bool diffuse = false, z = false; bool diffuse = false, z = false;
for (RenderPass *rpass = (RenderPass *)rl->passes.first; rpass; rpass = rpass->next) { 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)) { if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE_COLOR)) {
controller->setPassDiffuse(rpass_buffer_data, rpass->rectx, rpass->recty); controller->setPassDiffuse(rpass_buffer_data, rpass->rectx, rpass->recty);
diffuse = true; diffuse = true;

View File

@@ -44,7 +44,6 @@
#include "../blenlib/BLI_sys_types.h" #include "../blenlib/BLI_sys_types.h"
#include "../gpu/GPU_texture.h" #include "../gpu/GPU_texture.h"
#include "BLI_implicit_sharing.h"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include "IMB_imbuf_types.h" #include "IMB_imbuf_types.h"
@@ -152,19 +151,6 @@ struct ImBuf *IMB_allocFromBuffer(const uint8_t *byte_buffer,
unsigned int h, unsigned int h,
unsigned int channels); 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. * 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. * 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_freerectfloatImBuf(struct ImBuf *ibuf);
void imb_freemipmapImBuf(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); 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. * Threaded processors.
*/ */

View File

@@ -4,12 +4,12 @@
#pragma once #pragma once
#include "BLI_implicit_sharing.h"
#include "DNA_vec_types.h" /* for rcti */ #include "DNA_vec_types.h" /* for rcti */
#include "BLI_sys_types.h" #include "BLI_sys_types.h"
struct GPUTexture;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -172,17 +172,14 @@ typedef enum ImBufOwnership {
/* Different storage specialization. /* 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 * Accessing the data pointer directly is fine and is an expected way of accessing it. */
* ownership is set to IB_DO_NOT_TAKE_OWNERSHIP. */
/* TODO(sergey): Once everything is C++ replace with a template. */
typedef struct ImBufByteBuffer { typedef struct ImBufByteBuffer {
uint8_t *data; uint8_t *data;
ImBufOwnership ownership; ImBufOwnership ownership;
const ImplicitSharingInfoHandle *implicit_sharing;
struct ColorSpace *colorspace; struct ColorSpace *colorspace;
} ImBufByteBuffer; } ImBufByteBuffer;
@@ -190,11 +187,20 @@ typedef struct ImBufByteBuffer {
typedef struct ImBufFloatBuffer { typedef struct ImBufFloatBuffer {
float *data; float *data;
ImBufOwnership ownership; ImBufOwnership ownership;
const ImplicitSharingInfoHandle *implicit_sharing;
struct ColorSpace *colorspace; struct ColorSpace *colorspace;
} ImBufFloatBuffer; } 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; ImBufFloatBuffer float_buffer;
/* Image buffer on the GPU. */
ImBufGPU gpu;
/** Resolution in pixels per meter. Multiply by `0.0254` for DPI. */ /** Resolution in pixels per meter. Multiply by `0.0254` for DPI. */
double ppm[2]; double ppm[2];

View File

@@ -23,10 +23,11 @@
#include "MEM_guardedalloc.h" #include "MEM_guardedalloc.h"
#include "BLI_implicit_sharing.hh"
#include "BLI_threads.h" #include "BLI_threads.h"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include "GPU_texture.h"
static SpinLock refcounter_spin; static SpinLock refcounter_spin;
void imb_refcounter_lock_init() void imb_refcounter_lock_init()
@@ -67,16 +68,12 @@ void imb_mmap_unlock()
* buffer to its defaults. */ * buffer to its defaults. */
template<class BufferType> static void imb_free_buffer(BufferType &buffer) template<class BufferType> static void imb_free_buffer(BufferType &buffer)
{ {
if (buffer.implicit_sharing) { if (buffer.data) {
blender::implicit_sharing::free_shared_data(&buffer.data, &buffer.implicit_sharing);
}
else if (buffer.data) {
switch (buffer.ownership) { switch (buffer.ownership) {
case IB_DO_NOT_TAKE_OWNERSHIP: case IB_DO_NOT_TAKE_OWNERSHIP:
break; break;
case IB_TAKE_OWNERSHIP: case IB_TAKE_OWNERSHIP:
BLI_assert(buffer.implicit_sharing == nullptr);
MEM_freeN(buffer.data); MEM_freeN(buffer.data);
break; break;
} }
@@ -85,7 +82,6 @@ template<class BufferType> static void imb_free_buffer(BufferType &buffer)
/* Reset buffer to defaults. */ /* Reset buffer to defaults. */
buffer.data = nullptr; buffer.data = nullptr;
buffer.ownership = IB_DO_NOT_TAKE_OWNERSHIP; buffer.ownership = IB_DO_NOT_TAKE_OWNERSHIP;
buffer.implicit_sharing = nullptr;
} }
/* Allocate pixel storage of the given buffer. The buffer owns the allocated memory. /* 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.ownership = IB_TAKE_OWNERSHIP;
buffer.implicit_sharing = nullptr;
return true; return true;
} }
@@ -119,12 +114,6 @@ template<class BufferType> void imb_make_writeable_buffer(BufferType &buffer)
buffer.data = static_cast<decltype(BufferType::data)>(MEM_dupallocN(buffer.data)); buffer.data = static_cast<decltype(BufferType::data)>(MEM_dupallocN(buffer.data));
buffer.ownership = IB_TAKE_OWNERSHIP; 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: case IB_TAKE_OWNERSHIP:
break; break;
} }
@@ -157,30 +146,6 @@ auto imb_steal_buffer_data(BufferType &buffer) -> decltype(BufferType::data)
return nullptr; 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<class BufferType>
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) void imb_freemipmapImBuf(ImBuf *ibuf)
{ {
int a; int a;
@@ -244,6 +209,16 @@ void imb_freerectImbuf_all(ImBuf *ibuf)
freeencodedbufferImBuf(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) void IMB_freeImBuf(ImBuf *ibuf)
{ {
if (ibuf == nullptr) { if (ibuf == nullptr) {
@@ -267,6 +242,7 @@ void IMB_freeImBuf(ImBuf *ibuf)
"'.blend' relative \"//\" must not be used in ImBuf!"); "'.blend' relative \"//\" must not be used in ImBuf!");
imb_freerectImbuf_all(ibuf); imb_freerectImbuf_all(ibuf);
IMB_free_gpu_textures(ibuf);
IMB_metadata_free(ibuf->metadata); IMB_metadata_free(ibuf->metadata);
colormanage_cache_free(ibuf); colormanage_cache_free(ibuf);
@@ -459,32 +435,6 @@ void IMB_make_writable_float_buffer(ImBuf *ibuf)
imb_make_writeable_buffer(ibuf->float_buffer); 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) void IMB_assign_byte_buffer(ImBuf *ibuf, uint8_t *buffer_data, const ImBufOwnership ownership)
{ {
imb_free_buffer(ibuf->byte_buffer); imb_free_buffer(ibuf->byte_buffer);
@@ -626,8 +576,6 @@ ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
return nullptr; return nullptr;
} }
/* TODO(sergey): Use implicit sharing. */
if (ibuf1->byte_buffer.data) { if (ibuf1->byte_buffer.data) {
flags |= IB_rect; flags |= IB_rect;
} }

View File

@@ -93,6 +93,7 @@ const EnumPropertyItem rna_enum_bake_pass_type_items[] = {
# include "GPU_capabilities.h" # include "GPU_capabilities.h"
# include "GPU_shader.h" # include "GPU_shader.h"
# include "IMB_colormanagement.h" # include "IMB_colormanagement.h"
# include "IMB_imbuf_types.h"
# include "DEG_depsgraph_query.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) static void rna_RenderPass_rect_get(PointerRNA *ptr, float *values)
{ {
RenderPass *rpass = (RenderPass *)ptr->data; RenderPass *rpass = (RenderPass *)ptr->data;
memcpy( const size_t size_in_bytes = sizeof(float) * rpass->rectx * rpass->recty * rpass->channels;
values, rpass->buffer.data, 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) void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values)
{ {
RenderPass *rpass = (RenderPass *)ptr->data; RenderPass *rpass = (RenderPass *)ptr->data;
memcpy( float *buffer = rpass->ibuf ? rpass->ibuf->float_buffer.data : nullptr;
rpass->buffer.data, values, sizeof(float) * rpass->rectx * rpass->recty * rpass->channels);
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) static RenderPass *rna_RenderPass_find_by_type(RenderLayer *rl, int passtype, const char *view)

View File

@@ -42,43 +42,14 @@ extern "C" {
/* only used as handle */ /* only used as handle */
typedef struct Render Render; 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 { typedef struct RenderView {
struct RenderView *next, *prev; struct RenderView *next, *prev;
char name[64]; /* EXR_VIEW_MAXNAME */ char name[64]; /* EXR_VIEW_MAXNAME */
/* if this exists, result of composited layers */ /* Image buffer of a composited layer or a sequencer output.
RenderBuffer combined_buffer; * The ibuf is only allocated if it has an actual data in one of its buffers (float, byte, or
* GPU). */
/* optional, 32 bits version of picture, used for sequencer, OpenGL render and image curves */ struct ImBuf *ibuf;
RenderByteBuffer byte_buffer;
} RenderView; } RenderView;
typedef struct RenderPass { typedef struct RenderPass {
@@ -87,7 +58,14 @@ typedef struct RenderPass {
char name[64]; /* amount defined in IMB_openexr.h */ char name[64]; /* amount defined in IMB_openexr.h */
char chan_id[8]; /* 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; int rectx, recty;
@@ -126,14 +104,10 @@ typedef struct RenderResult {
/* target image size */ /* target image size */
int rectx, recty; int rectx, recty;
/* The following byte, combined, and z buffers are for temporary storage only, /* The temporary storage to pass image data from #RE_AcquireResultImage.
* for RenderResult structs created in #RE_AcquireResultImage - which do not have RenderView */ * 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. */
/* Optional, 32 bits version of picture, used for OpenGL render and image curves. */ struct ImBuf *ibuf;
RenderByteBuffer byte_buffer;
/* if this exists, a copy of one of layers, or result of composited layers */
RenderBuffer combined_buffer;
/* coordinates within final image (after cropping) */ /* coordinates within final image (after cropping) */
rcti tilerect; 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); struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
float *RE_RenderLayerGetPass(struct RenderLayer *rl, const char *name, const char *viewname); float *RE_RenderLayerGetPass(struct RenderLayer *rl, const char *name, const char *viewname);
RenderBuffer *RE_RenderLayerGetPassBuffer(struct RenderLayer *rl, struct ImBuf *RE_RenderLayerGetPassImBuf(struct RenderLayer *rl,
const char *name, const char *name,
const char *viewname); const char *viewname);
bool RE_HasSingleLayer(struct Render *re); 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); RenderResult *RE_DuplicateRenderResult(RenderResult *rr);
/** struct ImBuf *RE_RenderPassEnsureImBuf(RenderPass *render_pass);
* Create new render buffer which takes ownership of the given data. struct ImBuf *RE_RenderViewEnsureImBuf(const RenderResult *render_result, RenderView *render_view);
* 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);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -226,7 +226,7 @@ class Context : public realtime_compositor::Context {
RenderPass *rpass = (RenderPass *)BLI_findstring( RenderPass *rpass = (RenderPass *)BLI_findstring(
&rl->passes, pass_name, offsetof(RenderPass, name)); &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); input_texture = RE_pass_ensure_gpu_texture_cache(re, rpass);
if (input_texture) { 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); float *output_buffer = (float *)GPU_texture_read(output_texture_, GPU_DATA_FLOAT, 0);
if (output_buffer) { 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. */ /* TODO: z-buffer output. */

View File

@@ -43,6 +43,8 @@
# include "BPY_extern.h" # include "BPY_extern.h"
#endif #endif
#include "IMB_imbuf_types.h"
#include "RE_bake.h" #include "RE_bake.h"
#include "RE_engine.h" #include "RE_engine.h"
#include "RE_pipeline.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. */ /* Fill render passes from bake pixel array, to be read by the render engine. */
for (int ty = 0; ty < h; ty++) { for (int ty = 0; ty < h; ty++) {
size_t offset = ty * w * 4; size_t offset = ty * w * 4;
float *primitive = primitive_pass->buffer.data + offset; float *primitive = primitive_pass->ibuf->float_buffer.data + offset;
float *differential = differential_pass->buffer.data + offset; float *differential = differential_pass->ibuf->float_buffer.data + offset;
size_t bake_offset = (y + ty) * image->width + x; size_t bake_offset = (y + ty) * image->width + x;
const BakePixel *bake_pixel = pixels + bake_offset; 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 offset = ty * w;
const size_t bake_offset = (y + ty) * image->width + x; 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; const BakePixel *bake_pixel = pixels + bake_offset;
float *bake_result = result + bake_offset * channels_num; float *bake_result = result + bake_offset * channels_num;

View File

@@ -228,16 +228,16 @@ void RE_FreeRenderResult(RenderResult *rr)
render_result_free(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); 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) float *RE_RenderLayerGetPass(RenderLayer *rl, const char *name, const char *viewname)
{ {
RenderPass *rpass = RE_pass_find_by_name(rl, name, viewname); const ImBuf *ibuf = RE_RenderLayerGetPassImBuf(rl, name, viewname);
return rpass ? rpass->buffer.data : nullptr; return ibuf ? ibuf->float_buffer.data : nullptr;
} }
RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name) 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); render_result_views_shallowcopy(rr, re->result);
RenderView *rv = static_cast<RenderView *>(rr->views.first); RenderView *rv = static_cast<RenderView *>(rr->views.first);
rr->have_combined = (rv->combined_buffer.data != nullptr); rr->have_combined = (rv->ibuf != nullptr);
/* single layer */ /* single layer */
RenderLayer *rl = render_get_single_layer(re, re->result); 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. */ * explicitly free it. So simply assign the buffers as a shallow copy here as well. */
if (rl) { if (rl) {
if (rv->combined_buffer.data == nullptr) { if (rv->ibuf == nullptr) {
LISTBASE_FOREACH (RenderView *, rview, &rr->views) { LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
RenderBuffer *buffer = RE_RenderLayerGetPassBuffer( rview->ibuf = RE_RenderLayerGetPassImBuf(rl, RE_PASSNAME_COMBINED, rview->name);
rl, RE_PASSNAME_COMBINED, rview->name);
if (buffer) {
rview->combined_buffer = *buffer;
}
} }
} }
} }
@@ -435,24 +431,20 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
/* `scene.rd.actview` view. */ /* `scene.rd.actview` view. */
rv = RE_RenderViewGetById(re->result, view_id); 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 /* 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. * explicitly free it. So simply assign the buffers as a shallow copy here as well.
* *
* The thread safety is ensured via the re->resultmutex. */ * The thread safety is ensured via the re->resultmutex. */
rr->combined_buffer = rv->combined_buffer; rr->ibuf = rv->ibuf;
rr->byte_buffer = rv->byte_buffer;
/* active layer */ /* active layer */
rl = render_get_single_layer(re, re->result); rl = render_get_single_layer(re, re->result);
if (rl) { if (rl) {
if (rv->combined_buffer.data == nullptr) { if (rv->ibuf == nullptr) {
RenderBuffer *buffer = RE_RenderLayerGetPassBuffer(rl, RE_PASSNAME_COMBINED, rv->name); rr->ibuf = RE_RenderLayerGetPassImBuf(rl, RE_PASSNAME_COMBINED, rv->name);
if (buffer) {
rr->combined_buffer = *buffer;
}
} }
} }
@@ -1311,8 +1303,8 @@ static void renderresult_stampinfo(Render *re)
BKE_image_stamp_buf(re->scene, BKE_image_stamp_buf(re->scene,
ob_camera_eval, ob_camera_eval,
(re->r.stamp & R_STAMP_STRIPMETA) ? rres.stamp_data : nullptr, (re->r.stamp & R_STAMP_STRIPMETA) ? rres.stamp_data : nullptr,
rres.byte_buffer.data, rres.ibuf->byte_buffer.data,
rres.combined_buffer.data, rres.ibuf->float_buffer.data,
rres.rectx, rres.rectx,
rres.recty, rres.recty,
4); 4);
@@ -2594,7 +2586,7 @@ void RE_layer_load_from_file(
IMB_float_from_rect(ibuf); IMB_float_from_rect(ibuf);
} }
memcpy(rpass->buffer.data, memcpy(rpass->ibuf->float_buffer.data,
ibuf->float_buffer.data, ibuf->float_buffer.data,
sizeof(float[4]) * layer->rectx * layer->recty); sizeof(float[4]) * layer->rectx * layer->recty);
} }
@@ -2610,7 +2602,7 @@ void RE_layer_load_from_file(
if (ibuf_clip) { if (ibuf_clip) {
IMB_rectcpy(ibuf_clip, ibuf, 0, 0, x, y, layer->rectx, layer->recty); 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, ibuf_clip->float_buffer.data,
sizeof(float[4]) * layer->rectx * layer->recty); sizeof(float[4]) * layer->rectx * layer->recty);
IMB_freeImBuf(ibuf_clip); 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. */ /* 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); RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
if (rp) { if (rp) {
rp->buffer.sharing_info->remove_user_and_delete_if_last(); IMB_freeImBuf(rp->ibuf);
rp->buffer.sharing_info = nullptr;
BLI_freelinkN(&rl->passes, rp); BLI_freelinkN(&rl->passes, rp);
} }
/* create a totally new pass */ /* create a totally new pass */

View File

@@ -54,8 +54,7 @@ static void render_result_views_free(RenderResult *rr)
RenderView *rv = static_cast<RenderView *>(rr->views.first); RenderView *rv = static_cast<RenderView *>(rr->views.first);
BLI_remlink(&rr->views, rv); BLI_remlink(&rr->views, rv);
RE_RenderByteBuffer_data_free(&rv->byte_buffer); IMB_freeImBuf(rv->ibuf);
RE_RenderBuffer_data_free(&rv->combined_buffer);
MEM_freeN(rv); MEM_freeN(rv);
} }
@@ -75,7 +74,7 @@ void render_result_free(RenderResult *rr)
while (rl->passes.first) { while (rl->passes.first) {
RenderPass *rpass = static_cast<RenderPass *>(rl->passes.first); RenderPass *rpass = static_cast<RenderPass *>(rl->passes.first);
RE_RenderBuffer_data_free(&rpass->buffer); IMB_freeImBuf(rpass->ibuf);
BLI_freelinkN(&rl->passes, rpass); BLI_freelinkN(&rl->passes, rpass);
} }
@@ -85,8 +84,7 @@ void render_result_free(RenderResult *rr)
render_result_views_free(rr); render_result_views_free(rr);
RE_RenderByteBuffer_data_free(&rr->byte_buffer); IMB_freeImBuf(rr->ibuf);
RE_RenderBuffer_data_free(&rr->combined_buffer);
if (rr->text) { if (rr->text) {
MEM_freeN(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 (RenderLayer *, rl, &rr->layers) {
LISTBASE_FOREACH (RenderPass *, rpass, &rl->passes) { LISTBASE_FOREACH (RenderPass *, rpass, &rl->passes) {
if (rpass->buffer.gpu_texture) { IMB_free_gpu_textures(rpass->ibuf);
GPU_texture_free(rpass->buffer.gpu_texture);
rpass->buffer.gpu_texture = nullptr;
}
} }
} }
} }
@@ -143,8 +138,7 @@ void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src)
STRNCPY(rv->name, rview->name); STRNCPY(rv->name, rview->name);
rv->combined_buffer = rview->combined_buffer; rv->ibuf = rview->ibuf;
rv->byte_buffer = rview->byte_buffer;
} }
} }
@@ -165,14 +159,19 @@ void render_result_views_shallowdelete(RenderResult *rr)
static void render_layer_allocate_pass(RenderResult *rr, RenderPass *rp) static void render_layer_allocate_pass(RenderResult *rr, RenderPass *rp)
{ {
if (rp->buffer.data != nullptr) { if (rp->ibuf && rp->ibuf->float_buffer.data) {
return; 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; const size_t rectsize = size_t(rr->rectx) * rr->recty * rp->channels;
float *buffer_data = MEM_cnew_array<float>(rectsize, rp->name); float *buffer_data = MEM_cnew_array<float>(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)) { if (STREQ(rp->name, RE_PASSNAME_VECTOR)) {
/* initialize to max speed */ /* 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) 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) GPUTexture *RE_pass_ensure_gpu_texture_cache(Render *re, RenderPass *rpass)
{ {
if (rpass->buffer.gpu_texture) { ImBuf *ibuf = rpass->ibuf;
return rpass->buffer.gpu_texture;
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; return nullptr;
} }
@@ -431,20 +442,21 @@ GPUTexture *RE_pass_ensure_gpu_texture_cache(Render *re, RenderPass *rpass)
(rpass->channels == 3) ? GPU_RGB16F : (rpass->channels == 3) ? GPU_RGB16F :
GPU_RGBA16F; GPU_RGBA16F;
rpass->buffer.gpu_texture = GPU_texture_create_2d("RenderBuffer.gpu_texture", /* TODO(sergey): Use utility to assign the texture. */
rpass->rectx, ibuf->gpu.texture = GPU_texture_create_2d("RenderBuffer.gpu_texture",
rpass->recty, rpass->rectx,
1, rpass->recty,
format, 1,
GPU_TEXTURE_USAGE_GENERAL, format,
nullptr); GPU_TEXTURE_USAGE_GENERAL,
nullptr);
if (rpass->buffer.gpu_texture) { if (ibuf->gpu.texture) {
GPU_texture_update(rpass->buffer.gpu_texture, GPU_DATA_FLOAT, rpass->buffer.data); GPU_texture_update(ibuf->gpu.texture, GPU_DATA_FLOAT, ibuf->float_buffer.data);
re->result_has_gpu_texture_caches = true; 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, void RE_render_result_full_channel_name(char *fullname,
@@ -543,6 +555,8 @@ static void ml_addpass_cb(void *base,
RenderPass *rpass = MEM_cnew<RenderPass>("loaded pass"); RenderPass *rpass = MEM_cnew<RenderPass>("loaded pass");
BLI_addtail(&rl->passes, rpass); BLI_addtail(&rl->passes, rpass);
rpass->rectx = rr->rectx;
rpass->recty = rr->recty;
rpass->channels = totchan; rpass->channels = totchan;
rl->passflag |= passtype_from_name(name); rl->passflag |= passtype_from_name(name);
@@ -673,7 +687,7 @@ RenderResult *render_result_new_from_exr(
rpass->recty = recty; rpass->recty = recty;
if (rpass->channels >= 3) { if (rpass->channels >= 3) {
IMB_colormanagement_transform(rpass->buffer.data, IMB_colormanagement_transform(rpass->ibuf->float_buffer.data,
rpass->rectx, rpass->rectx,
rpass->recty, rpass->recty,
rpass->channels, rpass->channels,
@@ -753,7 +767,11 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
rpass = rpass->next) rpass = rpass->next)
{ {
/* For save buffers, skip any passes that are only saved to disk. */ /* 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; continue;
} }
/* Render-result have all passes, render-part only the active view's passes. */ /* 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; 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 */ /* manually get next render pass */
rpassp = rpassp->next; rpassp = rpassp->next;
@@ -865,13 +887,23 @@ bool render_result_exr_file_read_path(RenderResult *rr,
RE_render_result_full_channel_name( RE_render_result_full_channel_name(
fullname, nullptr, rpass->name, rpass->view, rpass->chan_id, a); fullname, nullptr, rpass->name, rpass->view, rpass->chan_id, a);
if (IMB_exr_set_channel( if (IMB_exr_set_channel(exrhandle,
exrhandle, rl->name, fullname, xstride, ystride, rpass->buffer.data + a)) { rl->name,
fullname,
xstride,
ystride,
rpass->ibuf->float_buffer.data + a))
{
found_channels = true; found_channels = true;
} }
else if (rl_single) { else if (rl_single) {
if (IMB_exr_set_channel( if (IMB_exr_set_channel(exrhandle,
exrhandle, nullptr, fullname, xstride, ystride, rpass->buffer.data + a)) { nullptr,
fullname,
xstride,
ystride,
rpass->ibuf->float_buffer.data + a))
{
found_channels = true; found_channels = true;
} }
else { else {
@@ -998,8 +1030,10 @@ ImBuf *RE_render_result_rect_to_ibuf(RenderResult *rr,
RenderView *rv = RE_RenderViewGetById(rr, view_id); RenderView *rv = RE_RenderViewGetById(rr, view_id);
/* if not exists, BKE_imbuf_write makes one */ /* if not exists, BKE_imbuf_write makes one */
IMB_assign_shared_byte_buffer(ibuf, rv->byte_buffer.data, rv->byte_buffer.sharing_info); if (rv->ibuf) {
IMB_assign_shared_float_buffer(ibuf, rv->combined_buffer.data, rv->combined_buffer.sharing_info); 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 */ /* float factor for random dither, imbuf takes care of it */
ibuf->dither = dither; 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); RenderView *rv = RE_RenderViewGetById(rr, view_id);
ImBuf *rv_ibuf = RE_RenderViewEnsureImBuf(rr, rv);
if (ibuf->float_buffer.data) { if (ibuf->float_buffer.data) {
rr->have_combined = true; rr->have_combined = true;
if (!rv->combined_buffer.data) { if (!rv_ibuf->float_buffer.data) {
float *data = MEM_cnew_array<float>(4 * rr->rectx * rr->recty, "render_seq rectf"); float *data = MEM_cnew_array<float>(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, ibuf->float_buffer.data,
sizeof(float[4]) * rr->rectx * rr->recty); sizeof(float[4]) * rr->rectx * rr->recty);
/* TSK! Since sequence render doesn't free the *rr render result, the old rect32 /* 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 */ * 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) { else if (ibuf->byte_buffer.data) {
rr->have_combined = true; rr->have_combined = true;
if (!rv->byte_buffer.data) { if (!rv_ibuf->byte_buffer.data) {
uint8_t *data = MEM_cnew_array<uint8_t>(4 * rr->rectx * rr->recty, "render_seq rect"); uint8_t *data = MEM_cnew_array<uint8_t>(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. */ /* 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); RenderView *rv = RE_RenderViewGetById(rr, view_id);
if (rv->combined_buffer.data) { ImBuf *ibuf = RE_RenderViewEnsureImBuf(rr, rv);
memset(rv->combined_buffer.data, 0, sizeof(float[4]) * rr->rectx * rr->recty);
} if (!ibuf->float_buffer.data && !ibuf->byte_buffer.data) {
else if (rv->byte_buffer.data) {
memset(rv->byte_buffer.data, 0, 4 * rr->rectx * rr->recty);
}
else {
uint8_t *data = MEM_cnew_array<uint8_t>(rr->rectx * rr->recty, "render_seq rect"); uint8_t *data = MEM_cnew_array<uint8_t>(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) const int view_id)
{ {
RenderView *rv = RE_RenderViewGetById(rr, view_id); RenderView *rv = RE_RenderViewGetById(rr, view_id);
ImBuf *ibuf = rv ? rv->ibuf : nullptr;
if (rv && rv->byte_buffer.data) { if (ibuf->byte_buffer.data) {
memcpy(rect, rv->byte_buffer.data, sizeof(int) * rr->rectx * rr->recty); 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, IMB_display_buffer_transform_apply((uchar *)rect,
rv->combined_buffer.data, ibuf->float_buffer.data,
rr->rectx, rr->rectx,
rr->recty, rr->recty,
4, 4,
@@ -1130,13 +1172,17 @@ bool RE_HasCombinedLayer(const RenderResult *result)
return false; return false;
} }
return (rv->byte_buffer.data || rv->combined_buffer.data); return (rv->ibuf);
} }
bool RE_HasFloatPixels(const RenderResult *result) bool RE_HasFloatPixels(const RenderResult *result)
{ {
LISTBASE_FOREACH (const RenderView *, rview, &result->views) { 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; return false;
} }
} }
@@ -1177,9 +1223,7 @@ static RenderPass *duplicate_render_pass(RenderPass *rpass)
RenderPass *new_rpass = MEM_cnew<RenderPass>("new render pass", *rpass); RenderPass *new_rpass = MEM_cnew<RenderPass>("new render pass", *rpass);
new_rpass->next = new_rpass->prev = nullptr; new_rpass->next = new_rpass->prev = nullptr;
if (new_rpass->buffer.sharing_info != nullptr) { new_rpass->ibuf = IMB_dupImBuf(rpass->ibuf);
new_rpass->buffer.sharing_info->add_user();
}
return new_rpass; return new_rpass;
} }
@@ -1201,19 +1245,7 @@ static RenderView *duplicate_render_view(RenderView *rview)
{ {
RenderView *new_rview = MEM_cnew<RenderView>("new render view", *rview); RenderView *new_rview = MEM_cnew<RenderView>("new render view", *rview);
/* Reset buffers, they are not supposed to be shallow-coped. */ new_rview->ibuf = IMB_dupImBuf(rview->ibuf);
new_rview->combined_buffer = {};
new_rview->byte_buffer = {};
if (rview->combined_buffer.data != nullptr) {
RE_RenderBuffer_assign_data(&new_rview->combined_buffer,
static_cast<float *>(MEM_dupallocN(rview->combined_buffer.data)));
}
if (rview->byte_buffer.data != nullptr) {
RE_RenderByteBuffer_assign_data(
&new_rview->byte_buffer, static_cast<uint8_t *>(MEM_dupallocN(rview->byte_buffer.data)));
}
return new_rview; return new_rview;
} }
@@ -1233,115 +1265,27 @@ RenderResult *RE_DuplicateRenderResult(RenderResult *rr)
BLI_addtail(&new_rr->views, new_rview); BLI_addtail(&new_rr->views, new_rview);
} }
/* Reset buffers, they are not supposed to be shallow-coped. */ new_rr->ibuf = IMB_dupImBuf(rr->ibuf);
new_rr->combined_buffer = {};
new_rr->byte_buffer = {};
if (rr->combined_buffer.data) {
RE_RenderBuffer_assign_data(&new_rr->combined_buffer,
static_cast<float *>(MEM_dupallocN(rr->combined_buffer.data)));
}
if (rr->byte_buffer.data) {
RE_RenderByteBuffer_assign_data(&new_rr->byte_buffer,
static_cast<uint8_t *>(MEM_dupallocN(rr->byte_buffer.data)));
}
new_rr->stamp_data = BKE_stamp_data_copy(new_rr->stamp_data); new_rr->stamp_data = BKE_stamp_data_copy(new_rr->stamp_data);
return new_rr; return new_rr;
} }
/* -------------------------------------------------------------------- ImBuf *RE_RenderPassEnsureImBuf(RenderPass *render_pass)
* Render buffer.
*/
template<class BufferType> static BufferType render_buffer_new(decltype(BufferType::data) data)
{ {
BufferType buffer; if (!render_pass->ibuf) {
render_pass->ibuf = IMB_allocImBuf(render_pass->rectx, render_pass->recty, 32, 0);
buffer.data = data; render_pass->ibuf->channels = render_pass->channels;
buffer.sharing_info = blender::implicit_sharing::info_for_mem_free(data);
buffer.gpu_texture = nullptr;
return buffer;
}
template<class BufferType> 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); return render_pass->ibuf;
if (render_buffer->gpu_texture) {
GPU_texture_free(render_buffer->gpu_texture);
render_buffer->gpu_texture = nullptr;
}
} }
template<class BufferType> ImBuf *RE_RenderViewEnsureImBuf(const RenderResult *render_result, RenderView *render_view)
static void render_buffer_assign_data(BufferType *render_buffer, decltype(BufferType::data) data)
{ {
render_buffer_data_free(render_buffer); if (!render_view->ibuf) {
render_view->ibuf = IMB_allocImBuf(render_result->rectx, render_result->recty, 32, 0);
if (!data) {
render_buffer->data = nullptr;
render_buffer->sharing_info = nullptr;
return;
} }
render_buffer->data = data; return render_view->ibuf;
render_buffer->sharing_info = blender::implicit_sharing::info_for_mem_free(data); }
}
template<class BufferType>
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<RenderBuffer>(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<RenderByteBuffer>(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);
}

View File

@@ -1577,18 +1577,18 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
RE_AcquireResultImage(re, &rres, view_id); 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); ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, 0);
IMB_assign_shared_float_buffer( IMB_assign_float_buffer(
ibufs_arr[view_id], rres.combined_buffer.data, rres.combined_buffer.sharing_info); ibufs_arr[view_id], rres.ibuf->float_buffer.data, IB_DO_NOT_TAKE_OWNERSHIP);
/* float buffers in the sequencer are not linear */ /* float buffers in the sequencer are not linear */
seq_imbuf_to_sequencer_space(context->scene, ibufs_arr[view_id], false); 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); ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
memcpy(ibufs_arr[view_id]->byte_buffer.data, memcpy(ibufs_arr[view_id]->byte_buffer.data,
rres.byte_buffer.data, rres.ibuf->byte_buffer.data,
4 * rres.rectx * rres.recty); 4 * rres.rectx * rres.recty);
} }