EEVEE: LightCache: Prevent crash when using a lightcache too big

Some implementation have different maximum texture size.
This patch avoid crash when texture allocation fails when:
- trying to bake a lightcache too big for the OpenGL imeplementaion.
- loading a cache from file that is too big for the OpenGL imeplementation.
This commit is contained in:
Clément Foucault 2020-08-04 19:52:18 +02:00
parent d1b3da697d
commit 6be8b6af40
7 changed files with 73 additions and 12 deletions

View File

@ -6048,6 +6048,7 @@ static void direct_link_lightcache_texture(BlendDataReader *reader, LightCacheTe
static void direct_link_lightcache(BlendDataReader *reader, LightCache *cache)
{
cache->flag &= ~LIGHTCACHE_NOT_USABLE;
direct_link_lightcache_texture(reader, &cache->cube_tx);
direct_link_lightcache_texture(reader, &cache->grid_tx);

View File

@ -228,7 +228,14 @@ void EEVEE_lightcache_info_update(SceneEEVEE *eevee)
if (lcache->cube_tx.tex_size[2] > GPU_max_texture_layers()) {
BLI_strncpy(eevee->light_cache_info,
TIP_("Error: Light cache is too big for your GPU to be loaded"),
TIP_("Error: Light cache is too big for the GPU to be loaded"),
sizeof(eevee->light_cache_info));
return;
}
if (lcache->flag & LIGHTCACHE_INVALID) {
BLI_strncpy(eevee->light_cache_info,
TIP_("Error: Light cache dimensions not supported by the GPU"),
sizeof(eevee->light_cache_info));
return;
}
@ -281,7 +288,7 @@ static bool EEVEE_lightcache_validate(const LightCache *light_cache,
const int grid_len,
const int irr_size[3])
{
if (light_cache) {
if (light_cache && !(light_cache->flag & LIGHTCACHE_INVALID)) {
/* See if we need the same amount of texture space. */
if ((irr_size[0] == light_cache->grid_tx.tex_size[0]) &&
(irr_size[1] == light_cache->grid_tx.tex_size[1]) &&
@ -343,12 +350,18 @@ LightCache *EEVEE_lightcache_create(const int grid_len,
light_cache->cube_mips = MEM_callocN(sizeof(LightCacheTexture) * light_cache->mips_len,
"LightCacheTexture");
for (int mip = 0; mip < light_cache->mips_len; mip++) {
GPU_texture_get_mipmap_size(
light_cache->cube_tx.tex, mip + 1, light_cache->cube_mips[mip].tex_size);
if (light_cache->grid_tx.tex == NULL || light_cache->cube_tx.tex == NULL) {
/* We could not create the requested textures size. Stop baking and do not use the cache. */
light_cache->flag = LIGHTCACHE_INVALID;
}
else {
light_cache->flag = LIGHTCACHE_UPDATE_WORLD | LIGHTCACHE_UPDATE_CUBE | LIGHTCACHE_UPDATE_GRID;
light_cache->flag = LIGHTCACHE_UPDATE_WORLD | LIGHTCACHE_UPDATE_CUBE | LIGHTCACHE_UPDATE_GRID;
for (int mip = 0; mip < light_cache->mips_len; mip++) {
GPU_texture_get_mipmap_size(
light_cache->cube_tx.tex, mip + 1, light_cache->cube_mips[mip].tex_size);
}
}
return light_cache;
}
@ -376,6 +389,12 @@ static bool eevee_lightcache_static_load(LightCache *lcache)
0,
false,
NULL);
if (lcache->grid_tx.tex == NULL) {
lcache->flag |= LIGHTCACHE_NOT_USABLE;
return false;
}
GPU_texture_filter_mode(lcache->grid_tx.tex, true);
}
@ -401,6 +420,11 @@ static bool eevee_lightcache_static_load(LightCache *lcache)
NULL);
}
if (lcache->cube_tx.tex == NULL) {
lcache->flag |= LIGHTCACHE_NOT_USABLE;
return false;
}
for (int mip = 0; mip < lcache->mips_len; mip++) {
GPU_texture_add_mipmap(
lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, mip + 1, lcache->cube_mips[mip].data);
@ -420,6 +444,10 @@ bool EEVEE_lightcache_load(LightCache *lcache)
return false;
}
if (lcache->flag & (LIGHTCACHE_INVALID | LIGHTCACHE_NOT_USABLE)) {
return false;
}
switch (lcache->type) {
case LIGHTCACHE_TYPE_STATIC:
return eevee_lightcache_static_load(lcache);
@ -590,9 +618,7 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake)
if (lbake->lcache == NULL) {
lbake->lcache = EEVEE_lightcache_create(
lbake->grid_len, lbake->cube_len, lbake->ref_cube_res, lbake->vis_res, lbake->irr_size);
lbake->lcache->flag = LIGHTCACHE_UPDATE_WORLD | LIGHTCACHE_UPDATE_CUBE |
LIGHTCACHE_UPDATE_GRID;
lbake->lcache->vis_res = lbake->vis_res;
lbake->own_light_cache = true;
eevee->light_cache_data = lbake->lcache;
@ -1269,6 +1295,17 @@ void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float
* We cannot do it in the main thread. */
eevee_lightbake_context_enable(lbake);
eevee_lightbake_create_resources(lbake);
/* Resource allocation can fail. Early exit in this case. */
if (lbake->lcache->flag & LIGHTCACHE_INVALID) {
*lbake->stop = 1;
*lbake->do_update = 1;
lbake->lcache->flag &= ~LIGHTCACHE_BAKING;
eevee_lightbake_context_disable(lbake);
eevee_lightbake_delete_resources(lbake);
return;
}
eevee_lightbake_create_render_target(lbake, lbake->rt_res);
eevee_lightbake_context_disable(lbake);

View File

@ -23,6 +23,7 @@
#include "DRW_render.h"
#include "BLI_rand.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "DNA_image_types.h"
@ -161,6 +162,7 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
const DRWContextState *draw_ctx = DRW_context_state_get();
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
vedata->info[0] = '\0';
if (!e_data.hammersley) {
EEVEE_shaders_lightprobe_shaders_init();
@ -176,6 +178,13 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
stl->g_data->light_cache = scene_eval->eevee.light_cache_data;
}
else {
if (scene_eval->eevee.light_cache_data &&
(scene_eval->eevee.light_cache_data->flag & LIGHTCACHE_NOT_USABLE)) {
/* Error message info. */
BLI_snprintf(
vedata->info, sizeof(vedata->info), "Error: LightCache cannot be loaded on this GPU");
}
if (!sldata->fallback_lightcache) {
#if defined(IRRADIANCE_SH_L2)
int grid_res = 4;

View File

@ -29,6 +29,8 @@
#include "DNA_lightprobe_types.h"
#include "GPU_viewport.h"
#include "BKE_camera.h"
struct EEVEE_ShadowCasterBuffer;
@ -891,6 +893,7 @@ typedef struct EEVEE_Data {
EEVEE_TextureList *txl;
EEVEE_PassList *psl;
EEVEE_StorageList *stl;
char info[GPU_INFO_SIZE];
} EEVEE_Data;
typedef struct EEVEE_PrivateData {

View File

@ -61,6 +61,10 @@ static bool drw_texture_format_supports_framebuffer(eGPUTextureFormat format)
void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags)
{
if (tex == NULL) {
return;
}
if (flags & DRW_TEX_MIPMAP) {
GPU_texture_mipmap_mode(tex, true, flags & DRW_TEX_FILTER);
GPU_texture_bind(tex, 0);
@ -119,7 +123,6 @@ GPUTexture *DRW_texture_create_cube(int w,
{
GPUTexture *tex = GPU_texture_create_cube(w, format, fpixels, NULL);
drw_texture_set_parameters(tex, flags);
return tex;
}
@ -128,7 +131,6 @@ GPUTexture *DRW_texture_create_cube_array(
{
GPUTexture *tex = GPU_texture_create_cube_array(w, d, format, fpixels, NULL);
drw_texture_set_parameters(tex, flags);
return tex;
}

View File

@ -945,6 +945,11 @@ static int light_cache_bake_modal(bContext *C, wmOperator *op, const wmEvent *ev
/* no running blender, remove handler and pass through */
if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER)) {
LightCache *lcache = scene->eevee.light_cache_data;
if (lcache && (lcache->flag & LIGHTCACHE_INVALID)) {
BKE_report(op->reports, RPT_ERROR, "Lightcache cannot allocate resources");
return OPERATOR_CANCELLED;
}
return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
}

View File

@ -150,7 +150,7 @@ BLI_STATIC_ASSERT_ALIGN(LightGridCache, 16)
typedef struct LightCacheTexture {
struct GPUTexture *tex;
/* Copy of GPU datas to create GPUTextures on file read. */
/** Copy of GPU datas to create GPUTextures on file read. */
char *data;
int tex_size[3];
char data_type;
@ -204,6 +204,10 @@ enum {
LIGHTCACHE_UPDATE_GRID = (1 << 5),
LIGHTCACHE_UPDATE_WORLD = (1 << 6),
LIGHTCACHE_UPDATE_AUTO = (1 << 7),
/** Invalid means we tried to alloc it but failed. */
LIGHTCACHE_INVALID = (1 << 8),
/** The data present in the cache is valid but unusable on this GPU. */
LIGHTCACHE_NOT_USABLE = (1 << 9),
};
/* EEVEE_LightCacheTexture->data_type */