Browse Source

Move the reflection cube to the reflection component

Panagiotis Christopoulos Charitos 2 years ago
parent
commit
e2460c123b

+ 1 - 1
AnKi/Gr/Texture.h

@@ -18,7 +18,7 @@ class alignas(4) TextureInitInfo : public GrBaseInitInfo
 public:
 public:
 	U32 m_width = 0;
 	U32 m_width = 0;
 	U32 m_height = 0;
 	U32 m_height = 0;
-	U32 m_depth = 1; //< Relevant only for 3D textures.
+	U32 m_depth = 1; ///< Relevant only for 3D textures.
 	U32 m_layerCount = 1; ///< Relevant only for texture arrays.
 	U32 m_layerCount = 1; ///< Relevant only for texture arrays.
 
 
 	Format m_format = Format::kNone;
 	Format m_format = Format::kNone;

+ 1 - 1
AnKi/Renderer/ClusterBinning.cpp

@@ -311,7 +311,7 @@ void ClusterBinning::writeClustererBuffersTask()
 			ReflectionProbe& out = probes[i];
 			ReflectionProbe& out = probes[i];
 
 
 			out.m_position = in.m_worldPosition;
 			out.m_position = in.m_worldPosition;
-			out.m_cubemapIndex = F32(in.m_textureArrayIndex);
+			out.m_cubeTexture = in.m_textureBindlessIndex;
 			out.m_aabbMin = in.m_aabbMin;
 			out.m_aabbMin = in.m_aabbMin;
 			out.m_aabbMax = in.m_aabbMax;
 			out.m_aabbMax = in.m_aabbMax;
 		}
 		}

+ 0 - 2
AnKi/Renderer/ConfigVars.defs.h

@@ -67,9 +67,7 @@ ANKI_CONFIG_VAR_U32(RShadowMappingTileCountPerRowOrColumn, 32, 1, 256,
 ANKI_CONFIG_VAR_U32(RShadowMappingPcf, ((ANKI_PLATFORM_MOBILE) ? 0 : 1), 0, 1, "Shadow PCF (0: off, 1: on)")
 ANKI_CONFIG_VAR_U32(RShadowMappingPcf, ((ANKI_PLATFORM_MOBILE) ? 0 : 1), 0, 1, "Shadow PCF (0: off, 1: on)")
 
 
 // Probe reflections
 // Probe reflections
-ANKI_CONFIG_VAR_U32(RProbeReflectionResolution, 128, 4, 2048, "Reflection probe face resolution")
 ANKI_CONFIG_VAR_U32(RProbeReflectionIrradianceResolution, 16, 4, 2048, "Reflection probe irradiance resolution")
 ANKI_CONFIG_VAR_U32(RProbeReflectionIrradianceResolution, 16, 4, 2048, "Reflection probe irradiance resolution")
-ANKI_CONFIG_VAR_U32(RProbeRefectionMaxCachedProbes, 32, 4, 256, "Max cached number of reflection probes")
 ANKI_CONFIG_VAR_U32(RProbeReflectionShadowMapResolution, 64, 4, 2048, "Reflection probe shadow resolution")
 ANKI_CONFIG_VAR_U32(RProbeReflectionShadowMapResolution, 64, 4, 2048, "Reflection probe shadow resolution")
 
 
 // Final composite
 // Final composite

+ 8 - 4
AnKi/Renderer/IndirectSpecular.cpp

@@ -153,7 +153,10 @@ void IndirectSpecular::populateRenderGraph(RenderingContext& ctx)
 			min(getExternalSubsystems().m_config->getRSsrDepthLod() + 1, m_r->getDepthDownscale().getMipmapCount());
 			min(getExternalSubsystems().m_config->getRSsrDepthLod() + 1, m_r->getDepthDownscale().getMipmapCount());
 		ppass->newTextureDependency(m_r->getDepthDownscale().getHiZRt(), readUsage, hizSubresource);
 		ppass->newTextureDependency(m_r->getDepthDownscale().getHiZRt(), readUsage, hizSubresource);
 
 
-		ppass->newTextureDependency(m_r->getProbeReflections().getReflectionRt(), readUsage);
+		if(m_r->getProbeReflections().getHasCurrentlyRefreshedReflectionRt())
+		{
+			ppass->newTextureDependency(m_r->getProbeReflections().getCurrentlyRefreshedReflectionRt(), readUsage);
+		}
 
 
 		ppass->newTextureDependency(m_r->getMotionVectors().getMotionVectorsRt(), readUsage);
 		ppass->newTextureDependency(m_r->getMotionVectors().getMotionVectorsRt(), readUsage);
 		ppass->newTextureDependency(m_r->getMotionVectors().getHistoryLengthRt(), readUsage);
 		ppass->newTextureDependency(m_r->getMotionVectors().getHistoryLengthRt(), readUsage);
@@ -210,12 +213,13 @@ void IndirectSpecular::run(const RenderingContext& ctx, RenderPassWorkContext& r
 	const ClusteredShadingContext& binning = ctx.m_clusteredShading;
 	const ClusteredShadingContext& binning = ctx.m_clusteredShading;
 	bindUniforms(cmdb, 0, 11, binning.m_clusteredShadingUniformsToken);
 	bindUniforms(cmdb, 0, 11, binning.m_clusteredShadingUniformsToken);
 	bindUniforms(cmdb, 0, 12, binning.m_reflectionProbesToken);
 	bindUniforms(cmdb, 0, 12, binning.m_reflectionProbesToken);
-	rgraphCtx.bindColorTexture(0, 13, m_r->getProbeReflections().getReflectionRt());
-	bindStorage(cmdb, 0, 14, binning.m_clustersToken);
+	bindStorage(cmdb, 0, 13, binning.m_clustersToken);
+
+	cmdb->bindAllBindless(1);
 
 
 	if(getExternalSubsystems().m_config->getRPreferCompute())
 	if(getExternalSubsystems().m_config->getRPreferCompute())
 	{
 	{
-		rgraphCtx.bindImage(0, 15, m_runCtx.m_rts[kWrite], TextureSubresourceInfo());
+		rgraphCtx.bindImage(0, 14, m_runCtx.m_rts[kWrite], TextureSubresourceInfo());
 
 
 		dispatchPPCompute(cmdb, 8, 8, m_r->getInternalResolution().x() / 2, m_r->getInternalResolution().y() / 2);
 		dispatchPPCompute(cmdb, 8, 8, m_r->getInternalResolution().x() / 2, m_r->getInternalResolution().y() / 2);
 	}
 	}

+ 34 - 184
AnKi/Renderer/ProbeReflections.cpp

@@ -23,8 +23,6 @@ ProbeReflections::ProbeReflections(Renderer* r)
 
 
 ProbeReflections::~ProbeReflections()
 ProbeReflections::~ProbeReflections()
 {
 {
-	m_cacheEntries.destroy(getMemoryPool());
-	m_probeUuidToCacheEntryIdx.destroy(getMemoryPool());
 }
 }
 
 
 Error ProbeReflections::init()
 Error ProbeReflections::init()
@@ -41,8 +39,6 @@ Error ProbeReflections::init()
 Error ProbeReflections::initInternal()
 Error ProbeReflections::initInternal()
 {
 {
 	// Init cache entries
 	// Init cache entries
-	m_cacheEntries.create(getMemoryPool(), getExternalSubsystems().m_config->getRProbeRefectionMaxCachedProbes());
-
 	ANKI_CHECK(initGBuffer());
 	ANKI_CHECK(initGBuffer());
 	ANKI_CHECK(initLightShading());
 	ANKI_CHECK(initLightShading());
 	ANKI_CHECK(initIrradiance());
 	ANKI_CHECK(initIrradiance());
@@ -65,7 +61,7 @@ Error ProbeReflections::initInternal()
 
 
 Error ProbeReflections::initGBuffer()
 Error ProbeReflections::initGBuffer()
 {
 {
-	m_gbuffer.m_tileSize = getExternalSubsystems().m_config->getRProbeReflectionResolution();
+	m_gbuffer.m_tileSize = getExternalSubsystems().m_config->getSceneReflectionProbeResolution();
 
 
 	// Create RT descriptions
 	// Create RT descriptions
 	{
 	{
@@ -110,22 +106,18 @@ Error ProbeReflections::initGBuffer()
 
 
 Error ProbeReflections::initLightShading()
 Error ProbeReflections::initLightShading()
 {
 {
-	m_lightShading.m_tileSize = getExternalSubsystems().m_config->getRProbeReflectionResolution();
+	m_lightShading.m_tileSize = getExternalSubsystems().m_config->getSceneReflectionProbeResolution();
 	m_lightShading.m_mipCount = computeMaxMipmapCount2d(m_lightShading.m_tileSize, m_lightShading.m_tileSize, 8);
 	m_lightShading.m_mipCount = computeMaxMipmapCount2d(m_lightShading.m_tileSize, m_lightShading.m_tileSize, 8);
 
 
-	// Init cube arr
+	for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
 	{
 	{
-		TextureInitInfo texinit = m_r->create2DRenderTargetInitInfo(
-			m_lightShading.m_tileSize, m_lightShading.m_tileSize, m_r->getHdrFormat(),
-			TextureUsageBit::kSampledFragment | TextureUsageBit::kSampledCompute | TextureUsageBit::kImageComputeRead
-				| TextureUsageBit::kImageComputeWrite | TextureUsageBit::kAllFramebuffer
-				| TextureUsageBit::kGenerateMipmaps,
-			"CubeRefl refl");
-		texinit.m_mipmapCount = U8(m_lightShading.m_mipCount);
-		texinit.m_type = TextureType::kCubeArray;
-		texinit.m_layerCount = m_cacheEntries.getSize();
-
-		m_lightShading.m_cubeArr = m_r->createAndClearRenderTarget(texinit, TextureUsageBit::kSampledFragment);
+		// Light pass FB
+		FramebufferDescription& fbDescr = m_lightShading.m_fbDescr[faceIdx];
+		ANKI_ASSERT(!fbDescr.isBacked());
+		fbDescr.m_colorAttachmentCount = 1;
+		fbDescr.m_colorAttachments[0].m_surface.m_face = faceIdx;
+		fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::kClear;
+		fbDescr.bake();
 	}
 	}
 
 
 	// Init deferred
 	// Init deferred
@@ -200,131 +192,11 @@ Error ProbeReflections::initShadowMapping()
 	return Error::kNone;
 	return Error::kNone;
 }
 }
 
 
-void ProbeReflections::initCacheEntry(U32 cacheEntryIdx)
-{
-	CacheEntry& cacheEntry = m_cacheEntries[cacheEntryIdx];
-
-	for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
-	{
-		// Light pass FB
-		FramebufferDescription& fbDescr = cacheEntry.m_lightShadingFbDescrs[faceIdx];
-		ANKI_ASSERT(!fbDescr.isBacked());
-		fbDescr.m_colorAttachmentCount = 1;
-		fbDescr.m_colorAttachments[0].m_surface.m_layer = cacheEntryIdx;
-		fbDescr.m_colorAttachments[0].m_surface.m_face = faceIdx;
-		fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::kClear;
-		fbDescr.bake();
-	}
-}
-
-void ProbeReflections::prepareProbes(RenderingContext& ctx, ReflectionProbeQueueElement*& probeToUpdateThisFrame,
-									 U32& probeToUpdateThisFrameCacheEntryIdx)
-{
-	probeToUpdateThisFrame = nullptr;
-	probeToUpdateThisFrameCacheEntryIdx = kMaxU32;
-
-	if(ctx.m_renderQueue->m_reflectionProbes.getSize() == 0) [[unlikely]]
-	{
-		return;
-	}
-
-	// Iterate the probes and:
-	// - Find a probe to update this frame
-	// - Find a probe to update next frame
-	// - Find the cache entries for each probe
-	DynamicArray<ReflectionProbeQueueElement> newListOfProbes;
-	newListOfProbes.create(*ctx.m_tempPool, ctx.m_renderQueue->m_reflectionProbes.getSize());
-	U32 newListOfProbeCount = 0;
-	Bool foundProbeToUpdateNextFrame = false;
-	for(U32 probeIdx = 0; probeIdx < ctx.m_renderQueue->m_reflectionProbes.getSize(); ++probeIdx)
-	{
-		ReflectionProbeQueueElement& probe = ctx.m_renderQueue->m_reflectionProbes[probeIdx];
-
-		// Find cache entry
-		const U32 cacheEntryIdx = findBestCacheEntry(probe.m_uuid, *getExternalSubsystems().m_globTimestamp,
-													 m_cacheEntries, m_probeUuidToCacheEntryIdx, getMemoryPool());
-		if(cacheEntryIdx == kMaxU32) [[unlikely]]
-		{
-			// Failed
-			ANKI_R_LOGW("There is not enough space in the indirect lighting atlas for more probes. "
-						"Increase the r_probeRefectionlMaxSimultaneousProbeCount or decrease the scene's probes");
-			continue;
-		}
-
-		const Bool probeFoundInCache = m_cacheEntries[cacheEntryIdx].m_uuid == probe.m_uuid;
-
-		// Check if we _should_ and _can_ update the probe
-		const Bool needsUpdate = !probeFoundInCache;
-		if(needsUpdate) [[unlikely]]
-		{
-			const Bool canUpdateThisFrame = probeToUpdateThisFrame == nullptr && probe.m_renderQueues[0] != nullptr;
-			const Bool canUpdateNextFrame = !foundProbeToUpdateNextFrame;
-
-			if(!canUpdateThisFrame && canUpdateNextFrame)
-			{
-				// Probe will be updated next frame
-				foundProbeToUpdateNextFrame = true;
-				probe.m_feedbackCallback(true, probe.m_feedbackCallbackUserData);
-				continue;
-			}
-			else if(!canUpdateThisFrame)
-			{
-				// Can't be updated this frame so remove it from the list
-				continue;
-			}
-			else
-			{
-				// Can be updated this frame so continue with it
-				probeToUpdateThisFrameCacheEntryIdx = cacheEntryIdx;
-				probeToUpdateThisFrame = &newListOfProbes[newListOfProbeCount];
-			}
-		}
-
-		// All good, can use this probe in this frame
-
-		// Update the cache entry
-		m_cacheEntries[cacheEntryIdx].m_uuid = probe.m_uuid;
-		m_cacheEntries[cacheEntryIdx].m_lastUsedTimestamp = *getExternalSubsystems().m_globTimestamp;
-
-		// Update the probe
-		probe.m_textureArrayIndex = cacheEntryIdx;
-
-		// Push the probe to the new list
-		newListOfProbes[newListOfProbeCount++] = probe;
-
-		// Update cache map
-		if(!probeFoundInCache)
-		{
-			m_probeUuidToCacheEntryIdx.emplace(getMemoryPool(), probe.m_uuid, cacheEntryIdx);
-		}
-
-		// Don't gather renderables next frame
-		if(probe.m_renderQueues[0] != nullptr)
-		{
-			probe.m_feedbackCallback(false, probe.m_feedbackCallbackUserData);
-		}
-	}
-
-	// Replace the probe list in the queue
-	if(newListOfProbeCount > 0)
-	{
-		ReflectionProbeQueueElement* firstProbe;
-		U32 probeCount, storage;
-		newListOfProbes.moveAndReset(firstProbe, probeCount, storage);
-		ctx.m_renderQueue->m_reflectionProbes = WeakArray<ReflectionProbeQueueElement>(firstProbe, newListOfProbeCount);
-	}
-	else
-	{
-		ctx.m_renderQueue->m_reflectionProbes = WeakArray<ReflectionProbeQueueElement>();
-		newListOfProbes.destroy(*ctx.m_tempPool);
-	}
-}
-
 void ProbeReflections::runGBuffer(RenderPassWorkContext& rgraphCtx)
 void ProbeReflections::runGBuffer(RenderPassWorkContext& rgraphCtx)
 {
 {
 	ANKI_ASSERT(m_ctx.m_probe);
 	ANKI_ASSERT(m_ctx.m_probe);
 	ANKI_TRACE_SCOPED_EVENT(RCubeRefl);
 	ANKI_TRACE_SCOPED_EVENT(RCubeRefl);
-	const ReflectionProbeQueueElement& probe = *m_ctx.m_probe;
+	const ReflectionProbeQueueElementForRefresh& probe = *m_ctx.m_probe;
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 
 
 	I32 start, end;
 	I32 start, end;
@@ -376,7 +248,7 @@ void ProbeReflections::runLightShading(U32 faceIdx, const RenderingContext& rctx
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 
 
 	ANKI_ASSERT(m_ctx.m_probe);
 	ANKI_ASSERT(m_ctx.m_probe);
-	const ReflectionProbeQueueElement& probe = *m_ctx.m_probe;
+	const ReflectionProbeQueueElementForRefresh& probe = *m_ctx.m_probe;
 	const RenderQueue& rqueue = *probe.m_renderQueues[faceIdx];
 	const RenderQueue& rqueue = *probe.m_renderQueues[faceIdx];
 	const Bool hasDirLight = probe.m_renderQueues[0]->m_directionalLight.m_uuid;
 	const Bool hasDirLight = probe.m_renderQueues[0]->m_directionalLight.m_uuid;
 
 
@@ -414,11 +286,10 @@ void ProbeReflections::runLightShading(U32 faceIdx, const RenderingContext& rctx
 void ProbeReflections::runMipmappingOfLightShading(U32 faceIdx, RenderPassWorkContext& rgraphCtx)
 void ProbeReflections::runMipmappingOfLightShading(U32 faceIdx, RenderPassWorkContext& rgraphCtx)
 {
 {
 	ANKI_ASSERT(faceIdx < 6);
 	ANKI_ASSERT(faceIdx < 6);
-	ANKI_ASSERT(m_ctx.m_cacheEntryIdx < m_cacheEntries.getSize());
 
 
 	ANKI_TRACE_SCOPED_EVENT(RCubeRefl);
 	ANKI_TRACE_SCOPED_EVENT(RCubeRefl);
 
 
-	TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, m_ctx.m_cacheEntryIdx));
+	TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, 0));
 	subresource.m_mipmapCount = m_lightShading.m_mipCount;
 	subresource.m_mipmapCount = m_lightShading.m_mipCount;
 
 
 	TexturePtr texToBind;
 	TexturePtr texToBind;
@@ -431,8 +302,6 @@ void ProbeReflections::runMipmappingOfLightShading(U32 faceIdx, RenderPassWorkCo
 void ProbeReflections::runIrradiance(RenderPassWorkContext& rgraphCtx)
 void ProbeReflections::runIrradiance(RenderPassWorkContext& rgraphCtx)
 {
 {
 	ANKI_TRACE_SCOPED_EVENT(RCubeRefl);
 	ANKI_TRACE_SCOPED_EVENT(RCubeRefl);
-	const U32 cacheEntryIdx = m_ctx.m_cacheEntryIdx;
-	ANKI_ASSERT(cacheEntryIdx < m_cacheEntries.getSize());
 
 
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 
 
@@ -443,7 +312,6 @@ void ProbeReflections::runIrradiance(RenderPassWorkContext& rgraphCtx)
 
 
 	TextureSubresourceInfo subresource;
 	TextureSubresourceInfo subresource;
 	subresource.m_faceCount = 6;
 	subresource.m_faceCount = 6;
-	subresource.m_firstLayer = cacheEntryIdx;
 	rgraphCtx.bindTexture(0, 1, m_ctx.m_lightShadingRt, subresource);
 	rgraphCtx.bindTexture(0, 1, m_ctx.m_lightShadingRt, subresource);
 
 
 	cmdb->bindStorageBuffer(0, 3, m_irradiance.m_diceValuesBuff, 0, m_irradiance.m_diceValuesBuff->getSize());
 	cmdb->bindStorageBuffer(0, 3, m_irradiance.m_diceValuesBuff, 0, m_irradiance.m_diceValuesBuff->getSize());
@@ -456,9 +324,6 @@ void ProbeReflections::runIrradianceToRefl(RenderPassWorkContext& rgraphCtx)
 {
 {
 	ANKI_TRACE_SCOPED_EVENT(RCubeRefl);
 	ANKI_TRACE_SCOPED_EVENT(RCubeRefl);
 
 
-	const U32 cacheEntryIdx = m_ctx.m_cacheEntryIdx;
-	ANKI_ASSERT(cacheEntryIdx < m_cacheEntries.getSize());
-
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 
 
 	cmdb->bindShaderProgram(m_irradianceToRefl.m_grProg);
 	cmdb->bindShaderProgram(m_irradianceToRefl.m_grProg);
@@ -477,7 +342,6 @@ void ProbeReflections::runIrradianceToRefl(RenderPassWorkContext& rgraphCtx)
 		TextureSubresourceInfo subresource;
 		TextureSubresourceInfo subresource;
 		subresource.m_faceCount = 1;
 		subresource.m_faceCount = 1;
 		subresource.m_firstFace = f;
 		subresource.m_firstFace = f;
-		subresource.m_firstLayer = cacheEntryIdx;
 		rgraphCtx.bindImage(0, 3, m_ctx.m_lightShadingRt, subresource, f);
 		rgraphCtx.bindImage(0, 3, m_ctx.m_lightShadingRt, subresource, f);
 	}
 	}
 
 
@@ -488,32 +352,20 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 {
 {
 	ANKI_TRACE_SCOPED_EVENT(RCubeRefl);
 	ANKI_TRACE_SCOPED_EVENT(RCubeRefl);
 
 
-#if ANKI_EXTRA_CHECKS
-	m_ctx = {};
-#endif
-	RenderGraphDescription& rgraph = rctx.m_renderGraphDescr;
-
-	// Prepare the probes and maybe get one to render this frame
-	ReflectionProbeQueueElement* probeToUpdate;
-	U32 probeToUpdateCacheEntryIdx;
-	prepareProbes(rctx, probeToUpdate, probeToUpdateCacheEntryIdx);
-
-	// Render a probe if needed
-	if(!probeToUpdate)
+	if(rctx.m_renderQueue->m_reflectionProbeForRefresh == nullptr) [[likely]]
 	{
 	{
-		// Just import and exit
-
-		m_ctx.m_lightShadingRt = rgraph.importRenderTarget(m_lightShading.m_cubeArr, TextureUsageBit::kSampledFragment);
+		// Early exit
+		m_ctx.m_lightShadingRt = {};
 		return;
 		return;
 	}
 	}
 
 
-	m_ctx.m_cacheEntryIdx = probeToUpdateCacheEntryIdx;
-	m_ctx.m_probe = probeToUpdate;
+#if ANKI_EXTRA_CHECKS
+	m_ctx = {};
+#endif
 
 
-	if(!m_cacheEntries[probeToUpdateCacheEntryIdx].m_lightShadingFbDescrs[0].isBacked())
-	{
-		initCacheEntry(probeToUpdateCacheEntryIdx);
-	}
+	m_ctx.m_probe = rctx.m_renderQueue->m_reflectionProbeForRefresh;
+
+	RenderGraphDescription& rgraph = rctx.m_renderGraphDescr;
 
 
 	// G-buffer pass
 	// G-buffer pass
 	{
 	{
@@ -530,7 +382,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		m_ctx.m_gbufferRenderableCount = 0;
 		m_ctx.m_gbufferRenderableCount = 0;
 		for(U32 i = 0; i < 6; ++i)
 		for(U32 i = 0; i < 6; ++i)
 		{
 		{
-			m_ctx.m_gbufferRenderableCount += probeToUpdate->m_renderQueues[i]->m_renderables.getSize();
+			m_ctx.m_gbufferRenderableCount += m_ctx.m_probe->m_renderQueues[i]->m_renderables.getSize();
 		}
 		}
 		const U32 taskCount = computeNumberOfSecondLevelCommandBuffers(m_ctx.m_gbufferRenderableCount);
 		const U32 taskCount = computeNumberOfSecondLevelCommandBuffers(m_ctx.m_gbufferRenderableCount);
 
 
@@ -554,14 +406,14 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 	}
 	}
 
 
 	// Shadow pass. Optional
 	// Shadow pass. Optional
-	if(probeToUpdate->m_renderQueues[0]->m_directionalLight.m_uuid
-	   && probeToUpdate->m_renderQueues[0]->m_directionalLight.m_shadowCascadeCount > 0)
+	if(m_ctx.m_probe->m_renderQueues[0]->m_directionalLight.m_uuid
+	   && m_ctx.m_probe->m_renderQueues[0]->m_directionalLight.m_shadowCascadeCount > 0)
 	{
 	{
 		// Update light matrices
 		// Update light matrices
 		for(U i = 0; i < 6; ++i)
 		for(U i = 0; i < 6; ++i)
 		{
 		{
-			ANKI_ASSERT(probeToUpdate->m_renderQueues[i]->m_directionalLight.m_uuid
-						&& probeToUpdate->m_renderQueues[i]->m_directionalLight.m_shadowCascadeCount == 1);
+			ANKI_ASSERT(m_ctx.m_probe->m_renderQueues[i]->m_directionalLight.m_uuid
+						&& m_ctx.m_probe->m_renderQueues[i]->m_directionalLight.m_shadowCascadeCount == 1);
 
 
 			const F32 xScale = 1.0f / 6.0f;
 			const F32 xScale = 1.0f / 6.0f;
 			const F32 yScale = 1.0f;
 			const F32 yScale = 1.0f;
@@ -570,7 +422,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 			const Mat4 atlasMtx(xScale, 0.0f, 0.0f, xOffset, 0.0f, yScale, 0.0f, yOffset, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
 			const Mat4 atlasMtx(xScale, 0.0f, 0.0f, xOffset, 0.0f, yScale, 0.0f, yOffset, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
 								0.0f, 0.0f, 1.0f);
 								0.0f, 0.0f, 1.0f);
 
 
-			Mat4& lightMat = probeToUpdate->m_renderQueues[i]->m_directionalLight.m_textureMatrices[0];
+			Mat4& lightMat = m_ctx.m_probe->m_renderQueues[i]->m_directionalLight.m_textureMatrices[0];
 			lightMat = atlasMtx * lightMat;
 			lightMat = atlasMtx * lightMat;
 		}
 		}
 
 
@@ -579,7 +431,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		for(U32 i = 0; i < 6; ++i)
 		for(U32 i = 0; i < 6; ++i)
 		{
 		{
 			m_ctx.m_shadowRenderableCount +=
 			m_ctx.m_shadowRenderableCount +=
-				probeToUpdate->m_renderQueues[i]->m_directionalLight.m_shadowRenderQueues[0]->m_renderables.getSize();
+				m_ctx.m_probe->m_renderQueues[i]->m_directionalLight.m_shadowRenderQueues[0]->m_renderables.getSize();
 		}
 		}
 		const U32 taskCount = computeNumberOfSecondLevelCommandBuffers(m_ctx.m_shadowRenderableCount);
 		const U32 taskCount = computeNumberOfSecondLevelCommandBuffers(m_ctx.m_shadowRenderableCount);
 
 
@@ -607,7 +459,8 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 	// Light shading passes
 	// Light shading passes
 	{
 	{
 		// RT
 		// RT
-		m_ctx.m_lightShadingRt = rgraph.importRenderTarget(m_lightShading.m_cubeArr, TextureUsageBit::kSampledFragment);
+		m_ctx.m_lightShadingRt =
+			rgraph.importRenderTarget(TexturePtr(m_ctx.m_probe->m_reflectionTexture), TextureUsageBit::kNone);
 
 
 		// Passes
 		// Passes
 		static constexpr Array<CString, 6> passNames = {"CubeRefl LightShad #0", "CubeRefl LightShad #1",
 		static constexpr Array<CString, 6> passNames = {"CubeRefl LightShad #0", "CubeRefl LightShad #1",
@@ -616,13 +469,12 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
 		for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
 		{
 		{
 			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
 			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
-			pass.setFramebufferInfo(m_cacheEntries[probeToUpdateCacheEntryIdx].m_lightShadingFbDescrs[faceIdx],
-									{m_ctx.m_lightShadingRt});
+			pass.setFramebufferInfo(m_lightShading.m_fbDescr[faceIdx], {m_ctx.m_lightShadingRt});
 			pass.setWork([this, faceIdx, &rctx](RenderPassWorkContext& rgraphCtx) {
 			pass.setWork([this, faceIdx, &rctx](RenderPassWorkContext& rgraphCtx) {
 				runLightShading(faceIdx, rctx, rgraphCtx);
 				runLightShading(faceIdx, rctx, rgraphCtx);
 			});
 			});
 
 
-			TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
+			TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, 0));
 			pass.newTextureDependency(m_ctx.m_lightShadingRt, TextureUsageBit::kFramebufferWrite, subresource);
 			pass.newTextureDependency(m_ctx.m_lightShadingRt, TextureUsageBit::kFramebufferWrite, subresource);
 
 
 			for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
 			for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)
@@ -653,7 +505,6 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		// Read a cube but only one layer and level
 		// Read a cube but only one layer and level
 		TextureSubresourceInfo readSubresource;
 		TextureSubresourceInfo readSubresource;
 		readSubresource.m_faceCount = 6;
 		readSubresource.m_faceCount = 6;
-		readSubresource.m_firstLayer = probeToUpdateCacheEntryIdx;
 		pass.newTextureDependency(m_ctx.m_lightShadingRt, TextureUsageBit::kSampledCompute, readSubresource);
 		pass.newTextureDependency(m_ctx.m_lightShadingRt, TextureUsageBit::kSampledCompute, readSubresource);
 
 
 		pass.newBufferDependency(m_ctx.m_irradianceDiceValuesBuffHandle, BufferUsageBit::kStorageComputeWrite);
 		pass.newBufferDependency(m_ctx.m_irradianceDiceValuesBuffHandle, BufferUsageBit::kStorageComputeWrite);
@@ -674,7 +525,6 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 
 
 		TextureSubresourceInfo subresource;
 		TextureSubresourceInfo subresource;
 		subresource.m_faceCount = 6;
 		subresource.m_faceCount = 6;
-		subresource.m_firstLayer = probeToUpdateCacheEntryIdx;
 		pass.newTextureDependency(m_ctx.m_lightShadingRt,
 		pass.newTextureDependency(m_ctx.m_lightShadingRt,
 								  TextureUsageBit::kImageComputeRead | TextureUsageBit::kImageComputeWrite,
 								  TextureUsageBit::kImageComputeRead | TextureUsageBit::kImageComputeWrite,
 								  subresource);
 								  subresource);
@@ -693,7 +543,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 				runMipmappingOfLightShading(faceIdx, rgraphCtx);
 				runMipmappingOfLightShading(faceIdx, rgraphCtx);
 			});
 			});
 
 
-			TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
+			TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, 0));
 			subresource.m_mipmapCount = m_lightShading.m_mipCount;
 			subresource.m_mipmapCount = m_lightShading.m_mipCount;
 
 
 			pass.newTextureDependency(m_ctx.m_lightShadingRt, TextureUsageBit::kGenerateMipmaps, subresource);
 			pass.newTextureDependency(m_ctx.m_lightShadingRt, TextureUsageBit::kGenerateMipmaps, subresource);

+ 9 - 23
AnKi/Renderer/ProbeReflections.h

@@ -45,11 +45,17 @@ public:
 		return m_integrationLutSampler;
 		return m_integrationLutSampler;
 	}
 	}
 
 
-	RenderTargetHandle getReflectionRt() const
+	RenderTargetHandle getCurrentlyRefreshedReflectionRt() const
 	{
 	{
+		ANKI_ASSERT(m_ctx.m_lightShadingRt.isValid());
 		return m_ctx.m_lightShadingRt;
 		return m_ctx.m_lightShadingRt;
 	}
 	}
 
 
+	Bool getHasCurrentlyRefreshedReflectionRt() const
+	{
+		return m_ctx.m_lightShadingRt.isValid();
+	}
+
 private:
 private:
 	class
 	class
 	{
 	{
@@ -65,8 +71,7 @@ private:
 	public:
 	public:
 		U32 m_tileSize = 0;
 		U32 m_tileSize = 0;
 		U32 m_mipCount = 0;
 		U32 m_mipCount = 0;
-		TexturePtr m_cubeArr;
-
+		Array<FramebufferDescription, 6> m_fbDescr;
 		TraditionalDeferredLightShading m_deferred;
 		TraditionalDeferredLightShading m_deferred;
 
 
 		LS(Renderer* r)
 		LS(Renderer* r)
@@ -98,18 +103,6 @@ private:
 		FramebufferDescription m_fbDescr;
 		FramebufferDescription m_fbDescr;
 	} m_shadowMapping;
 	} m_shadowMapping;
 
 
-	class CacheEntry
-	{
-	public:
-		U64 m_uuid; ///< Probe UUID.
-		Timestamp m_lastUsedTimestamp = 0; ///< When it was last seen by the renderer.
-
-		Array<FramebufferDescription, 6> m_lightShadingFbDescrs;
-	};
-
-	DynamicArray<CacheEntry> m_cacheEntries;
-	HashMap<U64, U32> m_probeUuidToCacheEntryIdx;
-
 	// Other
 	// Other
 	ImageResourcePtr m_integrationLut;
 	ImageResourcePtr m_integrationLut;
 	SamplerPtr m_integrationLutSampler;
 	SamplerPtr m_integrationLutSampler;
@@ -117,8 +110,7 @@ private:
 	class
 	class
 	{
 	{
 	public:
 	public:
-		const ReflectionProbeQueueElement* m_probe = nullptr;
-		U32 m_cacheEntryIdx = kMaxU32;
+		const ReflectionProbeQueueElementForRefresh* m_probe = nullptr;
 
 
 		Array<RenderTargetHandle, kGBufferColorRenderTargetCount> m_gbufferColorRts;
 		Array<RenderTargetHandle, kGBufferColorRenderTargetCount> m_gbufferColorRts;
 		RenderTargetHandle m_gbufferDepthRt;
 		RenderTargetHandle m_gbufferDepthRt;
@@ -137,12 +129,6 @@ private:
 	Error initIrradianceToRefl();
 	Error initIrradianceToRefl();
 	Error initShadowMapping();
 	Error initShadowMapping();
 
 
-	/// Lazily init the cache entry
-	void initCacheEntry(U32 cacheEntryIdx);
-
-	void prepareProbes(RenderingContext& ctx, ReflectionProbeQueueElement*& probeToUpdate,
-					   U32& probeToUpdateCacheEntryIdx);
-
 	void runGBuffer(RenderPassWorkContext& rgraphCtx);
 	void runGBuffer(RenderPassWorkContext& rgraphCtx);
 	void runShadowMapping(RenderPassWorkContext& rgraphCtx);
 	void runShadowMapping(RenderPassWorkContext& rgraphCtx);
 	void runLightShading(U32 faceIdx, const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx);
 	void runLightShading(U32 faceIdx, const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx);

+ 3 - 3
AnKi/Renderer/RenderQueue.cpp

@@ -33,13 +33,13 @@ U32 RenderQueue::countAllRenderables() const
 		}
 		}
 	}
 	}
 
 
-	for(const ReflectionProbeQueueElement& probe : m_reflectionProbes)
+	if(m_reflectionProbeForRefresh)
 	{
 	{
 		for(U i = 0; i < 6; ++i)
 		for(U i = 0; i < 6; ++i)
 		{
 		{
-			if(probe.m_renderQueues[i])
+			if(m_reflectionProbeForRefresh->m_renderQueues[i])
 			{
 			{
-				drawableCount += probe.m_renderQueues[i]->countAllRenderables();
+				drawableCount += m_reflectionProbeForRefresh->m_renderQueues[i]->countAllRenderables();
 			}
 			}
 		}
 		}
 	}
 	}

+ 12 - 10
AnKi/Renderer/RenderQueue.h

@@ -187,23 +187,14 @@ public:
 };
 };
 static_assert(std::is_trivially_destructible<DirectionalLightQueueElement>::value == true);
 static_assert(std::is_trivially_destructible<DirectionalLightQueueElement>::value == true);
 
 
-/// Normally the visibility tests don't perform tests on the reflection probes because probes dont change that often.
-/// This callback will be used by the renderer to inform a reflection probe that on the next frame it will be rendererd.
-/// In that case the visibility tests should fill the render queues of the probe.
-using ReflectionProbeQueueElementFeedbackCallback = void (*)(Bool fillRenderQueuesOnNextFrame, void* userData);
-
 /// Reflection probe render queue element.
 /// Reflection probe render queue element.
 class ReflectionProbeQueueElement final
 class ReflectionProbeQueueElement final
 {
 {
 public:
 public:
-	U64 m_uuid;
-	ReflectionProbeQueueElementFeedbackCallback m_feedbackCallback;
-	void* m_feedbackCallbackUserData;
-	Array<RenderQueue*, 6> m_renderQueues;
 	Vec3 m_worldPosition;
 	Vec3 m_worldPosition;
 	Vec3 m_aabbMin;
 	Vec3 m_aabbMin;
 	Vec3 m_aabbMax;
 	Vec3 m_aabbMax;
-	U32 m_textureArrayIndex; ///< Renderer internal.
+	U32 m_textureBindlessIndex;
 
 
 	ReflectionProbeQueueElement()
 	ReflectionProbeQueueElement()
 	{
 	{
@@ -211,6 +202,15 @@ public:
 };
 };
 static_assert(std::is_trivially_destructible<ReflectionProbeQueueElement>::value == true);
 static_assert(std::is_trivially_destructible<ReflectionProbeQueueElement>::value == true);
 
 
+/// Contains info for a reflection probe that the renderer will have to refresh.
+class ReflectionProbeQueueElementForRefresh final
+{
+public:
+	Array<RenderQueue*, 6> m_renderQueues;
+	Vec3 m_worldPosition;
+	Texture* m_reflectionTexture;
+};
+
 /// See ReflectionProbeQueueElementFeedbackCallback for its purpose.
 /// See ReflectionProbeQueueElementFeedbackCallback for its purpose.
 using GlobalIlluminationProbeQueueElementFeedbackCallback = void (*)(Bool fillRenderQueuesOnNextFrame, void* userData,
 using GlobalIlluminationProbeQueueElementFeedbackCallback = void (*)(Bool fillRenderQueuesOnNextFrame, void* userData,
 																	 const Vec4& eyeWorldPosition);
 																	 const Vec4& eyeWorldPosition);
@@ -401,6 +401,8 @@ public:
 	FillCoverageBufferCallback m_fillCoverageBufferCallback = nullptr;
 	FillCoverageBufferCallback m_fillCoverageBufferCallback = nullptr;
 	void* m_fillCoverageBufferCallbackUserData = nullptr;
 	void* m_fillCoverageBufferCallbackUserData = nullptr;
 
 
+	ReflectionProbeQueueElementForRefresh* m_reflectionProbeForRefresh = nullptr;
+
 	RenderQueue()
 	RenderQueue()
 	{
 	{
 		zeroMemory(m_directionalLight);
 		zeroMemory(m_directionalLight);

+ 27 - 5
AnKi/Scene/Components/ReflectionProbeComponent.cpp

@@ -13,7 +13,6 @@ namespace anki {
 
 
 ReflectionProbeComponent::ReflectionProbeComponent(SceneNode* node)
 ReflectionProbeComponent::ReflectionProbeComponent(SceneNode* node)
 	: SceneComponent(node, getStaticClassId())
 	: SceneComponent(node, getStaticClassId())
-	, m_uuid(node->getSceneGraph().getNewUuid())
 	, m_spatial(this)
 	, m_spatial(this)
 {
 {
 	m_worldPos = node->getWorldTransform().getOrigin().xyz();
 	m_worldPos = node->getWorldTransform().getOrigin().xyz();
@@ -43,8 +42,33 @@ Error ReflectionProbeComponent::update(SceneComponentUpdateInfo& info, Bool& upd
 	m_dirty = false;
 	m_dirty = false;
 	updated = moved || shapeUpdated;
 	updated = moved || shapeUpdated;
 
 
+	if(shapeUpdated && !m_reflectionTex) [[unlikely]]
+	{
+		TextureInitInfo texInit("ReflectionProbe");
+		texInit.m_format =
+			(getExternalSubsystems(*info.m_node).m_grManager->getDeviceCapabilities().m_unalignedBbpTextureFormats)
+				? Format::kR16G16B16_Sfloat
+				: Format::kR16G16B16A16_Sfloat;
+		texInit.m_width = getExternalSubsystems(*info.m_node).m_config->getSceneReflectionProbeResolution();
+		texInit.m_height = texInit.m_width;
+		texInit.m_mipmapCount = U8(computeMaxMipmapCount2d(texInit.m_width, texInit.m_height, 8));
+		texInit.m_type = TextureType::kCube;
+		texInit.m_usage = TextureUsageBit::kAllSampled | TextureUsageBit::kImageComputeWrite
+						  | TextureUsageBit::kImageComputeRead | TextureUsageBit::kAllFramebuffer
+						  | TextureUsageBit::kGenerateMipmaps;
+
+		m_reflectionTex = getExternalSubsystems(*info.m_node).m_grManager->newTexture(texInit);
+
+		TextureViewInitInfo viewInit(m_reflectionTex, "ReflectionPRobe");
+		m_reflectionView = getExternalSubsystems(*info.m_node).m_grManager->newTextureView(viewInit);
+
+		m_reflectionTexBindlessIndex = m_reflectionView->getOrCreateBindlessTextureIndex();
+	}
+
 	if(updated) [[unlikely]]
 	if(updated) [[unlikely]]
 	{
 	{
+		m_reflectionNeedsRefresh = true;
+
 		m_worldPos = info.m_node->getWorldTransform().getOrigin().xyz();
 		m_worldPos = info.m_node->getWorldTransform().getOrigin().xyz();
 
 
 		F32 effectiveDistance = max(m_halfSize.x(), m_halfSize.y());
 		F32 effectiveDistance = max(m_halfSize.x(), m_halfSize.y());
@@ -69,22 +93,20 @@ Error ReflectionProbeComponent::update(SceneComponentUpdateInfo& info, Bool& upd
 										   effectiveDistance - 1.0f * kEpsilonf});
 										   effectiveDistance - 1.0f * kEpsilonf});
 		}
 		}
 
 
-		// Set a new UUID to force the renderer to update the probe
-		m_uuid = info.m_node->getSceneGraph().getNewUuid();
-
 		const Aabb aabbWorld(-m_halfSize + m_worldPos, m_halfSize + m_worldPos);
 		const Aabb aabbWorld(-m_halfSize + m_worldPos, m_halfSize + m_worldPos);
 		m_spatial.setBoundingShape(aabbWorld);
 		m_spatial.setBoundingShape(aabbWorld);
 
 
 		// Upload to the GPU scene
 		// Upload to the GPU scene
 		GpuSceneReflectionProbe gpuProbe;
 		GpuSceneReflectionProbe gpuProbe;
 		gpuProbe.m_position = m_worldPos;
 		gpuProbe.m_position = m_worldPos;
-		gpuProbe.m_cubemapIndex = 0; // Unknown at this point
+		gpuProbe.m_cubeTexture = m_reflectionTexBindlessIndex;
 		gpuProbe.m_aabbMin = aabbWorld.getMin().xyz();
 		gpuProbe.m_aabbMin = aabbWorld.getMin().xyz();
 		gpuProbe.m_aabbMax = aabbWorld.getMax().xyz();
 		gpuProbe.m_aabbMax = aabbWorld.getMax().xyz();
 		getExternalSubsystems(*info.m_node)
 		getExternalSubsystems(*info.m_node)
 			.m_gpuSceneMicroPatcher->newCopy(*info.m_framePool, m_gpuSceneOffset, sizeof(gpuProbe), &gpuProbe);
 			.m_gpuSceneMicroPatcher->newCopy(*info.m_framePool, m_gpuSceneOffset, sizeof(gpuProbe), &gpuProbe);
 	}
 	}
 
 
+	// Update spatial and frustums
 	const Bool spatialUpdated = m_spatial.update(info.m_node->getSceneGraph().getOctree());
 	const Bool spatialUpdated = m_spatial.update(info.m_node->getSceneGraph().getOctree());
 	updated = updated || spatialUpdated;
 	updated = updated || spatialUpdated;
 
 

+ 27 - 19
AnKi/Scene/Components/ReflectionProbeComponent.h

@@ -38,30 +38,40 @@ public:
 		return m_halfSize * 2.0f;
 		return m_halfSize * 2.0f;
 	}
 	}
 
 
-	Bool getMarkedForRendering() const
-	{
-		return m_markedForRendering;
-	}
-
 	ANKI_INTERNAL WeakArray<Frustum> getFrustums()
 	ANKI_INTERNAL WeakArray<Frustum> getFrustums()
 	{
 	{
 		return WeakArray<Frustum>(m_frustums);
 		return WeakArray<Frustum>(m_frustums);
 	}
 	}
 
 
-	void setupReflectionProbeQueueElement(ReflectionProbeQueueElement& el) const
+	ANKI_INTERNAL void setupReflectionProbeQueueElement(ReflectionProbeQueueElement& el) const
 	{
 	{
+		ANKI_ASSERT(!m_reflectionNeedsRefresh);
 		ANKI_ASSERT(m_worldPos.x() != kMaxF32);
 		ANKI_ASSERT(m_worldPos.x() != kMaxF32);
-		el.m_feedbackCallback = reflectionProbeQueueElementFeedbackCallback;
-		el.m_feedbackCallbackUserData = const_cast<ReflectionProbeComponent*>(this);
-		el.m_uuid = m_uuid;
 		el.m_worldPosition = m_worldPos;
 		el.m_worldPosition = m_worldPos;
 		el.m_aabbMin = -m_halfSize + m_worldPos;
 		el.m_aabbMin = -m_halfSize + m_worldPos;
 		el.m_aabbMax = m_halfSize + m_worldPos;
 		el.m_aabbMax = m_halfSize + m_worldPos;
-		el.m_textureArrayIndex = kMaxU32;
+		ANKI_ASSERT(el.m_textureBindlessIndex != kMaxU32);
+		el.m_textureBindlessIndex = m_reflectionTexBindlessIndex;
+	}
+
+	ANKI_INTERNAL void setupReflectionProbeQueueElementForRefresh(ReflectionProbeQueueElementForRefresh& el) const
+	{
+		ANKI_ASSERT(m_reflectionNeedsRefresh);
+		el.m_worldPosition = m_worldPos;
+		el.m_reflectionTexture = m_reflectionTex.get();
+	}
+
+	ANKI_INTERNAL Bool getReflectionNeedsRefresh() const
+	{
+		return m_reflectionNeedsRefresh;
+	}
+
+	ANKI_INTERNAL void setReflectionNeedsRefresh(Bool needsRefresh)
+	{
+		m_reflectionNeedsRefresh = needsRefresh;
 	}
 	}
 
 
 private:
 private:
-	U64 m_uuid = 0;
 	Vec3 m_worldPos = Vec3(kMaxF32);
 	Vec3 m_worldPos = Vec3(kMaxF32);
 	Vec3 m_halfSize = Vec3(1.0f);
 	Vec3 m_halfSize = Vec3(1.0f);
 
 
@@ -71,18 +81,16 @@ private:
 
 
 	Array<Frustum, 6> m_frustums;
 	Array<Frustum, 6> m_frustums;
 
 
-	Bool m_markedForRendering : 1 = false;
-	Bool m_dirty : 1 = true;
+	TexturePtr m_reflectionTex;
+	TextureViewPtr m_reflectionView;
+	U32 m_reflectionTexBindlessIndex = kMaxU32;
+
+	Bool m_dirty = true;
+	Bool m_reflectionNeedsRefresh = true;
 
 
 	Error update(SceneComponentUpdateInfo& info, Bool& updated);
 	Error update(SceneComponentUpdateInfo& info, Bool& updated);
 
 
 	void onDestroy(SceneNode& node);
 	void onDestroy(SceneNode& node);
-
-	static void reflectionProbeQueueElementFeedbackCallback(Bool fillRenderQueuesOnNextFrame, void* userData)
-	{
-		ANKI_ASSERT(userData);
-		static_cast<ReflectionProbeComponent*>(userData)->m_markedForRendering = fillRenderQueuesOnNextFrame;
-	}
 };
 };
 /// @}
 /// @}
 
 

+ 3 - 0
AnKi/Scene/ConfigVars.defs.h

@@ -27,6 +27,9 @@ ANKI_CONFIG_VAR_BOOL(SceneRayTracedShadows, true, "Enable or not ray traced shad
 ANKI_CONFIG_VAR_F32(SceneRayTracingExtendedFrustumDistance, 100.0f, 10.0f, 10000.0f,
 ANKI_CONFIG_VAR_F32(SceneRayTracingExtendedFrustumDistance, 100.0f, 10.0f, 10000.0f,
 					"Every object that its distance from the camera is bellow that value will take part in ray tracing")
 					"Every object that its distance from the camera is bellow that value will take part in ray tracing")
 
 
+ANKI_CONFIG_VAR_U32(SceneReflectionProbeResolution, 128, 8, 2048, "The resolution of the reflection probe's reflection")
+
+// GPU scene
 ANKI_CONFIG_VAR_U32(SceneMinGpuSceneTransforms, 8 * 1024, 8, 100 * 1024,
 ANKI_CONFIG_VAR_U32(SceneMinGpuSceneTransforms, 8 * 1024, 8, 100 * 1024,
 					"The min number of transforms stored in the GPU scene")
 					"The min number of transforms stored in the GPU scene")
 ANKI_CONFIG_VAR_U32(SceneMinGpuSceneMeshes, 8 * 1024, 8, 100 * 1024, "The min number of meshes stored in the GPU scene")
 ANKI_CONFIG_VAR_U32(SceneMinGpuSceneMeshes, 8 * 1024, 8, 100 * 1024, "The min number of meshes stored in the GPU scene")

+ 15 - 8
AnKi/Scene/Visibility.cpp

@@ -516,24 +516,29 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 
 
 			ReflectionProbeComponent& reflc = static_cast<ReflectionProbeComponent&>(comp);
 			ReflectionProbeComponent& reflc = static_cast<ReflectionProbeComponent&>(comp);
 
 
-			ReflectionProbeQueueElement* el = result.m_reflectionProbes.newElement(pool);
-			reflc.setupReflectionProbeQueueElement(*el);
-
-			if(reflc.getMarkedForRendering())
+			if(reflc.getReflectionNeedsRefresh() && m_frcCtx->m_reflectionProbesForRefreshCount.fetchAdd(1) == 0)
 			{
 			{
+				ReflectionProbeQueueElementForRefresh* el = newInstance<ReflectionProbeQueueElementForRefresh>(pool);
+				m_frcCtx->m_reflectionProbeForRefresh = el;
+
+				reflc.setupReflectionProbeQueueElementForRefresh(*el);
+				reflc.setReflectionNeedsRefresh(false);
+
 				nextQueues = WeakArray<RenderQueue>(newArray<RenderQueue>(pool, 6), 6);
 				nextQueues = WeakArray<RenderQueue>(newArray<RenderQueue>(pool, 6), 6);
 				nextFrustums = WeakArray<VisibilityFrustum>(newArray<VisibilityFrustum>(pool, 6), 6);
 				nextFrustums = WeakArray<VisibilityFrustum>(newArray<VisibilityFrustum>(pool, 6), 6);
 
 
 				for(U32 i = 0; i < 6; ++i)
 				for(U32 i = 0; i < 6; ++i)
 				{
 				{
 					el->m_renderQueues[i] = &nextQueues[i];
 					el->m_renderQueues[i] = &nextQueues[i];
+
 					nextFrustums[i].m_frustum = &reflc.getFrustums()[i];
 					nextFrustums[i].m_frustum = &reflc.getFrustums()[i];
 					static_cast<FrustumFlags&>(nextFrustums[i]) = getProbeFrustumFlags();
 					static_cast<FrustumFlags&>(nextFrustums[i]) = getProbeFrustumFlags();
 				}
 				}
 			}
 			}
-			else
+			else if(!reflc.getReflectionNeedsRefresh())
 			{
 			{
-				memset(&el->m_renderQueues[0], 0, sizeof(el->m_renderQueues));
+				ReflectionProbeQueueElement* el = result.m_reflectionProbes.newElement(pool);
+				reflc.setupReflectionProbeQueueElement(*el);
 			}
 			}
 		}
 		}
 		else if(comp.getClassId() == DecalComponent::getStaticClassId())
 		else if(comp.getClassId() == DecalComponent::getStaticClassId())
@@ -684,6 +689,10 @@ void CombineResultsTask::combine()
 	ANKI_VIS_COMBINE(RayTracingInstanceQueueElement, m_rayTracingInstances);
 	ANKI_VIS_COMBINE(RayTracingInstanceQueueElement, m_rayTracingInstances);
 	ANKI_VIS_COMBINE(UiQueueElement, m_uis);
 	ANKI_VIS_COMBINE(UiQueueElement, m_uis);
 
 
+#undef ANKI_VIS_COMBINE
+
+	results.m_reflectionProbeForRefresh = m_frcCtx->m_reflectionProbeForRefresh;
+
 	for(U32 i = 0; i < threadCount; ++i)
 	for(U32 i = 0; i < threadCount; ++i)
 	{
 	{
 		if(m_frcCtx->m_queueViews[i].m_directionalLight.m_uuid != 0)
 		if(m_frcCtx->m_queueViews[i].m_directionalLight.m_uuid != 0)
@@ -697,8 +706,6 @@ void CombineResultsTask::combine()
 		}
 		}
 	}
 	}
 
 
-#undef ANKI_VIS_COMBINE
-
 	const Bool isShadowFrustum = m_frcCtx->m_frustum.m_gatherShadowCasterModelComponents;
 	const Bool isShadowFrustum = m_frcCtx->m_frustum.m_gatherShadowCasterModelComponents;
 
 
 	// Sort some of the arrays
 	// Sort some of the arrays

+ 3 - 0
AnKi/Scene/VisibilityInternal.h

@@ -173,6 +173,9 @@ public:
 
 
 	// Gather results members
 	// Gather results members
 	RenderQueue* m_renderQueue = nullptr;
 	RenderQueue* m_renderQueue = nullptr;
+
+	Atomic<U32> m_reflectionProbesForRefreshCount = {0};
+	ReflectionProbeQueueElementForRefresh* m_reflectionProbeForRefresh = nullptr;
 };
 };
 
 
 /// ThreadHive task to set the depth map of the S/W rasterizer.
 /// ThreadHive task to set the depth map of the S/W rasterizer.

+ 0 - 3
AnKi/Shaders/ClusteredShadingCommon.hlsl

@@ -40,9 +40,6 @@
 {
 {
 	ReflectionProbe g_reflectionProbes[kMaxVisibleReflectionProbes];
 	ReflectionProbe g_reflectionProbes[kMaxVisibleReflectionProbes];
 };
 };
-
-[[vk::binding(CLUSTERED_SHADING_REFLECTIONS_BINDING + 1u, CLUSTERED_SHADING_SET)]] TextureCubeArray<RVec4>
-	g_reflectionsTex;
 #endif
 #endif
 
 
 //
 //

+ 1 - 1
AnKi/Shaders/Include/ClusteredShadingTypes.h

@@ -127,7 +127,7 @@ ANKI_SHADER_STATIC_ASSERT(kMaxShadowCascades == 4u); // Because m_shadowCascadeD
 struct ReflectionProbe
 struct ReflectionProbe
 {
 {
 	Vec3 m_position; ///< Position of the probe in world space.
 	Vec3 m_position; ///< Position of the probe in world space.
-	F32 m_cubemapIndex; ///< Index in the cubemap array texture.
+	U32 m_cubeTexture; ///< Bindless index of the reflection texture.
 
 
 	Vec3 m_aabbMin;
 	Vec3 m_aabbMin;
 	F32 m_padding0;
 	F32 m_padding0;

+ 1 - 0
AnKi/Shaders/Include/Common.h

@@ -69,6 +69,7 @@ void maybeUnused(T a)
 		[[vk::binding(0, s)]] Texture2D<int4> g_bindlessTextures2dI32[kMaxBindlessTextures]; \
 		[[vk::binding(0, s)]] Texture2D<int4> g_bindlessTextures2dI32[kMaxBindlessTextures]; \
 		[[vk::binding(0, s)]] Texture2D<RVec4> g_bindlessTextures2dF32[kMaxBindlessTextures]; \
 		[[vk::binding(0, s)]] Texture2D<RVec4> g_bindlessTextures2dF32[kMaxBindlessTextures]; \
 		[[vk::binding(0, s)]] Texture2DArray<RVec4> g_bindlessTextures2dArrayF32[kMaxBindlessTextures]; \
 		[[vk::binding(0, s)]] Texture2DArray<RVec4> g_bindlessTextures2dArrayF32[kMaxBindlessTextures]; \
+		[[vk::binding(0, s)]] TextureCube<RVec4> g_bindlessTexturesCubeF32[kMaxBindlessTextures]; \
 		[[vk::binding(1, s)]] Buffer<float4> g_bindlessTextureBuffersF32[kMaxBindlessReadonlyTextureBuffers];
 		[[vk::binding(1, s)]] Buffer<float4> g_bindlessTextureBuffersF32[kMaxBindlessReadonlyTextureBuffers];
 
 
 #	define _ANKI_SCONST_X(type, n, id) [[vk::constant_id(id)]] const type n = (type)1;
 #	define _ANKI_SCONST_X(type, n, id) [[vk::constant_id(id)]] const type n = (type)1;

+ 1 - 1
AnKi/Shaders/Include/GpuSceneTypes.h

@@ -85,7 +85,7 @@ static_assert(sizeof(GpuSceneSpotLight) == kSizeof_GpuSceneSpotLight);
 struct GpuSceneReflectionProbe
 struct GpuSceneReflectionProbe
 {
 {
 	Vec3 m_position; ///< Position of the probe in world space.
 	Vec3 m_position; ///< Position of the probe in world space.
-	F32 m_cubemapIndex; ///< Index in the cubemap array texture.
+	U32 m_cubeTexture; ///< Bindless index of the reflection texture.
 
 
 	Vec3 m_aabbMin;
 	Vec3 m_aabbMin;
 	F32 m_padding0;
 	F32 m_padding0;

+ 12 - 7
AnKi/Shaders/IndirectSpecular.hlsl

@@ -31,13 +31,15 @@ constexpr Vec2 kNoiseTexSize = 64.0;
 #define CLUSTERED_SHADING_SET 0u
 #define CLUSTERED_SHADING_SET 0u
 #define CLUSTERED_SHADING_UNIFORMS_BINDING 11u
 #define CLUSTERED_SHADING_UNIFORMS_BINDING 11u
 #define CLUSTERED_SHADING_REFLECTIONS_BINDING 12u
 #define CLUSTERED_SHADING_REFLECTIONS_BINDING 12u
-#define CLUSTERED_SHADING_CLUSTERS_BINDING 14u
+#define CLUSTERED_SHADING_CLUSTERS_BINDING 13u
 #include <AnKi/Shaders/ClusteredShadingCommon.hlsl>
 #include <AnKi/Shaders/ClusteredShadingCommon.hlsl>
 
 
 #if defined(ANKI_COMPUTE_SHADER)
 #if defined(ANKI_COMPUTE_SHADER)
-[[vk::binding(15)]] RWTexture2D<RVec4> g_outUav;
+[[vk::binding(14)]] RWTexture2D<RVec4> g_outUav;
 #endif
 #endif
 
 
+ANKI_BINDLESS_SET(1)
+
 #if defined(ANKI_COMPUTE_SHADER)
 #if defined(ANKI_COMPUTE_SHADER)
 [numthreads(8, 8, 1)] void main(UVec3 svDispatchThreadId : SV_DISPATCHTHREADID)
 [numthreads(8, 8, 1)] void main(UVec3 svDispatchThreadId : SV_DISPATCHTHREADID)
 #else
 #else
@@ -203,7 +205,8 @@ RVec3 main(Vec2 uv : TEXCOORD, Vec4 svPosition : SV_POSITION) : SV_TARGET0
 
 
 		Vec3 probeColor = 0.0;
 		Vec3 probeColor = 0.0;
 
 
-		if(countbits(cluster.m_reflectionProbesMask) == 1)
+		const U32 oneProbe = WaveActiveAllTrue(countbits(cluster.m_reflectionProbesMask) == 1);
+		if(oneProbe)
 		{
 		{
 			// Only one probe, do a fast path without blend weight
 			// Only one probe, do a fast path without blend weight
 
 
@@ -211,8 +214,9 @@ RVec3 main(Vec2 uv : TEXCOORD, Vec4 svPosition : SV_POSITION) : SV_TARGET0
 
 
 			// Sample
 			// Sample
 			const Vec3 cubeUv = intersectProbe(worldPos, reflDir, probe.m_aabbMin, probe.m_aabbMax, probe.m_position);
 			const Vec3 cubeUv = intersectProbe(worldPos, reflDir, probe.m_aabbMin, probe.m_aabbMax, probe.m_position);
-			const Vec4 cubeArrUv = Vec4(cubeUv, probe.m_cubemapIndex);
-			probeColor = g_reflectionsTex.SampleLevel(g_trilinearClampSampler, cubeArrUv, reflLod).rgb;
+			probeColor = g_bindlessTexturesCubeF32[probe.m_cubeTexture]
+							 .SampleLevel(g_trilinearClampSampler, cubeUv, reflLod)
+							 .rgb;
 		}
 		}
 		else
 		else
 		{
 		{
@@ -234,8 +238,9 @@ RVec3 main(Vec2 uv : TEXCOORD, Vec4 svPosition : SV_POSITION) : SV_TARGET0
 				// Sample reflections
 				// Sample reflections
 				const Vec3 cubeUv =
 				const Vec3 cubeUv =
 					intersectProbe(worldPos, reflDir, probe.m_aabbMin, probe.m_aabbMax, probe.m_position);
 					intersectProbe(worldPos, reflDir, probe.m_aabbMin, probe.m_aabbMax, probe.m_position);
-				const Vec4 cubeArrUv = Vec4(cubeUv, probe.m_cubemapIndex);
-				const Vec3 c = g_reflectionsTex.SampleLevel(g_trilinearClampSampler, cubeArrUv, reflLod).rgb;
+				const Vec3 c = g_bindlessTexturesCubeF32[NonUniformResourceIndex(probe.m_cubeTexture)]
+								   .SampleLevel(g_trilinearClampSampler, cubeUv, reflLod)
+								   .rgb;
 				probeColor += c * blendWeight;
 				probeColor += c * blendWeight;
 			}
 			}