2
0
Panagiotis Christopoulos Charitos 10 жил өмнө
parent
commit
d8cd913dee

+ 1 - 0
include/anki/core/Trace.h

@@ -33,6 +33,7 @@ enum class TraceEventType
 	RENDER_MS,
 	RENDER_IS,
 	RENDER_SM,
+	RENDER_IR,
 	RENDER_DRAWER,
 	GL_THREAD,
 	SWAP_BUFFERS,

+ 20 - 2
include/anki/renderer/Ir.h

@@ -12,6 +12,7 @@ namespace anki {
 
 // Forward
 struct ShaderReflectionProbe;
+class IrBuildContext;
 
 /// @addtogroup renderer
 /// @{
@@ -40,6 +41,16 @@ anki_internal:
 		return m_probesToken;
 	}
 
+	DynamicBufferToken getProbeIndicesToken() const
+	{
+		return m_indicesToken;
+	}
+
+	DynamicBufferToken getClustersToken() const
+	{
+		return m_clustersToken;
+	}
+
 	U getCubemapArrayMipmapCount() const
 	{
 		return m_cubemapArrMipCount;
@@ -55,17 +66,24 @@ private:
 
 	Renderer m_nestedR;
 	TexturePtr m_cubemapArr;
-	U m_cubemapArrMipCount = 0;
+	U16 m_cubemapArrMipCount = 0;
 	U16 m_cubemapArrSize = 0;
 	U16 m_fbSize = 0;
-	DynamicBufferToken m_probesToken;
 	DArray<CacheEntry> m_cacheEntries;
 
+	// Tokens
+	DynamicBufferToken m_probesToken;
+	DynamicBufferToken m_clustersToken;
+	DynamicBufferToken m_indicesToken;
+
 	ANKI_USE_RESULT Error renderReflection(SceneNode& node,
 		ShaderReflectionProbe& shaderProb);
 
 	/// Find a cache entry to store the reflection.
 	void findCacheEntry(SceneNode& node, U& entry, Bool& render);
+
+	void binProbe(const SceneNode& node, U index, IrBuildContext& ctx);
+	void populateIndexAndClusterBuffers(IrBuildContext& ctx);
 };
 /// @}
 

+ 39 - 25
shaders/ImageReflections.glsl

@@ -21,13 +21,24 @@ struct ReflectionProbe
 };
 
 layout(std140, row_major, SS_BINDING(IMAGE_REFLECTIONS_SET,
-	IMAGE_REFLECTIONS_PROBE_SS_BINDING)) readonly buffer _irs1
+	IMAGE_REFLECTIONS_FIRST_SS_BINDING)) readonly buffer _irs1
 {
-	uvec4 u_reflectionProbeCountPad3;
 	mat3 u_invViewRotation;
 	ReflectionProbe u_reflectionProbes[];
 };
 
+layout(std430, row_major, SS_BINDING(IMAGE_REFLECTIONS_SET,
+	IMAGE_REFLECTIONS_FIRST_SS_BINDING + 1)) readonly buffer _irs2
+{
+	uint u_reflectionProbeIndices[];
+};
+
+layout(std430, row_major, SS_BINDING(IMAGE_REFLECTIONS_SET,
+	IMAGE_REFLECTIONS_FIRST_SS_BINDING + 2)) readonly buffer _irs3
+{
+	uint u_reflectionClusters[];
+};
+
 layout(TEX_BINDING(IMAGE_REFLECTIONS_SET, IMAGE_REFLECTIONS_TEX_BINDING))
 	uniform samplerCubeArray u_reflectionsTex;
 
@@ -59,7 +70,8 @@ vec3 computeCubemapVec(in vec3 r, in float R2, in vec3 f)
 }
 
 //==============================================================================
-vec3 readReflection(in vec3 posVSpace, in vec3 normalVSpace, in float lod)
+vec3 readReflection(in uint clusterIndex, in vec3 posVSpace,
+	in vec3 normalVSpace, in float lod)
 {
 	vec3 color = IMAGE_REFLECTIONS_DEFAULT_COLOR;
 
@@ -68,32 +80,34 @@ vec3 readReflection(in vec3 posVSpace, in vec3 normalVSpace, in float lod)
 	vec3 r = reflect(eye, normalVSpace);
 
 	// Check proxy
-	uint count = u_reflectionProbeCountPad3.x;
-	for(uint i = 0; i < count; ++i)
+	uint cluster = u_reflectionClusters[clusterIndex];
+	uint indexOffset = cluster >> 16u;
+	uint indexCount = cluster & 0xFFFFu;
+	for(uint i = 0; i < indexCount; ++i)
 	{
-		float R2 = u_reflectionProbes[i].positionRadiusSq.w;
-		vec3 center = u_reflectionProbes[i].positionRadiusSq.xyz;
+		uint probeIndex = u_reflectionProbeIndices[indexOffset++];
+		ReflectionProbe probe = u_reflectionProbes[probeIndex];
+
+		float R2 = probe.positionRadiusSq.w;
+		vec3 center = probe.positionRadiusSq.xyz;
 
-		// Check if the point is inside the sphere
+		// Get distance from the center of the probe
 		vec3 f = posVSpace - center;
+
+		// Cubemap UV in view space
+		vec3 uv = computeCubemapVec(r, R2, f);
+
+		// Read!
+		float cubemapIndex = probe.cubemapIndexPad3.x;
+		vec3 c =
+			textureLod(u_reflectionsTex, vec4(uv, cubemapIndex), lod).rgb;
+
+		// Combine (lerp) with previous color
 		float d = dot(f, f);
-		if(d < R2)
-		{
-			// Found something
-
-			// Cubemap UV in view space
-			vec3 uv = computeCubemapVec(r, R2, f);
-
-			// Read!
-			float cubemapIndex = u_reflectionProbes[i].cubemapIndexPad3.x;
-			vec3 c =
-				textureLod(u_reflectionsTex, vec4(uv, cubemapIndex), lod).rgb;
-
-			// Combine (lerp) with previous color
-			float factor = d / R2;
-			color = mix(c, color, factor);
-			//Equivelent: color = c * (1.0 - factor) + color * factor;
-		}
+		float factor = d / R2;
+		factor = min(factor, 1.0);
+		color = mix(c, color, factor);
+		//Equivelent: color = c * (1.0 - factor) + color * factor;
 	}
 
 	return color;

+ 6 - 5
shaders/IsLp.frag.glsl

@@ -29,12 +29,12 @@ layout(location = 0) out vec3 out_color;
 
 #if IR == 1
 #define IMAGE_REFLECTIONS_SET 0
-#define IMAGE_REFLECTIONS_PROBE_SS_BINDING 5
+#define IMAGE_REFLECTIONS_FIRST_SS_BINDING 5
 #define IMAGE_REFLECTIONS_TEX_BINDING 6
 #define IMAGE_REFLECTIONS_DEFAULT_COLOR vec3(0.0)
 #pragma anki include "shaders/ImageReflections.glsl"
 #undef IMAGE_REFLECTIONS_SET
-#undef IMAGE_REFLECTIONS_PROBE_SS_BINDING
+#undef IMAGE_REFLECTIONS_FIRST_SS_BINDING
 #undef IMAGE_REFLECTIONS_DEFAULT_COLOR
 #endif
 
@@ -105,7 +105,8 @@ void main()
 
 	// Get counts and offsets
 	uint k = calcClusterSplit(fragPos.z);
-	uint cluster = u_clusters[in_instanceId + k * TILE_COUNT];
+	uint clusterIndex = in_instanceId + k * TILE_COUNT;
+	uint cluster = u_clusters[clusterIndex];
 	uint lightOffset = cluster >> 16u;
 	uint pointLightsCount = (cluster >> 8u) & 0xFFu;
 	uint spotLightsCount = cluster & 0xFFu;
@@ -168,7 +169,7 @@ void main()
 #if IR == 1
 	{
 		float reflLod = float(IR_MIPMAP_COUNT) * roughness;
-		vec3 refl = readReflection(fragPos, normal, reflLod);
+		vec3 refl = readReflection(clusterIndex, fragPos, normal, reflLod);
 		out_color += refl * (1.0 - roughness);
 	}
 #endif
@@ -194,7 +195,7 @@ void main()
 		out_color += vec3(1.0, 0.0, 0.0);
 	}
 #if IR == 1
-	out_color = readReflection(fragPos, normal, 0.0);
+	out_color = readReflection(clusterIndex, fragPos, normal, 0.0);
 #endif
 #endif
 }

+ 1 - 0
src/core/Trace.cpp

@@ -25,6 +25,7 @@ static Array<const char*, U(TraceEventType::COUNT)> eventNames = {{
 	"RENDER_MS",
 	"RENDER_IS",
 	"RENDER_SM",
+	"RENDER_IR",
 	"RENDER_DRAWER",
 	"GL_THREAD",
 	"SWAP_BUFFERS"

+ 1 - 1
src/renderer/Clusterer.cpp

@@ -286,7 +286,7 @@ void Clusterer::binSphere(const Sphere& s, const Aabb& aabb,
 	for(Vec4& p : points)
 	{
 		p = vp * p;
-		p /= abs(p.w());
+		p = p.perspectiveDivide();
 
 		for(U i = 0; i < 2; ++i)
 		{

+ 202 - 20
src/renderer/Ir.cpp

@@ -6,11 +6,13 @@
 #include <anki/renderer/Ir.h>
 #include <anki/renderer/Is.h>
 #include <anki/renderer/Pps.h>
+#include <anki/renderer/Clusterer.h>
 #include <anki/core/Config.h>
 #include <anki/scene/SceneNode.h>
 #include <anki/scene/Visibility.h>
 #include <anki/scene/FrustumComponent.h>
 #include <anki/scene/ReflectionProbeComponent.h>
+#include <anki/core/Trace.h>
 
 namespace anki {
 
@@ -26,6 +28,72 @@ struct ShaderReflectionProbe
 	U32 _m_pading[3];
 };
 
+struct ShaderCluster
+{
+	/// If m_combo = 0xFFFFAAAA then FFFF is the probe index offset, AAAA the
+	/// number of probes
+	U32 m_combo;
+};
+
+static const U MAX_PROBES_PER_CLUSTER = 16;
+
+/// Store the probe radius for sorting the indices.
+class ClusterDataIndex
+{
+public:
+	U32 m_index = 0;
+	F32 m_probeRadius = 0.0;
+};
+
+class IrClusterData
+{
+public:
+	U32 m_probeCount = 0;
+	Array<ClusterDataIndex, MAX_PROBES_PER_CLUSTER> m_probeIds;
+
+	Bool operator==(const IrClusterData& b) const
+	{
+		if(m_probeCount != b.m_probeCount)
+		{
+			return false;
+		}
+
+		if(m_probeCount > 0)
+		{
+			if(memcmp(&m_probeIds[0], &b.m_probeIds[0],
+				sizeof(U32) * m_probeCount) != 0)
+			{
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	/// Sort the indices from the smallest probe to the biggest.
+	void sort()
+	{
+		if(m_probeCount > 1)
+		{
+			std::sort(m_probeIds.getBegin(),
+				m_probeIds.getBegin() + m_probeCount,
+				[](const ClusterDataIndex& a, const ClusterDataIndex& b)
+			{
+				ANKI_ASSERT(a.m_probeRadius > 0.0 && b.m_probeRadius > 0.0);
+				return a.m_probeRadius < b.m_probeRadius;
+			});
+		}
+	}
+};
+
+class IrBuildContext
+{
+public:
+	DArray<IrClusterData> m_clusterData;
+	U32 m_indexCount = 0;
+	ClustererTestResult m_clustererTestResult;
+};
+
 //==============================================================================
 // Ir                                                                          =
 //==============================================================================
@@ -108,52 +176,166 @@ Error Ir::init(const ConfigSet& initializer)
 //==============================================================================
 Error Ir::run(CommandBufferPtr cmdb)
 {
+	ANKI_TRACE_START_EVENT(RENDER_IR);
 	FrustumComponent& frc = m_r->getActiveFrustumComponent();
 	VisibilityTestResults& visRez = frc.getVisibilityTestResults();
 
-
 	if(visRez.getReflectionProbeCount() > m_cubemapArrSize)
 	{
 		ANKI_LOGW("Increase the ir.cubemapTextureArraySize");
 	}
 
-	// Do the probes
-	const VisibleNode* it = visRez.getReflectionProbesBegin();
-	const VisibleNode* end = visRez.getReflectionProbesEnd();
+	IrBuildContext ctx;
+
+	//
+	// Perform some allocations
+	//
 
+	// Allocate temp mem for clusters
+	ctx.m_clusterData.create(getFrameAllocator(), m_r->getClusterCount());
+
+	// Probes
 	void* data = getGrManager().allocateFrameHostVisibleMemory(
 		sizeof(ShaderReflectionProbe) * visRez.getReflectionProbeCount()
-		+ sizeof(Mat3x4) + sizeof(UVec4),
+		+ sizeof(Mat3x4),
 		BufferUsage::STORAGE, m_probesToken);
 
-	UVec4* counts = static_cast<UVec4*>(data);
-	counts->x() = visRez.getReflectionProbeCount();
-
-	Mat3x4* invViewRotation = reinterpret_cast<Mat3x4*>(counts + 1);
+	Mat3x4* invViewRotation = static_cast<Mat3x4*>(data);
 	*invViewRotation =
 		Mat3x4(frc.getViewMatrix().getInverse().getRotationPart());
 
-	ShaderReflectionProbe* probes = reinterpret_cast<ShaderReflectionProbe*>(
-		invViewRotation + 1);
-	ShaderReflectionProbe* probesBegin = probes;
+	SArray<ShaderReflectionProbe> probes(
+		reinterpret_cast<ShaderReflectionProbe*>(invViewRotation + 1),
+		visRez.getReflectionProbeCount());
 
+	//
+	// Render and bin the probes
+	//
+	const VisibleNode* it = visRez.getReflectionProbesBegin();
+	const VisibleNode* end = visRez.getReflectionProbesEnd();
+
+	m_r->getClusterer().initTestResults(getFrameAllocator(),
+		ctx.m_clustererTestResult);
+
+	U probeIdx = 0;
 	while(it != end)
 	{
-		ANKI_CHECK(renderReflection(*it->m_node, *probes));
+		// Render the probe
+		ANKI_CHECK(renderReflection(*it->m_node, probes[probeIdx]));
+
+		// Bin the probe
+		binProbe(*it->m_node, probeIdx, ctx);
+
 		++it;
-		++probes;
+		++probeIdx;
 	}
+	ANKI_ASSERT(probeIdx == visRez.getReflectionProbeCount());
 
-	// Sort the probes to satisfy hierarchy
-	std::sort(probesBegin, probes, [](const ShaderReflectionProbe& a,
-		const ShaderReflectionProbe& b) -> Bool
-	{
-		return a.m_radiusSq < b.m_radiusSq;
-	});
+	//
+	// Populate the index buffer and the clusters
+	//
+	populateIndexAndClusterBuffers(ctx);
 
+	// Bye
+	ctx.m_clusterData.destroy(getFrameAllocator());
+	ANKI_TRACE_STOP_EVENT(RENDER_IR);
 	return ErrorCode::NONE;
 }
 
+//==============================================================================
+void Ir::populateIndexAndClusterBuffers(IrBuildContext& ctx)
+{
+	// Allocate GPU mem for indices
+	SArray<U32> indices;
+	if(ctx.m_indexCount > 0)
+	{
+		void* mem = getGrManager().allocateFrameHostVisibleMemory(
+			ctx.m_indexCount * sizeof(U32), BufferUsage::STORAGE,
+			m_indicesToken);
+
+		indices = SArray<U32>(static_cast<U32*>(mem), ctx.m_indexCount);
+	}
+	else
+	{
+		m_indicesToken.markUnused();
+	}
+
+	U indexCount = 0;
+
+	// Allocate GPU mem for clusters
+	void* mem = getGrManager().allocateFrameHostVisibleMemory(
+		m_r->getClusterCount() * sizeof(ShaderCluster), BufferUsage::STORAGE,
+		m_clustersToken);
+	SArray<ShaderCluster> clusters(static_cast<ShaderCluster*>(mem),
+		m_r->getClusterCount());
+
+	for(U i = 0; i < m_r->getClusterCount(); ++i)
+	{
+		IrClusterData& cdata = ctx.m_clusterData[i];
+		ShaderCluster& cluster = clusters[i];
+
+		if(cdata.m_probeCount > 0)
+		{
+			// Sort to satisfy the probe hierarchy
+			cdata.sort();
+
+			// Check if the cdata is the same for the previous
+			if(i > 0 && cdata == ctx.m_clusterData[i - 1])
+			{
+				// Same data
+				cluster.m_combo = clusters[i - 1].m_combo;
+			}
+			else
+			{
+				// Have to store the indices
+				cluster.m_combo = (indexCount << 16) | cdata.m_probeCount;
+				for(U j = 0; j < cdata.m_probeCount; ++j)
+				{
+					indices[indexCount] = cdata.m_probeIds[j].m_index;
+					++indexCount;
+				}
+			}
+		}
+		else
+		{
+			cluster.m_combo = 0;
+		}
+	}
+}
+
+//==============================================================================
+void Ir::binProbe(const SceneNode& node, U index, IrBuildContext& ctx)
+{
+	const SpatialComponent& sp = node.getComponent<SpatialComponent>();
+	const ReflectionProbeComponent& reflc =
+		node.getComponent<ReflectionProbeComponent>();
+
+	m_r->getClusterer().bin(sp.getSpatialCollisionShape(), sp.getAabb(),
+		ctx.m_clustererTestResult);
+
+	// Bin to the correct tiles
+	auto it = ctx.m_clustererTestResult.getClustersBegin();
+	auto end = ctx.m_clustererTestResult.getClustersEnd();
+	for(; it != end; ++it)
+	{
+		U x = (*it)[0];
+		U y = (*it)[1];
+		U z = (*it)[2];
+
+		U i =
+			m_r->getTileCountXY().x() * (z * m_r->getTileCountXY().y() + y) + x;
+
+		auto& cluster = ctx.m_clusterData[i];
+
+		i = cluster.m_probeCount % MAX_PROBES_PER_CLUSTER;
+		++cluster.m_probeCount;
+		cluster.m_probeIds[i].m_index = index;
+		cluster.m_probeIds[i].m_probeRadius = reflc.getRadius();
+
+		++ctx.m_indexCount;
+	}
+}
+
 //==============================================================================
 Error Ir::renderReflection(SceneNode& node, ShaderReflectionProbe& shaderProb)
 {

+ 5 - 0
src/renderer/Is.cpp

@@ -319,6 +319,8 @@ Error Is::initInternal(const ConfigSet& config)
 		if(m_r->irEnabled())
 		{
 			init.m_storageBuffers[5].m_dynamic = true;
+			init.m_storageBuffers[6].m_dynamic = true;
+			init.m_storageBuffers[7].m_dynamic = true;
 		}
 
 		m_rcGroup = getGrManager().newInstance<ResourceGroup>(init);
@@ -764,6 +766,9 @@ void Is::setState(CommandBufferPtr& cmdb)
 	if(m_r->irEnabled())
 	{
 		dyn.m_storageBuffers[5] = m_r->getIr().getProbesToken();
+		dyn.m_storageBuffers[6] = m_r->getIr().getProbeIndicesToken();
+		dyn.m_storageBuffers[7] = m_r->getIr().getClustersToken();
+
 	}
 
 	cmdb->bindResourceGroup(m_rcGroup, 0, &dyn);

+ 4 - 1
src/renderer/MainRenderer.cpp

@@ -46,7 +46,7 @@ Error MainRenderer::create(
 
 	m_alloc = HeapAllocator<U8>(allocCb, allocCbUserData);
 	m_frameAlloc = StackAllocator<U8>(allocCb, allocCbUserData,
-		1024 * 1024 * 5);
+		1024 * 1024 * 10);
 
 	// Init default FB
 	m_width = config.getNumber("width");
@@ -107,6 +107,9 @@ Error MainRenderer::render(SceneGraph& scene)
 {
 	ANKI_TRACE_START_EVENT(RENDER);
 
+	// First thing, reset the temp mem pool
+	m_frameAlloc.getMemoryPool().reset();
+
 	GrManager& gl = m_r->getGrManager();
 	Array<CommandBufferPtr, RENDERER_COMMAND_BUFFERS_COUNT> cmdbs;
 	CommandBufferPtr& cmdb = cmdbs[RENDERER_COMMAND_BUFFERS_COUNT - 1];

+ 0 - 2
src/renderer/Renderer.cpp

@@ -154,8 +154,6 @@ Error Renderer::render(SceneNode& frustumableNode, U frustumIdx,
 	(void)err;
 	ANKI_ASSERT(m_frc && "Not enough frustum components");
 
-	m_frameAlloc.getMemoryPool().reset();
-
 	// Calc a few vars
 	//
 	if(m_frc->getProjectionParameters() != m_projectionParams)

+ 1 - 1
testapp/Main.cpp

@@ -42,7 +42,7 @@ App* app;
 ModelNode* horse;
 PerspectiveCamera* cam;
 
-#define PLAYER 1
+#define PLAYER 0
 #define MOUSE 1
 
 Bool profile = false;