[Bf-blender-cvs] [01422645089] blender2.8: Eevee: Lamps: Optimize lamps CPU/Memory usage.

Clément Foucault noreply at git.blender.org
Thu Jan 11 16:51:02 CET 2018


Commit: 0142264508925ddc02a67d5f65759ca24bafa387
Author: Clément Foucault
Date:   Thu Jan 11 14:08:21 2018 +0100
Branches: blender2.8
https://developer.blender.org/rB0142264508925ddc02a67d5f65759ca24bafa387

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.

===================================================================

M	source/blender/draw/engines/eevee/eevee_data.c
M	source/blender/draw/engines/eevee/eevee_engine.c
M	source/blender/draw/engines/eevee/eevee_lights.c
M	source/blender/draw/engines/eevee/eevee_private.h

===================================================================

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]

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list