Eevee: Lamps: Optimize lamps CPU/Memory usage.

Tests on my system with ~1200 objects with 128 shadow casting lamps (current max) show a significant perf improvment (cache timing : 22ms -> 9ms)
With a baseline with no shadow casting light at 6ms this give a reduction of the overhead from 16ms to 3ms.

This remove pretty much all allocations during the cache phase. Leading to a big improvement for scene with a large number of lights & shadowcasters.
The lamps storage has been replace by a union to remove the need to free/allocate everyframe (also reducing memory fragmentation).

We replaced the linked list system used to track shadow casters by a huge bitflag.
We gather the lights shadows bounds as well as the shadow casters AABB during the cache populate phase and put them in big arrays cache friendly.

Then in the cache finish phase, it's easier to iterate over the lamps shadow SphereBounds and test for intersection.

We use a double buffer system for the shadow casters arrays to detect deleted shadow casters.
Unfortunatly, it seems that deleting an object trigger an update for all other objects (thus tagging most shadow casting lamps to update), defeating the purpose of this tracking.
This needs further investigation.
This commit is contained in:
Clément Foucault 2018-01-11 14:08:21 +01:00
parent a08f687b91
commit 0142264508
4 changed files with 289 additions and 167 deletions

View File

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

View File

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

View File

@ -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,93 +897,15 @@ 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);
/* 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);
/* 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;
return true;
}
static ShadowCaster *search_object_in_list(ListBase *list, Object *ob)
{
for (ShadowCaster *ldata = list->first; ldata; ldata = ldata->next) {
if (ldata->ob == ob)
return ldata;
}
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);
}
}
}
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;
}
else {
EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
if (oedata->need_update) {
led->need_update = true;
}
}
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;
return x && y && z;
}
void EEVEE_lights_update(EEVEE_ViewLayerData *sldata)
@ -888,29 +913,70 @@ void EEVEE_lights_update(EEVEE_ViewLayerData *sldata)
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;
/* 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);
EEVEE_LightBits update_bits = {{0}};
if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) {
/* Update all lights. */
lightbits_set_all(&update_bits, true);
}
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);
}
if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) {
/* 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);
}
/* Only add to final bits if objects has been updated. */
if (*flag != 0) {
lightbits_or(&update_bits, &shcaster->bits);
}
}
/* 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);
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);

View File

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