Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c17
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c7
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c356
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h70
4 files changed, 286 insertions, 164 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index d5582a498a4..f34601ef7b6 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -45,7 +45,10 @@ static void eevee_view_layer_data_free(void *storage)
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_pool);
- BLI_freelistN(&sldata->shadow_casters);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[0].shadow_casters);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[0].flags);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[1].shadow_casters);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[1].flags);
/* Probes */
MEM_SAFE_FREE(sldata->probes);
@@ -64,14 +67,6 @@ static void eevee_view_layer_data_free(void *storage)
MEM_SAFE_FREE(sldata->volumetrics);
}
-static void eevee_lamp_data_free(void *storage)
-{
- EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)storage;
-
- MEM_SAFE_FREE(led->storage);
- BLI_freelistN(&led->shadow_caster_list);
-}
-
static void eevee_lightprobe_data_free(void *storage)
{
EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)storage;
@@ -110,6 +105,7 @@ EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob)
if (*oedata == NULL) {
*oedata = MEM_callocN(sizeof(**oedata), "EEVEE_ObjectEngineData");
+ (*oedata)->shadow_caster_id = -1;
}
return *oedata;
@@ -144,11 +140,12 @@ EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob)
EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob)
{
EEVEE_LampEngineData **ledata = (EEVEE_LampEngineData **)DRW_object_engine_data_ensure(
- ob, &draw_engine_eevee_type, &eevee_lamp_data_free);
+ ob, &draw_engine_eevee_type, NULL);
if (*ledata == NULL) {
*ledata = MEM_callocN(sizeof(**ledata), "EEVEE_LampEngineData");
(*ledata)->need_update = true;
+ (*ledata)->prev_cube_shadow_id = -1;
}
return *ledata;
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index bf699636fee..c49edd8a5e4 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -123,12 +123,7 @@ static void eevee_cache_populate(void *vedata, Object *ob)
const bool cast_shadow = true;
if (cast_shadow) {
- if ((ob->base_flag & BASE_FROMDUPLI) != 0) {
- /* TODO: Special case for dupli objects because we cannot save the object pointer. */
- }
- else {
- BLI_addtail(&sldata->shadow_casters, BLI_genericNodeN(ob));
- }
+ EEVEE_lights_cache_shcaster_object_add(sldata, ob);
}
}
else if (ob->type == OB_LIGHTPROBE) {
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index 274aa480473..3a9aaf9ede7 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -32,28 +32,7 @@
#include "eevee_engine.h"
#include "eevee_private.h"
-/* Theses are the structs stored inside Objects.
- * It works with even if the object is in multiple layers
- * because we don't get the same "Object *" for each layer. */
-typedef struct EEVEE_LightData {
- short light_id, shadow_id;
-} EEVEE_LightData;
-
-typedef struct EEVEE_ShadowCubeData {
- short light_id, shadow_id, cube_id, layer_id;
-} EEVEE_ShadowCubeData;
-
-typedef struct EEVEE_ShadowCascadeData {
- short light_id, shadow_id, cascade_id, layer_id;
- float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
- float radius[MAX_CASCADE_NUM];
-} EEVEE_ShadowCascadeData;
-
-typedef struct ShadowCaster {
- struct ShadowCaster *next, *prev;
- void *ob;
- bool prune;
-} ShadowCaster;
+#define SHADOW_CASTER_ALLOC_CHUNK 16
static struct {
struct GPUShader *shadow_sh;
@@ -73,6 +52,45 @@ extern char datatoc_concentric_samples_lib_glsl[];
/* Prototype */
static void eevee_light_setup(Object *ob, EEVEE_Light *evli);
+/* *********** LIGHT BITS *********** */
+static void lightbits_set_single(EEVEE_LightBits *bitf, unsigned int idx, bool val)
+{
+ if (val) {
+ bitf->fields[idx / 8] |= (1 << (idx % 8));
+ }
+ else {
+ bitf->fields[idx / 8] &= ~(1 << (idx % 8));
+ }
+}
+
+static void lightbits_set_all(EEVEE_LightBits *bitf, bool val)
+{
+ memset(bitf, (val) ? 0xFF : 0x00, sizeof(EEVEE_LightBits));
+}
+
+static void lightbits_or(EEVEE_LightBits *r, const EEVEE_LightBits *v)
+{
+ for (int i = 0; i < MAX_LIGHTBITS_FIELDS; ++i) {
+ r->fields[i] |= v->fields[i];
+ }
+}
+
+static bool lightbits_get(const EEVEE_LightBits *r, unsigned int idx)
+{
+ return r->fields[idx / 8] & (1 << (idx % 8));
+}
+
+static void lightbits_convert(EEVEE_LightBits *r, const EEVEE_LightBits *bitf, const int *light_bit_conv_table, unsigned int table_length)
+{
+ for (int i = 0; i < table_length; ++i) {
+ if (lightbits_get(bitf, i) != 0) {
+ if (light_bit_conv_table[i] >= 0) {
+ r->fields[i / 8] |= (1 << (i % 8));
+ }
+ }
+ }
+}
+
/* *********** FUNCTIONS *********** */
void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
@@ -139,8 +157,21 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
sldata->light_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL);
sldata->shadow_ubo = DRW_uniformbuffer_create(shadow_ubo_size, NULL);
sldata->shadow_render_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_ShadowRender), NULL);
+
+ for (int i = 0; i < 2; ++i) {
+ sldata->shcasters_buffers[i].shadow_casters = MEM_callocN(sizeof(EEVEE_ShadowCaster) * SHADOW_CASTER_ALLOC_CHUNK, "EEVEE_ShadowCaster buf");
+ sldata->shcasters_buffers[i].flags = MEM_callocN(sizeof(sldata->shcasters_buffers[0].flags) * SHADOW_CASTER_ALLOC_CHUNK, "EEVEE_shcast_buffer flags buf");
+ sldata->shcasters_buffers[i].alloc_count = SHADOW_CASTER_ALLOC_CHUNK;
+ sldata->shcasters_buffers[i].count = 0;
+ }
+
+ sldata->lamps->shcaster_frontbuffer = &sldata->shcasters_buffers[0];
+ sldata->lamps->shcaster_backbuffer = &sldata->shcasters_buffers[1];
}
+ /* Flip buffers */
+ SWAP(EEVEE_ShadowCasterBuffer *, sldata->lamps->shcaster_frontbuffer, sldata->lamps->shcaster_backbuffer);
+
int sh_method = BKE_collection_engine_property_value_get_int(props, "shadow_method");
int sh_size = BKE_collection_engine_property_value_get_int(props, "shadow_size");
int sh_high_bitdepth = BKE_collection_engine_property_value_get_int(props, "shadow_high_bitdepth");
@@ -178,6 +209,7 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
{
EEVEE_LampsInfo *linfo = sldata->lamps;
+ linfo->shcaster_frontbuffer->count = 0;
linfo->num_light = 0;
linfo->num_layer = 0;
linfo->gpu_cube_ct = linfo->gpu_cascade_ct = linfo->gpu_shadow_ct = 0;
@@ -185,6 +217,11 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
memset(linfo->light_ref, 0, sizeof(linfo->light_ref));
memset(linfo->shadow_cube_ref, 0, sizeof(linfo->shadow_cube_ref));
memset(linfo->shadow_cascade_ref, 0, sizeof(linfo->shadow_cascade_ref));
+ memset(linfo->new_shadow_id, -1, sizeof(linfo->new_shadow_id));
+
+ /* Shadow Casters: Reset flags. */
+ memset(linfo->shcaster_backbuffer->flags, (char)SHADOW_CASTER_PRUNED, linfo->shcaster_backbuffer->alloc_count);
+ memset(linfo->shcaster_frontbuffer->flags, 0x00, linfo->shcaster_frontbuffer->alloc_count);
{
psl->shadow_cube_store_pass = DRW_pass_create("Shadow Storage Pass", DRW_STATE_WRITE_COLOR);
@@ -244,9 +281,6 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
"Shadow Cascade Pass",
DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
}
-
- /* Reset shadow casters list */
- BLI_freelistN(&sldata->shadow_casters);
}
void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
@@ -256,7 +290,6 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
/* Step 1 find all lamps in the scene and setup them */
if (linfo->num_light >= MAX_LIGHT) {
printf("Too much lamps in the scene !!!\n");
- linfo->num_light = MAX_LIGHT - 1;
}
else {
Lamp *la = (Lamp *)ob->data;
@@ -271,7 +304,12 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
- MEM_SAFE_FREE(led->storage);
+ /* Save previous shadow id. */
+ int prev_cube_sh_id = led->prev_cube_shadow_id;
+
+ /* Default light without shadows */
+ led->data.ld.shadow_id = -1;
+ led->prev_cube_shadow_id = -1;
if (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY)) {
if (la->type == LA_SUN) {
@@ -282,13 +320,11 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
/* Save Light object. */
linfo->shadow_cascade_ref[linfo->cpu_cascade_ct] = ob;
- /* Create storage and store indices. */
- EEVEE_ShadowCascadeData *data = MEM_mallocN(
- sizeof(EEVEE_ShadowCascadeData), "EEVEE_ShadowCascadeData");
+ /* Store indices. */
+ EEVEE_ShadowCascadeData *data = &led->data.scad;
data->shadow_id = linfo->gpu_shadow_ct;
data->cascade_id = linfo->gpu_cascade_ct;
data->layer_id = linfo->num_layer;
- led->storage = data;
/* Increment indices. */
linfo->gpu_shadow_ct += 1;
@@ -305,13 +341,24 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
/* Save Light object. */
linfo->shadow_cube_ref[linfo->cpu_cube_ct] = ob;
- /* Create storage and store indices. */
- EEVEE_ShadowCubeData *data = MEM_mallocN(
- sizeof(EEVEE_ShadowCubeData), "EEVEE_ShadowCubeData");
+ /* For light update tracking. */
+ if ((prev_cube_sh_id >= 0) &&
+ (prev_cube_sh_id < linfo->shcaster_backbuffer->count))
+ {
+ linfo->new_shadow_id[prev_cube_sh_id] = linfo->cpu_cube_ct;
+ }
+ led->prev_cube_shadow_id = linfo->cpu_cube_ct;
+
+ /* Saving lamp bounds for later. */
+ BLI_assert(linfo->cpu_cube_ct >= 0 && linfo->cpu_cube_ct < MAX_LIGHT);
+ copy_v3_v3(linfo->shadow_bounds[linfo->cpu_cube_ct].center, ob->obmat[3]);
+ linfo->shadow_bounds[linfo->cpu_cube_ct].radius = la->clipend;
+
+ EEVEE_ShadowCubeData *data = &led->data.scd;
+ /* Store indices. */
data->shadow_id = linfo->gpu_shadow_ct;
data->cube_id = linfo->gpu_cube_ct;
data->layer_id = linfo->num_layer;
- led->storage = data;
/* Increment indices. */
linfo->gpu_shadow_ct += 1;
@@ -323,13 +370,7 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
}
}
- /* Default light without shadows */
- if (!led->storage) {
- led->storage = MEM_mallocN(sizeof(EEVEE_LightData), "EEVEE_LightData");
- ((EEVEE_LightData *)led->storage)->shadow_id = -1;
- }
-
- ((EEVEE_LightData *)led->storage)->light_id = linfo->num_light;
+ led->data.ld.light_id = linfo->num_light;
linfo->light_ref[linfo->num_light] = ob;
linfo->num_light++;
}
@@ -376,6 +417,68 @@ void EEVEE_lights_cache_shcaster_material_add(
DRW_shgroup_set_instance_count(grp, MAX_CASCADE_NUM);
}
+/* Make that object update shadow casting lamps inside its influence bounding box. */
+void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, Object *ob)
+{
+ if ((ob->base_flag & BASE_FROMDUPLI) != 0) {
+ /* TODO: Special case for dupli objects because we cannot save the object pointer. */
+ return;
+ }
+
+ EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+ int past_id = oedata->shadow_caster_id;
+
+ /* Update flags in backbuffer. */
+ if (past_id > -1 && past_id < backbuffer->count) {
+ backbuffer->flags[past_id] &= ~SHADOW_CASTER_PRUNED;
+
+ if (oedata->need_update) {
+ backbuffer->flags[past_id] |= SHADOW_CASTER_UPDATED;
+ }
+ }
+
+ /* Update id. */
+ oedata->shadow_caster_id = frontbuffer->count++;
+
+ /* Make sure shadow_casters is big enough. */
+ if (oedata->shadow_caster_id >= frontbuffer->alloc_count) {
+ frontbuffer->alloc_count += SHADOW_CASTER_ALLOC_CHUNK;
+ frontbuffer->shadow_casters = MEM_reallocN(frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
+ frontbuffer->flags = MEM_reallocN(frontbuffer->flags, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
+ }
+
+ EEVEE_ShadowCaster *shcaster = frontbuffer->shadow_casters + oedata->shadow_caster_id;
+
+ if (oedata->need_update) {
+ frontbuffer->flags[oedata->shadow_caster_id] = SHADOW_CASTER_UPDATED;
+ }
+
+ /* Update World AABB in frontbuffer. */
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ for (int i = 0; i < 8; ++i) {
+ float vec[3];
+ copy_v3_v3(vec, bb->vec[i]);
+ mul_m4_v3(ob->obmat, vec);
+ minmax_v3v3_v3(min, max, vec);
+ }
+
+ EEVEE_BoundBox *aabb = &shcaster->bbox;
+ add_v3_v3v3(aabb->center, min, max);
+ mul_v3_fl(aabb->center, 0.5f);
+ sub_v3_v3v3(aabb->halfdim, aabb->center, max);
+
+ aabb->halfdim[0] = fabsf(aabb->halfdim[0]);
+ aabb->halfdim[1] = fabsf(aabb->halfdim[1]);
+ aabb->halfdim[2] = fabsf(aabb->halfdim[2]);
+
+ oedata->need_update = false;
+}
+
void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata)
{
EEVEE_LampsInfo *linfo = sldata->lamps;
@@ -515,7 +618,7 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli)
static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led)
{
- EEVEE_ShadowCubeData *sh_data = (EEVEE_ShadowCubeData *)led->storage;
+ EEVEE_ShadowCubeData *sh_data = &led->data.scd;
EEVEE_Light *evli = linfo->light_data + sh_data->light_id;
EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id;
EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + sh_data->cube_id;
@@ -609,7 +712,7 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
int sh_nbr = 1; /* TODO : MSM */
int cascade_nbr = la->cascade_count;
- EEVEE_ShadowCascadeData *sh_data = (EEVEE_ShadowCascadeData *)led->storage;
+ EEVEE_ShadowCascadeData *sh_data = &led->data.scad;
EEVEE_Light *evli = linfo->light_data + sh_data->light_id;
EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id;
EEVEE_ShadowCascade *cascade_data = linfo->shadow_cascade_data + sh_data->cascade_id;
@@ -794,123 +897,86 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE
}
/* Used for checking if object is inside the shadow volume. */
-static bool cube_bbox_intersect(const float cube_center[3], float cube_half_dim, const BoundBox *bb, float (*obmat)[4])
+static bool sphere_bbox_intersect(const EEVEE_BoundSphere *bs, const EEVEE_BoundBox *bb)
{
- float min[3], max[4], tmp[4][4];
- unit_m4(tmp);
- translate_m4(tmp, -cube_center[0], -cube_center[1], -cube_center[2]);
- mul_m4_m4m4(tmp, tmp, obmat);
-
- /* Just simple AABB intersection test in world space. */
- INIT_MINMAX(min, max);
- for (int i = 0; i < 8; ++i) {
- float vec[3];
- copy_v3_v3(vec, bb->vec[i]);
- mul_m4_v3(tmp, vec);
- minmax_v3v3_v3(min, max, vec);
- }
-
- if (MAX3(max[0], max[1], max[2]) < -cube_half_dim) return false;
- if (MIN3(min[0], min[1], min[2]) > cube_half_dim) return false;
+ /* We are testing using a rougher AABB vs AABB test instead of full AABB vs Sphere. */
+ /* TODO test speed with AABB vs Sphere. */
+ bool x = fabsf(bb->center[0] - bs->center[0]) <= (bb->halfdim[0] + bs->radius);
+ bool y = fabsf(bb->center[1] - bs->center[1]) <= (bb->halfdim[1] + bs->radius);
+ bool z = fabsf(bb->center[2] - bs->center[2]) <= (bb->halfdim[2] + bs->radius);
- return true;
+ return x && y && z;
}
-static ShadowCaster *search_object_in_list(ListBase *list, Object *ob)
+void EEVEE_lights_update(EEVEE_ViewLayerData *sldata)
{
- for (ShadowCaster *ldata = list->first; ldata; ldata = ldata->next) {
- if (ldata->ob == ob)
- return ldata;
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ Object *ob;
+ int i;
+ char *flag;
+ EEVEE_ShadowCaster *shcaster;
+ EEVEE_BoundSphere *bsphere;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+
+ EEVEE_LightBits update_bits = {{0}};
+ if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) {
+ /* Update all lights. */
+ lightbits_set_all(&update_bits, true);
}
-
- return NULL;
-}
-
-static void delete_pruned_shadowcaster(EEVEE_LampEngineData *led)
-{
- ShadowCaster *next;
- for (ShadowCaster *ldata = led->shadow_caster_list.first; ldata; ldata = next) {
- next = ldata->next;
- if (ldata->prune == true) {
- led->need_update = true;
- BLI_freelinkN(&led->shadow_caster_list, ldata);
+ else {
+ /* Search for deleted shadow casters and if shcaster WAS in shadow radius. */
+ /* No need to run this if we already update all lamps. */
+ EEVEE_LightBits past_bits = {{0}};
+ EEVEE_LightBits curr_bits = {{0}};
+ shcaster = backbuffer->shadow_casters;
+ flag = backbuffer->flags;
+ for (i = 0; i < backbuffer->count; ++i, ++flag, ++shcaster) {
+ /* If the shadowcaster has been deleted or updated. */
+ if (*flag != 0) {
+ /* Add the lamps that were intersecting with its BBox. */
+ lightbits_or(&past_bits, &shcaster->bits);
+ }
}
+ /* Convert old bits to new bits and add result to final update bits. */
+ /* NOTE: This might be overkill since all lights are tagged to refresh if
+ * the light count changes. */
+ lightbits_convert(&curr_bits, &past_bits, linfo->new_shadow_id, MAX_LIGHT);
+ lightbits_or(&update_bits, &curr_bits);
}
-}
-static void light_tag_shadow_update(Object *lamp, Object *ob)
-{
- Lamp *la = lamp->data;
- EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(lamp);
-
- bool is_inside_range = cube_bbox_intersect(lamp->obmat[3], la->clipend, BKE_object_boundbox_get(ob), ob->obmat);
- ShadowCaster *ldata = search_object_in_list(&led->shadow_caster_list, ob);
-
- if (is_inside_range) {
- if (ldata == NULL) {
- /* Object was not a shadow caster previously but is now. Add it. */
- ldata = MEM_callocN(sizeof(ShadowCaster), "ShadowCaster");
- ldata->ob = ob;
- BLI_addtail(&led->shadow_caster_list, ldata);
- led->need_update = true;
+ /* Search for updates in current shadow casters. */
+ shcaster = frontbuffer->shadow_casters;
+ flag = frontbuffer->flags;
+ for (i = 0; i < frontbuffer->count; i++, flag++, shcaster++) {
+ /* Run intersection checks to fill the bitfields. */
+ bsphere = linfo->shadow_bounds;
+ for (int j = 0; j < linfo->cpu_cube_ct; j++, bsphere++) {
+ bool iter = sphere_bbox_intersect(bsphere, &shcaster->bbox);
+ lightbits_set_single(&shcaster->bits, j, iter);
}
- else {
- EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
- if (oedata->need_update) {
- led->need_update = true;
- }
+ /* Only add to final bits if objects has been updated. */
+ if (*flag != 0) {
+ lightbits_or(&update_bits, &shcaster->bits);
}
- ldata->prune = false;
- }
- else if (ldata != NULL) {
- /* Object was a shadow caster previously and is not anymore. Remove it. */
- led->need_update = true;
- BLI_freelinkN(&led->shadow_caster_list, ldata);
- }
-}
-
-static void eevee_lights_shcaster_updated(EEVEE_ViewLayerData *sldata, Object *ob)
-{
- Object *lamp;
- EEVEE_LampsInfo *linfo = sldata->lamps;
-
- /* Iterate over all shadow casting lamps to see if
- * each of them needs update because of this object */
- for (int i = 0; (lamp = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
- light_tag_shadow_update(lamp, ob);
}
- EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
- oedata->need_update = false;
-}
-void EEVEE_lights_update(EEVEE_ViewLayerData *sldata)
-{
- EEVEE_LampsInfo *linfo = sldata->lamps;
- Object *ob;
- int i;
-
- /* Prune shadow casters to remove if object does not exists anymore (unprune them if object exists) */
- Object *lamp;
- for (i = 0; (lamp = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
- EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(lamp);
+ /* Setup shadow cube in UBO and tag for update if necessary. */
+ for (i = 0; (i < MAX_SHADOW_CUBE) && (ob = linfo->shadow_cube_ref[i]); i++) {
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
- if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) {
+ eevee_shadow_cube_setup(ob, linfo, led);
+ if (lightbits_get(&update_bits, i) != 0) {
led->need_update = true;
}
-
- for (ShadowCaster *ldata = led->shadow_caster_list.first; ldata; ldata = ldata->next) {
- ldata->prune = true;
- }
- }
-
- for (LinkData *ldata = sldata->shadow_casters.first; ldata; ldata = ldata->next) {
- eevee_lights_shcaster_updated(sldata, ldata->data);
}
- for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
- EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
- eevee_shadow_cube_setup(ob, linfo, led);
- delete_pruned_shadowcaster(led);
+ /* Resize shcasters buffers if too big. */
+ if (frontbuffer->alloc_count - frontbuffer->count > SHADOW_CASTER_ALLOC_CHUNK) {
+ frontbuffer->alloc_count = (frontbuffer->count / SHADOW_CASTER_ALLOC_CHUNK) * SHADOW_CASTER_ALLOC_CHUNK;
+ frontbuffer->alloc_count += (frontbuffer->count % SHADOW_CASTER_ALLOC_CHUNK != 0) ? SHADOW_CASTER_ALLOC_CHUNK : 0;
+ frontbuffer->shadow_casters = MEM_reallocN(frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
+ frontbuffer->flags = MEM_reallocN(frontbuffer->flags, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
}
}
@@ -938,7 +1004,7 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
}
EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
- EEVEE_ShadowCubeData *evscd = (EEVEE_ShadowCubeData *)led->storage;
+ EEVEE_ShadowCubeData *evscd = &led->data.scd;
srd->clip_near = la->clipsta;
srd->clip_far = la->clipend;
@@ -1016,7 +1082,7 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
Lamp *la = (Lamp *)ob->data;
- EEVEE_ShadowCascadeData *evscd = (EEVEE_ShadowCascadeData *)led->storage;
+ EEVEE_ShadowCascadeData *evscd = &led->data.scad;
EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
eevee_shadow_cascade_setup(ob, linfo, led);
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index af3984b7c20..b1ea68debc4 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -27,6 +27,8 @@
#define __EEVEE_PRIVATE_H__
struct Object;
+struct EEVEE_BoundSphere;
+struct EEVEE_ShadowCasterBuffer;
extern struct DrawEngineType draw_engine_eevee_type;
@@ -127,6 +129,14 @@ enum {
SHADOW_METHOD_MAX = 3,
};
+typedef struct EEVEE_BoundSphere {
+ float center[3], radius;
+} EEVEE_BoundSphere;
+
+typedef struct EEVEE_BoundBox {
+ float center[3], halfdim[3];
+} EEVEE_BoundBox;
+
typedef struct EEVEE_PassList {
/* Shadows */
struct DRWPass *shadow_pass;
@@ -311,6 +321,24 @@ typedef struct EEVEE_ShadowRender {
float shadow_inv_samples_ct;
} EEVEE_ShadowRender;
+/* This is just a really long bitflag with special function to access it. */
+#define MAX_LIGHTBITS_FIELDS (MAX_LIGHT / 8)
+typedef struct EEVEE_LightBits {
+ unsigned char fields[MAX_LIGHTBITS_FIELDS];
+} EEVEE_LightBits;
+
+typedef struct EEVEE_ShadowCaster {
+ struct EEVEE_LightBits bits;
+ struct EEVEE_BoundBox bbox;
+} EEVEE_ShadowCaster;
+
+typedef struct EEVEE_ShadowCasterBuffer {
+ struct EEVEE_ShadowCaster *shadow_casters;
+ char *flags;
+ unsigned int alloc_count;
+ unsigned int count;
+} EEVEE_ShadowCasterBuffer;
+
/* ************ VOLUME DATA ************ */
typedef struct EEVEE_VolumetricsInfo {
float integration_step_count, shadow_step_count, sample_distribution, light_clamp;
@@ -347,8 +375,20 @@ typedef struct EEVEE_LampsInfo {
struct EEVEE_Shadow shadow_data[MAX_SHADOW];
struct EEVEE_ShadowCube shadow_cube_data[MAX_SHADOW_CUBE];
struct EEVEE_ShadowCascade shadow_cascade_data[MAX_SHADOW_CASCADE];
+ /* Lights tracking */
+ int new_shadow_id[MAX_LIGHT]; /* To be able to convert old bitfield to new bitfield */
+ struct EEVEE_BoundSphere shadow_bounds[MAX_LIGHT]; /* Tighly packed light bounds */
+ /* Pointers only. */
+ struct EEVEE_ShadowCasterBuffer *shcaster_frontbuffer;
+ struct EEVEE_ShadowCasterBuffer *shcaster_backbuffer;
} EEVEE_LampsInfo;
+/* EEVEE_LampsInfo->shadow_casters_flag */
+enum {
+ SHADOW_CASTER_PRUNED = (1 << 0),
+ SHADOW_CASTER_UPDATED = (1 << 1),
+};
+
/* EEVEE_LampsInfo->update_flag */
enum {
LIGHT_UPDATE_SHADOW_CUBE = (1 << 0),
@@ -550,7 +590,7 @@ typedef struct EEVEE_ViewLayerData {
struct GPUTexture *shadow_cascade_blur;
struct GPUTexture *shadow_pool;
- struct ListBase shadow_casters; /* Shadow casters gathered during cache iteration */
+ struct EEVEE_ShadowCasterBuffer shcasters_buffers[2];
/* Probes */
struct EEVEE_LightProbesInfo *probes;
@@ -575,10 +615,32 @@ typedef struct EEVEE_ViewLayerData {
} EEVEE_ViewLayerData;
/* ************ OBJECT DATA ************ */
+typedef struct EEVEE_LightData {
+ short light_id, shadow_id;
+} EEVEE_LightData;
+
+typedef struct EEVEE_ShadowCubeData {
+ short light_id, shadow_id, cube_id, layer_id;
+} EEVEE_ShadowCubeData;
+
+typedef struct EEVEE_ShadowCascadeData {
+ short light_id, shadow_id, cascade_id, layer_id;
+ float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
+ float radius[MAX_CASCADE_NUM];
+} EEVEE_ShadowCascadeData;
+
+/* Theses are the structs stored inside Objects.
+ * It works with even if the object is in multiple layers
+ * because we don't get the same "Object *" for each layer. */
typedef struct EEVEE_LampEngineData {
bool need_update;
- struct ListBase shadow_caster_list;
- void *storage; /* either EEVEE_LightData, EEVEE_ShadowCubeData, EEVEE_ShadowCascadeData */
+ /* This needs to be out of the union to avoid undefined behaviour. */
+ short prev_cube_shadow_id;
+ union {
+ struct EEVEE_LightData ld;
+ struct EEVEE_ShadowCubeData scd;
+ struct EEVEE_ShadowCascadeData scad;
+ } data;
} EEVEE_LampEngineData;
typedef struct EEVEE_LightProbeEngineData {
@@ -611,6 +673,7 @@ typedef struct EEVEE_LightProbeEngineData {
typedef struct EEVEE_ObjectEngineData {
bool need_update;
+ unsigned int shadow_caster_id;
} EEVEE_ObjectEngineData;
/* *********************************** */
@@ -692,6 +755,7 @@ void EEVEE_lights_cache_shcaster_material_add(
EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl,
struct GPUMaterial *gpumat, struct Gwn_Batch *geom, struct Object *ob,
float (*obmat)[4], float *alpha_threshold);
+void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, struct Object *ob);
void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata);
void EEVEE_lights_update(EEVEE_ViewLayerData *sldata);
void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl);