diff options
Diffstat (limited to 'source/blender/draw/engines/eevee/eevee_lightcache.c')
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_lightcache.c | 1957 |
1 files changed, 1003 insertions, 954 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 812af1c6ac0..9ebd9542ef5 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -50,14 +50,14 @@ /* Rounded to nearest PowerOfTwo */ #if defined(IRRADIANCE_SH_L2) -#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */ -#define IRRADIANCE_SAMPLE_SIZE_Y 4 /* 3 in reality */ +# define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */ +# define IRRADIANCE_SAMPLE_SIZE_Y 4 /* 3 in reality */ #elif defined(IRRADIANCE_CUBEMAP) -#define IRRADIANCE_SAMPLE_SIZE_X 8 -#define IRRADIANCE_SAMPLE_SIZE_Y 8 +# define IRRADIANCE_SAMPLE_SIZE_X 8 +# define IRRADIANCE_SAMPLE_SIZE_Y 8 #elif defined(IRRADIANCE_HL2) -#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */ -#define IRRADIANCE_SAMPLE_SIZE_Y 2 +# define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */ +# define IRRADIANCE_SAMPLE_SIZE_Y 2 #endif #ifdef IRRADIANCE_SH_L2 @@ -71,8 +71,8 @@ #define IRRADIANCE_MAX_POOL_LAYER 256 #define IRRADIANCE_MAX_POOL_SIZE 1024 #define MAX_IRRADIANCE_SAMPLES \ - (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_X) * \ - (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_Y) + (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_X) * \ + (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_Y) /* TODO should be replace by a more elegant alternative. */ extern void DRW_opengl_context_enable(void); @@ -84,64 +84,66 @@ extern void DRW_gawain_render_context_enable(void *re_gpu_context); extern void DRW_gawain_render_context_disable(void *re_gpu_context); typedef struct EEVEE_LightBake { - Depsgraph *depsgraph; - ViewLayer *view_layer; - ViewLayer *view_layer_input; - LightCache *lcache; - Scene *scene; - struct Main *bmain; - EEVEE_ViewLayerData *sldata; - - LightProbe **probe; /* Current probe being rendered. */ - GPUTexture *rt_color; /* Target cube color texture. */ - GPUTexture *rt_depth; /* Target cube depth texture. */ - GPUFrameBuffer *rt_fb[6]; /* Target cube framebuffers. */ - GPUFrameBuffer *store_fb; /* Storage framebuffer. */ - int rt_res; /* Cube render target resolution. */ - - /* Shared */ - int layer; /* Target layer to store the data to. */ - float samples_ct, invsamples_ct; /* Sample count for the convolution. */ - float lod_factor; /* Sampling bias during convolution step. */ - float lod_max; /* Max cubemap LOD to sample when convolving. */ - int cube_len, grid_len; /* Number of probes to render + world probe. */ - - /* Irradiance grid */ - EEVEE_LightGrid *grid; /* Current probe being rendered (UBO data). */ - int irr_cube_res; /* Target cubemap at MIP 0. */ - int irr_size[3]; /* Size of the irradiance texture. */ - int total_irr_samples; /* Total for all grids */ - int grid_sample; /* Nth sample of the current grid being rendered. */ - int grid_sample_len; /* Total number of samples for the current grid. */ - int grid_curr; /* Nth grid in the cache being rendered. */ - int bounce_curr, bounce_len; /* The current light bounce being evaluated. */ - float vis_res; /* Resolution of the Visibility shadowmap. */ - GPUTexture *grid_prev; /* Result of previous light bounce. */ - LightProbe **grid_prb; /* Pointer to the id.data of the probe object. */ - - /* Reflection probe */ - EEVEE_LightProbe *cube; /* Current probe being rendered (UBO data). */ - int ref_cube_res; /* Target cubemap at MIP 0. */ - int cube_offset; /* Index of the current cube. */ - LightProbe **cube_prb; /* Pointer to the id.data of the probe object. */ - - /* Dummy Textures */ - struct GPUTexture *dummy_color, *dummy_depth; - struct GPUTexture *dummy_layer_color; - - int total, done; /* to compute progress */ - short *stop, *do_update; - float *progress; - - bool resource_only; /* For only handling the resources. */ - bool own_resources; - bool own_light_cache; /* If the lightcache was created for baking, it's first owned by the baker. */ - int delay; /* ms. delay the start of the baking to not slowdown interactions (TODO remove) */ - int frame; /* Scene frame to bake. */ - - void *gl_context, *gpu_context; /* If running in parallel (in a separate thread), use this context. */ - - ThreadMutex *mutex; + Depsgraph *depsgraph; + ViewLayer *view_layer; + ViewLayer *view_layer_input; + LightCache *lcache; + Scene *scene; + struct Main *bmain; + EEVEE_ViewLayerData *sldata; + + LightProbe **probe; /* Current probe being rendered. */ + GPUTexture *rt_color; /* Target cube color texture. */ + GPUTexture *rt_depth; /* Target cube depth texture. */ + GPUFrameBuffer *rt_fb[6]; /* Target cube framebuffers. */ + GPUFrameBuffer *store_fb; /* Storage framebuffer. */ + int rt_res; /* Cube render target resolution. */ + + /* Shared */ + int layer; /* Target layer to store the data to. */ + float samples_ct, invsamples_ct; /* Sample count for the convolution. */ + float lod_factor; /* Sampling bias during convolution step. */ + float lod_max; /* Max cubemap LOD to sample when convolving. */ + int cube_len, grid_len; /* Number of probes to render + world probe. */ + + /* Irradiance grid */ + EEVEE_LightGrid *grid; /* Current probe being rendered (UBO data). */ + int irr_cube_res; /* Target cubemap at MIP 0. */ + int irr_size[3]; /* Size of the irradiance texture. */ + int total_irr_samples; /* Total for all grids */ + int grid_sample; /* Nth sample of the current grid being rendered. */ + int grid_sample_len; /* Total number of samples for the current grid. */ + int grid_curr; /* Nth grid in the cache being rendered. */ + int bounce_curr, bounce_len; /* The current light bounce being evaluated. */ + float vis_res; /* Resolution of the Visibility shadowmap. */ + GPUTexture *grid_prev; /* Result of previous light bounce. */ + LightProbe **grid_prb; /* Pointer to the id.data of the probe object. */ + + /* Reflection probe */ + EEVEE_LightProbe *cube; /* Current probe being rendered (UBO data). */ + int ref_cube_res; /* Target cubemap at MIP 0. */ + int cube_offset; /* Index of the current cube. */ + LightProbe **cube_prb; /* Pointer to the id.data of the probe object. */ + + /* Dummy Textures */ + struct GPUTexture *dummy_color, *dummy_depth; + struct GPUTexture *dummy_layer_color; + + int total, done; /* to compute progress */ + short *stop, *do_update; + float *progress; + + bool resource_only; /* For only handling the resources. */ + bool own_resources; + bool + own_light_cache; /* If the lightcache was created for baking, it's first owned by the baker. */ + int delay; /* ms. delay the start of the baking to not slowdown interactions (TODO remove) */ + int frame; /* Scene frame to bake. */ + + void *gl_context, + *gpu_context; /* If running in parallel (in a separate thread), use this context. */ + + ThreadMutex *mutex; } EEVEE_LightBake; /* -------------------------------------------------------------------- */ @@ -151,1068 +153,1115 @@ typedef struct EEVEE_LightBake { /* Return memory footprint in bytes. */ static uint eevee_lightcache_memsize_get(LightCache *lcache) { - uint size = 0; - if (lcache->grid_tx.data) { - size += MEM_allocN_len(lcache->grid_tx.data); - } - if (lcache->cube_tx.data) { - size += MEM_allocN_len(lcache->cube_tx.data); - for (int mip = 0; mip < lcache->mips_len; ++mip) { - size += MEM_allocN_len(lcache->cube_mips[mip].data); - } - } - return size; + uint size = 0; + if (lcache->grid_tx.data) { + size += MEM_allocN_len(lcache->grid_tx.data); + } + if (lcache->cube_tx.data) { + size += MEM_allocN_len(lcache->cube_tx.data); + for (int mip = 0; mip < lcache->mips_len; ++mip) { + size += MEM_allocN_len(lcache->cube_mips[mip].data); + } + } + return size; } static int eevee_lightcache_irradiance_sample_count(LightCache *lcache) { - int total_irr_samples = 0; + int total_irr_samples = 0; - for (int i = 1; i < lcache->grid_len; ++i) { - EEVEE_LightGrid *egrid = lcache->grid_data + i; - total_irr_samples += egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2]; - } - return total_irr_samples; + for (int i = 1; i < lcache->grid_len; ++i) { + EEVEE_LightGrid *egrid = lcache->grid_data + i; + total_irr_samples += egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2]; + } + return total_irr_samples; } void EEVEE_lightcache_info_update(SceneEEVEE *eevee) { - LightCache *lcache = eevee->light_cache; - - if (lcache != NULL) { - if (lcache->flag & LIGHTCACHE_BAKING) { - BLI_strncpy(eevee->light_cache_info, IFACE_("Baking light cache"), sizeof(eevee->light_cache_info)); - return; - } - - char formatted_mem[15]; - BLI_str_format_byte_unit(formatted_mem, eevee_lightcache_memsize_get(lcache), true); - - int irr_samples = eevee_lightcache_irradiance_sample_count(lcache); - - BLI_snprintf(eevee->light_cache_info, sizeof(eevee->light_cache_info), IFACE_("%d Ref. Cubemaps, %d Irr. Samples (%s in memory)"), lcache->cube_len - 1, irr_samples, formatted_mem); - } - else { - BLI_strncpy(eevee->light_cache_info, IFACE_("No light cache in this scene"), sizeof(eevee->light_cache_info)); - } + LightCache *lcache = eevee->light_cache; + + if (lcache != NULL) { + if (lcache->flag & LIGHTCACHE_BAKING) { + BLI_strncpy( + eevee->light_cache_info, IFACE_("Baking light cache"), sizeof(eevee->light_cache_info)); + return; + } + + char formatted_mem[15]; + BLI_str_format_byte_unit(formatted_mem, eevee_lightcache_memsize_get(lcache), true); + + int irr_samples = eevee_lightcache_irradiance_sample_count(lcache); + + BLI_snprintf(eevee->light_cache_info, + sizeof(eevee->light_cache_info), + IFACE_("%d Ref. Cubemaps, %d Irr. Samples (%s in memory)"), + lcache->cube_len - 1, + irr_samples, + formatted_mem); + } + else { + BLI_strncpy(eevee->light_cache_info, + IFACE_("No light cache in this scene"), + sizeof(eevee->light_cache_info)); + } } static void irradiance_pool_size_get(int visibility_size, int total_samples, int r_size[3]) { - /* Compute how many irradiance samples we can store per visibility sample. */ - int irr_per_vis = (visibility_size / IRRADIANCE_SAMPLE_SIZE_X) * - (visibility_size / IRRADIANCE_SAMPLE_SIZE_Y); - - /* The irradiance itself take one layer, hence the +1 */ - int layer_ct = MIN2(irr_per_vis + 1, IRRADIANCE_MAX_POOL_LAYER); - - int texel_ct = (int)ceilf((float)total_samples / (float)(layer_ct - 1)); - r_size[0] = visibility_size * max_ii(1, min_ii(texel_ct, (IRRADIANCE_MAX_POOL_SIZE / visibility_size))); - r_size[1] = visibility_size * max_ii(1, (texel_ct / (IRRADIANCE_MAX_POOL_SIZE / visibility_size))); - r_size[2] = layer_ct; + /* Compute how many irradiance samples we can store per visibility sample. */ + int irr_per_vis = (visibility_size / IRRADIANCE_SAMPLE_SIZE_X) * + (visibility_size / IRRADIANCE_SAMPLE_SIZE_Y); + + /* The irradiance itself take one layer, hence the +1 */ + int layer_ct = MIN2(irr_per_vis + 1, IRRADIANCE_MAX_POOL_LAYER); + + int texel_ct = (int)ceilf((float)total_samples / (float)(layer_ct - 1)); + r_size[0] = visibility_size * + max_ii(1, min_ii(texel_ct, (IRRADIANCE_MAX_POOL_SIZE / visibility_size))); + r_size[1] = visibility_size * + max_ii(1, (texel_ct / (IRRADIANCE_MAX_POOL_SIZE / visibility_size))); + r_size[2] = layer_ct; } -static bool EEVEE_lightcache_validate( - const LightCache *light_cache, - const int cube_len, - const int cube_res, - const int grid_len, - const int irr_size[3]) +static bool EEVEE_lightcache_validate(const LightCache *light_cache, + const int cube_len, + const int cube_res, + const int grid_len, + const int irr_size[3]) { - if (light_cache) { - /* 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]) && - (irr_size[2] == light_cache->grid_tx.tex_size[2]) && - (grid_len == light_cache->grid_len)) - { - int mip_len = (int)(floorf(log2f(cube_res)) - MIN_CUBE_LOD_LEVEL); - if ((cube_res == light_cache->cube_tx.tex_size[0]) && - (cube_len == light_cache->cube_tx.tex_size[2]) && - (mip_len == light_cache->mips_len)) - { - return true; - } - } - } - return false; + if (light_cache) { + /* 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]) && + (irr_size[2] == light_cache->grid_tx.tex_size[2]) && (grid_len == light_cache->grid_len)) { + int mip_len = (int)(floorf(log2f(cube_res)) - MIN_CUBE_LOD_LEVEL); + if ((cube_res == light_cache->cube_tx.tex_size[0]) && + (cube_len == light_cache->cube_tx.tex_size[2]) && (mip_len == light_cache->mips_len)) { + return true; + } + } + } + return false; } -LightCache *EEVEE_lightcache_create( - const int grid_len, - const int cube_len, - const int cube_size, - const int vis_size, - const int irr_size[3]) +LightCache *EEVEE_lightcache_create(const int grid_len, + const int cube_len, + const int cube_size, + const int vis_size, + const int irr_size[3]) { - LightCache *light_cache = MEM_callocN(sizeof(LightCache), "LightCache"); + LightCache *light_cache = MEM_callocN(sizeof(LightCache), "LightCache"); - light_cache->cube_data = MEM_callocN(sizeof(EEVEE_LightProbe) * cube_len, "EEVEE_LightProbe"); - light_cache->grid_data = MEM_callocN(sizeof(EEVEE_LightGrid) * grid_len, "EEVEE_LightGrid"); + light_cache->cube_data = MEM_callocN(sizeof(EEVEE_LightProbe) * cube_len, "EEVEE_LightProbe"); + light_cache->grid_data = MEM_callocN(sizeof(EEVEE_LightGrid) * grid_len, "EEVEE_LightGrid"); - light_cache->grid_tx.tex = DRW_texture_create_2d_array(irr_size[0], irr_size[1], irr_size[2], IRRADIANCE_FORMAT, DRW_TEX_FILTER, NULL); - light_cache->grid_tx.tex_size[0] = irr_size[0]; - light_cache->grid_tx.tex_size[1] = irr_size[1]; - light_cache->grid_tx.tex_size[2] = irr_size[2]; + light_cache->grid_tx.tex = DRW_texture_create_2d_array( + irr_size[0], irr_size[1], irr_size[2], IRRADIANCE_FORMAT, DRW_TEX_FILTER, NULL); + light_cache->grid_tx.tex_size[0] = irr_size[0]; + light_cache->grid_tx.tex_size[1] = irr_size[1]; + light_cache->grid_tx.tex_size[2] = irr_size[2]; - light_cache->cube_tx.tex = DRW_texture_create_2d_array(cube_size, cube_size, cube_len, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); - light_cache->cube_tx.tex_size[0] = cube_size; - light_cache->cube_tx.tex_size[1] = cube_size; - light_cache->cube_tx.tex_size[2] = cube_len; + light_cache->cube_tx.tex = DRW_texture_create_2d_array( + cube_size, cube_size, cube_len, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); + light_cache->cube_tx.tex_size[0] = cube_size; + light_cache->cube_tx.tex_size[1] = cube_size; + light_cache->cube_tx.tex_size[2] = cube_len; - light_cache->mips_len = (int)(floorf(log2f(cube_size)) - MIN_CUBE_LOD_LEVEL); - light_cache->vis_res = vis_size; - light_cache->ref_res = cube_size; + light_cache->mips_len = (int)(floorf(log2f(cube_size)) - MIN_CUBE_LOD_LEVEL); + light_cache->vis_res = vis_size; + light_cache->ref_res = cube_size; - light_cache->cube_mips = MEM_callocN(sizeof(LightCacheTexture) * light_cache->mips_len, "LightCacheTexture"); + 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); - } + 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); + } - light_cache->flag = LIGHTCACHE_UPDATE_WORLD | LIGHTCACHE_UPDATE_CUBE | LIGHTCACHE_UPDATE_GRID; + light_cache->flag = LIGHTCACHE_UPDATE_WORLD | LIGHTCACHE_UPDATE_CUBE | LIGHTCACHE_UPDATE_GRID; - return light_cache; + return light_cache; } void EEVEE_lightcache_load(LightCache *lcache) { - if (lcache->grid_tx.tex == NULL && lcache->grid_tx.data) { - lcache->grid_tx.tex = GPU_texture_create_nD( - lcache->grid_tx.tex_size[0], - lcache->grid_tx.tex_size[1], - lcache->grid_tx.tex_size[2], - 2, - lcache->grid_tx.data, - IRRADIANCE_FORMAT, - GPU_DATA_UNSIGNED_BYTE, - 0, - false, - NULL); - GPU_texture_bind(lcache->grid_tx.tex, 0); - GPU_texture_filter_mode(lcache->grid_tx.tex, true); - GPU_texture_unbind(lcache->grid_tx.tex); - } - - if (lcache->cube_tx.tex == NULL && lcache->cube_tx.data) { - lcache->cube_tx.tex = GPU_texture_create_nD( - lcache->cube_tx.tex_size[0], - lcache->cube_tx.tex_size[1], - lcache->cube_tx.tex_size[2], - 2, - lcache->cube_tx.data, - GPU_R11F_G11F_B10F, - GPU_DATA_10_11_11_REV, - 0, - false, - NULL); - GPU_texture_bind(lcache->cube_tx.tex, 0); - GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true); - 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); - } - GPU_texture_unbind(lcache->cube_tx.tex); - } + if (lcache->grid_tx.tex == NULL && lcache->grid_tx.data) { + lcache->grid_tx.tex = GPU_texture_create_nD(lcache->grid_tx.tex_size[0], + lcache->grid_tx.tex_size[1], + lcache->grid_tx.tex_size[2], + 2, + lcache->grid_tx.data, + IRRADIANCE_FORMAT, + GPU_DATA_UNSIGNED_BYTE, + 0, + false, + NULL); + GPU_texture_bind(lcache->grid_tx.tex, 0); + GPU_texture_filter_mode(lcache->grid_tx.tex, true); + GPU_texture_unbind(lcache->grid_tx.tex); + } + + if (lcache->cube_tx.tex == NULL && lcache->cube_tx.data) { + lcache->cube_tx.tex = GPU_texture_create_nD(lcache->cube_tx.tex_size[0], + lcache->cube_tx.tex_size[1], + lcache->cube_tx.tex_size[2], + 2, + lcache->cube_tx.data, + GPU_R11F_G11F_B10F, + GPU_DATA_10_11_11_REV, + 0, + false, + NULL); + GPU_texture_bind(lcache->cube_tx.tex, 0); + GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true); + 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); + } + GPU_texture_unbind(lcache->cube_tx.tex); + } } static void eevee_lightbake_readback_irradiance(LightCache *lcache) { - MEM_SAFE_FREE(lcache->grid_tx.data); - lcache->grid_tx.data = GPU_texture_read(lcache->grid_tx.tex, GPU_DATA_UNSIGNED_BYTE, 0); - lcache->grid_tx.data_type = LIGHTCACHETEX_BYTE; - lcache->grid_tx.components = 4; + MEM_SAFE_FREE(lcache->grid_tx.data); + lcache->grid_tx.data = GPU_texture_read(lcache->grid_tx.tex, GPU_DATA_UNSIGNED_BYTE, 0); + lcache->grid_tx.data_type = LIGHTCACHETEX_BYTE; + lcache->grid_tx.components = 4; } static void eevee_lightbake_readback_reflections(LightCache *lcache) { - MEM_SAFE_FREE(lcache->cube_tx.data); - lcache->cube_tx.data = GPU_texture_read(lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, 0); - lcache->cube_tx.data_type = LIGHTCACHETEX_UINT; - lcache->cube_tx.components = 1; - - for (int mip = 0; mip < lcache->mips_len; ++mip) { - LightCacheTexture *cube_mip = lcache->cube_mips + mip; - MEM_SAFE_FREE(cube_mip->data); - GPU_texture_get_mipmap_size(lcache->cube_tx.tex, mip + 1, cube_mip->tex_size); - - cube_mip->data = GPU_texture_read(lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, mip + 1); - cube_mip->data_type = LIGHTCACHETEX_UINT; - cube_mip->components = 1; - } + MEM_SAFE_FREE(lcache->cube_tx.data); + lcache->cube_tx.data = GPU_texture_read(lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, 0); + lcache->cube_tx.data_type = LIGHTCACHETEX_UINT; + lcache->cube_tx.components = 1; + + for (int mip = 0; mip < lcache->mips_len; ++mip) { + LightCacheTexture *cube_mip = lcache->cube_mips + mip; + MEM_SAFE_FREE(cube_mip->data); + GPU_texture_get_mipmap_size(lcache->cube_tx.tex, mip + 1, cube_mip->tex_size); + + cube_mip->data = GPU_texture_read(lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, mip + 1); + cube_mip->data_type = LIGHTCACHETEX_UINT; + cube_mip->components = 1; + } } void EEVEE_lightcache_free(LightCache *lcache) { - DRW_TEXTURE_FREE_SAFE(lcache->cube_tx.tex); - MEM_SAFE_FREE(lcache->cube_tx.data); - DRW_TEXTURE_FREE_SAFE(lcache->grid_tx.tex); - MEM_SAFE_FREE(lcache->grid_tx.data); - - if (lcache->cube_mips) { - for (int i = 0; i < lcache->mips_len; ++i) { - MEM_SAFE_FREE(lcache->cube_mips[i].data); - } - MEM_SAFE_FREE(lcache->cube_mips); - } - - MEM_SAFE_FREE(lcache->cube_data); - MEM_SAFE_FREE(lcache->grid_data); - MEM_freeN(lcache); + DRW_TEXTURE_FREE_SAFE(lcache->cube_tx.tex); + MEM_SAFE_FREE(lcache->cube_tx.data); + DRW_TEXTURE_FREE_SAFE(lcache->grid_tx.tex); + MEM_SAFE_FREE(lcache->grid_tx.data); + + if (lcache->cube_mips) { + for (int i = 0; i < lcache->mips_len; ++i) { + MEM_SAFE_FREE(lcache->cube_mips[i].data); + } + MEM_SAFE_FREE(lcache->cube_mips); + } + + MEM_SAFE_FREE(lcache->cube_data); + MEM_SAFE_FREE(lcache->grid_data); + MEM_freeN(lcache); } /** \} */ - /* -------------------------------------------------------------------- */ /** \name Light Bake Context * \{ */ static void eevee_lightbake_context_enable(EEVEE_LightBake *lbake) { - if (lbake->gl_context) { - DRW_opengl_render_context_enable(lbake->gl_context); - if (lbake->gpu_context == NULL) { - lbake->gpu_context = GPU_context_create(); - } - DRW_gawain_render_context_enable(lbake->gpu_context); - } - else { - DRW_opengl_context_enable(); - } + if (lbake->gl_context) { + DRW_opengl_render_context_enable(lbake->gl_context); + if (lbake->gpu_context == NULL) { + lbake->gpu_context = GPU_context_create(); + } + DRW_gawain_render_context_enable(lbake->gpu_context); + } + else { + DRW_opengl_context_enable(); + } } static void eevee_lightbake_context_disable(EEVEE_LightBake *lbake) { - if (lbake->gl_context) { - DRW_gawain_render_context_disable(lbake->gpu_context); - DRW_opengl_render_context_disable(lbake->gl_context); - } - else { - DRW_opengl_context_disable(); - } + if (lbake->gl_context) { + DRW_gawain_render_context_disable(lbake->gpu_context); + DRW_opengl_render_context_disable(lbake->gl_context); + } + else { + DRW_opengl_context_disable(); + } } /** \} */ - /* -------------------------------------------------------------------- */ /** \name Light Bake Job * \{ */ static void eevee_lightbake_count_probes(EEVEE_LightBake *lbake) { - Depsgraph *depsgraph = lbake->depsgraph; - - /* At least one of each for the world */ - lbake->grid_len = lbake->cube_len = lbake->total_irr_samples = 1; - - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob) - { - const int ob_visibility = BKE_object_visibility(ob, DAG_EVAL_RENDER); - if ((ob_visibility & OB_VISIBLE_SELF) == 0) { - continue; - } - - if (ob->type == OB_LIGHTPROBE) { - LightProbe *prb = (LightProbe *)ob->data; - - if (prb->type == LIGHTPROBE_TYPE_GRID) { - lbake->total_irr_samples += prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z; - lbake->grid_len++; - } - else if (prb->type == LIGHTPROBE_TYPE_CUBE) { - lbake->cube_len++; - } - } - } - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; + Depsgraph *depsgraph = lbake->depsgraph; + + /* At least one of each for the world */ + lbake->grid_len = lbake->cube_len = lbake->total_irr_samples = 1; + + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { + const int ob_visibility = BKE_object_visibility(ob, DAG_EVAL_RENDER); + if ((ob_visibility & OB_VISIBLE_SELF) == 0) { + continue; + } + + if (ob->type == OB_LIGHTPROBE) { + LightProbe *prb = (LightProbe *)ob->data; + + if (prb->type == LIGHTPROBE_TYPE_GRID) { + lbake->total_irr_samples += prb->grid_resolution_x * prb->grid_resolution_y * + prb->grid_resolution_z; + lbake->grid_len++; + } + else if (prb->type == LIGHTPROBE_TYPE_CUBE) { + lbake->cube_len++; + } + } + } + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; } static void eevee_lightbake_create_render_target(EEVEE_LightBake *lbake, int rt_res) { - lbake->rt_depth = DRW_texture_create_cube(rt_res, GPU_DEPTH_COMPONENT24, 0, NULL); - lbake->rt_color = DRW_texture_create_cube(rt_res, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); - - for (int i = 0; i < 6; ++i) { - GPU_framebuffer_ensure_config(&lbake->rt_fb[i], { - GPU_ATTACHMENT_TEXTURE_CUBEFACE(lbake->rt_depth, i), - GPU_ATTACHMENT_TEXTURE_CUBEFACE(lbake->rt_color, i) - }); - } - - GPU_framebuffer_ensure_config(&lbake->store_fb, { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_NONE - }); + lbake->rt_depth = DRW_texture_create_cube(rt_res, GPU_DEPTH_COMPONENT24, 0, NULL); + lbake->rt_color = DRW_texture_create_cube( + rt_res, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); + + for (int i = 0; i < 6; ++i) { + GPU_framebuffer_ensure_config(&lbake->rt_fb[i], + {GPU_ATTACHMENT_TEXTURE_CUBEFACE(lbake->rt_depth, i), + GPU_ATTACHMENT_TEXTURE_CUBEFACE(lbake->rt_color, i)}); + } + + GPU_framebuffer_ensure_config(&lbake->store_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_NONE}); } static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake) { - Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); - SceneEEVEE *eevee = &scene_eval->eevee; - - lbake->bounce_len = eevee->gi_diffuse_bounces; - lbake->vis_res = eevee->gi_visibility_resolution; - lbake->rt_res = eevee->gi_cubemap_resolution; - - irradiance_pool_size_get(lbake->vis_res, lbake->total_irr_samples, lbake->irr_size); - - lbake->ref_cube_res = OCTAHEDRAL_SIZE_FROM_CUBESIZE(lbake->rt_res); - - lbake->cube_prb = MEM_callocN(sizeof(LightProbe *) * lbake->cube_len, "EEVEE Cube visgroup ptr"); - lbake->grid_prb = MEM_callocN(sizeof(LightProbe *) * lbake->grid_len, "EEVEE Grid visgroup ptr"); - - lbake->grid_prev = DRW_texture_create_2d_array( - lbake->irr_size[0], lbake->irr_size[1], lbake->irr_size[2], - IRRADIANCE_FORMAT, DRW_TEX_FILTER, NULL); - - /* Ensure Light Cache is ready to accept new data. If not recreate one. - * WARNING: All the following must be threadsafe. It's currently protected - * by the DRW mutex. */ - lbake->lcache = eevee->light_cache; - - /* TODO validate irradiance and reflection cache independently... */ - if (!EEVEE_lightcache_validate( - lbake->lcache, lbake->cube_len, lbake->ref_cube_res, lbake->grid_len, lbake->irr_size)) - { - eevee->light_cache = lbake->lcache = NULL; - } - - 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 = lbake->lcache; - } - - EEVEE_lightcache_load(eevee->light_cache); - - lbake->lcache->flag |= LIGHTCACHE_BAKING; - lbake->lcache->cube_len = 1; + Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); + SceneEEVEE *eevee = &scene_eval->eevee; + + lbake->bounce_len = eevee->gi_diffuse_bounces; + lbake->vis_res = eevee->gi_visibility_resolution; + lbake->rt_res = eevee->gi_cubemap_resolution; + + irradiance_pool_size_get(lbake->vis_res, lbake->total_irr_samples, lbake->irr_size); + + lbake->ref_cube_res = OCTAHEDRAL_SIZE_FROM_CUBESIZE(lbake->rt_res); + + lbake->cube_prb = MEM_callocN(sizeof(LightProbe *) * lbake->cube_len, "EEVEE Cube visgroup ptr"); + lbake->grid_prb = MEM_callocN(sizeof(LightProbe *) * lbake->grid_len, "EEVEE Grid visgroup ptr"); + + lbake->grid_prev = DRW_texture_create_2d_array(lbake->irr_size[0], + lbake->irr_size[1], + lbake->irr_size[2], + IRRADIANCE_FORMAT, + DRW_TEX_FILTER, + NULL); + + /* Ensure Light Cache is ready to accept new data. If not recreate one. + * WARNING: All the following must be threadsafe. It's currently protected + * by the DRW mutex. */ + lbake->lcache = eevee->light_cache; + + /* TODO validate irradiance and reflection cache independently... */ + if (!EEVEE_lightcache_validate( + lbake->lcache, lbake->cube_len, lbake->ref_cube_res, lbake->grid_len, lbake->irr_size)) { + eevee->light_cache = lbake->lcache = NULL; + } + + 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 = lbake->lcache; + } + + EEVEE_lightcache_load(eevee->light_cache); + + lbake->lcache->flag |= LIGHTCACHE_BAKING; + lbake->lcache->cube_len = 1; } -wmJob *EEVEE_lightbake_job_create( - struct wmWindowManager *wm, struct wmWindow *win, struct Main *bmain, - struct ViewLayer *view_layer, struct Scene *scene, int delay, int frame) +wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm, + struct wmWindow *win, + struct Main *bmain, + struct ViewLayer *view_layer, + struct Scene *scene, + int delay, + int frame) { - EEVEE_LightBake *lbake = NULL; - - /* only one render job at a time */ - if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) { - return NULL; - } - - wmJob *wm_job = WM_jobs_get(wm, win, scene, "Bake Lighting", - WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, WM_JOB_TYPE_LIGHT_BAKE); - - /* If job exists do not recreate context and depsgraph. */ - EEVEE_LightBake *old_lbake = (EEVEE_LightBake *)WM_jobs_customdata_get(wm_job); - - if (old_lbake && (old_lbake->view_layer_input == view_layer) && (old_lbake->bmain == bmain)) { - lbake = MEM_callocN(sizeof(EEVEE_LightBake), "EEVEE_LightBake"); - /* Cannot reuse depsgraph for now because we cannot get the update from the - * main database directly. TODO reuse depsgraph and only update positions. */ - /* lbake->depsgraph = old_lbake->depsgraph; */ - lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER); - - lbake->mutex = BLI_mutex_alloc(); - - BLI_mutex_lock(old_lbake->mutex); - old_lbake->own_resources = false; - - lbake->scene = scene; - lbake->bmain = bmain; - lbake->view_layer_input = view_layer; - lbake->gl_context = old_lbake->gl_context; - lbake->own_resources = true; - lbake->delay = delay; - lbake->frame = frame; - - if (lbake->gl_context == NULL) { - lbake->gl_context = WM_opengl_context_create(); - wm_window_reset_drawable(); - } - - if (old_lbake->stop != NULL) { - *old_lbake->stop = 1; - } - BLI_mutex_unlock(old_lbake->mutex); - } - else { - lbake = EEVEE_lightbake_job_data_alloc(bmain, view_layer, scene, true, frame); - lbake->delay = delay; - } - - WM_jobs_customdata_set(wm_job, lbake, EEVEE_lightbake_job_data_free); - WM_jobs_timer(wm_job, 0.4, NC_SCENE | NA_EDITED, 0); - WM_jobs_callbacks(wm_job, EEVEE_lightbake_job, NULL, EEVEE_lightbake_update, EEVEE_lightbake_update); - - G.is_break = false; - - return wm_job; + EEVEE_LightBake *lbake = NULL; + + /* only one render job at a time */ + if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) { + return NULL; + } + + wmJob *wm_job = WM_jobs_get(wm, + win, + scene, + "Bake Lighting", + WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, + WM_JOB_TYPE_LIGHT_BAKE); + + /* If job exists do not recreate context and depsgraph. */ + EEVEE_LightBake *old_lbake = (EEVEE_LightBake *)WM_jobs_customdata_get(wm_job); + + if (old_lbake && (old_lbake->view_layer_input == view_layer) && (old_lbake->bmain == bmain)) { + lbake = MEM_callocN(sizeof(EEVEE_LightBake), "EEVEE_LightBake"); + /* Cannot reuse depsgraph for now because we cannot get the update from the + * main database directly. TODO reuse depsgraph and only update positions. */ + /* lbake->depsgraph = old_lbake->depsgraph; */ + lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER); + + lbake->mutex = BLI_mutex_alloc(); + + BLI_mutex_lock(old_lbake->mutex); + old_lbake->own_resources = false; + + lbake->scene = scene; + lbake->bmain = bmain; + lbake->view_layer_input = view_layer; + lbake->gl_context = old_lbake->gl_context; + lbake->own_resources = true; + lbake->delay = delay; + lbake->frame = frame; + + if (lbake->gl_context == NULL) { + lbake->gl_context = WM_opengl_context_create(); + wm_window_reset_drawable(); + } + + if (old_lbake->stop != NULL) { + *old_lbake->stop = 1; + } + BLI_mutex_unlock(old_lbake->mutex); + } + else { + lbake = EEVEE_lightbake_job_data_alloc(bmain, view_layer, scene, true, frame); + lbake->delay = delay; + } + + WM_jobs_customdata_set(wm_job, lbake, EEVEE_lightbake_job_data_free); + WM_jobs_timer(wm_job, 0.4, NC_SCENE | NA_EDITED, 0); + WM_jobs_callbacks( + wm_job, EEVEE_lightbake_job, NULL, EEVEE_lightbake_update, EEVEE_lightbake_update); + + G.is_break = false; + + return wm_job; } /* MUST run on the main thread. */ -void *EEVEE_lightbake_job_data_alloc( - struct Main *bmain, struct ViewLayer *view_layer, struct Scene *scene, bool run_as_job, int frame) +void *EEVEE_lightbake_job_data_alloc(struct Main *bmain, + struct ViewLayer *view_layer, + struct Scene *scene, + bool run_as_job, + int frame) { - BLI_assert(BLI_thread_is_main()); + BLI_assert(BLI_thread_is_main()); - EEVEE_LightBake *lbake = MEM_callocN(sizeof(EEVEE_LightBake), "EEVEE_LightBake"); + EEVEE_LightBake *lbake = MEM_callocN(sizeof(EEVEE_LightBake), "EEVEE_LightBake"); - lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER); - lbake->scene = scene; - lbake->bmain = bmain; - lbake->view_layer_input = view_layer; - lbake->own_resources = true; - lbake->own_light_cache = false; - lbake->mutex = BLI_mutex_alloc(); - lbake->frame = frame; + lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER); + lbake->scene = scene; + lbake->bmain = bmain; + lbake->view_layer_input = view_layer; + lbake->own_resources = true; + lbake->own_light_cache = false; + lbake->mutex = BLI_mutex_alloc(); + lbake->frame = frame; - if (run_as_job) { - lbake->gl_context = WM_opengl_context_create(); - wm_window_reset_drawable(); - } + if (run_as_job) { + lbake->gl_context = WM_opengl_context_create(); + wm_window_reset_drawable(); + } - return lbake; + return lbake; } void EEVEE_lightbake_job_data_free(void *custom_data) { - EEVEE_LightBake *lbake = (EEVEE_LightBake *)custom_data; + EEVEE_LightBake *lbake = (EEVEE_LightBake *)custom_data; + /* TODO reuse depsgraph. */ + /* if (lbake->own_resources) { */ + DEG_graph_free(lbake->depsgraph); + /* } */ + MEM_SAFE_FREE(lbake->cube_prb); + MEM_SAFE_FREE(lbake->grid_prb); - /* TODO reuse depsgraph. */ - /* if (lbake->own_resources) { */ - DEG_graph_free(lbake->depsgraph); - /* } */ + BLI_mutex_free(lbake->mutex); - MEM_SAFE_FREE(lbake->cube_prb); - MEM_SAFE_FREE(lbake->grid_prb); - - BLI_mutex_free(lbake->mutex); - - MEM_freeN(lbake); + MEM_freeN(lbake); } static void eevee_lightbake_delete_resources(EEVEE_LightBake *lbake) { - if (!lbake->resource_only) { - BLI_mutex_lock(lbake->mutex); - } - - if (lbake->gl_context) { - DRW_opengl_render_context_enable(lbake->gl_context); - DRW_gawain_render_context_enable(lbake->gpu_context); - } - else if (!lbake->resource_only) { - DRW_opengl_context_enable(); - } - - /* XXX Free the resources contained in the viewlayer data - * to be able to free the context before deleting the depsgraph. */ - if (lbake->sldata) { - EEVEE_view_layer_data_free(lbake->sldata); - } - - DRW_TEXTURE_FREE_SAFE(lbake->rt_depth); - DRW_TEXTURE_FREE_SAFE(lbake->rt_color); - DRW_TEXTURE_FREE_SAFE(lbake->grid_prev); - GPU_FRAMEBUFFER_FREE_SAFE(lbake->store_fb); - for (int i = 0; i < 6; ++i) { - GPU_FRAMEBUFFER_FREE_SAFE(lbake->rt_fb[i]); - } - - if (lbake->gpu_context) { - DRW_gawain_render_context_disable(lbake->gpu_context); - DRW_gawain_render_context_enable(lbake->gpu_context); - GPU_context_discard(lbake->gpu_context); - } - - if (lbake->gl_context && lbake->own_resources) { - /* Delete the baking context. */ - DRW_opengl_render_context_disable(lbake->gl_context); - WM_opengl_context_dispose(lbake->gl_context); - lbake->gpu_context = NULL; - lbake->gl_context = NULL; - } - else if (lbake->gl_context) { - DRW_opengl_render_context_disable(lbake->gl_context); - } - else if (!lbake->resource_only) { - DRW_opengl_context_disable(); - } - - if (!lbake->resource_only) { - BLI_mutex_unlock(lbake->mutex); - } + if (!lbake->resource_only) { + BLI_mutex_lock(lbake->mutex); + } + + if (lbake->gl_context) { + DRW_opengl_render_context_enable(lbake->gl_context); + DRW_gawain_render_context_enable(lbake->gpu_context); + } + else if (!lbake->resource_only) { + DRW_opengl_context_enable(); + } + + /* XXX Free the resources contained in the viewlayer data + * to be able to free the context before deleting the depsgraph. */ + if (lbake->sldata) { + EEVEE_view_layer_data_free(lbake->sldata); + } + + DRW_TEXTURE_FREE_SAFE(lbake->rt_depth); + DRW_TEXTURE_FREE_SAFE(lbake->rt_color); + DRW_TEXTURE_FREE_SAFE(lbake->grid_prev); + GPU_FRAMEBUFFER_FREE_SAFE(lbake->store_fb); + for (int i = 0; i < 6; ++i) { + GPU_FRAMEBUFFER_FREE_SAFE(lbake->rt_fb[i]); + } + + if (lbake->gpu_context) { + DRW_gawain_render_context_disable(lbake->gpu_context); + DRW_gawain_render_context_enable(lbake->gpu_context); + GPU_context_discard(lbake->gpu_context); + } + + if (lbake->gl_context && lbake->own_resources) { + /* Delete the baking context. */ + DRW_opengl_render_context_disable(lbake->gl_context); + WM_opengl_context_dispose(lbake->gl_context); + lbake->gpu_context = NULL; + lbake->gl_context = NULL; + } + else if (lbake->gl_context) { + DRW_opengl_render_context_disable(lbake->gl_context); + } + else if (!lbake->resource_only) { + DRW_opengl_context_disable(); + } + + if (!lbake->resource_only) { + BLI_mutex_unlock(lbake->mutex); + } } /* Cache as in draw cache not light cache. */ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lbake) { - EEVEE_TextureList *txl = vedata->txl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); - Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); - lbake->sldata = sldata; - - /* Disable all effects BUT high bitdepth shadows. */ - scene_eval->eevee.flag &= SCE_EEVEE_SHADOW_HIGH_BITDEPTH; - scene_eval->eevee.taa_samples = 1; - scene_eval->eevee.gi_irradiance_smoothing = 0.0f; - - stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); - stl->g_data->background_alpha = 1.0f; - - /* XXX TODO remove this. This is in order to make the init functions work. */ - DRWMatrixState dummy_mats = {{{{{0}}}}}; - DRW_viewport_matrix_override_set_all(&dummy_mats); - - if (sldata->common_ubo == NULL) { - sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data); - } - if (sldata->clip_ubo == NULL) { - sldata->clip_ubo = DRW_uniformbuffer_create(sizeof(sldata->clip_data), &sldata->clip_data); - } - - /* HACK: set txl->color but unset it before Draw Manager frees it. */ - txl->color = lbake->rt_color; - int viewport_size[2] = { - GPU_texture_width(txl->color), - GPU_texture_height(txl->color), - }; - DRW_render_viewport_size_set(viewport_size); - - EEVEE_effects_init(sldata, vedata, NULL, true); - EEVEE_materials_init(sldata, stl, fbl); - EEVEE_lights_init(sldata); - EEVEE_lightprobes_init(sldata, vedata); - - EEVEE_effects_cache_init(sldata, vedata); - EEVEE_materials_cache_init(sldata, vedata); - EEVEE_lights_cache_init(sldata, vedata); - EEVEE_lightprobes_cache_init(sldata, vedata); - - EEVEE_lightbake_cache_init(sldata, vedata, lbake->rt_color, lbake->rt_depth); - - if (lbake->probe) { - EEVEE_LightProbesInfo *pinfo = sldata->probes; - LightProbe *prb = *lbake->probe; - pinfo->vis_data.collection = prb->visibility_grp; - pinfo->vis_data.invert = prb->flag & LIGHTPROBE_FLAG_INVERT_GROUP; - pinfo->vis_data.cached = false; - } - DRW_render_object_iter(vedata, NULL, lbake->depsgraph, EEVEE_render_cache); - - EEVEE_materials_cache_finish(vedata); - EEVEE_lights_cache_finish(sldata, vedata); - EEVEE_lightprobes_cache_finish(sldata, vedata); - - txl->color = NULL; - - DRW_render_instance_buffer_finish(); - DRW_hair_update(); + EEVEE_TextureList *txl = vedata->txl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); + lbake->sldata = sldata; + + /* Disable all effects BUT high bitdepth shadows. */ + scene_eval->eevee.flag &= SCE_EEVEE_SHADOW_HIGH_BITDEPTH; + scene_eval->eevee.taa_samples = 1; + scene_eval->eevee.gi_irradiance_smoothing = 0.0f; + + stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); + stl->g_data->background_alpha = 1.0f; + + /* XXX TODO remove this. This is in order to make the init functions work. */ + DRWMatrixState dummy_mats = {{{{{0}}}}}; + DRW_viewport_matrix_override_set_all(&dummy_mats); + + if (sldata->common_ubo == NULL) { + sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), + &sldata->common_data); + } + if (sldata->clip_ubo == NULL) { + sldata->clip_ubo = DRW_uniformbuffer_create(sizeof(sldata->clip_data), &sldata->clip_data); + } + + /* HACK: set txl->color but unset it before Draw Manager frees it. */ + txl->color = lbake->rt_color; + int viewport_size[2] = { + GPU_texture_width(txl->color), + GPU_texture_height(txl->color), + }; + DRW_render_viewport_size_set(viewport_size); + + EEVEE_effects_init(sldata, vedata, NULL, true); + EEVEE_materials_init(sldata, stl, fbl); + EEVEE_lights_init(sldata); + EEVEE_lightprobes_init(sldata, vedata); + + EEVEE_effects_cache_init(sldata, vedata); + EEVEE_materials_cache_init(sldata, vedata); + EEVEE_lights_cache_init(sldata, vedata); + EEVEE_lightprobes_cache_init(sldata, vedata); + + EEVEE_lightbake_cache_init(sldata, vedata, lbake->rt_color, lbake->rt_depth); + + if (lbake->probe) { + EEVEE_LightProbesInfo *pinfo = sldata->probes; + LightProbe *prb = *lbake->probe; + pinfo->vis_data.collection = prb->visibility_grp; + pinfo->vis_data.invert = prb->flag & LIGHTPROBE_FLAG_INVERT_GROUP; + pinfo->vis_data.cached = false; + } + DRW_render_object_iter(vedata, NULL, lbake->depsgraph, EEVEE_render_cache); + + EEVEE_materials_cache_finish(vedata); + EEVEE_lights_cache_finish(sldata, vedata); + EEVEE_lightprobes_cache_finish(sldata, vedata); + + txl->color = NULL; + + DRW_render_instance_buffer_finish(); + DRW_hair_update(); } static void eevee_lightbake_copy_irradiance(EEVEE_LightBake *lbake, LightCache *lcache) { - DRW_TEXTURE_FREE_SAFE(lbake->grid_prev); - - /* Copy texture by reading back and reuploading it. */ - float *tex = GPU_texture_read(lcache->grid_tx.tex, GPU_DATA_FLOAT, 0); - lbake->grid_prev = DRW_texture_create_2d_array(lbake->irr_size[0], lbake->irr_size[1], lbake->irr_size[2], - IRRADIANCE_FORMAT, DRW_TEX_FILTER, tex); - - MEM_freeN(tex); + DRW_TEXTURE_FREE_SAFE(lbake->grid_prev); + + /* Copy texture by reading back and reuploading it. */ + float *tex = GPU_texture_read(lcache->grid_tx.tex, GPU_DATA_FLOAT, 0); + lbake->grid_prev = DRW_texture_create_2d_array(lbake->irr_size[0], + lbake->irr_size[1], + lbake->irr_size[2], + IRRADIANCE_FORMAT, + DRW_TEX_FILTER, + tex); + + MEM_freeN(tex); } static void eevee_lightbake_render_world_sample(void *ved, void *user_data) { - EEVEE_Data *vedata = (EEVEE_Data *)ved; - EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); - EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data; - Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); - LightCache *lcache = scene_eval->eevee.light_cache; - float clamp = scene_eval->eevee.gi_glossy_clamp; - float filter_quality = scene_eval->eevee.gi_filter_quality; - - /* TODO do this once for the whole bake when we have independent DRWManagers. */ - eevee_lightbake_cache_create(vedata, lbake); - - sldata->common_data.ray_type = EEVEE_RAY_GLOSSY; - sldata->common_data.ray_depth = 1; - DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); - EEVEE_lightbake_render_world(sldata, vedata, lbake->rt_fb); - EEVEE_lightbake_filter_glossy(sldata, vedata, lbake->rt_color, lbake->store_fb, 0, 1.0f, lcache->mips_len, filter_quality, clamp); - - sldata->common_data.ray_type = EEVEE_RAY_DIFFUSE; - sldata->common_data.ray_depth = 1; - DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); - EEVEE_lightbake_render_world(sldata, vedata, lbake->rt_fb); - EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake->rt_color, lbake->store_fb, 0, 1.0f); - - /* Clear the cache to avoid white values in the grid. */ - GPU_framebuffer_texture_attach(lbake->store_fb, lbake->grid_prev, 0, 0); - GPU_framebuffer_bind(lbake->store_fb); - /* Clear to 1.0f for visibility. */ - GPU_framebuffer_clear_color(lbake->store_fb, ((float[4]){1.0f, 1.0f, 1.0f, 1.0f})); - DRW_draw_pass(vedata->psl->probe_grid_fill); - - SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex); - - /* Make a copy for later. */ - eevee_lightbake_copy_irradiance(lbake, lcache); - - lcache->cube_len = 1; - lcache->grid_len = lbake->grid_len; - - lcache->flag |= LIGHTCACHE_CUBE_READY | LIGHTCACHE_GRID_READY; - lcache->flag &= ~LIGHTCACHE_UPDATE_WORLD; + EEVEE_Data *vedata = (EEVEE_Data *)ved; + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data; + Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); + LightCache *lcache = scene_eval->eevee.light_cache; + float clamp = scene_eval->eevee.gi_glossy_clamp; + float filter_quality = scene_eval->eevee.gi_filter_quality; + + /* TODO do this once for the whole bake when we have independent DRWManagers. */ + eevee_lightbake_cache_create(vedata, lbake); + + sldata->common_data.ray_type = EEVEE_RAY_GLOSSY; + sldata->common_data.ray_depth = 1; + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + EEVEE_lightbake_render_world(sldata, vedata, lbake->rt_fb); + EEVEE_lightbake_filter_glossy(sldata, + vedata, + lbake->rt_color, + lbake->store_fb, + 0, + 1.0f, + lcache->mips_len, + filter_quality, + clamp); + + sldata->common_data.ray_type = EEVEE_RAY_DIFFUSE; + sldata->common_data.ray_depth = 1; + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + EEVEE_lightbake_render_world(sldata, vedata, lbake->rt_fb); + EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake->rt_color, lbake->store_fb, 0, 1.0f); + + /* Clear the cache to avoid white values in the grid. */ + GPU_framebuffer_texture_attach(lbake->store_fb, lbake->grid_prev, 0, 0); + GPU_framebuffer_bind(lbake->store_fb); + /* Clear to 1.0f for visibility. */ + GPU_framebuffer_clear_color(lbake->store_fb, ((float[4]){1.0f, 1.0f, 1.0f, 1.0f})); + DRW_draw_pass(vedata->psl->probe_grid_fill); + + SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex); + + /* Make a copy for later. */ + eevee_lightbake_copy_irradiance(lbake, lcache); + + lcache->cube_len = 1; + lcache->grid_len = lbake->grid_len; + + lcache->flag |= LIGHTCACHE_CUBE_READY | LIGHTCACHE_GRID_READY; + lcache->flag &= ~LIGHTCACHE_UPDATE_WORLD; } static void cell_id_to_grid_loc(EEVEE_LightGrid *egrid, int cell_idx, int r_local_cell[3]) { - /* Keep in sync with lightprobe_grid_display_vert */ - r_local_cell[2] = cell_idx % egrid->resolution[2]; - r_local_cell[1] = (cell_idx / egrid->resolution[2]) % egrid->resolution[1]; - r_local_cell[0] = cell_idx / (egrid->resolution[2] * egrid->resolution[1]); + /* Keep in sync with lightprobe_grid_display_vert */ + r_local_cell[2] = cell_idx % egrid->resolution[2]; + r_local_cell[1] = (cell_idx / egrid->resolution[2]) % egrid->resolution[1]; + r_local_cell[0] = cell_idx / (egrid->resolution[2] * egrid->resolution[1]); } -static void compute_cell_id( - EEVEE_LightGrid *egrid, LightProbe *probe, - int cell_idx, int *r_final_idx, int r_local_cell[3], int *r_stride) +static void compute_cell_id(EEVEE_LightGrid *egrid, + LightProbe *probe, + int cell_idx, + int *r_final_idx, + int r_local_cell[3], + int *r_stride) { - const int cell_count = probe->grid_resolution_x * probe->grid_resolution_y * probe->grid_resolution_z; - - /* Add one for level 0 */ - int max_lvl = (int)floorf(log2f((float)MAX3(probe->grid_resolution_x, - probe->grid_resolution_y, - probe->grid_resolution_z))); - - int visited_cells = 0; - *r_stride = 0; - *r_final_idx = 0; - r_local_cell[0] = r_local_cell[1] = r_local_cell[2] = 0; - for (int lvl = max_lvl; lvl >= 0; --lvl) { - *r_stride = 1 << lvl; - int prev_stride = *r_stride << 1; - for (int i = 0; i < cell_count; ++i) { - *r_final_idx = i; - cell_id_to_grid_loc(egrid, *r_final_idx, r_local_cell); - if (((r_local_cell[0] % *r_stride) == 0) && - ((r_local_cell[1] % *r_stride) == 0) && - ((r_local_cell[2] % *r_stride) == 0)) - { - if (!(((r_local_cell[0] % prev_stride) == 0) && - ((r_local_cell[1] % prev_stride) == 0) && - ((r_local_cell[2] % prev_stride) == 0)) || - ((i == 0) && (lvl == max_lvl))) - { - if (visited_cells == cell_idx) { - return; - } - else { - visited_cells++; - } - } - } - } - } - - BLI_assert(0); + const int cell_count = probe->grid_resolution_x * probe->grid_resolution_y * + probe->grid_resolution_z; + + /* Add one for level 0 */ + int max_lvl = (int)floorf(log2f( + (float)MAX3(probe->grid_resolution_x, probe->grid_resolution_y, probe->grid_resolution_z))); + + int visited_cells = 0; + *r_stride = 0; + *r_final_idx = 0; + r_local_cell[0] = r_local_cell[1] = r_local_cell[2] = 0; + for (int lvl = max_lvl; lvl >= 0; --lvl) { + *r_stride = 1 << lvl; + int prev_stride = *r_stride << 1; + for (int i = 0; i < cell_count; ++i) { + *r_final_idx = i; + cell_id_to_grid_loc(egrid, *r_final_idx, r_local_cell); + if (((r_local_cell[0] % *r_stride) == 0) && ((r_local_cell[1] % *r_stride) == 0) && + ((r_local_cell[2] % *r_stride) == 0)) { + if (!(((r_local_cell[0] % prev_stride) == 0) && ((r_local_cell[1] % prev_stride) == 0) && + ((r_local_cell[2] % prev_stride) == 0)) || + ((i == 0) && (lvl == max_lvl))) { + if (visited_cells == cell_idx) { + return; + } + else { + visited_cells++; + } + } + } + } + } + + BLI_assert(0); } static void grid_loc_to_world_loc(EEVEE_LightGrid *egrid, int local_cell[3], float r_pos[3]) { - copy_v3_v3(r_pos, egrid->corner); - madd_v3_v3fl(r_pos, egrid->increment_x, local_cell[0]); - madd_v3_v3fl(r_pos, egrid->increment_y, local_cell[1]); - madd_v3_v3fl(r_pos, egrid->increment_z, local_cell[2]); + copy_v3_v3(r_pos, egrid->corner); + madd_v3_v3fl(r_pos, egrid->increment_x, local_cell[0]); + madd_v3_v3fl(r_pos, egrid->increment_y, local_cell[1]); + madd_v3_v3fl(r_pos, egrid->increment_z, local_cell[2]); } static void eevee_lightbake_render_grid_sample(void *ved, void *user_data) { - EEVEE_Data *vedata = (EEVEE_Data *)ved; - EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); - EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data; - EEVEE_LightGrid *egrid = lbake->grid; - LightProbe *prb = *lbake->probe; - Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); - LightCache *lcache = scene_eval->eevee.light_cache; - int grid_loc[3], sample_id, sample_offset, stride; - float pos[3]; - const bool is_last_bounce_sample = ((egrid->offset + lbake->grid_sample) == (lbake->total_irr_samples - 1)); - - /* No bias for rendering the probe. */ - egrid->level_bias = 1.0f; - - /* Use the previous bounce for rendering this bounce. */ - SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex); - - /* TODO do this once for the whole bake when we have independent DRWManagers. - * Warning: Some of the things above require this. */ - eevee_lightbake_cache_create(vedata, lbake); - - /* Compute sample position */ - compute_cell_id(egrid, prb, lbake->grid_sample, &sample_id, grid_loc, &stride); - sample_offset = egrid->offset + sample_id; - - grid_loc_to_world_loc(egrid, grid_loc, pos); - - /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */ - common_data->spec_toggle = false; - common_data->prb_num_planar = 0; - common_data->prb_num_render_cube = 0; - common_data->ray_type = EEVEE_RAY_DIFFUSE; - common_data->ray_depth = lbake->bounce_curr + 1; - if (lbake->bounce_curr == 0) { - common_data->prb_num_render_grid = 0; - } - DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); - - EEVEE_lightbake_render_scene(sldata, vedata, lbake->rt_fb, pos, prb->clipsta, prb->clipend); - - /* Restore before filtering. */ - SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex); - - EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake->rt_color, lbake->store_fb, sample_offset, prb->intensity); - - if (lbake->bounce_curr == 0) { - /* We only need to filter the visibility for the first bounce. */ - EEVEE_lightbake_filter_visibility( - sldata, vedata, lbake->rt_depth, lbake->store_fb, sample_offset, - prb->clipsta, prb->clipend, egrid->visibility_range, - prb->vis_blur, lbake->vis_res); - } - - /* Update level for progressive update. */ - if (is_last_bounce_sample) { - egrid->level_bias = 1.0f; - } - else if (lbake->bounce_curr == 0) { - egrid->level_bias = (float)(stride << 1); - } - - /* Only run this for the last sample of a bounce. */ - if (is_last_bounce_sample) { - eevee_lightbake_copy_irradiance(lbake, lcache); - } - - /* If it is the last sample grid sample (and last bounce). */ - if ((lbake->bounce_curr == lbake->bounce_len - 1) && - (lbake->grid_curr == lbake->grid_len - 1) && - (lbake->grid_sample == lbake->grid_sample_len - 1)) - { - lcache->flag &= ~LIGHTCACHE_UPDATE_GRID; - } + EEVEE_Data *vedata = (EEVEE_Data *)ved; + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data; + EEVEE_LightGrid *egrid = lbake->grid; + LightProbe *prb = *lbake->probe; + Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); + LightCache *lcache = scene_eval->eevee.light_cache; + int grid_loc[3], sample_id, sample_offset, stride; + float pos[3]; + const bool is_last_bounce_sample = ((egrid->offset + lbake->grid_sample) == + (lbake->total_irr_samples - 1)); + + /* No bias for rendering the probe. */ + egrid->level_bias = 1.0f; + + /* Use the previous bounce for rendering this bounce. */ + SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex); + + /* TODO do this once for the whole bake when we have independent DRWManagers. + * Warning: Some of the things above require this. */ + eevee_lightbake_cache_create(vedata, lbake); + + /* Compute sample position */ + compute_cell_id(egrid, prb, lbake->grid_sample, &sample_id, grid_loc, &stride); + sample_offset = egrid->offset + sample_id; + + grid_loc_to_world_loc(egrid, grid_loc, pos); + + /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */ + common_data->spec_toggle = false; + common_data->prb_num_planar = 0; + common_data->prb_num_render_cube = 0; + common_data->ray_type = EEVEE_RAY_DIFFUSE; + common_data->ray_depth = lbake->bounce_curr + 1; + if (lbake->bounce_curr == 0) { + common_data->prb_num_render_grid = 0; + } + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + + EEVEE_lightbake_render_scene(sldata, vedata, lbake->rt_fb, pos, prb->clipsta, prb->clipend); + + /* Restore before filtering. */ + SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex); + + EEVEE_lightbake_filter_diffuse( + sldata, vedata, lbake->rt_color, lbake->store_fb, sample_offset, prb->intensity); + + if (lbake->bounce_curr == 0) { + /* We only need to filter the visibility for the first bounce. */ + EEVEE_lightbake_filter_visibility(sldata, + vedata, + lbake->rt_depth, + lbake->store_fb, + sample_offset, + prb->clipsta, + prb->clipend, + egrid->visibility_range, + prb->vis_blur, + lbake->vis_res); + } + + /* Update level for progressive update. */ + if (is_last_bounce_sample) { + egrid->level_bias = 1.0f; + } + else if (lbake->bounce_curr == 0) { + egrid->level_bias = (float)(stride << 1); + } + + /* Only run this for the last sample of a bounce. */ + if (is_last_bounce_sample) { + eevee_lightbake_copy_irradiance(lbake, lcache); + } + + /* If it is the last sample grid sample (and last bounce). */ + if ((lbake->bounce_curr == lbake->bounce_len - 1) && (lbake->grid_curr == lbake->grid_len - 1) && + (lbake->grid_sample == lbake->grid_sample_len - 1)) { + lcache->flag &= ~LIGHTCACHE_UPDATE_GRID; + } } static void eevee_lightbake_render_probe_sample(void *ved, void *user_data) { - EEVEE_Data *vedata = (EEVEE_Data *)ved; - EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); - EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data; - Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); - LightCache *lcache = scene_eval->eevee.light_cache; - EEVEE_LightProbe *eprobe = lbake->cube; - LightProbe *prb = *lbake->probe; - float clamp = scene_eval->eevee.gi_glossy_clamp; - float filter_quality = scene_eval->eevee.gi_filter_quality; - - /* TODO do this once for the whole bake when we have independent DRWManagers. */ - eevee_lightbake_cache_create(vedata, lbake); - - /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */ - common_data->spec_toggle = false; - common_data->prb_num_planar = 0; - common_data->prb_num_render_cube = 0; - common_data->ray_type = EEVEE_RAY_GLOSSY; - common_data->ray_depth = 1; - DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); - - EEVEE_lightbake_render_scene(sldata, vedata, lbake->rt_fb, eprobe->position, prb->clipsta, prb->clipend); - EEVEE_lightbake_filter_glossy( - sldata, vedata, lbake->rt_color, lbake->store_fb, lbake->cube_offset, prb->intensity, - lcache->mips_len, filter_quality, clamp); - - lcache->cube_len += 1; - - /* If it's the last probe. */ - if (lbake->cube_offset == lbake->cube_len - 1) { - lcache->flag &= ~LIGHTCACHE_UPDATE_CUBE; - } + EEVEE_Data *vedata = (EEVEE_Data *)ved; + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data; + Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); + LightCache *lcache = scene_eval->eevee.light_cache; + EEVEE_LightProbe *eprobe = lbake->cube; + LightProbe *prb = *lbake->probe; + float clamp = scene_eval->eevee.gi_glossy_clamp; + float filter_quality = scene_eval->eevee.gi_filter_quality; + + /* TODO do this once for the whole bake when we have independent DRWManagers. */ + eevee_lightbake_cache_create(vedata, lbake); + + /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */ + common_data->spec_toggle = false; + common_data->prb_num_planar = 0; + common_data->prb_num_render_cube = 0; + common_data->ray_type = EEVEE_RAY_GLOSSY; + common_data->ray_depth = 1; + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + + EEVEE_lightbake_render_scene( + sldata, vedata, lbake->rt_fb, eprobe->position, prb->clipsta, prb->clipend); + EEVEE_lightbake_filter_glossy(sldata, + vedata, + lbake->rt_color, + lbake->store_fb, + lbake->cube_offset, + prb->intensity, + lcache->mips_len, + filter_quality, + clamp); + + lcache->cube_len += 1; + + /* If it's the last probe. */ + if (lbake->cube_offset == lbake->cube_len - 1) { + lcache->flag &= ~LIGHTCACHE_UPDATE_CUBE; + } } static float eevee_lightbake_grid_influence_volume(EEVEE_LightGrid *grid) { - return mat4_to_scale(grid->mat); + return mat4_to_scale(grid->mat); } static float eevee_lightbake_cube_influence_volume(EEVEE_LightProbe *eprb) { - return mat4_to_scale(eprb->attenuationmat); + return mat4_to_scale(eprb->attenuationmat); } static bool eevee_lightbake_grid_comp(EEVEE_LightGrid *grid_a, EEVEE_LightGrid *grid_b) { - float vol_a = eevee_lightbake_grid_influence_volume(grid_a); - float vol_b = eevee_lightbake_grid_influence_volume(grid_b); - return (vol_a < vol_b); + float vol_a = eevee_lightbake_grid_influence_volume(grid_a); + float vol_b = eevee_lightbake_grid_influence_volume(grid_b); + return (vol_a < vol_b); } static bool eevee_lightbake_cube_comp(EEVEE_LightProbe *prb_a, EEVEE_LightProbe *prb_b) { - float vol_a = eevee_lightbake_cube_influence_volume(prb_a); - float vol_b = eevee_lightbake_cube_influence_volume(prb_b); - return (vol_a < vol_b); + float vol_a = eevee_lightbake_cube_influence_volume(prb_a); + float vol_b = eevee_lightbake_cube_influence_volume(prb_b); + return (vol_a < vol_b); } #define SORT_PROBE(elems_type, prbs, elems, elems_len, comp_fn) \ -{ \ - bool sorted = false; \ - while (!sorted) { \ - sorted = true; \ - for (int i = 0; i < (elems_len) - 1; i++) { \ - if ((comp_fn)((elems) + i, (elems) + i + 1)) { \ - SWAP(elems_type, (elems)[i], (elems)[i + 1]); \ - SWAP(LightProbe *, (prbs)[i], (prbs)[i + 1]); \ - sorted = false; \ - } \ - } \ - } \ -} ((void)0) + { \ + bool sorted = false; \ + while (!sorted) { \ + sorted = true; \ + for (int i = 0; i < (elems_len)-1; i++) { \ + if ((comp_fn)((elems) + i, (elems) + i + 1)) { \ + SWAP(elems_type, (elems)[i], (elems)[i + 1]); \ + SWAP(LightProbe *, (prbs)[i], (prbs)[i + 1]); \ + sorted = false; \ + } \ + } \ + } \ + } \ + ((void)0) static void eevee_lightbake_gather_probes(EEVEE_LightBake *lbake) { - Depsgraph *depsgraph = lbake->depsgraph; - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - LightCache *lcache = scene_eval->eevee.light_cache; - - /* At least one for the world */ - int grid_len = 1; - int cube_len = 1; - int total_irr_samples = 1; - - /* Convert all lightprobes to tight UBO data from all lightprobes in the scene. - * This allows a large number of probe to be precomputed (even dupli ones). */ - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob) - { - const int ob_visibility = BKE_object_visibility(ob, DAG_EVAL_RENDER); - if ((ob_visibility & OB_VISIBLE_SELF) == 0) { - continue; - } - - if (ob->type == OB_LIGHTPROBE) { - LightProbe *prb = (LightProbe *)ob->data; - - if (prb->type == LIGHTPROBE_TYPE_GRID) { - lbake->grid_prb[grid_len] = prb; - EEVEE_LightGrid *egrid = &lcache->grid_data[grid_len++]; - EEVEE_lightprobes_grid_data_from_object(ob, egrid, &total_irr_samples); - } - else if (prb->type == LIGHTPROBE_TYPE_CUBE) { - lbake->cube_prb[cube_len] = prb; - EEVEE_LightProbe *eprobe = &lcache->cube_data[cube_len++]; - EEVEE_lightprobes_cube_data_from_object(ob, eprobe); - } - } - } - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; - - SORT_PROBE(EEVEE_LightGrid, lbake->grid_prb + 1, lcache->grid_data + 1, lbake->grid_len - 1, eevee_lightbake_grid_comp); - SORT_PROBE(EEVEE_LightProbe, lbake->cube_prb + 1, lcache->cube_data + 1, lbake->cube_len - 1, eevee_lightbake_cube_comp); - - lbake->total = lbake->total_irr_samples * lbake->bounce_len + lbake->cube_len; - lbake->done = 0; + Depsgraph *depsgraph = lbake->depsgraph; + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + LightCache *lcache = scene_eval->eevee.light_cache; + + /* At least one for the world */ + int grid_len = 1; + int cube_len = 1; + int total_irr_samples = 1; + + /* Convert all lightprobes to tight UBO data from all lightprobes in the scene. + * This allows a large number of probe to be precomputed (even dupli ones). */ + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { + const int ob_visibility = BKE_object_visibility(ob, DAG_EVAL_RENDER); + if ((ob_visibility & OB_VISIBLE_SELF) == 0) { + continue; + } + + if (ob->type == OB_LIGHTPROBE) { + LightProbe *prb = (LightProbe *)ob->data; + + if (prb->type == LIGHTPROBE_TYPE_GRID) { + lbake->grid_prb[grid_len] = prb; + EEVEE_LightGrid *egrid = &lcache->grid_data[grid_len++]; + EEVEE_lightprobes_grid_data_from_object(ob, egrid, &total_irr_samples); + } + else if (prb->type == LIGHTPROBE_TYPE_CUBE) { + lbake->cube_prb[cube_len] = prb; + EEVEE_LightProbe *eprobe = &lcache->cube_data[cube_len++]; + EEVEE_lightprobes_cube_data_from_object(ob, eprobe); + } + } + } + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; + + SORT_PROBE(EEVEE_LightGrid, + lbake->grid_prb + 1, + lcache->grid_data + 1, + lbake->grid_len - 1, + eevee_lightbake_grid_comp); + SORT_PROBE(EEVEE_LightProbe, + lbake->cube_prb + 1, + lcache->cube_data + 1, + lbake->cube_len - 1, + eevee_lightbake_cube_comp); + + lbake->total = lbake->total_irr_samples * lbake->bounce_len + lbake->cube_len; + lbake->done = 0; } void EEVEE_lightbake_update(void *custom_data) { - EEVEE_LightBake *lbake = (EEVEE_LightBake *)custom_data; - Scene *scene_orig = lbake->scene; + EEVEE_LightBake *lbake = (EEVEE_LightBake *)custom_data; + Scene *scene_orig = lbake->scene; - /* If a new lightcache was created, free the old one and reference the new. */ - if (lbake->lcache && scene_orig->eevee.light_cache != lbake->lcache) { - if (scene_orig->eevee.light_cache != NULL) { - EEVEE_lightcache_free(scene_orig->eevee.light_cache); - } - scene_orig->eevee.light_cache = lbake->lcache; - lbake->own_light_cache = false; - } + /* If a new lightcache was created, free the old one and reference the new. */ + if (lbake->lcache && scene_orig->eevee.light_cache != lbake->lcache) { + if (scene_orig->eevee.light_cache != NULL) { + EEVEE_lightcache_free(scene_orig->eevee.light_cache); + } + scene_orig->eevee.light_cache = lbake->lcache; + lbake->own_light_cache = false; + } - EEVEE_lightcache_info_update(&lbake->scene->eevee); + EEVEE_lightcache_info_update(&lbake->scene->eevee); - DEG_id_tag_update(&scene_orig->id, ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update(&scene_orig->id, ID_RECALC_COPY_ON_WRITE); } -static bool lightbake_do_sample(EEVEE_LightBake *lbake, void (*render_callback)(void *ved, void *user_data)) +static bool lightbake_do_sample(EEVEE_LightBake *lbake, + void (*render_callback)(void *ved, void *user_data)) { - if (G.is_break == true || *lbake->stop) { - return false; - } + if (G.is_break == true || *lbake->stop) { + return false; + } - Depsgraph *depsgraph = lbake->depsgraph; + Depsgraph *depsgraph = lbake->depsgraph; - /* TODO: make DRW manager instanciable (and only lock on drawing) */ - eevee_lightbake_context_enable(lbake); - DRW_custom_pipeline(&draw_engine_eevee_type, depsgraph, render_callback, lbake); - lbake->done += 1; - *lbake->progress = lbake->done / (float)lbake->total; - *lbake->do_update = 1; - eevee_lightbake_context_disable(lbake); + /* TODO: make DRW manager instanciable (and only lock on drawing) */ + eevee_lightbake_context_enable(lbake); + DRW_custom_pipeline(&draw_engine_eevee_type, depsgraph, render_callback, lbake); + lbake->done += 1; + *lbake->progress = lbake->done / (float)lbake->total; + *lbake->do_update = 1; + eevee_lightbake_context_disable(lbake); - return true; + return true; } void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float *progress) { - EEVEE_LightBake *lbake = (EEVEE_LightBake *)custom_data; - Depsgraph *depsgraph = lbake->depsgraph; - - DEG_graph_relations_update(depsgraph, lbake->bmain, lbake->scene, lbake->view_layer_input); - DEG_evaluate_on_framechange(lbake->bmain, depsgraph, lbake->frame); - - lbake->view_layer = DEG_get_evaluated_view_layer(depsgraph); - lbake->stop = stop; - lbake->do_update = do_update; - lbake->progress = progress; - - /* Count lightprobes */ - eevee_lightbake_count_probes(lbake); - - /* We need to create the FBOs in the right context. - * We cannot do it in the main thread. */ - eevee_lightbake_context_enable(lbake); - eevee_lightbake_create_resources(lbake); - eevee_lightbake_create_render_target(lbake, lbake->rt_res); - eevee_lightbake_context_disable(lbake); - - /* Gather all probes data */ - eevee_lightbake_gather_probes(lbake); - - LightCache *lcache = lbake->lcache; - - /* HACK: Sleep to delay the first rendering operation - * that causes a small freeze (caused by VBO generation) - * because this step is locking at this moment. */ - /* TODO remove this. */ - if (lbake->delay) { - PIL_sleep_ms(lbake->delay); - } - - /* Render world irradiance and reflection first */ - if (lcache->flag & LIGHTCACHE_UPDATE_WORLD) { - lbake->probe = NULL; - lightbake_do_sample(lbake, eevee_lightbake_render_world_sample); - } - - /* Render irradiance grids */ - if (lcache->flag & LIGHTCACHE_UPDATE_GRID) { - for (lbake->bounce_curr = 0; lbake->bounce_curr < lbake->bounce_len; ++lbake->bounce_curr) { - /* Bypass world, start at 1. */ - lbake->probe = lbake->grid_prb + 1; - lbake->grid = lcache->grid_data + 1; - for (lbake->grid_curr = 1; - lbake->grid_curr < lbake->grid_len; - ++lbake->grid_curr, ++lbake->probe, ++lbake->grid) - { - LightProbe *prb = *lbake->probe; - lbake->grid_sample_len = prb->grid_resolution_x * - prb->grid_resolution_y * - prb->grid_resolution_z; - for (lbake->grid_sample = 0; - lbake->grid_sample < lbake->grid_sample_len; - ++lbake->grid_sample) - { - lightbake_do_sample(lbake, eevee_lightbake_render_grid_sample); - } - } - } - } - - /* Render reflections */ - if (lcache->flag & LIGHTCACHE_UPDATE_CUBE) { - /* Bypass world, start at 1. */ - lbake->probe = lbake->cube_prb + 1; - lbake->cube = lcache->cube_data + 1; - for (lbake->cube_offset = 1; - lbake->cube_offset < lbake->cube_len; - ++lbake->cube_offset, ++lbake->probe, ++lbake->cube) - { - lightbake_do_sample(lbake, eevee_lightbake_render_probe_sample); - } - } - - /* Read the resulting lighting data to save it to file/disk. */ - eevee_lightbake_context_enable(lbake); - eevee_lightbake_readback_irradiance(lcache); - eevee_lightbake_readback_reflections(lcache); - eevee_lightbake_context_disable(lbake); - - lcache->flag |= LIGHTCACHE_BAKED; - lcache->flag &= ~LIGHTCACHE_BAKING; - - /* Assume that if lbake->gl_context is NULL - * we are not running in this in a job, so update - * the scene lightcache pointer before deleting it. */ - if (lbake->gl_context == NULL) { - BLI_assert(BLI_thread_is_main()); - EEVEE_lightbake_update(lbake); - } - - eevee_lightbake_delete_resources(lbake); + EEVEE_LightBake *lbake = (EEVEE_LightBake *)custom_data; + Depsgraph *depsgraph = lbake->depsgraph; + + DEG_graph_relations_update(depsgraph, lbake->bmain, lbake->scene, lbake->view_layer_input); + DEG_evaluate_on_framechange(lbake->bmain, depsgraph, lbake->frame); + + lbake->view_layer = DEG_get_evaluated_view_layer(depsgraph); + lbake->stop = stop; + lbake->do_update = do_update; + lbake->progress = progress; + + /* Count lightprobes */ + eevee_lightbake_count_probes(lbake); + + /* We need to create the FBOs in the right context. + * We cannot do it in the main thread. */ + eevee_lightbake_context_enable(lbake); + eevee_lightbake_create_resources(lbake); + eevee_lightbake_create_render_target(lbake, lbake->rt_res); + eevee_lightbake_context_disable(lbake); + + /* Gather all probes data */ + eevee_lightbake_gather_probes(lbake); + + LightCache *lcache = lbake->lcache; + + /* HACK: Sleep to delay the first rendering operation + * that causes a small freeze (caused by VBO generation) + * because this step is locking at this moment. */ + /* TODO remove this. */ + if (lbake->delay) { + PIL_sleep_ms(lbake->delay); + } + + /* Render world irradiance and reflection first */ + if (lcache->flag & LIGHTCACHE_UPDATE_WORLD) { + lbake->probe = NULL; + lightbake_do_sample(lbake, eevee_lightbake_render_world_sample); + } + + /* Render irradiance grids */ + if (lcache->flag & LIGHTCACHE_UPDATE_GRID) { + for (lbake->bounce_curr = 0; lbake->bounce_curr < lbake->bounce_len; ++lbake->bounce_curr) { + /* Bypass world, start at 1. */ + lbake->probe = lbake->grid_prb + 1; + lbake->grid = lcache->grid_data + 1; + for (lbake->grid_curr = 1; lbake->grid_curr < lbake->grid_len; + ++lbake->grid_curr, ++lbake->probe, ++lbake->grid) { + LightProbe *prb = *lbake->probe; + lbake->grid_sample_len = prb->grid_resolution_x * prb->grid_resolution_y * + prb->grid_resolution_z; + for (lbake->grid_sample = 0; lbake->grid_sample < lbake->grid_sample_len; + ++lbake->grid_sample) { + lightbake_do_sample(lbake, eevee_lightbake_render_grid_sample); + } + } + } + } + + /* Render reflections */ + if (lcache->flag & LIGHTCACHE_UPDATE_CUBE) { + /* Bypass world, start at 1. */ + lbake->probe = lbake->cube_prb + 1; + lbake->cube = lcache->cube_data + 1; + for (lbake->cube_offset = 1; lbake->cube_offset < lbake->cube_len; + ++lbake->cube_offset, ++lbake->probe, ++lbake->cube) { + lightbake_do_sample(lbake, eevee_lightbake_render_probe_sample); + } + } + + /* Read the resulting lighting data to save it to file/disk. */ + eevee_lightbake_context_enable(lbake); + eevee_lightbake_readback_irradiance(lcache); + eevee_lightbake_readback_reflections(lcache); + eevee_lightbake_context_disable(lbake); + + lcache->flag |= LIGHTCACHE_BAKED; + lcache->flag &= ~LIGHTCACHE_BAKING; + + /* Assume that if lbake->gl_context is NULL + * we are not running in this in a job, so update + * the scene lightcache pointer before deleting it. */ + if (lbake->gl_context == NULL) { + BLI_assert(BLI_thread_is_main()); + EEVEE_lightbake_update(lbake); + } + + eevee_lightbake_delete_resources(lbake); } /* This is to update the world irradiance and reflection contribution from * within the viewport drawing (does not have the overhead of a full light cache rebuild.) */ -void EEVEE_lightbake_update_world_quick(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, const Scene *scene) +void EEVEE_lightbake_update_world_quick(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + const Scene *scene) { - LightCache *lcache = vedata->stl->g_data->light_cache; - float clamp = scene->eevee.gi_glossy_clamp; - float filter_quality = scene->eevee.gi_filter_quality; - - EEVEE_LightBake lbake = { - .resource_only = true, - }; - - /* Create resources. */ - eevee_lightbake_create_render_target(&lbake, scene->eevee.gi_cubemap_resolution); - - EEVEE_lightbake_cache_init(sldata, vedata, lbake.rt_color, lbake.rt_depth); - - sldata->common_data.ray_type = EEVEE_RAY_GLOSSY; - sldata->common_data.ray_depth = 1; - DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); - EEVEE_lightbake_render_world(sldata, vedata, lbake.rt_fb); - EEVEE_lightbake_filter_glossy(sldata, vedata, lbake.rt_color, lbake.store_fb, 0, 1.0f, lcache->mips_len, - filter_quality, clamp); - - sldata->common_data.ray_type = EEVEE_RAY_DIFFUSE; - sldata->common_data.ray_depth = 1; - DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); - EEVEE_lightbake_render_world(sldata, vedata, lbake.rt_fb); - EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake.rt_color, lbake.store_fb, 0, 1.0f); - - /* Don't hide grids if they are already rendered. */ - lcache->grid_len = max_ii(1, lcache->grid_len); - lcache->cube_len = 1; - - lcache->flag |= LIGHTCACHE_CUBE_READY | LIGHTCACHE_GRID_READY; - lcache->flag &= ~LIGHTCACHE_UPDATE_WORLD; - - eevee_lightbake_delete_resources(&lbake); + LightCache *lcache = vedata->stl->g_data->light_cache; + float clamp = scene->eevee.gi_glossy_clamp; + float filter_quality = scene->eevee.gi_filter_quality; + + EEVEE_LightBake lbake = { + .resource_only = true, + }; + + /* Create resources. */ + eevee_lightbake_create_render_target(&lbake, scene->eevee.gi_cubemap_resolution); + + EEVEE_lightbake_cache_init(sldata, vedata, lbake.rt_color, lbake.rt_depth); + + sldata->common_data.ray_type = EEVEE_RAY_GLOSSY; + sldata->common_data.ray_depth = 1; + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + EEVEE_lightbake_render_world(sldata, vedata, lbake.rt_fb); + EEVEE_lightbake_filter_glossy(sldata, + vedata, + lbake.rt_color, + lbake.store_fb, + 0, + 1.0f, + lcache->mips_len, + filter_quality, + clamp); + + sldata->common_data.ray_type = EEVEE_RAY_DIFFUSE; + sldata->common_data.ray_depth = 1; + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + EEVEE_lightbake_render_world(sldata, vedata, lbake.rt_fb); + EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake.rt_color, lbake.store_fb, 0, 1.0f); + + /* Don't hide grids if they are already rendered. */ + lcache->grid_len = max_ii(1, lcache->grid_len); + lcache->cube_len = 1; + + lcache->flag |= LIGHTCACHE_CUBE_READY | LIGHTCACHE_GRID_READY; + lcache->flag &= ~LIGHTCACHE_UPDATE_WORLD; + + eevee_lightbake_delete_resources(&lbake); } /** \} */ |