Refactor Render Result to allow implicit buffer sharing #108045

Merged
Sergey Sharybin merged 5 commits from Sergey/blender:render_result_implicit_sharing into main 2023-05-23 09:19:44 +02:00
24 changed files with 542 additions and 236 deletions

View File

@ -3989,12 +3989,11 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int e
if (rpass) {
// printf("load from pass %s\n", rpass->name);
/* since we free render results, we copy the rect */
ibuf = IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0);
IMB_assign_float_buffer(
ibuf, static_cast<float *>(MEM_dupallocN(rpass->rect)), IB_TAKE_OWNERSHIP);
ibuf->channels = rpass->channels;
IMB_assign_shared_float_buffer(ibuf, rpass->buffer.data, rpass->buffer.sharing_info);
BKE_imbuf_stamp_info(ima->rr, ibuf);
image_init_after_load(ima, iuser, ibuf);
@ -4301,7 +4300,8 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
image_init_after_load(ima, iuser, ibuf);
IMB_assign_float_buffer(ibuf, rpass->rect, IB_DO_NOT_TAKE_OWNERSHIP);
IMB_assign_shared_float_buffer(ibuf, rpass->buffer.data, rpass->buffer.sharing_info);
ibuf->channels = rpass->channels;
BKE_imbuf_stamp_info(ima->rr, ibuf);
@ -4320,8 +4320,8 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
{
Render *re;
RenderView *rv;
float *rectf, *rectz;
uint *rect;
RenderBuffer *combined_buffer, *z_buffer;
RenderByteBuffer *byte_buffer;
float dither;
int channels, layer, pass;
ImBuf *ibuf;
@ -4355,7 +4355,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
}
else if ((slot = BKE_image_get_renderslot(ima, ima->render_slot))->render) {
rres = *(slot->render);
rres.have_combined = ((RenderView *)rres.views.first)->rectf != nullptr;
rres.have_combined = ((RenderView *)rres.views.first)->combined_buffer.data != nullptr;
}
if (!(rres.rectx > 0 && rres.recty > 0)) {
@ -4380,14 +4380,14 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
/* this gives active layer, composite or sequence result */
if (rv == nullptr) {
rect = (uint *)rres.rect32;
rectf = rres.rectf;
rectz = rres.rectz;
byte_buffer = &rres.byte_buffer;
combined_buffer = &rres.combined_buffer;
z_buffer = &rres.z_buffer;
}
else {
rect = (uint *)rv->rect32;
rectf = rv->rectf;
rectz = rv->rectz;
byte_buffer = &rv->byte_buffer;
combined_buffer = &rv->combined_buffer;
z_buffer = &rv->z_buffer;
}
dither = iuser->scene->r.dither_intensity;
@ -4396,13 +4396,13 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
if (rres.have_combined && layer == 0) {
/* pass */
}
else if (rect && layer == 0) {
else if (byte_buffer && byte_buffer->data && layer == 0) {
/* rect32 is set when there's a Sequence pass, this pass seems
* to have layer=0 (this is from image_buttons.c)
* in this case we ignore float buffer, because it could have
* hung from previous pass which was float
*/
rectf = nullptr;
combined_buffer = nullptr;
}
else if (rres.layers.first) {
RenderLayer *rl = static_cast<RenderLayer *>(
@ -4410,7 +4410,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
if (rl) {
RenderPass *rpass = image_render_pass_get(rl, pass, actview, nullptr);
if (rpass) {
rectf = rpass->rect;
combined_buffer = &rpass->buffer;
if (pass != 0) {
channels = rpass->channels;
dither = 0.0f; /* don't dither passes */
@ -4419,7 +4419,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
for (rpass = static_cast<RenderPass *>(rl->passes.first); rpass; rpass = rpass->next) {
if (STREQ(rpass->name, RE_PASSNAME_Z) && rpass->view_id == actview) {
rectz = rpass->rect;
z_buffer = &rpass->buffer;
}
}
}
@ -4441,14 +4441,16 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
*
* For other cases we need to be sure it stays to default byte buffer space.
*/
if (ibuf->byte_buffer.data != (uint8_t *)rect) {
if (ibuf->byte_buffer.data != byte_buffer->data) {
const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE);
IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace);
}
/* invalidate color managed buffers if render result changed */
BLI_thread_lock(LOCK_COLORMANAGE);
if (ibuf->x != rres.rectx || ibuf->y != rres.recty || ibuf->float_buffer.data != rectf) {
if (combined_buffer && (ibuf->x != rres.rectx || ibuf->y != rres.recty ||
ibuf->float_buffer.data != combined_buffer->data))
{
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
}
@ -4458,9 +4460,26 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
imb_freerectImBuf(ibuf);
IMB_assign_byte_buffer(ibuf, (uint8_t *)rect, IB_DO_NOT_TAKE_OWNERSHIP);
IMB_assign_float_buffer(ibuf, rectf, IB_DO_NOT_TAKE_OWNERSHIP);
IMB_assign_float_z_buffer(ibuf, rectz, IB_DO_NOT_TAKE_OWNERSHIP);
if (byte_buffer) {
IMB_assign_shared_byte_buffer(ibuf, byte_buffer->data, byte_buffer->sharing_info);
}
else {
IMB_assign_byte_buffer(ibuf, nullptr, IB_DO_NOT_TAKE_OWNERSHIP);
}
if (combined_buffer) {
IMB_assign_shared_float_buffer(ibuf, combined_buffer->data, combined_buffer->sharing_info);
}
else {
IMB_assign_float_buffer(ibuf, nullptr, IB_DO_NOT_TAKE_OWNERSHIP);
}
if (z_buffer) {
IMB_assign_shared_float_z_buffer(ibuf, z_buffer->data, z_buffer->sharing_info);
}
else {
IMB_assign_float_z_buffer(ibuf, nullptr, IB_DO_NOT_TAKE_OWNERSHIP);
}
/* TODO(sergey): Make this faster by either simply referencing the stamp
* or by changing both ImBuf and RenderResult to use same data type to

View File

@ -738,7 +738,7 @@ bool BKE_image_render_write_exr(ReportList *reports,
/* Compositing result. */
if (rr->have_combined) {
LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
if (!rview->rectf) {
if (!rview->combined_buffer.data) {
continue;
}
@ -756,10 +756,11 @@ bool BKE_image_render_write_exr(ReportList *reports,
continue;
}
float *output_rect = (save_as_render) ?
image_exr_from_scene_linear_to_output(
rview->rectf, rr->rectx, rr->recty, 4, imf, tmp_output_rects) :
rview->rectf;
float *output_rect =
(save_as_render) ?
image_exr_from_scene_linear_to_output(
rview->combined_buffer.data, rr->rectx, rr->recty, 4, imf, tmp_output_rects) :
rview->combined_buffer.data;
for (int a = 0; a < channels; a++) {
char passname[EXR_PASS_MAXNAME];
@ -781,9 +782,10 @@ bool BKE_image_render_write_exr(ReportList *reports,
exrhandle, layname, passname, viewname, 4, 4 * rr->rectx, output_rect + a, half_float);
}
if (write_z && rview->rectz) {
if (write_z && rview->z_buffer.data) {
const char *layname = (multi_layer) ? "Composite" : "";
IMB_exr_add_channel(exrhandle, layname, "Z", viewname, 1, rr->rectx, rview->rectz, false);
IMB_exr_add_channel(
exrhandle, layname, "Z", viewname, 1, rr->rectx, rview->z_buffer.data, false);
}
}
}
@ -825,8 +827,8 @@ bool BKE_image_render_write_exr(ReportList *reports,
float *output_rect =
(save_as_render && pass_RGBA) ?
image_exr_from_scene_linear_to_output(
rp->rect, rr->rectx, rr->recty, rp->channels, imf, tmp_output_rects) :
rp->rect;
rp->buffer.data, rr->rectx, rr->recty, rp->channels, imf, tmp_output_rects) :
rp->buffer.data;
for (int a = 0; a < std::min(channels, rp->channels); a++) {
/* Save Combined as RGBA or RGB if single layer save. */

View File

@ -67,14 +67,9 @@ void CompositorOperation::deinit_execution()
if (rr) {
RenderView *rv = RE_RenderViewGetByName(rr, view_name_);
if (rv->rectf != nullptr) {
MEM_freeN(rv->rectf);
}
rv->rectf = output_buffer_;
if (rv->rectz != nullptr) {
MEM_freeN(rv->rectz);
}
rv->rectz = depth_buffer_;
RE_RenderBuffer_assign_data(&rv->combined_buffer, output_buffer_);
RE_RenderBuffer_assign_data(&rv->z_buffer, depth_buffer_);
rr->have_combined = true;
}
else {

View File

@ -582,6 +582,7 @@ static void eevee_cryptomatte_extract_render_passes(
const int pass_offset = pass * 2;
SNPRINTF_RLEN(cryptomatte_pass_name, render_pass_name_format, pass);
RenderPass *rp_object = RE_pass_find_by_name(rl, cryptomatte_pass_name, viewname);
float *rp_buffer_data = rp_object->buffer.data;
for (int y = 0; y < rect_height; y++) {
for (int x = 0; x < rect_width; x++) {
const int accum_buffer_offset = (rect_offset_x + x +
@ -589,15 +590,15 @@ static void eevee_cryptomatte_extract_render_passes(
accum_pixel_stride +
layer_index * layer_stride + pass_offset;
const int render_pass_offset = (y * rect_width + x) * 4;
rp_object->rect[render_pass_offset] = accum_buffer[accum_buffer_offset].hash;
rp_object->rect[render_pass_offset + 1] = accum_buffer[accum_buffer_offset].weight;
rp_buffer_data[render_pass_offset] = accum_buffer[accum_buffer_offset].hash;
rp_buffer_data[render_pass_offset + 1] = accum_buffer[accum_buffer_offset].weight;
if (levels_done + 1 < num_cryptomatte_levels) {
rp_object->rect[render_pass_offset + 2] = accum_buffer[accum_buffer_offset + 1].hash;
rp_object->rect[render_pass_offset + 3] = accum_buffer[accum_buffer_offset + 1].weight;
rp_buffer_data[render_pass_offset + 2] = accum_buffer[accum_buffer_offset + 1].hash;
rp_buffer_data[render_pass_offset + 3] = accum_buffer[accum_buffer_offset + 1].weight;
}
else {
rp_object->rect[render_pass_offset + 2] = 0.0f;
rp_object->rect[render_pass_offset + 3] = 0.0f;
rp_buffer_data[render_pass_offset + 2] = 0.0f;
rp_buffer_data[render_pass_offset + 3] = 0.0f;
}
}
}

View File

@ -271,7 +271,7 @@ static void eevee_render_color_result(RenderLayer *rl,
num_channels,
0,
GPU_DATA_FLOAT,
rp->rect);
rp->buffer.data);
}
static void eevee_render_result_combined(RenderLayer *rl,

View File

@ -276,8 +276,7 @@ void Instance::render_read_result(RenderLayer *render_layer, const char *view_na
* However, on some implementation, we need a buffer with a few extra bytes for the read to
* happen correctly (see GLTexture::read()). So we need a custom memory allocation. */
/* Avoid memcpy(), replace the pointer directly. */
MEM_SAFE_FREE(rp->rect);
rp->rect = result;
RE_pass_set_buffer_data(rp, result);
BLI_mutex_unlock(&render->update_render_passes_mutex);
}
}
@ -291,7 +290,7 @@ void Instance::render_read_result(RenderLayer *render_layer, const char *view_na
RenderPass *vector_rp = RE_pass_find_by_name(
render_layer, vector_pass_name.c_str(), view_name);
if (vector_rp) {
memset(vector_rp->rect, 0, sizeof(float) * 4 * vector_rp->rectx * vector_rp->recty);
memset(vector_rp->buffer.data, 0, sizeof(float) * 4 * vector_rp->rectx * vector_rp->recty);
}
}
}

View File

@ -49,8 +49,8 @@ void GPENCIL_render_init(GPENCIL_Data *vedata,
RenderPass *rpass_z_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname);
RenderPass *rpass_col_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
float *pix_z = (rpass_z_src) ? rpass_z_src->rect : NULL;
float *pix_col = (rpass_col_src) ? rpass_col_src->rect : NULL;
float *pix_z = (rpass_z_src) ? rpass_z_src->buffer.data : NULL;
float *pix_col = (rpass_col_src) ? rpass_col_src->buffer.data : NULL;
if (!pix_z || !pix_col) {
RE_engine_set_error_message(engine,
@ -160,6 +160,7 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl,
if ((view_layer->passflag & SCE_PASS_Z) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
float *ro_buffer_data = rp->buffer.data;
GPU_framebuffer_read_depth(vedata->fbl->render_fb,
rect->xmin,
@ -167,7 +168,7 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
GPU_DATA_FLOAT,
rp->rect);
ro_buffer_data);
float winmat[4][4];
DRW_view_winmat_get(NULL, winmat, false);
@ -177,12 +178,12 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl,
/* Convert GPU depth [0..1] to view Z [near..far] */
if (DRW_view_is_persp_get(NULL)) {
for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
if (ro_buffer_data[i] == 1.0f) {
ro_buffer_data[i] = 1e10f; /* Background */
}
else {
rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]);
ro_buffer_data[i] = ro_buffer_data[i] * 2.0f - 1.0f;
ro_buffer_data[i] = winmat[3][2] / (ro_buffer_data[i] + winmat[2][2]);
}
}
}
@ -193,11 +194,11 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl,
float range = fabsf(far - near);
for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
if (ro_buffer_data[i] == 1.0f) {
ro_buffer_data[i] = 1e10f; /* Background */
}
else {
rp->rect[i] = rp->rect[i] * range - near;
ro_buffer_data[i] = ro_buffer_data[i] * range - near;
}
}
}
@ -221,7 +222,7 @@ static void GPENCIL_render_result_combined(struct RenderLayer *rl,
4,
0,
GPU_DATA_FLOAT,
rp->rect);
rp->buffer.data);
}
void GPENCIL_render_to_image(void *ved,

View File

@ -552,7 +552,7 @@ static void write_render_color_output(struct RenderLayer *layer,
4,
0,
GPU_DATA_FLOAT,
rp->rect);
rp->buffer.data);
}
}
@ -571,13 +571,13 @@ static void write_render_z_output(struct RenderLayer *layer,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
GPU_DATA_FLOAT,
rp->rect);
rp->buffer.data);
int pix_num = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
/* Convert GPU depth [0..1] to view Z [near..far] */
if (DRW_view_is_persp_get(nullptr)) {
for (float &z : MutableSpan(rp->rect, pix_num)) {
for (float &z : MutableSpan(rp->buffer.data, pix_num)) {
if (z == 1.0f) {
z = 1e10f; /* Background */
}
@ -593,7 +593,7 @@ static void write_render_z_output(struct RenderLayer *layer,
float far = DRW_view_far_distance_get(nullptr);
float range = fabsf(far - near);
for (float &z : MutableSpan(rp->rect, pix_num)) {
for (float &z : MutableSpan(rp->buffer.data, pix_num)) {
if (z == 1.0f) {
z = 1e10f; /* Background */
}

View File

@ -105,6 +105,7 @@ static void workbench_render_result_z(struct RenderLayer *rl,
if ((view_layer->passflag & SCE_PASS_Z) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
float *rp_buffer_data = rp->buffer.data;
GPU_framebuffer_bind(dfbl->default_fb);
GPU_framebuffer_read_depth(dfbl->default_fb,
@ -113,7 +114,7 @@ static void workbench_render_result_z(struct RenderLayer *rl,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
GPU_DATA_FLOAT,
rp->rect);
rp_buffer_data);
float winmat[4][4];
DRW_view_winmat_get(NULL, winmat, false);
@ -123,12 +124,12 @@ static void workbench_render_result_z(struct RenderLayer *rl,
/* Convert GPU depth [0..1] to view Z [near..far] */
if (DRW_view_is_persp_get(NULL)) {
for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
if (rp_buffer_data[i] == 1.0f) {
rp_buffer_data[i] = 1e10f; /* Background */
}
else {
rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]);
rp_buffer_data[i] = rp_buffer_data[i] * 2.0f - 1.0f;
rp_buffer_data[i] = winmat[3][2] / (rp_buffer_data[i] + winmat[2][2]);
}
}
}
@ -139,11 +140,11 @@ static void workbench_render_result_z(struct RenderLayer *rl,
float range = fabsf(far - near);
for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
if (rp_buffer_data[i] == 1.0f) {
rp_buffer_data[i] = 1e10f; /* Background */
}
else {
rp->rect[i] = rp->rect[i] * range - near;
rp_buffer_data[i] = rp_buffer_data[i] * range - near;
}
}
}
@ -208,7 +209,7 @@ void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer
4,
0,
GPU_DATA_FLOAT,
rp->rect);
rp->buffer.data);
workbench_render_result_z(render_layer, viewname, rect);
}

View File

@ -181,7 +181,7 @@ static bool eyedropper_cryptomatte_sample_renderlayer_fl(RenderLayer *render_lay
const int y = int(fpos[1] * render_pass->recty);
const int offset = 4 * (y * render_pass->rectx + x);
zero_v3(r_col);
r_col[0] = render_pass->rect[offset];
r_col[0] = render_pass->buffer.data[offset];
return true;
}
}

View File

@ -207,11 +207,11 @@ static void image_buffer_rect_update(RenderJob *rj,
rv = RE_RenderViewGetById(rr, view_id);
/* find current float rect for display, first case is after composite... still weak */
if (rv->rectf) {
rectf = rv->rectf;
if (rv->combined_buffer.data) {
rectf = rv->combined_buffer.data;
}
else {
if (rv->rect32) {
if (rv->byte_buffer.data) {
/* special case, currently only happens with sequencer rendering,
* which updates the whole frame, so we can only mark display buffer
* as invalid here (sergey)

View File

@ -193,17 +193,9 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
RenderView *rv_del = rv->next;
BLI_remlink(&rr->views, rv_del);
if (rv_del->rectf) {
MEM_freeN(rv_del->rectf);
}
if (rv_del->rectz) {
MEM_freeN(rv_del->rectz);
}
if (rv_del->rect32) {
MEM_freeN(rv_del->rect32);
}
RE_RenderBuffer_data_free(&rv_del->combined_buffer);
RE_RenderBuffer_data_free(&rv_del->z_buffer);
RE_RenderByteBuffer_data_free(&rv_del->byte_buffer);
MEM_freeN(rv_del);
}
@ -227,17 +219,9 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
BLI_remlink(&rr->views, rv_del);
if (rv_del->rectf) {
MEM_freeN(rv_del->rectf);
}
if (rv_del->rectz) {
MEM_freeN(rv_del->rectz);
}
if (rv_del->rect32) {
MEM_freeN(rv_del->rect32);
}
RE_RenderBuffer_data_free(&rv_del->combined_buffer);
RE_RenderBuffer_data_free(&rv_del->z_buffer);
RE_RenderByteBuffer_data_free(&rv_del->byte_buffer);
MEM_freeN(rv_del);
}

View File

@ -666,7 +666,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
rv = nullptr;
}
if (rv && rv->rectf) {
if (rv && rv->combined_buffer.data) {
if (abs(rres.rectx - newx) < 2 && abs(rres.recty - newy) < 2) {
@ -1073,8 +1073,9 @@ static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Rend
/* Create buffer in empty RenderView created in the init step. */
RenderResult *rr = RE_AcquireResultWrite(re);
RenderView *rv = (RenderView *)rr->views.first;
rv->rectf = static_cast<float *>(
MEM_callocN(sizeof(float[4]) * width * height, "texture render result"));
RE_RenderBuffer_assign_data(&rv->combined_buffer,
static_cast<float *>(MEM_callocN(sizeof(float[4]) * width * height,
"texture render result")));
RE_ReleaseResult(re);
/* Get texture image pool (if any) */
@ -1082,7 +1083,7 @@ static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Rend
BKE_texture_fetch_images_for_pool(tex, img_pool);
/* Fill in image buffer. */
float *rect_float = rv->rectf;
float *rect_float = rv->combined_buffer.data;
float tex_coord[3] = {0.0f, 0.0f, 0.0f};
bool color_manage = true;

View File

@ -127,10 +127,10 @@ static bool ui_imageuser_slot_menu_step(bContext *C, int direction, void *image_
static const char *ui_imageuser_layer_fake_name(RenderResult *rr)
{
RenderView *rv = RE_RenderViewGetById(rr, 0);
if (rv->rectf) {
if (rv->combined_buffer.data) {
return IFACE_("Composite");
}
if (rv->rect32) {
if (rv->byte_buffer.data) {
return IFACE_("Sequence");
}
return NULL;

View File

@ -445,12 +445,13 @@ static void prepare(Render *re, ViewLayer *view_layer, Depsgraph *depsgraph)
RenderLayer *rl = RE_GetRenderLayer(re->result, view_layer->name);
bool diffuse = false, z = false;
for (RenderPass *rpass = (RenderPass *)rl->passes.first; rpass; rpass = rpass->next) {
float *rpass_buffer_data = rpass->buffer.data;
if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE_COLOR)) {
controller->setPassDiffuse(rpass->rect, rpass->rectx, rpass->recty);
controller->setPassDiffuse(rpass_buffer_data, rpass->rectx, rpass->recty);
diffuse = true;
}
if (STREQ(rpass->name, RE_PASSNAME_Z)) {
controller->setPassZ(rpass->rect, rpass->rectx, rpass->recty);
controller->setPassZ(rpass_buffer_data, rpass->rectx, rpass->recty);
z = true;
}
}

View File

@ -43,6 +43,7 @@
#include "../blenlib/BLI_sys_types.h"
#include "../gpu/GPU_texture.h"
#include "BLI_implicit_sharing.h"
#include "IMB_imbuf_types.h"
#ifdef __cplusplus
@ -148,6 +149,20 @@ struct ImBuf *IMB_allocFromBuffer(const uint8_t *byte_buffer,
unsigned int h,
unsigned int channels);
/* Assign the content of the corresponding buffer using an implicitly shareable data pointer.
*
* NOTE: Does not modify the the topology (width, height, number of channels) or the mipmaps in any
* way. */
void IMB_assign_shared_byte_buffer(struct ImBuf *ibuf,
uint8_t *buffer_data,
const ImplicitSharingInfoHandle *implicit_sharing);
void IMB_assign_shared_float_buffer(struct ImBuf *ibuf,
float *buffer_data,
const ImplicitSharingInfoHandle *implicit_sharing);
void IMB_assign_shared_float_z_buffer(struct ImBuf *ibuf,
float *buffer_data,
const ImplicitSharingInfoHandle *implicit_sharing);
/* Assign the content of the corresponding buffer with the given data and ownership.
* The current content of the buffer is released corresponding to its ownership configuration.
*

View File

@ -3,6 +3,8 @@
#pragma once
#include "BLI_implicit_sharing.h"
#include "DNA_vec_types.h" /* for rcti */
#include "BLI_sys_types.h"
@ -169,22 +171,31 @@ typedef enum ImBufOwnership {
IB_TAKE_OWNERSHIP = 1,
} ImBufOwnership;
/* Different storage specialization. */
/* Different storage specialization.
*
* Note on the implicit sharing
* ----------------------------
*
* The buffer allows implicitly sharing data with other users of such data. In this case the

Grammar:
allows to implicitly share -> allows implicitly sharing

Grammar: `allows to implicitly share` -> `allows implicitly sharing`
* ownership is set to IB_DO_NOT_TAKE_OWNERSHIP. */
/* TODO(sergey): Once everything is C++ replace with a template. */
typedef struct ImBufIntBuffer {
int *data;
ImBufOwnership ownership;
const ImplicitSharingInfoHandle *implicit_sharing;
} ImBufIntBuffer;
typedef struct ImBufByteBuffer {
uint8_t *data;
ImBufOwnership ownership;
const ImplicitSharingInfoHandle *implicit_sharing;
} ImBufByteBuffer;
typedef struct ImBufFloatBuffer {
float *data;
ImBufOwnership ownership;
const ImplicitSharingInfoHandle *implicit_sharing;
} ImBufFloatBuffer;
/** \} */

View File

@ -22,6 +22,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_implicit_sharing.hh"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@ -65,12 +66,16 @@ void imb_mmap_unlock(void)
* buffer to its defaults. */
template<class BufferType> static void imb_free_buffer(BufferType &buffer)
{
if (buffer.data) {
if (buffer.implicit_sharing) {
blender::implicit_sharing::free_shared_data(&buffer.data, &buffer.implicit_sharing);
}
else if (buffer.data) {
switch (buffer.ownership) {
case IB_DO_NOT_TAKE_OWNERSHIP:
break;
case IB_TAKE_OWNERSHIP:
BLI_assert(buffer.implicit_sharing == nullptr);
MEM_freeN(buffer.data);
break;
}
@ -79,6 +84,7 @@ template<class BufferType> static void imb_free_buffer(BufferType &buffer)
/* Reset buffer to defaults. */
buffer.data = nullptr;
buffer.ownership = IB_DO_NOT_TAKE_OWNERSHIP;
buffer.implicit_sharing = nullptr;
}
/* Allocate pixel storage of the given buffer. The buffer owns the allocated memory.
@ -110,6 +116,11 @@ template<class BufferType> void imb_make_writeable_buffer(BufferType &buffer)
case IB_DO_NOT_TAKE_OWNERSHIP:
buffer.data = static_cast<decltype(BufferType::data)>(MEM_dupallocN(buffer.data));
buffer.ownership = IB_TAKE_OWNERSHIP;
if (buffer.implicit_sharing) {
buffer.implicit_sharing->remove_user_and_delete_if_last();
buffer.implicit_sharing = nullptr;
}
break;
case IB_TAKE_OWNERSHIP:
@ -144,6 +155,30 @@ auto imb_steal_buffer_data(BufferType &buffer) -> decltype(BufferType::data)
return nullptr;
}
/* Assign the new data of the buffer which is implicitly shared via the given handle.
* The old content of the buffer is freed using imb_free_buffer. */
template<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)
{
int a;
@ -483,6 +518,45 @@ void IMB_make_writable_float_buffer(ImBuf *ibuf)
imb_make_writeable_buffer(ibuf->float_buffer);
}
void IMB_assign_shared_byte_buffer(ImBuf *ibuf,
uint8_t *buffer_data,
const ImplicitSharingInfoHandle *implicit_sharing)
{
imb_free_buffer(ibuf->byte_buffer);
ibuf->flags &= ~IB_rect;
if (buffer_data) {
imb_assign_shared_buffer(ibuf->byte_buffer, buffer_data, implicit_sharing);
ibuf->flags |= IB_rect;
}
}
void IMB_assign_shared_float_buffer(ImBuf *ibuf,
float *buffer_data,
const ImplicitSharingInfoHandle *implicit_sharing)
{
imb_free_buffer(ibuf->float_buffer);
ibuf->flags &= ~IB_rectfloat;
if (buffer_data) {
imb_assign_shared_buffer(ibuf->float_buffer, buffer_data, implicit_sharing);
ibuf->flags |= IB_rectfloat;
}
}
void IMB_assign_shared_float_z_buffer(ImBuf *ibuf,
float *buffer_data,
const ImplicitSharingInfoHandle *implicit_sharing)
{
imb_free_buffer(ibuf->float_z_buffer);
ibuf->flags &= ~IB_zbuffloat;
if (buffer_data) {
imb_assign_shared_buffer(ibuf->float_z_buffer, buffer_data, implicit_sharing);
ibuf->flags |= IB_zbuffloat;
}
}
void IMB_assign_byte_buffer(ImBuf *ibuf, uint8_t *buffer_data, const ImBufOwnership ownership)
{
imb_free_buffer(ibuf->byte_buffer);

View File

@ -503,13 +503,15 @@ static int rna_RenderPass_rect_get_length(const PointerRNA *ptr,
static void rna_RenderPass_rect_get(PointerRNA *ptr, float *values)
{
RenderPass *rpass = (RenderPass *)ptr->data;
memcpy(values, rpass->rect, sizeof(float) * rpass->rectx * rpass->recty * rpass->channels);
memcpy(
values, rpass->buffer.data, sizeof(float) * rpass->rectx * rpass->recty * rpass->channels);
}
void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values)
{
RenderPass *rpass = (RenderPass *)ptr->data;
memcpy(rpass->rect, values, sizeof(float) * rpass->rectx * rpass->recty * rpass->channels);
memcpy(
rpass->buffer.data, values, sizeof(float) * rpass->rectx * rpass->recty * rpass->channels);
}
static RenderPass *rna_RenderPass_find_by_type(RenderLayer *rl, int passtype, const char *view)

View File

@ -11,6 +11,8 @@
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
#include "BLI_implicit_sharing.h"
struct ImBuf;
struct Image;
struct ImageFormatData;
@ -38,6 +40,21 @@ extern "C" {
/* only used as handle */
typedef struct Render Render;
/* Buffer of a floating point values which uses implicit sharing.
*
* The buffer is allocated by render passes creation, and then is shared with the render result
* and image buffer. */
typedef struct RenderBuffer {
float *data;
const ImplicitSharingInfoHandle *sharing_info;
} RenderBuffer;
/* Specialized render buffer to store 8bpp passes. */
typedef struct RenderByteBuffer {
uint8_t *data;
const ImplicitSharingInfoHandle *sharing_info;
} RenderByteBuffer;
/* Render Result usage:
*
* - render engine allocates/frees and delivers raw floating point rects
@ -51,11 +68,11 @@ typedef struct RenderView {
char name[64]; /* EXR_VIEW_MAXNAME */
/* if this exists, result of composited layers */
float *rectf;
/* if this exists, result of composited layers */
float *rectz;
RenderBuffer combined_buffer;
RenderBuffer z_buffer;
/* optional, 32 bits version of picture, used for sequencer, OpenGL render and image curves */
int *rect32;
RenderByteBuffer byte_buffer;
} RenderView;
@ -64,7 +81,9 @@ typedef struct RenderPass {
int channels;
char name[64]; /* amount defined in IMB_openexr.h */
char chan_id[8]; /* amount defined in IMB_openexr.h */
float *rect;
RenderBuffer buffer;
int rectx, recty;
char fullname[64]; /* EXR_PASS_MAXNAME */
@ -102,15 +121,15 @@ typedef struct RenderResult {
/* target image size */
int rectx, recty;
/* The following rect32, rectf and rectz buffers are for temporary storage only,
/* The following byte, combined, and z buffers are for temporary storage only,
* for RenderResult structs created in #RE_AcquireResultImage - which do not have RenderView */
/* Optional, 32 bits version of picture, used for OpenGL render and image curves. */
int *rect32;
RenderByteBuffer byte_buffer;
/* if this exists, a copy of one of layers, or result of composited layers */
float *rectf;
/* if this exists, a copy of one of layers, or result of composited layers */
float *rectz;
RenderBuffer combined_buffer;
RenderBuffer z_buffer;
/* coordinates within final image (after cropping) */
rcti tilerect;
@ -259,6 +278,9 @@ void RE_render_result_rect_from_ibuf(struct RenderResult *rr,
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
float *RE_RenderLayerGetPass(struct RenderLayer *rl, const char *name, const char *viewname);
RenderBuffer *RE_RenderLayerGetPassBuffer(struct RenderLayer *rl,
const char *name,
const char *viewname);
bool RE_HasSingleLayer(struct Render *re);
@ -433,6 +455,13 @@ struct RenderPass *RE_pass_find_by_type(struct RenderLayer *rl,
int passtype,
const char *viewname);
/**
* Set the buffer data of the render pass.
* The pass takes ownership of the data, and creates an implicit sharing handle to allow its
* sharing with other users.
*/
void RE_pass_set_buffer_data(struct RenderPass *pass, float *data);
/* shaded view or baking options */
#define RE_BAKE_NORMALS 0
#define RE_BAKE_DISPLACEMENT 1
@ -467,6 +496,43 @@ struct RenderView *RE_RenderViewGetByName(struct RenderResult *rr, const char *v
RenderResult *RE_DuplicateRenderResult(RenderResult *rr);
/**
* Create new render buffer which takes ownership of the given data.
* Creates an implicit sharing handle for the data as well. */
RenderBuffer RE_RenderBuffer_new(float *data);
/**
* Assign the buffer data.
*
* The current buffer data is freed and the new one is assigned, and the implicit sharing for it.
*/
void RE_RenderBuffer_assign_data(RenderBuffer *render_buffer, float *data);
/**
* Effectively `lhs = rhs`. The ths will share the same buffer as the ths (with an increased user
* counter).
*
* The current content of the lhs is freed.
* The rhs and its data is allowed to be nullptr, in which case the lhs's data will be nullptr
* after this call.
*/
void RE_RenderBuffer_assign_shared(RenderBuffer *lhs, const RenderBuffer *rhs);
/**
* Free data of the given buffer.
*
* The data and implicit sharing information of the buffer is set to nullptr after this call.
* The buffer itself is not freed.
*/
void RE_RenderBuffer_data_free(RenderBuffer *render_buffer);
/* Implementation of above, but for byte buffer. */
/* TODO(sergey): Once everything is C++ we can remove the duplicated API. */
RenderByteBuffer RE_RenderByteBuffer_new(uint8_t *data);
void RE_RenderByteBuffer_assign_data(RenderByteBuffer *render_buffer, uint8_t *data);
void RE_RenderByteBuffer_assign_shared(RenderByteBuffer *lhs, const RenderByteBuffer *rhs);
void RE_RenderByteBuffer_data_free(RenderByteBuffer *render_buffer);
#ifdef __cplusplus
}
#endif

View File

@ -222,8 +222,8 @@ static RenderResult *render_result_from_bake(
/* Fill render passes from bake pixel array, to be read by the render engine. */
for (int ty = 0; ty < h; ty++) {
size_t offset = ty * w * 4;
float *primitive = primitive_pass->rect + offset;
float *differential = differential_pass->rect + offset;
float *primitive = primitive_pass->buffer.data + offset;
float *differential = differential_pass->buffer.data + offset;
size_t bake_offset = (y + ty) * image->width + x;
const BakePixel *bake_pixel = pixels + bake_offset;
@ -290,7 +290,7 @@ static void render_result_to_bake(RenderEngine *engine, RenderResult *rr)
const size_t offset = ty * w;
const size_t bake_offset = (y + ty) * image->width + x;
const float *pass_rect = rpass->rect + offset * channels_num;
const float *pass_rect = rpass->buffer.data + offset * channels_num;
const BakePixel *bake_pixel = pixels + bake_offset;
float *bake_result = result + bake_offset * channels_num;

View File

@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_fileops.h"
#include "BLI_implicit_sharing.hh"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_path_util.h"
@ -225,10 +226,18 @@ void RE_FreeRenderResult(RenderResult *rr)
render_result_free(rr);
}
RenderBuffer *RE_RenderLayerGetPassBuffer(struct RenderLayer *rl,
const char *name,
const char *viewname)
{
RenderPass *rpass = RE_pass_find_by_name(rl, name, viewname);
return rpass ? &rpass->buffer : nullptr;
}
float *RE_RenderLayerGetPass(RenderLayer *rl, const char *name, const char *viewname)
{
RenderPass *rpass = RE_pass_find_by_name(rl, name, viewname);
return rpass ? rpass->rect : nullptr;
return rpass ? rpass->buffer.data : nullptr;
}
RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name)
@ -371,21 +380,31 @@ void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
render_result_views_shallowcopy(rr, re->result);
RenderView *rv = static_cast<RenderView *>(rr->views.first);
rr->have_combined = (rv->rectf != nullptr);
rr->have_combined = (rv->combined_buffer.data != nullptr);
/* single layer */
RenderLayer *rl = render_get_single_layer(re, re->result);
/* The render result uses shallow initialization, and the caller is not expected to
* explicitly free it. So simply assign the buffers as a shallow copy here as well. */
if (rl) {
if (rv->rectf == nullptr) {
if (rv->combined_buffer.data == nullptr) {
LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
rview->rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, rview->name);
RenderBuffer *buffer = RE_RenderLayerGetPassBuffer(
rl, RE_PASSNAME_COMBINED, rview->name);
if (buffer) {
rview->combined_buffer = *buffer;
}
}
}
if (rv->rectz == nullptr) {
if (rv->z_buffer.data == nullptr) {
LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
rview->rectz = RE_RenderLayerGetPass(rl, RE_PASSNAME_Z, rview->name);
RenderBuffer *buffer = RE_RenderLayerGetPassBuffer(rl, RE_PASSNAME_Z, rview->name);
if (buffer) {
rview->z_buffer = *buffer;
}
}
}
}
@ -424,22 +443,32 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
/* `scene.rd.actview` view. */
rv = RE_RenderViewGetById(re->result, view_id);
rr->have_combined = (rv->rectf != nullptr);
rr->have_combined = (rv->combined_buffer.data != nullptr);
rr->rectf = rv->rectf;
rr->rectz = rv->rectz;
rr->rect32 = rv->rect32;
/* The render result uses shallow initialization, and the caller is not expected to
* explicitly free it. So simply assign the buffers as a shallow copy here as well.
*
* The thread safety is ensured via the re->resultmutex. */
rr->combined_buffer = rv->combined_buffer;
rr->z_buffer = rv->z_buffer;
rr->byte_buffer = rv->byte_buffer;
/* active layer */
rl = render_get_single_layer(re, re->result);
if (rl) {
if (rv->rectf == nullptr) {
rr->rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, rv->name);
if (rv->combined_buffer.data == nullptr) {
RenderBuffer *buffer = RE_RenderLayerGetPassBuffer(rl, RE_PASSNAME_COMBINED, rv->name);
if (buffer) {
rr->combined_buffer = *buffer;
}
}
if (rv->rectz == nullptr) {
rr->rectz = RE_RenderLayerGetPass(rl, RE_PASSNAME_Z, rv->name);
if (rv->z_buffer.data == nullptr) {
RenderBuffer *buffer = RE_RenderLayerGetPassBuffer(rl, RE_PASSNAME_Z, rv->name);
if (buffer) {
rr->z_buffer = *buffer;
}
}
}
@ -1198,8 +1227,8 @@ static void renderresult_stampinfo(Render *re)
BKE_image_stamp_buf(re->scene,
ob_camera_eval,
(re->r.stamp & R_STAMP_STRIPMETA) ? rres.stamp_data : nullptr,
(uchar *)rres.rect32,
rres.rectf,
rres.byte_buffer.data,
rres.combined_buffer.data,
rres.rectx,
rres.recty,
4);
@ -2464,7 +2493,9 @@ void RE_layer_load_from_file(
IMB_float_from_rect(ibuf);
}
memcpy(rpass->rect, ibuf->float_buffer.data, sizeof(float[4]) * layer->rectx * layer->recty);
memcpy(rpass->buffer.data,
ibuf->float_buffer.data,
sizeof(float[4]) * layer->rectx * layer->recty);
}
else {
if ((ibuf->x - x >= layer->rectx) && (ibuf->y - y >= layer->recty)) {
@ -2478,7 +2509,7 @@ void RE_layer_load_from_file(
if (ibuf_clip) {
IMB_rectcpy(ibuf_clip, ibuf, 0, 0, x, y, layer->rectx, layer->recty);
memcpy(rpass->rect,
memcpy(rpass->buffer.data,
ibuf_clip->float_buffer.data,
sizeof(float[4]) * layer->rectx * layer->recty);
IMB_freeImBuf(ibuf_clip);
@ -2605,9 +2636,9 @@ RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const cha
/* Clear previous pass if exist or the new image will be over previous one. */
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
if (rp) {
if (rp->rect) {
MEM_freeN(rp->rect);
}
rp->buffer.sharing_info->remove_user_and_delete_if_last();
rp->buffer.sharing_info = nullptr;
BLI_freelinkN(&rl->passes, rp);
}
/* create a totally new pass */

View File

@ -14,6 +14,7 @@
#include "BLI_ghash.h"
#include "BLI_hash_md5.h"
#include "BLI_implicit_sharing.hh"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_rect.h"
@ -50,17 +51,9 @@ static void render_result_views_free(RenderResult *rr)
RenderView *rv = static_cast<RenderView *>(rr->views.first);
BLI_remlink(&rr->views, rv);
if (rv->rect32) {
MEM_freeN(rv->rect32);
}
if (rv->rectz) {
MEM_freeN(rv->rectz);
}
if (rv->rectf) {
MEM_freeN(rv->rectf);
}
RE_RenderByteBuffer_data_free(&rv->byte_buffer);
RE_RenderBuffer_data_free(&rv->combined_buffer);
RE_RenderBuffer_data_free(&rv->z_buffer);
MEM_freeN(rv);
}
@ -79,11 +72,10 @@ void render_result_free(RenderResult *rr)
while (rl->passes.first) {
RenderPass *rpass = static_cast<RenderPass *>(rl->passes.first);
if (rpass->rect) {
MEM_freeN(rpass->rect);
}
BLI_remlink(&rl->passes, rpass);
MEM_freeN(rpass);
RE_RenderBuffer_data_free(&rpass->buffer);
BLI_freelinkN(&rl->passes, rpass);
}
BLI_remlink(&rr->layers, rl);
MEM_freeN(rl);
@ -91,15 +83,10 @@ void render_result_free(RenderResult *rr)
render_result_views_free(rr);
if (rr->rect32) {
MEM_freeN(rr->rect32);
}
if (rr->rectz) {
MEM_freeN(rr->rectz);
}
if (rr->rectf) {
MEM_freeN(rr->rectf);
}
RE_RenderByteBuffer_data_free(&rr->byte_buffer);
RE_RenderBuffer_data_free(&rr->combined_buffer);
RE_RenderBuffer_data_free(&rr->z_buffer);
if (rr->text) {
MEM_freeN(rr->text);
}
@ -142,9 +129,10 @@ void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src)
BLI_addtail(&dst->views, rv);
STRNCPY(rv->name, rview->name);
rv->rectf = rview->rectf;
rv->rectz = rview->rectz;
rv->rect32 = rview->rect32;
rv->combined_buffer = rview->combined_buffer;
rv->z_buffer = rview->z_buffer;
rv->byte_buffer = rview->byte_buffer;
}
}
@ -165,24 +153,24 @@ void render_result_views_shallowdelete(RenderResult *rr)
static void render_layer_allocate_pass(RenderResult *rr, RenderPass *rp)
{
if (rp->rect != nullptr) {
if (rp->buffer.data != nullptr) {
return;
}
const size_t rectsize = size_t(rr->rectx) * rr->recty * rp->channels;
rp->rect = MEM_cnew_array<float>(rectsize, rp->name);
float *buffer_data = MEM_cnew_array<float>(rectsize, rp->name);
rp->buffer = RE_RenderBuffer_new(buffer_data);
if (STREQ(rp->name, RE_PASSNAME_VECTOR)) {
/* initialize to max speed */
float *rect = rp->rect;
for (int x = rectsize - 1; x >= 0; x--) {
rect[x] = PASS_VECTOR_MAX;
buffer_data[x] = PASS_VECTOR_MAX;
}
}
else if (STREQ(rp->name, RE_PASSNAME_Z)) {
float *rect = rp->rect;
for (int x = rectsize - 1; x >= 0; x--) {
rect[x] = 10e10;
buffer_data[x] = 10e10;
}
}
}
@ -413,6 +401,11 @@ void RE_create_render_pass(RenderResult *rr,
}
}
void RE_pass_set_buffer_data(struct RenderPass *pass, float *data)
{
RE_RenderBuffer_assign_data(&pass->buffer, data);
}
void RE_render_result_full_channel_name(char *fullname,
const char *layname,
const char *passname,
@ -515,7 +508,8 @@ static void ml_addpass_cb(void *base,
/* channel id chars */
STRNCPY(rpass->chan_id, chan_id);
rpass->rect = rect;
RE_pass_set_buffer_data(rpass, rect);
STRNCPY(rpass->name, name);
STRNCPY(rpass->view, view);
RE_render_result_full_channel_name(rpass->fullname, nullptr, name, view, rpass->chan_id, -1);
@ -638,7 +632,7 @@ RenderResult *render_result_new_from_exr(
rpass->recty = recty;
if (rpass->channels >= 3) {
IMB_colormanagement_transform(rpass->rect,
IMB_colormanagement_transform(rpass->buffer.data,
rpass->rectx,
rpass->recty,
rpass->channels,
@ -718,7 +712,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
rpass = rpass->next)
{
/* For save buffers, skip any passes that are only saved to disk. */
if (rpass->rect == nullptr || rpassp->rect == nullptr) {
if (rpass->buffer.data == nullptr || rpassp->buffer.data == nullptr) {
continue;
}
/* Render-result have all passes, render-part only the active view's passes. */
@ -726,7 +720,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
continue;
}
do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels);
do_merge_tile(rr, rrpart, rpass->buffer.data, rpassp->buffer.data, rpass->channels);
/* manually get next render pass */
rpassp = rpassp->next;
@ -825,7 +819,7 @@ int render_result_exr_file_read_path(RenderResult *rr,
RE_render_result_full_channel_name(
fullname, nullptr, rpass->name, rpass->view, rpass->chan_id, a);
IMB_exr_set_channel(
exrhandle, rl->name, fullname, xstride, xstride * rectx, rpass->rect + a);
exrhandle, rl->name, fullname, xstride, xstride * rectx, rpass->buffer.data + a);
}
RE_render_result_full_channel_name(
@ -931,9 +925,9 @@ ImBuf *RE_render_result_rect_to_ibuf(RenderResult *rr,
RenderView *rv = RE_RenderViewGetById(rr, view_id);
/* if not exists, BKE_imbuf_write makes one */
IMB_assign_byte_buffer(ibuf, reinterpret_cast<uint8_t *>(rv->rect32), IB_DO_NOT_TAKE_OWNERSHIP);
IMB_assign_float_buffer(ibuf, rv->rectf, IB_DO_NOT_TAKE_OWNERSHIP);
IMB_assign_float_z_buffer(ibuf, rv->rectz, IB_DO_NOT_TAKE_OWNERSHIP);
IMB_assign_shared_byte_buffer(ibuf, rv->byte_buffer.data, rv->byte_buffer.sharing_info);
IMB_assign_shared_float_buffer(ibuf, rv->combined_buffer.data, rv->combined_buffer.sharing_info);
IMB_assign_shared_float_z_buffer(ibuf, rv->z_buffer.data, rv->z_buffer.sharing_info);
/* float factor for random dither, imbuf takes care of it */
ibuf->dither = dither;
@ -978,27 +972,31 @@ void RE_render_result_rect_from_ibuf(RenderResult *rr, const ImBuf *ibuf, const
if (ibuf->float_buffer.data) {
rr->have_combined = true;
if (!rv->rectf) {
rv->rectf = MEM_cnew_array<float>(4 * rr->rectx * rr->recty, "render_seq rectf");
if (!rv->combined_buffer.data) {
float *data = MEM_cnew_array<float>(4 * rr->rectx * rr->recty, "render_seq rectf");
RE_RenderBuffer_assign_data(&rv->combined_buffer, data);
}
memcpy(rv->rectf, ibuf->float_buffer.data, sizeof(float[4]) * rr->rectx * rr->recty);
memcpy(rv->combined_buffer.data,
ibuf->float_buffer.data,
sizeof(float[4]) * rr->rectx * rr->recty);
/* TSK! Since sequence render doesn't free the *rr render result, the old rect32
* can hang around when sequence render has rendered a 32 bits one before */
MEM_SAFE_FREE(rv->rect32);
RE_RenderByteBuffer_data_free(&rv->byte_buffer);
}
else if (ibuf->byte_buffer.data) {
rr->have_combined = true;
if (!rv->rect32) {
rv->rect32 = MEM_cnew_array<int>(rr->rectx * rr->recty, "render_seq rect");
if (!rv->byte_buffer.data) {
uint8_t *data = MEM_cnew_array<uint8_t>(4 * rr->rectx * rr->recty, "render_seq rect");
RE_RenderByteBuffer_assign_data(&rv->byte_buffer, data);
}
memcpy(rv->rect32, ibuf->byte_buffer.data, sizeof(int) * rr->rectx * rr->recty);
memcpy(rv->byte_buffer.data, ibuf->byte_buffer.data, sizeof(int) * rr->rectx * rr->recty);
/* Same things as above, old rectf can hang around from previous render. */
MEM_SAFE_FREE(rv->rectf);
RE_RenderBuffer_data_free(&rv->combined_buffer);
}
}
@ -1006,14 +1004,15 @@ void render_result_rect_fill_zero(RenderResult *rr, const int view_id)
{
RenderView *rv = RE_RenderViewGetById(rr, view_id);
if (rv->rectf) {
memset(rv->rectf, 0, sizeof(float[4]) * rr->rectx * rr->recty);
if (rv->combined_buffer.data) {
memset(rv->combined_buffer.data, 0, sizeof(float[4]) * rr->rectx * rr->recty);
}
else if (rv->rect32) {
memset(rv->rect32, 0, 4 * rr->rectx * rr->recty);
else if (rv->byte_buffer.data) {
memset(rv->byte_buffer.data, 0, 4 * rr->rectx * rr->recty);
}
else {
rv->rect32 = MEM_cnew_array<int>(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);
}
}
@ -1027,12 +1026,18 @@ void render_result_rect_get_pixels(RenderResult *rr,
{
RenderView *rv = RE_RenderViewGetById(rr, view_id);
if (rv && rv->rect32) {
memcpy(rect, rv->rect32, sizeof(int) * rr->rectx * rr->recty);
if (rv && rv->byte_buffer.data) {
memcpy(rect, rv->byte_buffer.data, sizeof(int) * rr->rectx * rr->recty);
}
else if (rv && rv->rectf) {
IMB_display_buffer_transform_apply(
(uchar *)rect, rv->rectf, rr->rectx, rr->recty, 4, view_settings, display_settings, true);
else if (rv && rv->combined_buffer.data) {
IMB_display_buffer_transform_apply((uchar *)rect,
rv->combined_buffer.data,
rr->rectx,
rr->recty,
4,
view_settings,
display_settings,
true);
}
else {
/* else fill with black */
@ -1053,13 +1058,13 @@ bool RE_HasCombinedLayer(const RenderResult *result)
return false;
}
return (rv->rect32 || rv->rectf);
return (rv->byte_buffer.data || rv->combined_buffer.data);
}
bool RE_HasFloatPixels(const RenderResult *result)
{
LISTBASE_FOREACH (const RenderView *, rview, &result->views) {
if (rview->rect32 && !rview->rectf) {
if (rview->byte_buffer.data && !rview->combined_buffer.data) {
return false;
}
}
@ -1099,9 +1104,11 @@ static RenderPass *duplicate_render_pass(RenderPass *rpass)
{
RenderPass *new_rpass = MEM_cnew<RenderPass>("new render pass", *rpass);
new_rpass->next = new_rpass->prev = nullptr;
if (new_rpass->rect != nullptr) {
new_rpass->rect = static_cast<float *>(MEM_dupallocN(new_rpass->rect));
if (new_rpass->buffer.sharing_info != nullptr) {
new_rpass->buffer.sharing_info->add_user();
}
return new_rpass;
}
@ -1121,15 +1128,22 @@ static RenderLayer *duplicate_render_layer(RenderLayer *rl)
static RenderView *duplicate_render_view(RenderView *rview)
{
RenderView *new_rview = MEM_cnew<RenderView>("new render view", *rview);
if (new_rview->rectf != nullptr) {
new_rview->rectf = static_cast<float *>(MEM_dupallocN(new_rview->rectf));
if (rview->combined_buffer.data != nullptr) {
RE_RenderBuffer_assign_data(&new_rview->combined_buffer,
static_cast<float *>(MEM_dupallocN(rview->combined_buffer.data)));
}
if (new_rview->rectz != nullptr) {
new_rview->rectz = static_cast<float *>(MEM_dupallocN(new_rview->rectz));
if (rview->z_buffer.data != nullptr) {
RE_RenderBuffer_assign_data(&new_rview->z_buffer,
static_cast<float *>(MEM_dupallocN(rview->z_buffer.data)));
}
if (new_rview->rect32 != nullptr) {
new_rview->rect32 = static_cast<int *>(MEM_dupallocN(new_rview->rect32));
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;
}
@ -1147,15 +1161,105 @@ RenderResult *RE_DuplicateRenderResult(RenderResult *rr)
RenderView *new_rview = duplicate_render_view(rview);
BLI_addtail(&new_rr->views, new_rview);
}
if (new_rr->rectf != nullptr) {
new_rr->rectf = static_cast<float *>(MEM_dupallocN(new_rr->rectf));
}
if (new_rr->rectz != nullptr) {
new_rr->rectz = static_cast<float *>(MEM_dupallocN(new_rr->rectz));
}
if (new_rr->rect32 != nullptr) {
new_rr->rect32 = static_cast<int *>(MEM_dupallocN(new_rr->rect32));
}
RE_RenderBuffer_assign_data(&new_rr->combined_buffer,
static_cast<float *>(MEM_dupallocN(rr->combined_buffer.data)));
RE_RenderBuffer_assign_data(&new_rr->z_buffer,
static_cast<float *>(MEM_dupallocN(rr->z_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);
return new_rr;
}
/* --------------------------------------------------------------------
* Render buffer.
*/
template<class BufferType> static BufferType render_buffer_new(decltype(BufferType::data) data)
{
BufferType buffer;
buffer.data = data;
buffer.sharing_info = blender::implicit_sharing::info_for_mem_free(data);
return buffer;
}
template<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);
}
template<class BufferType>
static void render_buffer_assign_data(BufferType *render_buffer, decltype(BufferType::data) data)
{
render_buffer_data_free(render_buffer);
if (!data) {
render_buffer->data = nullptr;
render_buffer->sharing_info = nullptr;
return;
}
render_buffer->data = data;
render_buffer->sharing_info = blender::implicit_sharing::info_for_mem_free(data);
}
template<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

@ -1575,25 +1575,24 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
RE_AcquireResultImage(re, &rres, view_id);
if (rres.rectf) {
ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
memcpy(ibufs_arr[view_id]->float_buffer.data,
rres.rectf,
sizeof(float[4]) * rres.rectx * rres.recty);
if (rres.combined_buffer.data) {
ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, 0);
IMB_assign_shared_float_buffer(
ibufs_arr[view_id], rres.combined_buffer.data, rres.combined_buffer.sharing_info);
if (rres.rectz) {
addzbuffloatImBuf(ibufs_arr[view_id]);
memcpy(ibufs_arr[view_id]->float_z_buffer.data,
rres.rectz,
sizeof(float) * rres.rectx * rres.recty);
if (rres.z_buffer.data) {
IMB_assign_shared_float_z_buffer(
ibufs_arr[view_id], rres.z_buffer.data, rres.z_buffer.sharing_info);
}
/* float buffers in the sequencer are not linear */
seq_imbuf_to_sequencer_space(context->scene, ibufs_arr[view_id], false);
}
else if (rres.rect32) {
else if (rres.byte_buffer.data) {
ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
memcpy(ibufs_arr[view_id]->byte_buffer.data, rres.rect32, 4 * rres.rectx * rres.recty);
memcpy(ibufs_arr[view_id]->byte_buffer.data,
rres.byte_buffer.data,
4 * rres.rectx * rres.recty);
}
if (view_id != context->view_id) {