diff options
32 files changed, 480 insertions, 273 deletions
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 027933e17c6..6ca14ec9197 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -395,9 +395,9 @@ static void scene_free_data(ID *id) scene->master_collection = NULL; } - if (scene->eevee.light_cache) { - EEVEE_lightcache_free(scene->eevee.light_cache); - scene->eevee.light_cache = NULL; + if (scene->eevee.light_cache_data) { + EEVEE_lightcache_free(scene->eevee.light_cache_data); + scene->eevee.light_cache_data = NULL; } if (scene->display.shading.prop) { @@ -583,7 +583,7 @@ void BKE_scene_copy_data_eevee(Scene *sce_dst, const Scene *sce_src) { /* Copy eevee data between scenes. */ sce_dst->eevee = sce_src->eevee; - sce_dst->eevee.light_cache = NULL; + sce_dst->eevee.light_cache_data = NULL; sce_dst->eevee.light_cache_info[0] = '\0'; /* TODO Copy the cache. */ } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f73dc9a5466..49b51c34562 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -157,6 +157,8 @@ #include "RE_engine.h" +#include "engines/eevee/eevee_lightcache.h" + #include "readfile.h" #include <errno.h> @@ -1852,8 +1854,8 @@ void blo_make_scene_pointer_map(FileData *fd, Main *oldmain) fd->scenemap = oldnewmap_new(); for (; sce; sce = sce->id.next) { - if (sce->eevee.light_cache) { - struct LightCache *light_cache = sce->eevee.light_cache; + if (sce->eevee.light_cache_data) { + struct LightCache *light_cache = sce->eevee.light_cache_data; oldnewmap_insert(fd->scenemap, light_cache, light_cache, 0); } } @@ -1873,7 +1875,7 @@ void blo_end_scene_pointer_map(FileData *fd, Main *oldmain) } for (; sce; sce = sce->id.next) { - sce->eevee.light_cache = newsceadr(fd, sce->eevee.light_cache); + sce->eevee.light_cache_data = newsceadr(fd, sce->eevee.light_cache_data); } } @@ -6927,19 +6929,20 @@ static void direct_link_scene(FileData *fd, Scene *sce) if (fd->memfile) { /* If it's undo try to recover the cache. */ if (fd->scenemap) { - sce->eevee.light_cache = newsceadr(fd, sce->eevee.light_cache); + sce->eevee.light_cache_data = newsceadr(fd, sce->eevee.light_cache_data); } else { - sce->eevee.light_cache = NULL; + sce->eevee.light_cache_data = NULL; } } else { /* else try to read the cache from file. */ - sce->eevee.light_cache = newdataadr(fd, sce->eevee.light_cache); - if (sce->eevee.light_cache) { - direct_link_lightcache(fd, sce->eevee.light_cache); + sce->eevee.light_cache_data = newdataadr(fd, sce->eevee.light_cache_data); + if (sce->eevee.light_cache_data) { + direct_link_lightcache(fd, sce->eevee.light_cache_data); } } + EEVEE_lightcache_info_update(&sce->eevee); direct_link_view3dshading(fd, &sce->display.shading); diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 81df00ebdef..a9c5008062b 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2767,9 +2767,9 @@ static void write_scene(WriteData *wd, Scene *sce) } /* Eevee Lightcache */ - if (sce->eevee.light_cache && !wd->use_memfile) { - writestruct(wd, DATA, LightCache, 1, sce->eevee.light_cache); - write_lightcache(wd, sce->eevee.light_cache); + if (sce->eevee.light_cache_data && !wd->use_memfile) { + writestruct(wd, DATA, LightCache, 1, sce->eevee.light_cache_data); + write_lightcache(wd, sce->eevee.light_cache_data); } write_view3dshading(wd, &sce->display.shading); diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 1841f5f024f..50870d1e4aa 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -804,7 +804,7 @@ void update_id_after_copy(const Depsgraph *depsgraph, Scene *scene_cow = (Scene *)id_cow; const Scene *scene_orig = (const Scene *)id_orig; scene_cow->toolsettings = scene_orig->toolsettings; - scene_cow->eevee.light_cache = scene_orig->eevee.light_cache; + scene_cow->eevee.light_cache_data = scene_orig->eevee.light_cache_data; scene_setup_view_layers_after_remap(depsgraph, id_node, reinterpret_cast<Scene *>(id_cow)); update_scene_orig_pointers(scene_orig, scene_cow); break; @@ -1000,7 +1000,7 @@ void discard_scene_pointers(ID *id_cow) { Scene *scene_cow = (Scene *)id_cow; scene_cow->toolsettings = nullptr; - scene_cow->eevee.light_cache = nullptr; + scene_cow->eevee.light_cache_data = nullptr; } /* nullptr-ify all edit mode pointers which points to data from diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index fe03a32fd07..a1213be4be0 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -230,6 +230,7 @@ data_to_c_simple(engines/eevee/shaders/btdf_lut_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/bsdf_common_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/irradiance_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/octahedron_lib.glsl SRC) +data_to_c_simple(engines/eevee/shaders/cubemap_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_frag.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 2b11a608bd0..ae4c7dec1e1 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -42,6 +42,7 @@ #include "eevee_private.h" #include "GPU_context.h" +#include "GPU_extensions.h" #include "WM_api.h" #include "WM_types.h" @@ -195,6 +196,16 @@ static uint eevee_lightcache_memsize_get(LightCache *lcache) return size; } +static bool eevee_lightcache_version_check(LightCache *lcache) +{ + switch (lcache->type) { + case LIGHTCACHE_TYPE_STATIC: + return lcache->version == LIGHTCACHE_STATIC_VERSION; + default: + return false; + } +} + static int eevee_lightcache_irradiance_sample_count(LightCache *lcache) { int total_irr_samples = 0; @@ -208,9 +219,23 @@ static int eevee_lightcache_irradiance_sample_count(LightCache *lcache) void EEVEE_lightcache_info_update(SceneEEVEE *eevee) { - LightCache *lcache = eevee->light_cache; + LightCache *lcache = eevee->light_cache_data; if (lcache != NULL) { + if (!eevee_lightcache_version_check(lcache)) { + BLI_strncpy(eevee->light_cache_info, + TIP_("Incompatible Light cache version, please bake again"), + sizeof(eevee->light_cache_info)); + return; + } + + 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"), + sizeof(eevee->light_cache_info)); + return; + } + if (lcache->flag & LIGHTCACHE_BAKING) { BLI_strncpy( eevee->light_cache_info, TIP_("Baking light cache"), sizeof(eevee->light_cache_info)); @@ -266,8 +291,8 @@ static bool EEVEE_lightcache_validate(const LightCache *light_cache, (irr_size[2] == light_cache->grid_tx.tex_size[2]) && (grid_len == light_cache->grid_len)) { int mip_len = log2_floor_u(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]) && (cube_len == light_cache->cube_len) && - (mip_len == light_cache->mips_len)) { + (cube_len == light_cache->cube_tx.tex_size[2] / 6) && + (cube_len == light_cache->cube_len) && (mip_len == light_cache->mips_len)) { return true; } } @@ -283,6 +308,9 @@ LightCache *EEVEE_lightcache_create(const int grid_len, { LightCache *light_cache = MEM_callocN(sizeof(LightCache), "LightCache"); + light_cache->version = LIGHTCACHE_STATIC_VERSION; + light_cache->type = LIGHTCACHE_TYPE_STATIC; + 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"); @@ -292,13 +320,26 @@ LightCache *EEVEE_lightcache_create(const int grid_len, 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); + int mips_len = log2_floor_u(cube_size) - MIN_CUBE_LOD_LEVEL; + + if (GPU_arb_texture_cube_map_array_is_supported()) { + light_cache->cube_tx.tex = DRW_texture_create_cube_array( + cube_size, cube_len, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); + } + else { + light_cache->cube_tx.tex = DRW_texture_create_2d_array(cube_size, + cube_size, + cube_len * 6, + 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_size[2] = cube_len * 6; - light_cache->mips_len = log2_floor_u(cube_size) - MIN_CUBE_LOD_LEVEL; + light_cache->mips_len = mips_len; light_cache->vis_res = vis_size; light_cache->ref_res = cube_size; @@ -315,9 +356,19 @@ LightCache *EEVEE_lightcache_create(const int grid_len, return light_cache; } -void EEVEE_lightcache_load(LightCache *lcache) +static bool eevee_lightcache_static_load(LightCache *lcache) { - if (lcache->grid_tx.tex == NULL && lcache->grid_tx.data) { + /* We use fallback if a texture is not setup and there is no data to restore it. */ + if ((!lcache->grid_tx.tex && !lcache->grid_tx.data) || + (!lcache->cube_tx.tex && !lcache->cube_tx.data)) { + return false; + } + /* If cache is too big for this GPU. */ + if (lcache->cube_tx.tex_size[2] > GPU_max_texture_layers()) { + return false; + } + + if (lcache->grid_tx.tex == NULL) { 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], @@ -333,17 +384,28 @@ void EEVEE_lightcache_load(LightCache *lcache) 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); + if (lcache->cube_tx.tex == NULL) { + if (GPU_arb_texture_cube_map_array_is_supported()) { + lcache->cube_tx.tex = GPU_texture_cube_create(lcache->cube_tx.tex_size[0], + lcache->cube_tx.tex_size[2] / 6, + lcache->cube_tx.data, + GPU_R11F_G11F_B10F, + GPU_DATA_10_11_11_REV, + NULL); + } + else { + 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++) { @@ -352,6 +414,25 @@ void EEVEE_lightcache_load(LightCache *lcache) } GPU_texture_unbind(lcache->cube_tx.tex); } + return true; +} + +bool EEVEE_lightcache_load(LightCache *lcache) +{ + if (lcache == NULL) { + return false; + } + + if (!eevee_lightcache_version_check(lcache)) { + return false; + } + + switch (lcache->type) { + case LIGHTCACHE_TYPE_STATIC: + return eevee_lightcache_static_load(lcache); + default: + return false; + } } static void eevee_lightbake_readback_irradiance(LightCache *lcache) @@ -457,7 +538,7 @@ static void eevee_lightbake_count_probes(EEVEE_LightBake *lbake) prb->grid_resolution_z; lbake->grid_len++; } - else if (prb->type == LIGHTPROBE_TYPE_CUBE) { + else if (prb->type == LIGHTPROBE_TYPE_CUBE && lbake->cube_len < EEVEE_PROBE_MAX) { lbake->cube_len++; } } @@ -491,8 +572,7 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake) 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->ref_cube_res = 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"); @@ -506,12 +586,12 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake) /* 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; + lbake->lcache = eevee->light_cache_data; /* 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; + eevee->light_cache_data = lbake->lcache = NULL; } if (lbake->lcache == NULL) { @@ -522,10 +602,10 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake) lbake->lcache->vis_res = lbake->vis_res; lbake->own_light_cache = true; - eevee->light_cache = lbake->lcache; + eevee->light_cache_data = lbake->lcache; } - EEVEE_lightcache_load(eevee->light_cache); + EEVEE_lightcache_load(eevee->light_cache_data); lbake->lcache->flag |= LIGHTCACHE_BAKING; lbake->lcache->cube_len = 1; @@ -804,7 +884,7 @@ static void eevee_lightbake_render_world_sample(void *ved, void *user_data) 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; + LightCache *lcache = scene_eval->eevee.light_cache_data; float clamp = scene_eval->eevee.gi_glossy_clamp; float filter_quality = scene_eval->eevee.gi_filter_quality; @@ -920,7 +1000,7 @@ static void eevee_lightbake_render_grid_sample(void *ved, void *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; + LightCache *lcache = scene_eval->eevee.light_cache_data; int grid_loc[3], sample_id, sample_offset, stride; float pos[3]; const bool is_last_bounce_sample = ((egrid->offset + lbake->grid_sample) == @@ -1002,7 +1082,7 @@ static void eevee_lightbake_render_probe_sample(void *ved, void *user_data) 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; + LightCache *lcache = scene_eval->eevee.light_cache_data; EEVEE_LightProbe *eprobe = lbake->cube; LightProbe *prb = *lbake->probe; float clamp = scene_eval->eevee.gi_glossy_clamp; @@ -1083,7 +1163,7 @@ 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; + LightCache *lcache = scene_eval->eevee.light_cache_data; /* At least one for the world */ int grid_len = 1; @@ -1106,7 +1186,7 @@ static void eevee_lightbake_gather_probes(EEVEE_LightBake *lbake) 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) { + else if (prb->type == LIGHTPROBE_TYPE_CUBE && cube_len < EEVEE_PROBE_MAX) { lbake->cube_prb[cube_len] = prb; EEVEE_LightProbe *eprobe = &lcache->cube_data[cube_len++]; EEVEE_lightprobes_cube_data_from_object(ob, eprobe); @@ -1136,11 +1216,11 @@ void EEVEE_lightbake_update(void *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); + if (lbake->lcache && scene_orig->eevee.light_cache_data != lbake->lcache) { + if (scene_orig->eevee.light_cache_data != NULL) { + EEVEE_lightcache_free(scene_orig->eevee.light_cache_data); } - scene_orig->eevee.light_cache = lbake->lcache; + scene_orig->eevee.light_cache_data = lbake->lcache; lbake->own_light_cache = false; } diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h index ede2de13dce..0db36ce0c2e 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.h +++ b/source/blender/draw/engines/eevee/eevee_lightcache.h @@ -60,7 +60,7 @@ struct LightCache *EEVEE_lightcache_create(const int grid_len, const int vis_size, const int irr_size[3]); void EEVEE_lightcache_free(struct LightCache *lcache); -void EEVEE_lightcache_load(struct LightCache *lcache); +bool EEVEE_lightcache_load(struct LightCache *lcache); void EEVEE_lightcache_info_update(struct SceneEEVEE *eevee); #endif /* __EEVEE_LIGHTCACHE_H__ */ diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 4fbecfe3120..61ca2317572 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -37,6 +37,7 @@ #include "GPU_material.h" #include "GPU_texture.h" +#include "GPU_extensions.h" #include "DEG_depsgraph_query.h" @@ -171,32 +172,28 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) memset(stl->g_data->world_views, 0, sizeof(stl->g_data->world_views)); memset(stl->g_data->planar_views, 0, sizeof(stl->g_data->planar_views)); - /* Use fallback if we don't have gpu texture allocated an we cannot restore them. */ - bool use_fallback_lightcache = (scene_eval->eevee.light_cache == NULL) || - ((scene_eval->eevee.light_cache->grid_tx.tex == NULL) && - (scene_eval->eevee.light_cache->grid_tx.data == NULL)) || - ((scene_eval->eevee.light_cache->cube_tx.tex == NULL) && - (scene_eval->eevee.light_cache->cube_tx.data == NULL)); - - if (use_fallback_lightcache && (sldata->fallback_lightcache == NULL)) { + if (EEVEE_lightcache_load(scene_eval->eevee.light_cache_data)) { + stl->g_data->light_cache = scene_eval->eevee.light_cache_data; + } + else { + if (!sldata->fallback_lightcache) { #if defined(IRRADIANCE_SH_L2) - int grid_res = 4; + int grid_res = 4; #elif defined(IRRADIANCE_CUBEMAP) - int grid_res = 8; + int grid_res = 8; #elif defined(IRRADIANCE_HL2) - int grid_res = 4; + int grid_res = 4; #endif - int cube_res = octahedral_size_from_cubesize(scene_eval->eevee.gi_cubemap_resolution); - int vis_res = scene_eval->eevee.gi_visibility_resolution; - sldata->fallback_lightcache = EEVEE_lightcache_create( - 1, 1, cube_res, vis_res, (int[3]){grid_res, grid_res, 1}); + sldata->fallback_lightcache = EEVEE_lightcache_create( + 1, + 1, + scene_eval->eevee.gi_cubemap_resolution, + scene_eval->eevee.gi_visibility_resolution, + (int[3]){grid_res, grid_res, 1}); + } + stl->g_data->light_cache = sldata->fallback_lightcache; } - stl->g_data->light_cache = (use_fallback_lightcache) ? sldata->fallback_lightcache : - scene_eval->eevee.light_cache; - - EEVEE_lightcache_load(stl->g_data->light_cache); - if (!sldata->probes) { sldata->probes = MEM_callocN(sizeof(EEVEE_LightProbesInfo), "EEVEE_LightProbesInfo"); sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL); @@ -255,7 +252,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call(grp, geom, NULL); + DRW_shgroup_call_instances(grp, NULL, geom, 6); } { @@ -508,8 +505,8 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata EEVEE_LightProbesInfo *pinfo = sldata->probes; LightProbe *probe = (LightProbe *)ob->data; - if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= MAX_PROBE) || - (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= MAX_PROBE) || + if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= EEVEE_PROBE_MAX) || + (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= EEVEE_PROBE_MAX) || (probe->type == LIGHTPROBE_TYPE_PLANAR && pinfo->num_planar >= MAX_PLANAR)) { printf("Too many probes in the view !!!\n"); return; @@ -762,7 +759,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); /* For shading, save max level of the octahedron map */ - sldata->common_data.prb_lod_cube_max = (float)light_cache->mips_len - 1.0f; + sldata->common_data.prb_lod_cube_max = (float)light_cache->mips_len; sldata->common_data.prb_lod_planar_max = (float)MAX_PLANAR_LOD_LEVEL; sldata->common_data.prb_irradiance_vis_size = light_cache->vis_res; sldata->common_data.prb_irradiance_smooth = square_f(scene_eval->eevee.gi_irradiance_smoothing); @@ -785,15 +782,15 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved if (draw_ctx->scene->eevee.flag & SCE_EEVEE_GI_AUTOBAKE) { Scene *scene_orig = DEG_get_input_scene(draw_ctx->depsgraph); - if (scene_orig->eevee.light_cache != NULL) { + if (scene_orig->eevee.light_cache_data != NULL) { if (pinfo->do_grid_update) { - scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_GRID; + scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_GRID; } - /* If we update grid we need to update the cube-maps too. - * So always refresh cube-maps. */ - scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_CUBE; - /* Tag the light-cache to auto update. */ - scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_AUTO; + /* If we update grid we need to update the cubemaps too. + * So always refresh cubemaps. */ + scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_CUBE; + /* Tag the lightcache to auto update. */ + scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_AUTO; /* Use a notifier to trigger the operator after drawing. */ WM_event_add_notifier(draw_ctx->evil_C, NC_LIGHTPROBE, scene_orig); } @@ -1077,7 +1074,7 @@ void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata, pinfo->texel_size = 1.0f / (float)mipsize; pinfo->padding_size = (i == maxlevel) ? 0 : (float)(1 << (maxlevel - i - 1)); pinfo->padding_size *= pinfo->texel_size; - pinfo->layer = probe_idx; + pinfo->layer = probe_idx * 6; pinfo->roughness = i / (float)maxlevel; pinfo->roughness *= pinfo->roughness; /* Disney Roughness */ pinfo->roughness *= pinfo->roughness; /* Distribute Roughness accros lod more evenly */ diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c index 7be6fc2d030..0cbd3d9ac83 100644 --- a/source/blender/draw/engines/eevee/eevee_lookdev.c +++ b/source/blender/draw/engines/eevee/eevee_lookdev.c @@ -116,7 +116,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, EEVEE_shaders_background_studiolight_sh_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - int cube_res = octahedral_size_from_cubesize(scene_eval->eevee.gi_cubemap_resolution); + int cube_res = scene_eval->eevee.gi_cubemap_resolution; /* If one of the component is missing we start from scratch. */ if ((stl->lookdev_grid_data == NULL) || (stl->lookdev_cube_data == NULL) || diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 05127585e6c..19d674bfc9c 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -89,6 +89,7 @@ extern char datatoc_common_hair_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_lit_surface_frag_glsl[]; extern char datatoc_lit_surface_vert_glsl[]; extern char datatoc_raytrace_lib_glsl[]; @@ -618,6 +619,7 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, datatoc_raytrace_lib_glsl, datatoc_ssr_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_ltc_lib_glsl, @@ -641,6 +643,7 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, datatoc_bsdf_common_lib_glsl, datatoc_ambient_occlusion_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_ltc_lib_glsl, diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 5ffea393e1f..d266b7793c4 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -78,6 +78,8 @@ extern struct DrawEngineType draw_engine_eevee_type; SHADER_IRRADIANCE /* clang-format on */ +#define EEVEE_PROBE_MAX min_ii(MAX_PROBE, GPU_max_texture_layers() / 6) + #define SWAP_DOUBLE_BUFFERS() \ { \ if (effects->swap_double_buffer) { \ @@ -136,20 +138,7 @@ extern struct DrawEngineType draw_engine_eevee_type; ((v3d->shading.type == OB_RENDER) && \ ((v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER) == 0)))) -#define MIN_CUBE_LOD_LEVEL 3 - -BLI_INLINE int octahedral_size_from_cubesize(int cube_size) -{ - int cube_pixel_count = square_i(cube_size) * 6; - int octa_size = (int)ceilf(sqrtf(cube_pixel_count)); - int lod_count = log2_floor_u(octa_size) - MIN_CUBE_LOD_LEVEL; - /* Find lowest lod size and grow back to avoid having non matching mipsizes that would - * break trilinear interpolation. */ - octa_size /= 1 << lod_count; - octa_size *= 1 << lod_count; - return octa_size; -} - +#define MIN_CUBE_LOD_LEVEL 1 #define MAX_PLANAR_LOD_LEVEL 9 /* All the renderpasses that use the GPUMaterial for accumulation */ diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index d231edf1383..e875187bdbf 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -54,6 +54,7 @@ extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_effect_ssr_frag_glsl[]; extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_raytrace_lib_glsl[]; @@ -67,6 +68,7 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options) datatoc_bsdf_sampling_lib_glsl, datatoc_ambient_occlusion_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_raytrace_lib_glsl, datatoc_effect_ssr_frag_glsl); diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index 2d91e4bb4bd..50b7c5c5f97 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -88,6 +88,7 @@ extern char datatoc_lightprobe_planar_downsample_vert_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; /* Velocity Resolve */ extern char datatoc_effect_velocity_resolve_frag_glsl[]; @@ -196,6 +197,7 @@ GPUShader *EEVEE_shaders_background_studiolight_sh_get(void) { if (e_data.probe_background_studiolight_sh == NULL) { char *frag_str = BLI_string_joinN(datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_lightprobe_lib_glsl, @@ -217,6 +219,7 @@ GPUShader *EEVEE_shaders_probe_cube_display_sh_get(void) { if (e_data.probe_cube_display_sh == NULL) { char *shader_str = BLI_string_joinN(datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, @@ -238,6 +241,7 @@ GPUShader *EEVEE_shaders_probe_grid_display_sh_get(void) { if (e_data.probe_grid_display_sh == NULL) { char *shader_str = BLI_string_joinN(datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 98e799acb5e..bab89a8a87b 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -41,6 +41,7 @@ extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_lights_lib_glsl[]; extern char datatoc_raytrace_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_effect_subsurface_frag_glsl[]; @@ -59,6 +60,7 @@ static void eevee_create_shader_subsurface(void) datatoc_bsdf_sampling_lib_glsl, datatoc_raytrace_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_lights_lib_glsl, datatoc_effect_translucency_frag_glsl); diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index efe2ef5fc17..8c1c72a3c20 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -72,6 +72,7 @@ extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lights_lib_glsl[]; extern char datatoc_volumetric_accum_frag_glsl[]; @@ -99,6 +100,7 @@ static void eevee_create_shader_volumes(void) datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lights_lib_glsl, datatoc_volumetric_lib_glsl); diff --git a/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl new file mode 100644 index 00000000000..90272400915 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl @@ -0,0 +1,130 @@ + +#ifdef GPU_ARB_texture_cube_map_array + +# define textureLod_cubemapArray(tex, co, lod) textureLod(tex, co, lod) + +#else + +/* Fallback implementation for hardware not supporting cubemap arrays. */ +# define samplerCubeArray sampler2DArray + +float cubemap_face_index(vec3 P) +{ + vec3 aP = abs(P); + if (all(greaterThan(aP.xx, aP.yz))) { + return (P.x > 0.0) ? 0.0 : 1.0; + } + else if (all(greaterThan(aP.yy, aP.xz))) { + return (P.y > 0.0) ? 2.0 : 3.0; + } + else { + return (P.z > 0.0) ? 4.0 : 5.0; + } +} + +vec2 cubemap_face_coord(vec3 P, float face) +{ + if (face < 2.0) { + return (P.zy / P.x) * vec2(-0.5, -sign(P.x) * 0.5) + 0.5; + } + else if (face < 4.0) { + return (P.xz / P.y) * vec2(sign(P.y) * 0.5, 0.5) + 0.5; + } + else { + return (P.xy / P.z) * vec2(0.5, -sign(P.z) * 0.5) + 0.5; + } +} + +vec3 cubemap_adj_x(float face) +{ + bool y_axis = (face == 2.0 || face == 3.0); + return y_axis ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); +} + +vec3 cubemap_adj_y(float face) +{ + bool x_axis = (face < 2.0); + return x_axis ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); +} + +vec3 cubemap_adj_xy(float face) +{ + if (face < 2.0) { + return vec3(0.0, 1.0, 1.0); + } + else if (face < 4.0) { + return vec3(1.0, 0.0, 1.0); + } + else { + return vec3(1.0, 1.0, 0.0); + } +} + +vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod) +{ + /* Manual Cube map Layer indexing. */ + float face = cubemap_face_index(cubevec.xyz); + vec2 uv = cubemap_face_coord(cubevec.xyz, face); + vec3 coord = vec3(uv, cubevec.w * 6.0 + face); + + vec4 col = textureLod(tex, coord, lod); + + float cube_size = float(textureSize(tex, int(lod)).x); + + vec2 uv_border = (abs(uv - 0.5) + (0.5 / cube_size - 0.5)) * 2.0 * cube_size; + bvec2 border = greaterThan(uv_border, vec2(0.0)); + if (all(border)) { + /* Corners case. */ + vec3 cubevec_adj; + float face_adj; + /* Get the other face coords. */ + cubevec_adj = cubevec.xyz * cubemap_adj_x(face); + face_adj = cubemap_face_index(cubevec_adj); + /* Still use the original cubevec to get the outer texels or the face. */ + uv = cubemap_face_coord(cubevec.xyz, face_adj); + coord = vec3(uv, cubevec.w * 6.0 + face_adj); + vec4 col1 = textureLod(tex, coord, lod); + + /* Get the 3rd face coords. */ + cubevec_adj = cubevec.xyz * cubemap_adj_y(face); + face_adj = cubemap_face_index(cubevec_adj); + /* Still use the original cubevec to get the outer texels or the face. */ + uv = cubemap_face_coord(cubevec.xyz, face_adj); + coord = vec3(uv, cubevec.w * 6.0 + face_adj); + vec4 col2 = textureLod(tex, coord, lod); + + /* Mix all colors to get the corner color. */ + vec4 col3 = (col + col1 + col2) / 3.0; + + vec2 mix_fac = uv_border * 0.5; + return mix(mix(col, col2, mix_fac.x), mix(col1, col3, mix_fac.x), mix_fac.y); + } + else if (any(border)) { + /* Edges case. */ + /* Get the other face coords. */ + vec3 cubevec_adj = cubevec.xyz * cubemap_adj_xy(face); + face = cubemap_face_index(cubevec_adj); + /* Still use the original cubevec to get the outer texels or the face. */ + uv = cubemap_face_coord(cubevec.xyz, face); + coord = vec3(uv, cubevec.w * 6.0 + face); + + float mix_fac = max(uv_border.x, uv_border.y) * 0.5; + return mix(col, textureLod(tex, coord, lod), mix_fac); + } + else { + return col; + } +} + +vec4 textureLod_cubemapArray(sampler2DArray tex, vec4 cubevec, float lod) +{ + float lod1 = floor(lod); + float lod2 = ceil(lod); + + vec4 col_lod1 = cubemap_seamless(tex, cubevec, lod1); + vec4 col_lod2 = cubemap_seamless(tex, cubevec, lod2); + + return mix(col_lod1, col_lod2, lod - lod1); +} + +#endif diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl index a852dd47872..96fe94fc41e 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl @@ -15,6 +15,5 @@ void main() vec3 view_nor = vec3(quadCoord, sqrt(max(0.0, 1.0 - dist_sqr))); vec3 world_ref = mat3(ViewMatrixInverse) * reflect(vec3(0.0, 0.0, -1.0), view_nor); - FragColor = vec4(textureLod_octahedron(probeCubes, vec4(world_ref, pid), 0.0, prbLodCubeMax).rgb, - 1.0); + FragColor = vec4(textureLod_cubemapArray(probeCubes, vec4(world_ref, pid), 0.0).rgb, 1.0); } diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl index 06c31272ecd..00eb3c7e200 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl @@ -33,29 +33,9 @@ vec3 octahedral_to_cubemap_proj(vec2 co) void main() { - vec2 uvs = gl_FragCoord.xy * texelSize; - - /* Add a N pixel border to ensure filtering is correct - * for N mipmap levels. */ - uvs = (uvs - paddingSize) / (1.0 - 2.0 * paddingSize); - - /* edge mirroring : only mirror if directly adjacent - * (not diagonally adjacent) */ - vec2 m = abs(uvs - 0.5) + 0.5; - vec2 f = floor(m); - if (f.x - f.y != 0.0) { - uvs = 1.0 - uvs; - } - - /* clamp to [0-1] */ - uvs = fract(uvs); - - /* get cubemap vector */ - vec3 cubevec = octahedral_to_cubemap_proj(uvs); - vec3 N, T, B, V; - vec3 R = normalize(cubevec); + vec3 R = normalize(worldPosition); /* Isotropic assumption */ N = V = R; diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl index ab205b78274..6c6db88139b 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl @@ -1,7 +1,7 @@ /* ----------- Uniforms --------- */ uniform sampler2DArray probePlanars; -uniform sampler2DArray probeCubes; +uniform samplerCubeArray probeCubes; /* ----------- Structures --------- */ @@ -172,15 +172,12 @@ vec3 probe_evaluate_cube(int pd_id, vec3 W, vec3 R, float roughness) float fac = saturate(original_roughness * 2.0 - 1.0); R = mix(intersection, R, fac * fac); - return textureLod_octahedron( - probeCubes, vec4(R, float(pd_id)), roughness * prbLodCubeMax, prbLodCubeMax) - .rgb; + return textureLod_cubemapArray(probeCubes, vec4(R, float(pd_id)), roughness * prbLodCubeMax).rgb; } vec3 probe_evaluate_world_spec(vec3 R, float roughness) { - return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax, prbLodCubeMax) - .rgb; + return textureLod_cubemapArray(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax).rgb; } vec3 probe_evaluate_planar( diff --git a/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl b/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl index bfb6bc890ec..e05cc2719fa 100644 --- a/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl @@ -18,21 +18,3 @@ vec2 mapping_octahedron(vec3 cubevec, vec2 texel_size) return uvs; } - -vec4 textureLod_octahedron(sampler2DArray tex, vec4 cubevec, float lod, float lod_max) -{ - vec2 texelSize = 1.0 / vec2(textureSize(tex, int(lod_max))); - - vec2 uvs = mapping_octahedron(cubevec.xyz, texelSize); - - return textureLod(tex, vec3(uvs, cubevec.w), lod); -} - -vec4 texture_octahedron(sampler2DArray tex, vec4 cubevec) -{ - vec2 texelSize = 1.0 / vec2(textureSize(tex, 0)); - - vec2 uvs = mapping_octahedron(cubevec.xyz, texelSize); - - return texture(tex, vec3(uvs, cubevec.w)); -} diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 5122b1ea1ac..6a6cdd8f51c 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -166,6 +166,8 @@ struct GPUTexture *DRW_texture_create_cube(int w, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels); +struct GPUTexture *DRW_texture_create_cube_array( + int w, int d, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels); void DRW_texture_ensure_fullscreen_2d(struct GPUTexture **tex, eGPUTextureFormat format, diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c index c75299158a3..3f11fe9d11e 100644 --- a/source/blender/draw/intern/draw_manager_texture.c +++ b/source/blender/draw/intern/draw_manager_texture.c @@ -123,6 +123,15 @@ GPUTexture *DRW_texture_create_cube(int w, return tex; } +GPUTexture *DRW_texture_create_cube_array( + int w, int d, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex = GPU_texture_create_cube_array(w, d, format, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + return tex; +} + GPUTexture *DRW_texture_pool_query_2d(int w, int h, eGPUTextureFormat format, diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 94e210b7243..95d044554f1 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -890,14 +890,14 @@ enum { static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op) { - if (scene->eevee.light_cache != NULL) { + if (scene->eevee.light_cache_data != NULL) { int subset = RNA_enum_get(op->ptr, "subset"); switch (subset) { case LIGHTCACHE_SUBSET_ALL: - scene->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_GRID | LIGHTCACHE_UPDATE_CUBE; + scene->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_GRID | LIGHTCACHE_UPDATE_CUBE; break; case LIGHTCACHE_SUBSET_CUBE: - scene->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_CUBE; + scene->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_CUBE; break; case LIGHTCACHE_SUBSET_DIRTY: /* Leave tag untouched. */ @@ -1046,7 +1046,7 @@ static bool light_cache_free_poll(bContext *C) { Scene *scene = CTX_data_scene(C); - return scene->eevee.light_cache; + return scene->eevee.light_cache_data; } static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op)) @@ -1057,12 +1057,12 @@ static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op)) wmWindowManager *wm = CTX_wm_manager(C); WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_LIGHT_BAKE); - if (!scene->eevee.light_cache) { + if (!scene->eevee.light_cache_data) { return OPERATOR_CANCELLED; } - EEVEE_lightcache_free(scene->eevee.light_cache); - scene->eevee.light_cache = NULL; + EEVEE_lightcache_free(scene->eevee.light_cache_data); + scene->eevee.light_cache_data = NULL; EEVEE_lightcache_info_update(&scene->eevee); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 8c884783913..8ec7d5a166b 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1422,7 +1422,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win), static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(sa)) { Scene *scene = CTX_data_scene(C); - LightCache *lcache = scene->eevee.light_cache; + LightCache *lcache = scene->eevee.light_cache_data; if (lcache && (lcache->flag & LIGHTCACHE_UPDATE_AUTO) != 0) { lcache->flag &= ~LIGHTCACHE_UPDATE_AUTO; diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 245f7f47510..4ffe4a53a52 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -44,6 +44,7 @@ int GPU_max_ubo_size(void); float GPU_max_line_width(void); void GPU_get_dfdy_factors(float fac[2]); bool GPU_arb_base_instance_is_supported(void); +bool GPU_arb_texture_cube_map_array_is_supported(void); bool GPU_mip_render_workaround(void); bool GPU_depth_blitting_workaround(void); bool GPU_unused_fb_slot_workaround(void); diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index bd15030d135..892452a2738 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -162,6 +162,12 @@ GPUTexture *GPU_texture_create_nD(int w, int samples, const bool can_rescale, char err_out[256]); +GPUTexture *GPU_texture_cube_create(int w, + int d, + const void *pixels, + eGPUTextureFormat tex_format, + eGPUDataFormat gpu_data_format, + char err_out[256]); GPUTexture *GPU_texture_create_1d(int w, eGPUTextureFormat data_type, @@ -185,6 +191,9 @@ GPUTexture *GPU_texture_create_cube(int w, eGPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_cube_array( + int w, int d, eGPUTextureFormat data_type, const float *pixels, char err_out[256]); + GPUTexture *GPU_texture_create_from_vertbuf(struct GPUVertBuf *vert); GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat data_type, const uint buffer); @@ -252,6 +261,7 @@ void GPU_texture_orig_size_set(GPUTexture *tex, int w, int h); int GPU_texture_layers(const GPUTexture *tex); eGPUTextureFormat GPU_texture_format(const GPUTexture *tex); int GPU_texture_samples(const GPUTexture *tex); +bool GPU_texture_array(const GPUTexture *tex); bool GPU_texture_cube(const GPUTexture *tex); bool GPU_texture_depth(const GPUTexture *tex); bool GPU_texture_stencil(const GPUTexture *tex); diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 5a2b74f3407..f497ed22bec 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -78,6 +78,8 @@ static struct GPUGlobal { /* Some Intel drivers have limited support for `GLEW_ARB_base_instance` so in * these cases it is best to indicate that it is not supported. See T67951 */ bool glew_arb_base_instance_is_supported; + /* Cubemap Array support. */ + bool glew_arb_texture_cube_map_array_is_supported; /* Some Intel drivers have issues with using mips as framebuffer targets if * GL_TEXTURE_MAX_LEVEL is higher than the target mip. * We need a workaround in this cases. */ @@ -197,6 +199,11 @@ bool GPU_arb_base_instance_is_supported(void) return GG.glew_arb_base_instance_is_supported; } +bool GPU_arb_texture_cube_map_array_is_supported(void) +{ + return GG.glew_arb_texture_cube_map_array_is_supported; +} + bool GPU_mip_render_workaround(void) { return GG.mip_render_workaround; @@ -281,6 +288,7 @@ void gpu_extensions_init(void) } GG.glew_arb_base_instance_is_supported = GLEW_ARB_base_instance; + GG.glew_arb_texture_cube_map_array_is_supported = GLEW_ARB_texture_cube_map_array; gpu_detect_mip_render_workaround(); if (G.debug & G_DEBUG_GPU_FORCE_WORKAROUNDS) { diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index c950a1daaa5..0993d69e14d 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -46,7 +46,7 @@ /* Adjust these constants as needed. */ #define MAX_DEFINE_LENGTH 256 -#define MAX_EXT_DEFINE_LENGTH 256 +#define MAX_EXT_DEFINE_LENGTH 512 /* Non-generated shaders */ extern char datatoc_gpu_shader_depth_only_frag_glsl[]; @@ -235,6 +235,10 @@ static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH]) if (GLEW_ARB_shader_draw_parameters) { strcat(defines, "#extension GL_ARB_shader_draw_parameters : enable\n"); } + if (GPU_arb_texture_cube_map_array_is_supported()) { + strcat(defines, "#extension GL_ARB_texture_cube_map_array : enable\n"); + strcat(defines, "#define GPU_ARB_texture_cube_map_array\n"); + } } static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH]) diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 2fd3e618664..7b51b03096f 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -109,7 +109,7 @@ static uint gpu_texture_memory_footprint_compute(GPUTexture *tex) return tex->bytesize * tex->w * tex->h * tex->d * samp; case GL_TEXTURE_CUBE_MAP: return tex->bytesize * 6 * tex->w * tex->h * samp; - case GL_TEXTURE_CUBE_MAP_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY_ARB: return tex->bytesize * 6 * tex->w * tex->h * tex->d * samp; default: return 0; @@ -138,6 +138,7 @@ static const char *gl_enum_to_str(GLenum e) #define ENUM_TO_STRING(e) [GL_##e] = STRINGIFY_ARG(e) static const char *enum_strings[] = { ENUM_TO_STRING(TEXTURE_CUBE_MAP), + ENUM_TO_STRING(TEXTURE_CUBE_MAP_ARRAY), ENUM_TO_STRING(TEXTURE_2D), ENUM_TO_STRING(TEXTURE_2D_ARRAY), ENUM_TO_STRING(TEXTURE_1D), @@ -202,6 +203,25 @@ static int gpu_get_component_count(eGPUTextureFormat format) } } +static uint gpu_get_data_format_bytesize(int comp, eGPUDataFormat data_format) +{ + switch (data_format) { + case GPU_DATA_FLOAT: + return sizeof(float) * comp; + case GPU_DATA_INT: + case GPU_DATA_UNSIGNED_INT: + return sizeof(int) * comp; + case GPU_DATA_UNSIGNED_INT_24_8: + case GPU_DATA_10_11_11_REV: + return sizeof(int); + case GPU_DATA_UNSIGNED_BYTE: + return sizeof(char) * comp; + default: + BLI_assert(0); + return 0; + } +} + /* Definitely not complete, edit according to the gl specification. */ static void gpu_validate_data_format(eGPUTextureFormat tex_format, eGPUDataFormat data_format) { @@ -679,6 +699,7 @@ GPUTexture *GPU_texture_create_nD(int w, } else { tex->target_base = tex->target = GL_TEXTURE_2D_ARRAY; + tex->format_flag |= GPU_FORMAT_ARRAY; } } else if (n == 1) { @@ -687,6 +708,7 @@ GPUTexture *GPU_texture_create_nD(int w, } else { tex->target_base = tex->target = GL_TEXTURE_1D_ARRAY; + tex->format_flag |= GPU_FORMAT_ARRAY; } } else if (n == 3) { @@ -839,17 +861,12 @@ GPUTexture *GPU_texture_create_nD(int w, return tex; } -static GPUTexture *GPU_texture_cube_create(int w, - int d, - const float *fpixels_px, - const float *fpixels_py, - const float *fpixels_pz, - const float *fpixels_nx, - const float *fpixels_ny, - const float *fpixels_nz, - eGPUTextureFormat tex_format, - eGPUDataFormat gpu_data_format, - char err_out[256]) +GPUTexture *GPU_texture_cube_create(int w, + int d, + const void *pixels, + eGPUTextureFormat tex_format, + eGPUDataFormat gpu_data_format, + char err_out[256]) { GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->w = w; @@ -867,8 +884,21 @@ static GPUTexture *GPU_texture_cube_create(int w, tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP; } else { - BLI_assert(false && "Cubemap array Not implemented yet"); - // tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY; + tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY_ARB; + tex->format_flag |= GPU_FORMAT_ARRAY; + + if (!GPU_arb_texture_cube_map_array_is_supported()) { + fprintf(stderr, "ERROR: Attempt to create a cubemap array without hardware support!\n"); + BLI_assert(0); + GPU_texture_free(tex); + return NULL; + } + + if (d > GPU_max_texture_layers() / 6) { + BLI_assert(0); + GPU_texture_free(tex); + return NULL; + } } GLenum internalformat = gpu_get_gl_internalformat(tex_format); @@ -905,60 +935,42 @@ static GPUTexture *GPU_texture_cube_create(int w, glBindTexture(tex->target, tex->bindcode); /* Upload Texture */ - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, - 0, - internalformat, - tex->w, - tex->h, - 0, - data_format, - data_type, - fpixels_px); - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - 0, - internalformat, - tex->w, - tex->h, - 0, - data_format, - data_type, - fpixels_py); - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - 0, - internalformat, - tex->w, - tex->h, - 0, - data_format, - data_type, - fpixels_pz); - glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - 0, - internalformat, - tex->w, - tex->h, - 0, - data_format, - data_type, - fpixels_nx); - glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - 0, - internalformat, - tex->w, - tex->h, - 0, - data_format, - data_type, - fpixels_ny); - glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - 0, - internalformat, - tex->w, - tex->h, - 0, - data_format, - data_type, - fpixels_nz); + if (d == 0) { + const char *pixels_px, *pixels_py, *pixels_pz, *pixels_nx, *pixels_ny, *pixels_nz; + + if (pixels) { + size_t face_ofs = w * w * gpu_get_data_format_bytesize(tex->components, gpu_data_format); + pixels_px = (char *)pixels + 0 * face_ofs; + pixels_nx = (char *)pixels + 1 * face_ofs; + pixels_py = (char *)pixels + 2 * face_ofs; + pixels_ny = (char *)pixels + 3 * face_ofs; + pixels_pz = (char *)pixels + 4 * face_ofs; + pixels_nz = (char *)pixels + 5 * face_ofs; + } + else { + pixels_px = pixels_py = pixels_pz = pixels_nx = pixels_ny = pixels_nz = NULL; + } + + GLuint face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_px); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_nx); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_py); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_ny); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_pz); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_nz); + } + else { + glTexImage3D(tex->target, + 0, + internalformat, + tex->w, + tex->h, + tex->d * 6, + 0, + data_format, + data_type, + pixels); + } /* Texture Parameters */ if (GPU_texture_stencil(tex) || /* Does not support filtering */ @@ -1131,33 +1143,16 @@ GPUTexture *GPU_texture_create_cube(int w, char err_out[256]) { BLI_assert(w > 0); - const float *fpixels_px, *fpixels_py, *fpixels_pz, *fpixels_nx, *fpixels_ny, *fpixels_nz; - const int channels = gpu_get_component_count(tex_format); - - if (fpixels) { - int face_ofs = w * w * channels; - fpixels_px = fpixels + 0 * face_ofs; - fpixels_nx = fpixels + 1 * face_ofs; - fpixels_py = fpixels + 2 * face_ofs; - fpixels_ny = fpixels + 3 * face_ofs; - fpixels_pz = fpixels + 4 * face_ofs; - fpixels_nz = fpixels + 5 * face_ofs; - } - else { - fpixels_px = fpixels_py = fpixels_pz = fpixels_nx = fpixels_ny = fpixels_nz = NULL; - } + eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format); + return GPU_texture_cube_create(w, 0, fpixels, tex_format, data_format, err_out); +} - return GPU_texture_cube_create(w, - 0, - fpixels_px, - fpixels_py, - fpixels_pz, - fpixels_nx, - fpixels_ny, - fpixels_nz, - tex_format, - GPU_DATA_FLOAT, - err_out); +GPUTexture *GPU_texture_create_cube_array( + int w, int d, eGPUTextureFormat tex_format, const float *fpixels, char err_out[256]) +{ + BLI_assert(w > 0 && d > 0); + eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format); + return GPU_texture_cube_create(w, d, fpixels, tex_format, data_format, err_out); } GPUTexture *GPU_texture_create_from_vertbuf(GPUVertBuf *vert) @@ -1297,6 +1292,7 @@ void GPU_texture_add_mipmap(GPUTexture *tex, break; case GL_TEXTURE_3D: case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY_ARB: glTexImage3D(tex->target, miplvl, internalformat, @@ -1385,29 +1381,13 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl gpu_validate_data_format(tex->format, gpu_data_format); - size_t buf_size = gpu_texture_memory_footprint_compute(tex); size_t samples_count = max_ii(1, tex->samples); - samples_count *= size[0]; samples_count *= max_ii(1, size[1]); samples_count *= max_ii(1, size[2]); - samples_count *= (GPU_texture_cube(tex)) ? 6 : 1; + samples_count *= (GPU_texture_cube(tex) && !GPU_texture_array(tex)) ? 6 : 1; - switch (gpu_data_format) { - case GPU_DATA_FLOAT: - buf_size = sizeof(float) * samples_count * tex->components; - break; - case GPU_DATA_INT: - case GPU_DATA_UNSIGNED_INT: - buf_size = sizeof(int) * samples_count * tex->components; - break; - case GPU_DATA_UNSIGNED_INT_24_8: - case GPU_DATA_10_11_11_REV: - buf_size = sizeof(int) * samples_count; - break; - case GPU_DATA_UNSIGNED_BYTE: - break; - } + size_t buf_size = samples_count * gpu_get_data_format_bytesize(tex->components, gpu_data_format); /* AMD Pro driver have a bug that write 8 bytes past buffer size * if the texture is big. (see T66573) */ @@ -1418,7 +1398,7 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl glBindTexture(tex->target, tex->bindcode); - if (GPU_texture_cube(tex)) { + if (GPU_texture_cube(tex) && !GPU_texture_array(tex)) { int cube_face_size = buf_size / 6; for (int i = 0; i < 6; i++) { glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, @@ -1763,6 +1743,11 @@ int GPU_texture_samples(const GPUTexture *tex) return tex->samples; } +bool GPU_texture_array(const GPUTexture *tex) +{ + return (tex->format_flag & GPU_FORMAT_ARRAY) != 0; +} + bool GPU_texture_depth(const GPUTexture *tex) { return (tex->format_flag & GPU_FORMAT_DEPTH) != 0; @@ -1828,8 +1813,12 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size) size[1] = max_ii(1, tex->h / div); } - if (tex->target == GL_TEXTURE_2D_ARRAY) { + if (GPU_texture_array(tex)) { size[2] = tex->d; + /* Return the number of face layers. */ + if (GPU_texture_cube(tex)) { + size[2] *= 6; + } } else if (tex->d > 0) { size[2] = max_ii(1, tex->d / div); diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index 6ffdd60a094..d9cc549229d 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -160,6 +160,10 @@ typedef struct LightCacheTexture { typedef struct LightCache { int flag; + /** Version number to know if the cache data is compatible with this version of blender. */ + int version; + /** Type of data this cache contains. */ + int type; /* only a single cache for now */ /** Number of probes to use for rendering. */ int cube_len, grid_len; @@ -181,6 +185,14 @@ typedef struct LightCache { LightGridCache *grid_data; } LightCache; +/* Bump the version number for lightcache data structure changes. */ +#define LIGHTCACHE_STATIC_VERSION 1 + +/* LightCache->type */ +enum { + LIGHTCACHE_TYPE_STATIC = 0, +}; + /* LightCache->flag */ enum { LIGHTCACHE_BAKED = (1 << 0), diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h index db3566710b4..4b6f079aa28 100644 --- a/source/blender/makesdna/DNA_scene_defaults.h +++ b/source/blender/makesdna/DNA_scene_defaults.h @@ -224,7 +224,7 @@ .shadow_cube_size = 512, \ .shadow_cascade_size = 1024, \ \ - .light_cache = NULL, \ + .light_cache_data = NULL, \ .light_threshold = 0.01f, \ \ .overscan = 3.0f, \ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 5759b237f83..aac976fbabd 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1633,7 +1633,8 @@ typedef struct SceneEEVEE { int shadow_cube_size; int shadow_cascade_size; - struct LightCache *light_cache; + struct LightCache *light_cache DNA_DEPRECATED; + struct LightCache *light_cache_data; char light_cache_info[64]; float overscan; |