EEVEE: Replace octahedron reflection probe by cubemap array

We implement cubemap array support for EEVEE's lightcache reflection probes.
This removes stretched texels and bottom hemisphere seams artifacts caused
by the octahedral projection previously used.

This introduce versioning code for the lightcache which will discard any
lightcache version that is not compatible.

Differential Revision: https://developer.blender.org/D7066
This commit is contained in:
Clément Foucault 2020-03-11 17:12:01 +01:00
parent c476c36e40
commit 7dd0be9554
Notes: blender-bot 2023-02-13 22:58:02 +01:00
Referenced by issue #75943, EEVEE can't show reflections from hdri - blender v2.83.13 beta
Referenced by issue #75443, Color Management - Use Curves - crash
32 changed files with 484 additions and 277 deletions

View File

@ -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. */
}

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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__ */

View File

@ -37,6 +37,7 @@
#include "GPU_material.h"
#include "GPU_texture.h"
#include "GPU_extensions.h"
#include "DEG_depsgraph_query.h"
@ -171,31 +172,27 @@ 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 defined(IRRADIANCE_SH_L2)
int grid_res = 4;
#elif defined(IRRADIANCE_CUBEMAP)
int grid_res = 8;
#elif defined(IRRADIANCE_HL2)
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});
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;
#elif defined(IRRADIANCE_CUBEMAP)
int grid_res = 8;
#elif defined(IRRADIANCE_HL2)
int grid_res = 4;
#endif
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");
@ -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 */

View File

@ -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) ||

View File

@ -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,

View File

@ -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 */

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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(

View File

@ -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));
}

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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) {

View File

@ -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])

View File

@ -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);
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);
}
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;
}
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);

View File

@ -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),

View File

@ -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, \

View File

@ -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;