Refactor Render Result to allow implicit buffer sharing
Allows to share buffer data between the render result and image buffers. The storage of the passes and buffers in the render result have been wrapped into utility structures, with functions to operate on them. Currently only image buffers which are sharing buffers with the render results are using the implicit sharing. This allows proper decoupling of the image buffers from the lifetime of the underlying render result. Fixes #107248: Compositor ACCESS VIOLATION when updating datablocks from handlers Additionally, this lowers the memory usage of multi-layer EXR sequences by avoiding having two copies of render passes in memory. It is possible to use implicit sharing in more places, but needs some API to ensure the render result is the only owner of data before writing to its pixels. Pull Request: https://projects.blender.org/blender/blender/pulls/108045
This commit is contained in:
committed by
Sergey Sharybin
parent
495e4f2d0e
commit
a5677d225b
@@ -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
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_implicit_sharing.h"
|
||||
|
||||
#include "DNA_vec_types.h" /* for rcti */
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
@@ -169,22 +171,31 @@ typedef enum ImBufOwnership {
|
||||
IB_TAKE_OWNERSHIP = 1,
|
||||
} ImBufOwnership;
|
||||
|
||||
/* Different storage specialization. */
|
||||
/* Different storage specialization.
|
||||
*
|
||||
* Note on the implicit sharing
|
||||
* ----------------------------
|
||||
*
|
||||
* The buffer allows implicitly sharing data with other users of such data. In this case the
|
||||
* ownership is set to IB_DO_NOT_TAKE_OWNERSHIP. */
|
||||
/* TODO(sergey): Once everything is C++ replace with a template. */
|
||||
|
||||
typedef struct ImBufIntBuffer {
|
||||
int *data;
|
||||
ImBufOwnership ownership;
|
||||
const ImplicitSharingInfoHandle *implicit_sharing;
|
||||
} ImBufIntBuffer;
|
||||
|
||||
typedef struct ImBufByteBuffer {
|
||||
uint8_t *data;
|
||||
ImBufOwnership ownership;
|
||||
const ImplicitSharingInfoHandle *implicit_sharing;
|
||||
} ImBufByteBuffer;
|
||||
|
||||
typedef struct ImBufFloatBuffer {
|
||||
float *data;
|
||||
ImBufOwnership ownership;
|
||||
const ImplicitSharingInfoHandle *implicit_sharing;
|
||||
} ImBufFloatBuffer;
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user