Render: Lazily allocate render passes pixels storage
The idea is to only allocate pixel storage only when there is an actual data to be written to them. This moves the code forward a better support of high-res rendering when pixel storage is not allocated until render engine is ready to provide pixel data. Is expected to be no functional changes for neither users no external engines. The only difference is that the motion and depth passes will be displayed as transparent for until render engine provides any tile result (at which point the pixels will be allocated and initialized to infinite depth). Differential Revision: https://developer.blender.org/D12195
This commit is contained in:
parent
7aff40f410
commit
038f9b7f4a
Notes:
blender-bot
2023-02-13 17:51:20 +01:00
Referenced by issue #99955, Regression: Crash when trying to 'Cache Result' of render when 'all render layers are disabled' Referenced by issue #94506, Crash in Compositing Referenced by issue #91629, Blender crashing with "Open Cached Render" function Referenced by issue #91058, Bordered Rendering not working properly Referenced by issue #90902, Rendering with render region active doesn't work / crashes while saving the result
|
@ -115,33 +115,48 @@ static void space_image_gpu_texture_get(Image *image,
|
|||
BKE_image_multiview_index(image, &sima->iuser);
|
||||
}
|
||||
|
||||
if (ibuf) {
|
||||
const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(ibuf);
|
||||
if (sima_flag & SI_SHOW_ZBUF && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1))) {
|
||||
if (ibuf->zbuf) {
|
||||
BLI_assert_msg(0, "Integer based depth buffers not supported");
|
||||
}
|
||||
else if (ibuf->zbuf_float) {
|
||||
*r_gpu_texture = GPU_texture_create_2d(
|
||||
__func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->zbuf_float);
|
||||
*r_owns_texture = true;
|
||||
}
|
||||
else if (ibuf->rect_float && ibuf->channels == 1) {
|
||||
*r_gpu_texture = GPU_texture_create_2d(
|
||||
__func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->rect_float);
|
||||
*r_owns_texture = true;
|
||||
}
|
||||
if (ibuf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
|
||||
/* This codepath is only supposed to happen when drawing a lazily-allocatable render result.
|
||||
* In all the other cases the `ED_space_image_acquire_buffer()` is expected to return NULL as
|
||||
* an image buffer when it has no pixels. */
|
||||
|
||||
BLI_assert(image->type == IMA_TYPE_R_RESULT);
|
||||
|
||||
float zero[4] = {0, 0, 0, 0};
|
||||
*r_gpu_texture = GPU_texture_create_2d(__func__, 1, 1, 0, GPU_RGBA16F, zero);
|
||||
*r_owns_texture = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(ibuf);
|
||||
if (sima_flag & SI_SHOW_ZBUF && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1))) {
|
||||
if (ibuf->zbuf) {
|
||||
BLI_assert_msg(0, "Integer based depth buffers not supported");
|
||||
}
|
||||
else if (image->source == IMA_SRC_TILED) {
|
||||
*r_gpu_texture = BKE_image_get_gpu_tiles(image, iuser, ibuf);
|
||||
*r_tex_tile_data = BKE_image_get_gpu_tilemap(image, iuser, NULL);
|
||||
*r_owns_texture = false;
|
||||
else if (ibuf->zbuf_float) {
|
||||
*r_gpu_texture = GPU_texture_create_2d(
|
||||
__func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->zbuf_float);
|
||||
*r_owns_texture = true;
|
||||
}
|
||||
else {
|
||||
*r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, ibuf);
|
||||
*r_owns_texture = false;
|
||||
else if (ibuf->rect_float && ibuf->channels == 1) {
|
||||
*r_gpu_texture = GPU_texture_create_2d(
|
||||
__func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->rect_float);
|
||||
*r_owns_texture = true;
|
||||
}
|
||||
}
|
||||
else if (image->source == IMA_SRC_TILED) {
|
||||
*r_gpu_texture = BKE_image_get_gpu_tiles(image, iuser, ibuf);
|
||||
*r_tex_tile_data = BKE_image_get_gpu_tilemap(image, iuser, NULL);
|
||||
*r_owns_texture = false;
|
||||
}
|
||||
else {
|
||||
*r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, ibuf);
|
||||
*r_owns_texture = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void space_node_gpu_texture_get(Image *image,
|
||||
|
|
|
@ -139,8 +139,10 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock, int tile)
|
|||
ImBuf *ibuf;
|
||||
|
||||
if (sima && sima->image) {
|
||||
const Image *image = sima->image;
|
||||
|
||||
#if 0
|
||||
if (sima->image->type == IMA_TYPE_R_RESULT && BIF_show_render_spare()) {
|
||||
if (image->type == IMA_TYPE_R_RESULT && BIF_show_render_spare()) {
|
||||
return BIF_render_spare_imbuf();
|
||||
}
|
||||
else
|
||||
|
@ -152,6 +154,12 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock, int tile)
|
|||
}
|
||||
|
||||
if (ibuf) {
|
||||
if (image->type == IMA_TYPE_R_RESULT && ibuf->x != 0 && ibuf->y != 0) {
|
||||
/* Render result might be lazily allocated. Return ibuf without buffers to indicate that
|
||||
* there is image buffer but it has no data yet. */
|
||||
return ibuf;
|
||||
}
|
||||
|
||||
if (ibuf->rect || ibuf->rect_float) {
|
||||
return ibuf;
|
||||
}
|
||||
|
|
|
@ -155,6 +155,8 @@ typedef struct RenderResult {
|
|||
char *error;
|
||||
|
||||
struct StampData *stamp_data;
|
||||
|
||||
bool passes_allocated;
|
||||
} RenderResult;
|
||||
|
||||
typedef struct RenderStats {
|
||||
|
|
|
@ -212,6 +212,8 @@ static RenderResult *render_result_from_bake(RenderEngine *engine, int x, int y,
|
|||
RenderPass *primitive_pass = render_layer_add_pass(rr, rl, 4, "BakePrimitive", "", "RGBA");
|
||||
RenderPass *differential_pass = render_layer_add_pass(rr, rl, 4, "BakeDifferential", "", "RGBA");
|
||||
|
||||
render_result_passes_allocated_ensure(rr);
|
||||
|
||||
/* 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;
|
||||
|
@ -328,6 +330,7 @@ RenderResult *RE_engine_begin_result(
|
|||
/* can be NULL if we CLAMP the width or height to 0 */
|
||||
if (result) {
|
||||
render_result_clone_passes(re, result, viewname);
|
||||
render_result_passes_allocated_ensure(result);
|
||||
|
||||
RenderPart *pa;
|
||||
|
||||
|
@ -400,6 +403,14 @@ void RE_engine_end_result(
|
|||
return;
|
||||
}
|
||||
|
||||
if (!re->result->passes_allocated) {
|
||||
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
||||
if (!re->result->passes_allocated) {
|
||||
render_result_passes_allocated_ensure(re->result);
|
||||
}
|
||||
BLI_rw_mutex_unlock(&re->resultmutex);
|
||||
}
|
||||
|
||||
/* merge. on break, don't merge in result for preview renders, looks nicer */
|
||||
if (!highlight) {
|
||||
/* for exr tile render, detect tiles that are done */
|
||||
|
|
|
@ -354,6 +354,7 @@ RenderResult *RE_AcquireResultWrite(Render *re)
|
|||
{
|
||||
if (re) {
|
||||
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
||||
render_result_passes_allocated_ensure(re->result);
|
||||
return re->result;
|
||||
}
|
||||
|
||||
|
|
|
@ -222,7 +222,6 @@ RenderPass *render_layer_add_pass(RenderResult *rr,
|
|||
{
|
||||
const int view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name));
|
||||
RenderPass *rpass = MEM_callocN(sizeof(RenderPass), name);
|
||||
size_t rectsize = ((size_t)rr->rectx) * rr->recty * channels;
|
||||
|
||||
rpass->channels = channels;
|
||||
rpass->rectx = rl->rectx;
|
||||
|
@ -249,33 +248,6 @@ RenderPass *render_layer_add_pass(RenderResult *rr,
|
|||
}
|
||||
}
|
||||
|
||||
/* Always allocate combined for display, in case of save buffers
|
||||
* other passes are not allocated and only saved to the EXR file. */
|
||||
if (rl->exrhandle == NULL || STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
|
||||
float *rect;
|
||||
int x;
|
||||
|
||||
rpass->rect = MEM_callocN(sizeof(float) * rectsize, name);
|
||||
if (rpass->rect == NULL) {
|
||||
MEM_freeN(rpass);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
|
||||
/* initialize to max speed */
|
||||
rect = rpass->rect;
|
||||
for (x = rectsize - 1; x >= 0; x--) {
|
||||
rect[x] = PASS_VECTOR_MAX;
|
||||
}
|
||||
}
|
||||
else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
|
||||
rect = rpass->rect;
|
||||
for (x = rectsize - 1; x >= 0; x--) {
|
||||
rect[x] = 10e10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_addtail(&rl->passes, rpass);
|
||||
|
||||
return rpass;
|
||||
|
@ -316,6 +288,8 @@ RenderResult *render_result_new(
|
|||
rr->do_exr_tile = true;
|
||||
}
|
||||
|
||||
rr->passes_allocated = false;
|
||||
|
||||
render_result_views_new(rr, &re->r);
|
||||
|
||||
/* check renderdata for amount of layers */
|
||||
|
@ -484,6 +458,40 @@ RenderResult *render_result_new(
|
|||
return rr;
|
||||
}
|
||||
|
||||
void render_result_passes_allocated_ensure(RenderResult *rr)
|
||||
{
|
||||
LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
|
||||
LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) {
|
||||
if (rl->exrhandle != NULL && !STREQ(rp->name, RE_PASSNAME_COMBINED)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rp->rect != NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const size_t rectsize = ((size_t)rr->rectx) * rr->recty * rp->channels;
|
||||
rp->rect = MEM_callocN(sizeof(float) * rectsize, rp->name);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
else if (STREQ(rp->name, RE_PASSNAME_Z)) {
|
||||
float *rect = rp->rect;
|
||||
for (int x = rectsize - 1; x >= 0; x--) {
|
||||
rect[x] = 10e10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rr->passes_allocated = true;
|
||||
}
|
||||
|
||||
void render_result_clone_passes(Render *re, RenderResult *rr, const char *viewname)
|
||||
{
|
||||
RenderLayer *rl;
|
||||
|
@ -1243,6 +1251,7 @@ void render_result_exr_file_end(Render *re, RenderEngine *engine)
|
|||
render_result_free_list(&re->fullresult, re->result);
|
||||
re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
|
||||
re->result->stamp_data = stamp_data;
|
||||
render_result_passes_allocated_ensure(re->result);
|
||||
BLI_rw_mutex_unlock(&re->resultmutex);
|
||||
|
||||
LISTBASE_FOREACH (RenderLayer *, rl, &re->result->layers) {
|
||||
|
|
|
@ -55,6 +55,8 @@ struct RenderResult *render_result_new(struct Render *re,
|
|||
const char *layername,
|
||||
const char *viewname);
|
||||
|
||||
void render_result_passes_allocated_ensure(struct RenderResult *rr);
|
||||
|
||||
struct RenderResult *render_result_new_from_exr(
|
||||
void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
|
||||
|
||||
|
|
Loading…
Reference in New Issue