소스 검색

More work on RT

Panagiotis Christopoulos Charitos 5 년 전
부모
커밋
34beadd39e

+ 20 - 0
src/anki/gr/CommandBuffer.h

@@ -336,6 +336,26 @@ public:
 	void dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
 	void dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
 
 
 	/// Trace rays.
 	/// Trace rays.
+	///
+	/// The 1st thing in the sbtBuffer is the ray gen shader group handle:
+	/// @code RG = RG_offset @endcode
+	/// The RG_offset is equal to the stbBufferOffset.
+	///
+	/// Then the sbtBuffer contains the miss shader group handles and their data. The indexing is as follows:
+	/// @code M = M_offset + M_stride * R_miss @endcode
+	/// The M_offset is equal to stbBufferOffset + GpuDeviceCapabilities::m_sbtRecordSize.
+	/// The M_stride is equal to GpuDeviceCapabilities::m_sbtRecordSize.
+	/// The R_miss is defined in the traceRayEXT and it's the "ray type".
+	///
+	/// After the miss shaders the sbtBuffer has the hit group shader group handles and their data. The indexing is:
+	/// @code HG = HG_offset + (HG_stride * (R_offset + R_stride * G_id + I_offset)) @endcode
+	/// The HG_offset is equal to sbtBufferOffset + GpuDeviceCapabilities::m_sbtRecordSize * (missShaderCount + 1).
+	/// The HG_stride is equal GpuDeviceCapabilities::m_sbtRecordSize.
+	/// The R_offset and R_stride are provided in traceRayEXT. The R_offset is the "ray type" and R_stride the number of
+	/// ray types.
+	/// The G_id is always 0 ATM.
+	/// The I_offset is the AccelerationStructureInstance::m_sbtRecordIndex.
+	///
 	/// @param[in] sbtBuffer The SBT buffer.
 	/// @param[in] sbtBuffer The SBT buffer.
 	/// @param sbtBufferOffset Offset inside the sbtBuffer where SBT records start.
 	/// @param sbtBufferOffset Offset inside the sbtBuffer where SBT records start.
 	/// @param hitGroupSbtRecordCount The number of SBT records that contain hit groups.
 	/// @param hitGroupSbtRecordCount The number of SBT records that contain hit groups.

+ 9 - 9
src/anki/gr/Enums.h

@@ -386,7 +386,7 @@ enum class TextureUsageBit : U32
 	SAMPLED_GEOMETRY = 1 << 0,
 	SAMPLED_GEOMETRY = 1 << 0,
 	SAMPLED_FRAGMENT = 1 << 1,
 	SAMPLED_FRAGMENT = 1 << 1,
 	SAMPLED_COMPUTE = 1 << 2,
 	SAMPLED_COMPUTE = 1 << 2,
-	SAMPLED_RAY_GEN = 1 << 3,
+	SAMPLED_TRACE_RAYS = 1 << 3,
 
 
 	IMAGE_GEOMETRY_READ = 1 << 4,
 	IMAGE_GEOMETRY_READ = 1 << 4,
 	IMAGE_GEOMETRY_WRITE = 1 << 5,
 	IMAGE_GEOMETRY_WRITE = 1 << 5,
@@ -394,8 +394,8 @@ enum class TextureUsageBit : U32
 	IMAGE_FRAGMENT_WRITE = 1 << 7,
 	IMAGE_FRAGMENT_WRITE = 1 << 7,
 	IMAGE_COMPUTE_READ = 1 << 8,
 	IMAGE_COMPUTE_READ = 1 << 8,
 	IMAGE_COMPUTE_WRITE = 1 << 9,
 	IMAGE_COMPUTE_WRITE = 1 << 9,
-	IMAGE_RAY_GEN_READ = 1 << 10,
-	IMAGE_RAY_GEN_WRITE = 1 << 11,
+	IMAGE_TRACE_RAYS_READ = 1 << 10,
+	IMAGE_TRACE_RAYS_WRITE = 1 << 11,
 
 
 	FRAMEBUFFER_ATTACHMENT_READ = 1 << 12,
 	FRAMEBUFFER_ATTACHMENT_READ = 1 << 12,
 	FRAMEBUFFER_ATTACHMENT_WRITE = 1 << 13,
 	FRAMEBUFFER_ATTACHMENT_WRITE = 1 << 13,
@@ -406,9 +406,9 @@ enum class TextureUsageBit : U32
 	PRESENT = 1 << 16,
 	PRESENT = 1 << 16,
 
 
 	// Derived
 	// Derived
-	ALL_SAMPLED = SAMPLED_GEOMETRY | SAMPLED_FRAGMENT | SAMPLED_COMPUTE | SAMPLED_RAY_GEN,
+	ALL_SAMPLED = SAMPLED_GEOMETRY | SAMPLED_FRAGMENT | SAMPLED_COMPUTE | SAMPLED_TRACE_RAYS,
 	ALL_IMAGE = IMAGE_GEOMETRY_READ | IMAGE_GEOMETRY_WRITE | IMAGE_FRAGMENT_READ | IMAGE_FRAGMENT_WRITE
 	ALL_IMAGE = IMAGE_GEOMETRY_READ | IMAGE_GEOMETRY_WRITE | IMAGE_FRAGMENT_READ | IMAGE_FRAGMENT_WRITE
-				| IMAGE_COMPUTE_READ | IMAGE_COMPUTE_WRITE | IMAGE_RAY_GEN_READ | IMAGE_RAY_GEN_WRITE,
+				| IMAGE_COMPUTE_READ | IMAGE_COMPUTE_WRITE | IMAGE_TRACE_RAYS_READ | IMAGE_TRACE_RAYS_WRITE,
 	ALL_FRAMEBUFFER_ATTACHMENT = FRAMEBUFFER_ATTACHMENT_READ | FRAMEBUFFER_ATTACHMENT_WRITE,
 	ALL_FRAMEBUFFER_ATTACHMENT = FRAMEBUFFER_ATTACHMENT_READ | FRAMEBUFFER_ATTACHMENT_WRITE,
 
 
 	ALL_GRAPHICS = SAMPLED_GEOMETRY | SAMPLED_FRAGMENT | IMAGE_GEOMETRY_READ | IMAGE_GEOMETRY_WRITE
 	ALL_GRAPHICS = SAMPLED_GEOMETRY | SAMPLED_FRAGMENT | IMAGE_GEOMETRY_READ | IMAGE_GEOMETRY_WRITE
@@ -417,9 +417,9 @@ enum class TextureUsageBit : U32
 	ALL_COMPUTE = SAMPLED_COMPUTE | IMAGE_COMPUTE_READ | IMAGE_COMPUTE_WRITE,
 	ALL_COMPUTE = SAMPLED_COMPUTE | IMAGE_COMPUTE_READ | IMAGE_COMPUTE_WRITE,
 	ALL_TRANSFER = TRANSFER_DESTINATION | GENERATE_MIPMAPS,
 	ALL_TRANSFER = TRANSFER_DESTINATION | GENERATE_MIPMAPS,
 
 
-	ALL_READ = ALL_SAMPLED | IMAGE_GEOMETRY_READ | IMAGE_FRAGMENT_READ | IMAGE_COMPUTE_READ | IMAGE_RAY_GEN_READ
+	ALL_READ = ALL_SAMPLED | IMAGE_GEOMETRY_READ | IMAGE_FRAGMENT_READ | IMAGE_COMPUTE_READ | IMAGE_TRACE_RAYS_READ
 			   | FRAMEBUFFER_ATTACHMENT_READ | PRESENT | GENERATE_MIPMAPS,
 			   | FRAMEBUFFER_ATTACHMENT_READ | PRESENT | GENERATE_MIPMAPS,
-	ALL_WRITE = IMAGE_GEOMETRY_WRITE | IMAGE_FRAGMENT_WRITE | IMAGE_COMPUTE_WRITE | IMAGE_RAY_GEN_WRITE
+	ALL_WRITE = IMAGE_GEOMETRY_WRITE | IMAGE_FRAGMENT_WRITE | IMAGE_COMPUTE_WRITE | IMAGE_TRACE_RAYS_WRITE
 				| FRAMEBUFFER_ATTACHMENT_WRITE | TRANSFER_DESTINATION | GENERATE_MIPMAPS
 				| FRAMEBUFFER_ATTACHMENT_WRITE | TRANSFER_DESTINATION | GENERATE_MIPMAPS
 };
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(TextureUsageBit)
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(TextureUsageBit)
@@ -680,11 +680,11 @@ enum class AccelerationStructureUsageBit : U8
 	GEOMETRY_READ = 1 << 2,
 	GEOMETRY_READ = 1 << 2,
 	FRAGMENT_READ = 1 << 3,
 	FRAGMENT_READ = 1 << 3,
 	COMPUTE_READ = 1 << 4,
 	COMPUTE_READ = 1 << 4,
-	RAY_GEN_READ = 1 << 5,
+	TRACE_RAYS_READ = 1 << 5,
 
 
 	// Derived
 	// Derived
 	ALL_GRAPHICS = GEOMETRY_READ | FRAGMENT_READ,
 	ALL_GRAPHICS = GEOMETRY_READ | FRAGMENT_READ,
-	ALL_READ = ATTACH | GEOMETRY_READ | FRAGMENT_READ | COMPUTE_READ | RAY_GEN_READ,
+	ALL_READ = ATTACH | GEOMETRY_READ | FRAGMENT_READ | COMPUTE_READ | TRACE_RAYS_READ,
 	ALL_WRITE = BUILD
 	ALL_WRITE = BUILD
 };
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(AccelerationStructureUsageBit)
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(AccelerationStructureUsageBit)

+ 4 - 4
src/anki/gr/RenderGraph.cpp

@@ -1430,15 +1430,15 @@ StringAuto RenderGraph::textureUsageToStr(StackAllocator<U8>& alloc, TextureUsag
 	ANKI_TEX_USAGE(SAMPLED_GEOMETRY);
 	ANKI_TEX_USAGE(SAMPLED_GEOMETRY);
 	ANKI_TEX_USAGE(SAMPLED_FRAGMENT);
 	ANKI_TEX_USAGE(SAMPLED_FRAGMENT);
 	ANKI_TEX_USAGE(SAMPLED_COMPUTE);
 	ANKI_TEX_USAGE(SAMPLED_COMPUTE);
-	ANKI_TEX_USAGE(SAMPLED_RAY_GEN);
+	ANKI_TEX_USAGE(SAMPLED_TRACE_RAYS);
 	ANKI_TEX_USAGE(IMAGE_GEOMETRY_READ);
 	ANKI_TEX_USAGE(IMAGE_GEOMETRY_READ);
 	ANKI_TEX_USAGE(IMAGE_GEOMETRY_WRITE);
 	ANKI_TEX_USAGE(IMAGE_GEOMETRY_WRITE);
 	ANKI_TEX_USAGE(IMAGE_FRAGMENT_READ);
 	ANKI_TEX_USAGE(IMAGE_FRAGMENT_READ);
 	ANKI_TEX_USAGE(IMAGE_FRAGMENT_WRITE);
 	ANKI_TEX_USAGE(IMAGE_FRAGMENT_WRITE);
 	ANKI_TEX_USAGE(IMAGE_COMPUTE_READ);
 	ANKI_TEX_USAGE(IMAGE_COMPUTE_READ);
 	ANKI_TEX_USAGE(IMAGE_COMPUTE_WRITE);
 	ANKI_TEX_USAGE(IMAGE_COMPUTE_WRITE);
-	ANKI_TEX_USAGE(IMAGE_RAY_GEN_READ);
-	ANKI_TEX_USAGE(IMAGE_RAY_GEN_WRITE);
+	ANKI_TEX_USAGE(IMAGE_TRACE_RAYS_READ);
+	ANKI_TEX_USAGE(IMAGE_TRACE_RAYS_WRITE);
 	ANKI_TEX_USAGE(FRAMEBUFFER_ATTACHMENT_READ);
 	ANKI_TEX_USAGE(FRAMEBUFFER_ATTACHMENT_READ);
 	ANKI_TEX_USAGE(FRAMEBUFFER_ATTACHMENT_WRITE);
 	ANKI_TEX_USAGE(FRAMEBUFFER_ATTACHMENT_WRITE);
 	ANKI_TEX_USAGE(TRANSFER_DESTINATION);
 	ANKI_TEX_USAGE(TRANSFER_DESTINATION);
@@ -1525,7 +1525,7 @@ StringAuto RenderGraph::asUsageToStr(StackAllocator<U8>& alloc, AccelerationStru
 	ANKI_AS_USAGE(GEOMETRY_READ);
 	ANKI_AS_USAGE(GEOMETRY_READ);
 	ANKI_AS_USAGE(FRAGMENT_READ);
 	ANKI_AS_USAGE(FRAGMENT_READ);
 	ANKI_AS_USAGE(COMPUTE_READ);
 	ANKI_AS_USAGE(COMPUTE_READ);
-	ANKI_AS_USAGE(RAY_GEN_READ);
+	ANKI_AS_USAGE(TRACE_RAYS_READ);
 
 
 #	undef ANKI_AS_USAGE
 #	undef ANKI_AS_USAGE
 
 

+ 2 - 2
src/anki/gr/vulkan/AccelerationStructureImpl.cpp

@@ -283,7 +283,7 @@ void AccelerationStructureImpl::computeBarrierInfo(AccelerationStructureUsageBit
 		srcAccesses |= VK_ACCESS_MEMORY_READ_BIT;
 		srcAccesses |= VK_ACCESS_MEMORY_READ_BIT;
 	}
 	}
 
 
-	if(!!(before & AccelerationStructureUsageBit::RAY_GEN_READ))
+	if(!!(before & AccelerationStructureUsageBit::TRACE_RAYS_READ))
 	{
 	{
 		srcStages |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
 		srcStages |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
 		srcAccesses |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
 		srcAccesses |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
@@ -324,7 +324,7 @@ void AccelerationStructureImpl::computeBarrierInfo(AccelerationStructureUsageBit
 		dstAccesses |= VK_ACCESS_MEMORY_READ_BIT;
 		dstAccesses |= VK_ACCESS_MEMORY_READ_BIT;
 	}
 	}
 
 
-	if(!!(after & AccelerationStructureUsageBit::RAY_GEN_READ))
+	if(!!(after & AccelerationStructureUsageBit::TRACE_RAYS_READ))
 	{
 	{
 		dstStages |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
 		dstStages |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
 		dstAccesses |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
 		dstAccesses |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;

+ 5 - 2
src/anki/gr/vulkan/CommandBufferImpl.inl.h

@@ -432,7 +432,7 @@ inline void CommandBufferImpl::traceRaysInternal(BufferPtr& sbtBuffer, PtrSize s
 		}
 		}
 	}
 	}
 
 
-	Array<VkStridedBufferRegionKHR, 3> regions;
+	Array<VkStridedBufferRegionKHR, 4> regions;
 
 
 	// Rgen
 	// Rgen
 	regions[0].buffer = static_cast<const BufferImpl&>(*sbtBuffer).getHandle();
 	regions[0].buffer = static_cast<const BufferImpl&>(*sbtBuffer).getHandle();
@@ -452,7 +452,10 @@ inline void CommandBufferImpl::traceRaysInternal(BufferPtr& sbtBuffer, PtrSize s
 	regions[2].stride = shaderGroupBaseAlignment;
 	regions[2].stride = shaderGroupBaseAlignment;
 	regions[2].size = shaderGroupBaseAlignment * hitGroupSbtRecordCount;
 	regions[2].size = shaderGroupBaseAlignment * hitGroupSbtRecordCount;
 
 
-	ANKI_CMD(vkCmdTraceRaysKHR(m_handle, &regions[0], &regions[1], &regions[2], nullptr, width, height, depth),
+	// Callable, nothing for now
+	regions[3] = VkStridedBufferRegionKHR();
+
+	ANKI_CMD(vkCmdTraceRaysKHR(m_handle, &regions[0], &regions[1], &regions[2], &regions[3], width, height, depth),
 			 ANY_OTHER_COMMAND);
 			 ANY_OTHER_COMMAND);
 }
 }
 
 

+ 3 - 2
src/anki/gr/vulkan/SwapchainFactory.cpp

@@ -145,7 +145,7 @@ Error MicroSwapchain::initInternal()
 		ci.imageColorSpace = colorspace;
 		ci.imageColorSpace = colorspace;
 		ci.imageExtent = surfaceProperties.currentExtent;
 		ci.imageExtent = surfaceProperties.currentExtent;
 		ci.imageArrayLayers = 1;
 		ci.imageArrayLayers = 1;
-		ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+		ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
 		ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
 		ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
 		ci.queueFamilyIndexCount = 1;
 		ci.queueFamilyIndexCount = 1;
 		U32 idx = m_factory->m_gr->getGraphicsQueueIndex();
 		U32 idx = m_factory->m_gr->getGraphicsQueueIndex();
@@ -181,7 +181,8 @@ Error MicroSwapchain::initInternal()
 			init.m_height = surfaceHeight;
 			init.m_height = surfaceHeight;
 			init.m_format = Format::B8G8R8A8_UNORM;
 			init.m_format = Format::B8G8R8A8_UNORM;
 			ANKI_ASSERT(surfaceFormat == VK_FORMAT_B8G8R8A8_UNORM);
 			ANKI_ASSERT(surfaceFormat == VK_FORMAT_B8G8R8A8_UNORM);
-			init.m_usage = TextureUsageBit::IMAGE_COMPUTE_WRITE | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ
+			init.m_usage = TextureUsageBit::IMAGE_COMPUTE_WRITE | TextureUsageBit::IMAGE_TRACE_RAYS_WRITE
+						   | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ
 						   | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE | TextureUsageBit::PRESENT;
 						   | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE | TextureUsageBit::PRESENT;
 			init.m_type = TextureType::_2D;
 			init.m_type = TextureType::_2D;
 
 

+ 12 - 0
src/anki/gr/vulkan/TextureImpl.cpp

@@ -425,6 +425,18 @@ void TextureImpl::computeBarrierInfo(TextureUsageBit usage, Bool src, U32 level,
 		accesses |= VK_ACCESS_SHADER_WRITE_BIT;
 		accesses |= VK_ACCESS_SHADER_WRITE_BIT;
 	}
 	}
 
 
+	if(!!(usage & (TextureUsageBit::SAMPLED_TRACE_RAYS | TextureUsageBit::IMAGE_TRACE_RAYS_READ)))
+	{
+		stages |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
+		accesses |= VK_ACCESS_SHADER_READ_BIT;
+	}
+
+	if(!!(usage & TextureUsageBit::IMAGE_TRACE_RAYS_WRITE))
+	{
+		stages |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
+		accesses |= VK_ACCESS_SHADER_WRITE_BIT;
+	}
+
 	if(!!(usage & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ))
 	if(!!(usage & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ))
 	{
 	{
 		if(depthStencil)
 		if(depthStencil)

+ 2 - 2
src/anki/resource/Common.h

@@ -33,9 +33,9 @@ class TransferGpuAllocatorHandle;
 /// @name Constants
 /// @name Constants
 /// @{
 /// @{
 constexpr U32 MAX_LOD_COUNT = 3;
 constexpr U32 MAX_LOD_COUNT = 3;
-constexpr U32 MAX_INSTANCES = 64; /// @warning Change MAX_INSTANCE_GROUPS as well
+constexpr U32 MAX_INSTANCES = 64; ///< @warning Change MAX_INSTANCE_GROUPS as well
 constexpr U32 MAX_SUB_DRAWCALLS = 64;
 constexpr U32 MAX_SUB_DRAWCALLS = 64;
-constexpr U32 MAX_INSTANCE_GROUPS = 7; /// It's log2(MAX_INSTANCES) + 1
+constexpr U32 MAX_INSTANCE_GROUPS = 7; ///< It's log2(MAX_INSTANCES) + 1
 
 
 /// Standard attribute locations. Should be the same as in Common.glsl.
 /// Standard attribute locations. Should be the same as in Common.glsl.
 enum class VertexAttributeLocation : U8
 enum class VertexAttributeLocation : U8

+ 80 - 3
tests/gr/Gr.cpp

@@ -2851,7 +2851,7 @@ layout(set = 0, binding = 2, rgba8) uniform image2D u_outImg;
 
 
 void main()
 void main()
 {
 {
-	imageStore(u_outImg, IVec2(gl_LaunchIDEXT.xy), Vec4(0.0));
+	imageStore(u_outImg, IVec2(gl_LaunchIDEXT.xy), Vec4(0.1));
 }
 }
 		)";
 		)";
 
 
@@ -2900,7 +2900,7 @@ void main()
 	}
 	}
 
 
 	// Create AS
 	// Create AS
-	AccelerationStructurePtr tlas;
+	AccelerationStructurePtr smallBlas, tlas;
 	if(useRayTracing)
 	if(useRayTracing)
 	{
 	{
 		// Small box
 		// Small box
@@ -2914,7 +2914,7 @@ void main()
 		inf.m_bottomLevel.m_positionsFormat = Format::R32G32B32_SFLOAT;
 		inf.m_bottomLevel.m_positionsFormat = Format::R32G32B32_SFLOAT;
 		inf.m_bottomLevel.m_positionStride = sizeof(Vec3);
 		inf.m_bottomLevel.m_positionStride = sizeof(Vec3);
 
 
-		AccelerationStructurePtr smallBlas = gr->newAccelerationStructure(inf);
+		smallBlas = gr->newAccelerationStructure(inf);
 
 
 		// TLAS
 		// TLAS
 		Array<AccelerationStructureInstance, 1> instances;
 		Array<AccelerationStructureInstance, 1> instances;
@@ -2955,6 +2955,43 @@ void main()
 		sbt->unmap();
 		sbt->unmap();
 	}
 	}
 
 
+	// Create model info
+	BufferPtr modelBuffer;
+	if(useRayTracing)
+	{
+		struct Material
+		{
+			Vec3 m_diffuseColor;
+		};
+
+		struct Mesh
+		{
+			U64 m_indexBufferPtr;
+			U64 m_positionBufferPtr;
+		};
+
+		struct Model
+		{
+			Material m_mtl;
+			Mesh m_mesh;
+		};
+
+		const U32 modelCount = 1;
+
+		BufferInitInfo inf;
+		inf.m_mapAccess = BufferMapAccessBit::WRITE;
+		inf.m_usage = BufferUsageBit::ALL_STORAGE;
+		inf.m_size = sizeof(Model) * modelCount;
+
+		modelBuffer = gr->newBuffer(inf);
+		WeakArray<Model, PtrSize> models = modelBuffer->map<Model>(0, modelCount, BufferMapAccessBit::WRITE);
+		memset(&models[0], 0, inf.m_size);
+
+		models[0].m_mtl.m_diffuseColor = Vec3(0.75f);
+
+		modelBuffer->unmap();
+	}
+
 	// Draw
 	// Draw
 	constexpr U32 ITERATIONS = 200;
 	constexpr U32 ITERATIONS = 200;
 	for(U i = 0; i < ITERATIONS; ++i)
 	for(U i = 0; i < ITERATIONS; ++i)
@@ -2972,6 +3009,46 @@ void main()
 		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK | CommandBufferFlag::SMALL_BATCH;
 		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK | CommandBufferFlag::SMALL_BATCH;
 		CommandBufferPtr cmdb = gr->newCommandBuffer(cinit);
 		CommandBufferPtr cmdb = gr->newCommandBuffer(cinit);
 
 
+		if(i == 0)
+		{
+			cmdb->setAccelerationStructureBarrier(smallBlas, AccelerationStructureUsageBit::NONE,
+												  AccelerationStructureUsageBit::BUILD);
+			cmdb->buildAccelerationStructure(smallBlas);
+			cmdb->setAccelerationStructureBarrier(smallBlas, AccelerationStructureUsageBit::BUILD,
+												  AccelerationStructureUsageBit::ATTACH);
+
+			cmdb->setAccelerationStructureBarrier(tlas, AccelerationStructureUsageBit::NONE,
+												  AccelerationStructureUsageBit::BUILD);
+			cmdb->buildAccelerationStructure(tlas);
+			cmdb->setAccelerationStructureBarrier(smallBlas, AccelerationStructureUsageBit::BUILD,
+												  AccelerationStructureUsageBit::TRACE_RAYS_READ);
+		}
+
+		TexturePtr presentTex = gr->acquireNextPresentableTexture();
+
+		TextureViewPtr presentView;
+		{
+
+			TextureViewInitInfo inf;
+			inf.m_texture = presentTex;
+
+			presentView = gr->newTextureView(inf);
+		}
+
+		cmdb->setTextureBarrier(presentTex, TextureUsageBit::NONE, TextureUsageBit::IMAGE_TRACE_RAYS_WRITE,
+								TextureSubresourceInfo());
+
+		cmdb->bindStorageBuffer(0, 0, modelBuffer, 0, MAX_PTR_SIZE);
+		cmdb->bindAccelerationStructure(0, 1, tlas);
+		cmdb->bindImage(0, 2, presentView);
+
+		cmdb->bindShaderProgram(rtProg);
+
+		cmdb->traceRays(sbt, 0, 1, WIDTH, HEIGHT, 1);
+
+		cmdb->setTextureBarrier(presentTex, TextureUsageBit::IMAGE_TRACE_RAYS_WRITE, TextureUsageBit::PRESENT,
+								TextureSubresourceInfo());
+
 #if 0
 #if 0
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);