Browse Source

GR: Add DrawID support for both D3D and VK

Panagiotis Christopoulos Charitos 1 month ago
parent
commit
b88d2a1cd8

+ 3 - 0
AnKi/Gr/Common.cpp

@@ -174,6 +174,8 @@ Error ShaderReflection::linkShaderReflection(const ShaderReflection& a, const Sh
 	c.m_descriptor.m_d3dShaderBindingTableRecordConstantsSize =
 		max(a.m_descriptor.m_d3dShaderBindingTableRecordConstantsSize, b.m_descriptor.m_d3dShaderBindingTableRecordConstantsSize);
 
+	c.m_descriptor.m_d3dHasDrawId = a.m_descriptor.m_d3dHasDrawId || b.m_descriptor.m_d3dHasDrawId;
+
 	c.m_descriptor.m_hasVkBindlessDescriptorSet = a.m_descriptor.m_hasVkBindlessDescriptorSet || b.m_descriptor.m_hasVkBindlessDescriptorSet;
 
 	c.m_vertex.m_vkVertexAttributeLocations =
@@ -200,6 +202,7 @@ StringList ShaderReflectionDescriptorRelated::toString() const
 
 	list.pushBackSprintf("Fast constants: %u", m_fastConstantsSize);
 	list.pushBackSprintf("Has VK bindless sets: %u", m_hasVkBindlessDescriptorSet);
+	list.pushBackSprintf("Has D3D DrawID: %u", m_d3dHasDrawId);
 
 	return list;
 }

+ 1 - 0
AnKi/Gr/Common.h

@@ -997,6 +997,7 @@ public:
 
 	Bool m_hasVkBindlessDescriptorSet = false; ///< Filled by the shader compiler.
 	U8 m_vkBindlessDescriptorSet = kMaxU8; ///< Filled by the VK backend.
+	Bool m_d3dHasDrawId = false;
 
 	void validate() const
 	{

+ 19 - 10
AnKi/Gr/D3D/D3DCommandBuffer.cpp

@@ -442,9 +442,11 @@ void CommandBuffer::drawIndirect(PrimitiveTopology topology, const BufferView& b
 	self.m_graphicsState.setPrimitiveTopology(topology);
 	self.drawcallCommon();
 
+	const ShaderProgramImpl& internalProg = static_cast<const ShaderProgramImpl&>(self.m_graphicsState.getShaderProgram());
+
 	ID3D12CommandSignature* signature;
-	ANKI_CHECKF(
-		IndirectCommandSignatureFactory::getSingleton().getOrCreateSignature(D3D12_INDIRECT_ARGUMENT_TYPE_DRAW, sizeof(DrawIndirectArgs), signature));
+	ANKI_CHECKF(IndirectCommandSignatureFactory::getSingleton().getOrCreateSignature(D3D12_INDIRECT_ARGUMENT_TYPE_DRAW, sizeof(DrawIndirectArgs),
+																					 internalProg.m_rootSignature, signature));
 
 	const BufferImpl& buffImpl = static_cast<const BufferImpl&>(buff.getBuffer());
 	ANKI_ASSERT(!!(buffImpl.getBufferUsage() & BufferUsageBit::kIndirectDraw));
@@ -462,8 +464,11 @@ void CommandBuffer::drawIndirectCount(PrimitiveTopology topology, const BufferVi
 	self.m_graphicsState.setPrimitiveTopology(topology);
 	self.drawcallCommon();
 
+	const ShaderProgramImpl& internalProg = static_cast<const ShaderProgramImpl&>(self.m_graphicsState.getShaderProgram());
+
 	ID3D12CommandSignature* signature;
-	ANKI_CHECKF(IndirectCommandSignatureFactory::getSingleton().getOrCreateSignature(D3D12_INDIRECT_ARGUMENT_TYPE_DRAW, argBufferStride, signature));
+	ANKI_CHECKF(IndirectCommandSignatureFactory::getSingleton().getOrCreateSignature(D3D12_INDIRECT_ARGUMENT_TYPE_DRAW, argBufferStride,
+																					 internalProg.m_rootSignature, signature));
 
 	const BufferImpl& argBuffImpl = static_cast<const BufferImpl&>(argBuffer.getBuffer());
 	ANKI_ASSERT(!!(argBuffImpl.getBufferUsage() & BufferUsageBit::kIndirectDraw));
@@ -487,9 +492,11 @@ void CommandBuffer::drawIndexedIndirect(PrimitiveTopology topology, const Buffer
 	self.m_graphicsState.setPrimitiveTopology(topology);
 	self.drawcallCommon();
 
+	const ShaderProgramImpl& internalProg = static_cast<const ShaderProgramImpl&>(self.m_graphicsState.getShaderProgram());
+
 	ID3D12CommandSignature* signature;
-	ANKI_CHECKF(IndirectCommandSignatureFactory::getSingleton().getOrCreateSignature(D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED,
-																					 sizeof(DrawIndexedIndirectArgs), signature));
+	ANKI_CHECKF(IndirectCommandSignatureFactory::getSingleton().getOrCreateSignature(
+		D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED, sizeof(DrawIndexedIndirectArgs), internalProg.m_rootSignature, signature));
 
 	const BufferImpl& buffImpl = static_cast<const BufferImpl&>(buff.getBuffer());
 	ANKI_ASSERT(!!(buffImpl.getBufferUsage() & BufferUsageBit::kIndirectDraw));
@@ -509,9 +516,11 @@ void CommandBuffer::drawIndexedIndirectCount(PrimitiveTopology topology, const B
 	self.m_graphicsState.setPrimitiveTopology(topology);
 	self.drawcallCommon();
 
+	const ShaderProgramImpl& internalProg = static_cast<const ShaderProgramImpl&>(self.m_graphicsState.getShaderProgram());
+
 	ID3D12CommandSignature* signature;
-	ANKI_CHECKF(
-		IndirectCommandSignatureFactory::getSingleton().getOrCreateSignature(D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED, argBufferStride, signature));
+	ANKI_CHECKF(IndirectCommandSignatureFactory::getSingleton().getOrCreateSignature(D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED, argBufferStride,
+																					 internalProg.m_rootSignature, signature));
 
 	const BufferImpl& argBuffImpl = static_cast<const BufferImpl&>(argBuffer.getBuffer());
 	ANKI_ASSERT(!!(argBuffImpl.getBufferUsage() & BufferUsageBit::kIndirectDraw));
@@ -551,7 +560,7 @@ void CommandBuffer::drawMeshTasksIndirect(const BufferView& argBuffer, U32 drawC
 
 	ID3D12CommandSignature* signature;
 	ANKI_CHECKF(IndirectCommandSignatureFactory::getSingleton().getOrCreateSignature(D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH,
-																					 sizeof(DispatchIndirectArgs), signature));
+																					 sizeof(DispatchIndirectArgs), nullptr, signature));
 
 	self.m_cmdList->ExecuteIndirect(signature, drawCount, &impl.getD3DResource(), argBuffer.getOffset(), nullptr, 0);
 }
@@ -576,7 +585,7 @@ void CommandBuffer::dispatchComputeIndirect(const BufferView& argBuffer)
 
 	ID3D12CommandSignature* signature;
 	ANKI_CHECKF(IndirectCommandSignatureFactory::getSingleton().getOrCreateSignature(D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH,
-																					 sizeof(DispatchIndirectArgs), signature));
+																					 sizeof(DispatchIndirectArgs), nullptr, signature));
 
 	self.m_cmdList->ExecuteIndirect(signature, 1, &impl.getD3DResource(), argBuffer.getOffset(), nullptr, 0);
 }
@@ -687,7 +696,7 @@ void CommandBuffer::dispatchRaysIndirect(const BufferView& sbtBuffer, U32 sbtRec
 	// Execute
 	ID3D12CommandSignature* signature;
 	ANKI_CHECKF(IndirectCommandSignatureFactory::getSingleton().getOrCreateSignature(D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_RAYS,
-																					 sizeof(D3D12_DISPATCH_RAYS_DESC), signature));
+																					 sizeof(D3D12_DISPATCH_RAYS_DESC), nullptr, signature));
 
 	self.m_cmdList->ExecuteIndirect(signature, 1, self.m_indirectDispatchRays.m_indirectBuff, indirectBuffOffset, nullptr, 0);
 

+ 36 - 11
AnKi/Gr/D3D/D3DCommandBufferFactory.cpp

@@ -4,6 +4,7 @@
 // http://www.anki3d.org/LICENSE
 
 #include <AnKi/Gr/D3D/D3DCommandBufferFactory.h>
+#include <AnKi/Gr/D3D/D3DDescriptor.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Core/StatsSet.h>
 
@@ -100,24 +101,27 @@ Error IndirectCommandSignatureFactory::init()
 	for(IndirectCommandSignatureType i : EnumIterable<IndirectCommandSignatureType>())
 	{
 		ID3D12CommandSignature* sig;
-		ANKI_CHECK(getOrCreateSignatureInternal(false, kAnkiToD3D[i], kCommonStrides[i], sig));
+		ANKI_CHECK(getOrCreateSignatureInternal(false, kAnkiToD3D[i], kCommonStrides[i], nullptr, sig));
 	}
 	return Error::kNone;
 }
 
-Error IndirectCommandSignatureFactory::getOrCreateSignatureInternal(Bool takeFastPath, D3D12_INDIRECT_ARGUMENT_TYPE type, U32 stride,
-																	ID3D12CommandSignature*& signature)
+Error IndirectCommandSignatureFactory::getOrCreateSignatureInternal(Bool tryThePreCreatedRootSignaturesFirst, D3D12_INDIRECT_ARGUMENT_TYPE type,
+																	U32 stride, RootSignature* rootSignature, ID3D12CommandSignature*& signature)
 {
 	signature = nullptr;
 
+	Bool hasVertexShader = false;
 	IndirectCommandSignatureType akType = IndirectCommandSignatureType::kCount;
 	switch(type)
 	{
 	case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW:
 		akType = IndirectCommandSignatureType::kDraw;
+		hasVertexShader = true;
 		break;
 	case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED:
 		akType = IndirectCommandSignatureType::kDrawIndexed;
+		hasVertexShader = true;
 		break;
 	case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH:
 		akType = IndirectCommandSignatureType::kDispatch;
@@ -132,8 +136,22 @@ Error IndirectCommandSignatureFactory::getOrCreateSignatureInternal(Bool takeFas
 		ANKI_ASSERT(!"Unsupported");
 	}
 
-	// Check if it's a common stride
-	if(takeFastPath && stride == kCommonStrides[akType])
+	if(tryThePreCreatedRootSignaturesFirst)
+	{
+		ANKI_ASSERT((!rootSignature || hasVertexShader)
+					&& "If signature will be used with a vert shader we need the root signature to determin the DrawID");
+	}
+	else
+	{
+		ANKI_ASSERT(rootSignature == nullptr);
+	}
+
+	const Bool needsDrawId = rootSignature && rootSignature->getDrawIdRootParamIdx() != kMaxU32;
+	ID3D12RootSignature* d3dRootSignature = needsDrawId ? &rootSignature->getD3DRootSignature() : nullptr;
+	const U32 drawIdParameterIdx = needsDrawId ? rootSignature->getDrawIdRootParamIdx() : kMaxU32;
+
+	// Check if it's one of the pre-created
+	if(tryThePreCreatedRootSignaturesFirst && stride == kCommonStrides[akType] && d3dRootSignature == nullptr)
 	{
 		signature = m_arrays[akType][0].m_d3dSignature;
 		return Error::kNone;
@@ -144,7 +162,7 @@ Error IndirectCommandSignatureFactory::getOrCreateSignatureInternal(Bool takeFas
 
 		for(const Signature& sig : m_arrays[akType])
 		{
-			if(sig.m_stride == stride)
+			if(sig.m_stride == stride && sig.m_d3dRootSignature == d3dRootSignature)
 			{
 				signature = sig.m_d3dSignature;
 				break;
@@ -156,10 +174,17 @@ Error IndirectCommandSignatureFactory::getOrCreateSignatureInternal(Bool takeFas
 	{
 		// Proactively create it without locking
 
-		const D3D12_INDIRECT_ARGUMENT_DESC arg = {.Type = type};
-		const D3D12_COMMAND_SIGNATURE_DESC desc = {.ByteStride = stride, .NumArgumentDescs = 1, .pArgumentDescs = &arg, .NodeMask = 0};
+		Array<D3D12_INDIRECT_ARGUMENT_DESC, 2> args = {};
+		args[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_INCREMENTING_CONSTANT;
+		args[0].IncrementingConstant.RootParameterIndex = drawIdParameterIdx;
+		args[0].IncrementingConstant.DestOffsetIn32BitValues = 0;
+		args[1].Type = type;
+		const D3D12_COMMAND_SIGNATURE_DESC desc = {.ByteStride = stride,
+												   .NumArgumentDescs = needsDrawId ? 2u : 1u,
+												   .pArgumentDescs = args.getBegin() + (needsDrawId ? 0 : 1),
+												   .NodeMask = 0};
 
-		ANKI_D3D_CHECK(getDevice().CreateCommandSignature(&desc, nullptr, IID_PPV_ARGS(&signature)));
+		ANKI_D3D_CHECK(getDevice().CreateCommandSignature(&desc, d3dRootSignature, IID_PPV_ARGS(&signature)));
 
 		// Try to do bookkeeping
 
@@ -169,7 +194,7 @@ Error IndirectCommandSignatureFactory::getOrCreateSignatureInternal(Bool takeFas
 			ID3D12CommandSignature* oldSignature = nullptr;
 			for(const Signature& sig : m_arrays[akType])
 			{
-				if(sig.m_stride == stride)
+				if(sig.m_stride == stride && sig.m_d3dRootSignature == d3dRootSignature)
 				{
 					oldSignature = sig.m_d3dSignature;
 					break;
@@ -185,7 +210,7 @@ Error IndirectCommandSignatureFactory::getOrCreateSignatureInternal(Bool takeFas
 			else
 			{
 				// New signature, do bookkeeping
-				const Signature sig = {.m_d3dSignature = signature, .m_stride = stride};
+				const Signature sig = {.m_d3dSignature = signature, .m_d3dRootSignature = d3dRootSignature, .m_stride = stride};
 				m_arrays[akType].emplaceBack(sig);
 			}
 		}

+ 9 - 4
AnKi/Gr/D3D/D3DCommandBufferFactory.h

@@ -12,6 +12,8 @@
 
 namespace anki {
 
+class RootSignature;
+
 /// @addtogroup directx
 /// @{
 
@@ -109,10 +111,11 @@ public:
 
 	Error init();
 
-	/// @note Thread-safe.
-	Error getOrCreateSignature(D3D12_INDIRECT_ARGUMENT_TYPE type, U32 stride, ID3D12CommandSignature*& signature)
+	// Thread-safe
+	// rootSignature: Only useful for drawcalls with vertex shader (needed for the DrawID)
+	Error getOrCreateSignature(D3D12_INDIRECT_ARGUMENT_TYPE type, U32 stride, RootSignature* rootSignature, ID3D12CommandSignature*& signature)
 	{
-		return getOrCreateSignatureInternal(true, type, stride, signature);
+		return getOrCreateSignatureInternal(true, type, stride, rootSignature, signature);
 	}
 
 private:
@@ -132,6 +135,7 @@ private:
 	{
 	public:
 		ID3D12CommandSignature* m_d3dSignature;
+		ID3D12RootSignature* m_d3dRootSignature;
 		U32 m_stride;
 	};
 
@@ -147,7 +151,8 @@ private:
 
 	Array<RWMutex, U32(IndirectCommandSignatureType::kCount)> m_mutexes;
 
-	Error getOrCreateSignatureInternal(Bool takeFastPath, D3D12_INDIRECT_ARGUMENT_TYPE type, U32 stride, ID3D12CommandSignature*& signature);
+	Error getOrCreateSignatureInternal(Bool tryThePreCreatedRootSignaturesFirst, D3D12_INDIRECT_ARGUMENT_TYPE type, U32 stride,
+									   RootSignature* rootSignature, ID3D12CommandSignature*& signature);
 };
 /// @}
 

+ 18 - 2
AnKi/Gr/D3D/D3DDescriptor.cpp

@@ -343,11 +343,26 @@ Error RootSignatureFactory::getOrCreateRootSignature(const ShaderReflection& ref
 		rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
 		ANKI_ASSERT((refl.m_descriptor.m_fastConstantsSize % 4) == 0);
 		rootParam.Constants.Num32BitValues = refl.m_descriptor.m_fastConstantsSize / 4;
-		rootParam.Constants.RegisterSpace = 3000;
+		rootParam.Constants.RegisterSpace = ANKI_D3D_FAST_CONSTANTS_SPACE;
 		rootParam.Constants.ShaderRegister = 0;
 		rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
 	}
 
+	// DrawID
+	U32 drawIdRootParam = kMaxU32;
+	if(refl.m_descriptor.m_d3dHasDrawId)
+	{
+		drawIdRootParam = rootParameters.getSize();
+
+		D3D12_ROOT_PARAMETER1& rootParam = *rootParameters.emplaceBack();
+		rootParam = {};
+		rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
+		rootParam.Constants.Num32BitValues = 1;
+		rootParam.Constants.RegisterSpace = ANKI_D3D_DRAW_ID_CONSTANT_SPACE;
+		rootParam.Constants.ShaderRegister = 0;
+		rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
+	}
+
 	D3D12_VERSIONED_ROOT_SIGNATURE_DESC verSigDesc = {};
 	verSigDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
 
@@ -372,6 +387,7 @@ Error RootSignatureFactory::getOrCreateRootSignature(const ShaderReflection& ref
 	signature = newInstance<RootSignature>(GrMemoryPool::getSingleton());
 	signature->m_hash = hash;
 	signature->m_rootSignature = dxRootSig;
+	signature->m_drawIdRootParamIdx = drawIdRootParam;
 
 	U8 rootParameterIdx = 0;
 	for(U32 spaceIdx = 0; spaceIdx < kMaxRegisterSpaces; ++spaceIdx)
@@ -470,7 +486,7 @@ Error RootSignatureFactory::getOrCreateLocalRootSignature(const ShaderReflection
 	D3D12_ROOT_PARAMETER1 rootParam = {};
 	rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
 	rootParam.Constants.Num32BitValues = refl.m_descriptor.m_d3dShaderBindingTableRecordConstantsSize / 4;
-	rootParam.Constants.RegisterSpace = 3001;
+	rootParam.Constants.RegisterSpace = ANKI_D3D_SHADER_RECORD_CONSTANTS_SPACE;
 	rootParam.Constants.ShaderRegister = 0;
 
 	D3D12_VERSIONED_ROOT_SIGNATURE_DESC verSigDesc = {};

+ 7 - 0
AnKi/Gr/D3D/D3DDescriptor.h

@@ -273,6 +273,11 @@ public:
 		return *m_rootSignature;
 	}
 
+	U32 getDrawIdRootParamIdx() const
+	{
+		return m_drawIdRootParamIdx;
+	}
+
 private:
 	class Descriptor
 	{
@@ -302,6 +307,8 @@ private:
 
 	Array<Space, kMaxRegisterSpaces> m_spaces;
 
+	U32 m_drawIdRootParamIdx = kMaxU32;
+
 	U32 m_rootConstantsSize = kMaxU32;
 	U8 m_rootConstantsParameterIdx = kMaxU8;
 

+ 2 - 1
AnKi/Gr/Vulkan/VkShaderProgram.cpp

@@ -541,7 +541,8 @@ void ShaderProgramImpl::rewriteSpirv(ShaderReflectionDescriptorRelated& refl, Gr
 					++vkBindingCount[set];
 				}
 			}
-			else if(cmd == spv::OpDecorate && instructions[1] == spv::DecorationDescriptorSet && instructions[2] == kDxcVkBindlessRegisterSpace)
+			else if(cmd == spv::OpDecorate && instructions[1] == spv::DecorationDescriptorSet
+					&& instructions[2] == ANKI_VK_BINDLESS_TEXTURES_DESCRIPTOR_SET)
 			{
 				// Bindless set, rewrite its set
 				instructions[2] = refl.m_vkBindlessDescriptorSet;

+ 10 - 2
AnKi/ShaderCompiler/Dxc.cpp

@@ -385,7 +385,7 @@ Error doReflectionDxil(ConstWeakArray<U8> dxil, ShaderType type, ShaderReflectio
 			{
 				// ConstantBuffer
 
-				if(bindDesc.Space == 3000 && bindDesc.BindPoint == 0)
+				if(bindDesc.Space == ANKI_D3D_FAST_CONSTANTS_SPACE && bindDesc.BindPoint == 0)
 				{
 					// It's push/root constants
 
@@ -397,7 +397,7 @@ Error doReflectionDxil(ConstWeakArray<U8> dxil, ShaderType type, ShaderReflectio
 
 					continue;
 				}
-				else if(bindDesc.Space == 3001 && bindDesc.BindPoint == 0)
+				else if(bindDesc.Space == ANKI_D3D_SHADER_RECORD_CONSTANTS_SPACE && bindDesc.BindPoint == 0)
 				{
 					// It's SBT consts
 
@@ -414,6 +414,14 @@ Error doReflectionDxil(ConstWeakArray<U8> dxil, ShaderType type, ShaderReflectio
 
 					continue;
 				}
+				else if(bindDesc.Space == ANKI_D3D_DRAW_ID_CONSTANT_SPACE && bindDesc.BindPoint == 0)
+				{
+					// It's DrawID
+
+					refl.m_descriptor.m_d3dHasDrawId = true;
+
+					continue;
+				}
 
 				akBinding.m_type = DescriptorType::kConstantBuffer;
 			}

+ 0 - 3
AnKi/ShaderCompiler/Dxc.h

@@ -17,9 +17,6 @@ namespace anki {
 inline constexpr Array2d<U32, kMaxRegisterSpaces, U32(HlslResourceType::kCount)> kDxcVkBindingShifts = {
 	{{1000, 2000, 3000, 4000}, {5000, 6000, 7000, 8000}, {9000, 10000, 11000, 12000}}};
 
-// !!!!WARNING!!!! Need to change HLSL if you change the value bellow
-inline constexpr U32 kDxcVkBindlessRegisterSpace = 1000000;
-
 /// Compile HLSL to SPIR-V.
 Error compileHlslToSpirv(CString src, ShaderType shaderType, Bool compileWith16bitTypes, Bool debugInfo, ShaderModel sm,
 						 ConstWeakArray<CString> compilerArgs, ShaderCompilerDynamicArray<U8>& spirv, ShaderCompilerString& errorMessage);

+ 2 - 1
AnKi/ShaderCompiler/ShaderDump.cpp

@@ -207,7 +207,8 @@ void dumpShaderBinary(const ShaderDumpOptions& options, const ShaderBinary& bina
 		Error visitErr = Error::kNone;
 		visitSpirv(WeakArray<U32>(reinterpret_cast<U32*>(newSpirv.getBegin()), U32(newSpirv.getSizeInBytes() / sizeof(U32))),
 				   [&](U32 cmd, WeakArray<U32> instructions) {
-					   if(cmd == spv::OpDecorate && instructions[1] == spv::DecorationDescriptorSet && instructions[2] == kDxcVkBindlessRegisterSpace)
+					   if(cmd == spv::OpDecorate && instructions[1] == spv::DecorationDescriptorSet
+						  && instructions[2] == ANKI_VK_BINDLESS_TEXTURES_DESCRIPTOR_SET)
 					   {
 						   // Bindless set, rewrite its set
 						   instructions[2] = kMaxRegisterSpaces;

+ 3 - 3
AnKi/ShaderCompiler/Spirv.cpp

@@ -22,7 +22,7 @@ Error doReflectionSpirv(ConstWeakArray<U8> spirv, ShaderType type, ShaderReflect
 
 			const U32 set = spvc.get_decoration(id, spv::Decoration::DecorationDescriptorSet);
 			const U32 binding = spvc.get_decoration(id, spv::Decoration::DecorationBinding);
-			if(set >= kMaxRegisterSpaces && set != kDxcVkBindlessRegisterSpace)
+			if(set >= kMaxRegisterSpaces && set != ANKI_VK_BINDLESS_TEXTURES_DESCRIPTOR_SET)
 			{
 				errorStr.sprintf("Exceeded set for: %s", r.name.c_str());
 				return Error::kUserData;
@@ -38,7 +38,7 @@ Error doReflectionSpirv(ConstWeakArray<U8> spirv, ShaderType type, ShaderReflect
 					return Error::kUserData;
 				}
 
-				if(set == kDxcVkBindlessRegisterSpace && typeInfo.array[0] != 0)
+				if(set == ANKI_VK_BINDLESS_TEXTURES_DESCRIPTOR_SET && typeInfo.array[0] != 0)
 				{
 					errorStr.sprintf("Only the bindless descriptor set can be an unbound array: %s", r.name.c_str());
 					return Error::kUserData;
@@ -62,7 +62,7 @@ Error doReflectionSpirv(ConstWeakArray<U8> spirv, ShaderType type, ShaderReflect
 				}
 			}
 
-			if(set == kDxcVkBindlessRegisterSpace)
+			if(set == ANKI_VK_BINDLESS_TEXTURES_DESCRIPTOR_SET)
 			{
 				// Bindless dset
 

+ 19 - 3
AnKi/Shaders/Common.hlsl

@@ -104,18 +104,34 @@ struct Barycentrics
 #if ANKI_GR_BACKEND_VULKAN
 #	define ANKI_FAST_CONSTANTS(type, var) [[vk::push_constant]] ConstantBuffer<type> var;
 #else
-#	define ANKI_FAST_CONSTANTS(type, var) ConstantBuffer<type> var : register(b0, space3000);
+#	define ANKI_FAST_CONSTANTS(type, var) ConstantBuffer<type> var : register(b0, ANKI_CONCATENATE(space, ANKI_D3D_FAST_CONSTANTS_SPACE));
 #endif
 
 #if ANKI_GR_BACKEND_VULKAN
 #	define ANKI_SHADER_RECORD_CONSTANTS(type, var) [[vk::shader_record_ext]] ConstantBuffer<type> var : register(b0, space3001);
 #else
-#	define ANKI_SHADER_RECORD_CONSTANTS(type, var) ConstantBuffer<type> var : register(b0, space3001);
+#	define ANKI_SHADER_RECORD_CONSTANTS(type, var) \
+		ConstantBuffer<type> var : register(b0, ANKI_CONCATENATE(space, ANKI_D3D_SHADER_RECORD_CONSTANTS_SPACE));
+#endif
+
+// This is the implementation of gl_DrawID for both D3D anv VK
+#if ANKI_VERTEX_SHADER
+#	if ANKI_GR_BACKEND_VULKAN
+#		define SpvDrawIndex 4426
+[[vk::ext_builtin_input(SpvDrawIndex)]] const static U32 gl_DrawID;
+#	else
+struct U32Struct
+{
+	U32 m_data;
+};
+ConstantBuffer<U32Struct> g_drawIdConstant : register(b0, ANKI_CONCATENATE(space, ANKI_D3D_DRAW_ID_CONSTANT_SPACE));
+#		define gl_DrawID g_drawIdConstant.m_data
+#	endif
 #endif
 
 #if ANKI_GR_BACKEND_VULKAN
 #	define ANKI_BINDLESS(texType, compType) \
-		[[vk::binding(0, 1000000)]] Texture##texType<compType> g_bindlessTextures##texType##compType[]; \
+		[[vk::binding(0, ANKI_VK_BINDLESS_TEXTURES_DESCRIPTOR_SET)]] Texture##texType<compType> g_bindlessTextures##texType##compType[]; \
 		Texture##texType<compType> getBindlessTexture##texType##compType(U32 idx) \
 		{ \
 			return g_bindlessTextures##texType##compType[idx]; \

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

@@ -450,6 +450,12 @@ constexpr F32 kPcssSearchTexelRadius = 12.0;
 constexpr F32 kPcssTexelRadius = 12.0;
 constexpr F32 kPcssDirLightMaxPenumbraMeters = 6.0; // If the occluder and the reciever have more than this value then do full penumbra
 
+// Some special spaces or sets for reflection to identify special shader input
+#define ANKI_D3D_FAST_CONSTANTS_SPACE 3000
+#define ANKI_D3D_SHADER_RECORD_CONSTANTS_SPACE 3001
+#define ANKI_D3D_DRAW_ID_CONSTANT_SPACE 3002
+#define ANKI_VK_BINDLESS_TEXTURES_DESCRIPTOR_SET 1000000
+
 struct DrawIndirectArgs
 {
 	U32 m_vertexCount;

+ 141 - 0
Tests/Gr/Gr.cpp

@@ -3888,3 +3888,144 @@ void main()
 	COMMON_END()
 #endif
 }
+
+ANKI_TEST(Gr, DrawID)
+{
+	commonInit();
+
+	{
+		// Prog
+		constexpr const char* kVert = R"(
+struct Consts
+{
+	uint index;
+	int padding;
+	int padding1;
+	int padding2;
+};
+
+#if defined(__spirv__)
+#	define SpvDrawIndex 4426
+[[vk::ext_builtin_input(SpvDrawIndex)]] const static uint gl_DrawID;
+
+[[vk::push_constant]] ConstantBuffer<Consts> g_consts;
+#else
+struct U32Struct
+{
+	uint m_data;
+};
+ConstantBuffer<U32Struct> g_drawIdConstant : register(b0, space%u);
+#	define gl_DrawID g_drawIdConstant.m_data
+
+ConstantBuffer<Consts> g_consts : register(b0, space%u);
+#endif
+
+struct VertOut
+{
+	float4 m_svPosition : SV_POSITION;
+	float3 m_color : COLOR;
+};
+
+VertOut main(uint svVertexId : SV_VERTEXID)
+{
+	float2 verts[6] = {float2(0, 0), float2(0, 1), float2(1, 1), float2(1, 1), float2(1, 0), float2(0, 0)};
+
+	uint maxDraws = 32;
+
+	float2 pos = verts[svVertexId];
+	pos.x /= maxDraws;
+	pos.x += gl_DrawID * 1.0 / maxDraws;
+	pos = pos * 2.0 - 1.0;
+	pos.y *= -1.0;
+
+	VertOut o;
+	o.m_svPosition = float4(pos, 0.0, 1.0);
+
+	uint index = gl_DrawID + g_consts.index;
+	index = index %% 6;
+	o.m_color = float3(index & 1, (index / 2) & 1, (index / 3) & 1);
+
+	return o;
+})";
+
+		constexpr const char* kUboFrag = R"(
+struct VertOut
+{
+	float4 m_svPosition : SV_POSITION;
+	float3 m_color : COLOR;
+};
+
+float4 main(VertOut i) : SV_TARGET0
+{
+	return float4(i.m_color, 1.0);
+})";
+
+		ShaderProgramPtr prog = createVertFragProg(String().sprintf(kVert, ANKI_D3D_DRAW_ID_CONSTANT_SPACE, ANKI_D3D_FAST_CONSTANTS_SPACE), kUboFrag);
+
+		constexpr U32 maxDraws = 32;
+		Array<DrawIndirectArgs, maxDraws> data = {};
+		for(DrawIndirectArgs& arg : data)
+		{
+			arg.m_instanceCount = 1;
+			arg.m_vertexCount = 6;
+		}
+		BufferPtr indirectArgs = createBuffer(BufferUsageBit::kIndirectDraw, ConstWeakArray(data), "indirect args");
+
+		U32 count = maxDraws;
+		BufferPtr indirectCount = createBuffer(BufferUsageBit::kIndirectDraw, ConstWeakArray<U32>(&count, 1), "indirect count");
+
+		const U kIterationCount = 200;
+		U iterations = kIterationCount;
+		while(iterations--)
+		{
+			HighRezTimer timer;
+			timer.start();
+
+			GrManager::getSingleton().beginFrame();
+
+			TexturePtr presentTex = GrManager::getSingleton().acquireNextPresentableTexture();
+
+			CommandBufferInitInfo cinit;
+			cinit.m_flags = CommandBufferFlag::kGeneralWork;
+			CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cinit);
+
+			cmdb->setViewport(0, 0, NativeWindow::getSingleton().getWidth(), NativeWindow::getSingleton().getHeight());
+			cmdb->bindShaderProgram(prog.get());
+
+			const TextureBarrierInfo barrier = {TextureView(presentTex.get(), TextureSubresourceDesc::all()), TextureUsageBit::kNone,
+												TextureUsageBit::kRtvDsvWrite};
+			cmdb->setPipelineBarrier({&barrier, 1}, {}, {});
+
+			cmdb->pushDebugMarker("AnKi", Vec3(1.0f, 0.0f, 0.0f));
+
+			cmdb->beginRenderPass({TextureView(presentTex.get(), TextureSubresourceDesc::firstSurface())});
+
+			UVec4 consts(iterations / 10);
+			cmdb->setFastConstants(&consts, sizeof(consts));
+
+			cmdb->drawIndirectCount(PrimitiveTopology::kTriangles, BufferView(indirectArgs.get()), sizeof(DrawIndirectArgs),
+									BufferView(indirectCount.get()), maxDraws);
+			cmdb->endRenderPass();
+
+			const TextureBarrierInfo barrier2 = {TextureView(presentTex.get(), TextureSubresourceDesc::all()), TextureUsageBit::kRtvDsvWrite,
+												 TextureUsageBit::kPresent};
+			cmdb->setPipelineBarrier({&barrier2, 1}, {}, {});
+
+			cmdb->popDebugMarker();
+
+			cmdb->endRecording();
+			GrManager::getSingleton().submit(cmdb.get());
+
+			GrManager::getSingleton().endFrame();
+
+			timer.stop();
+			const Second kTick = 1.0f / 30.0f;
+			if(timer.getElapsedTime() < kTick)
+			{
+				HighRezTimer::sleep(kTick - timer.getElapsedTime());
+			}
+		}
+	}
+
+	commonDestroy();
+}

+ 1 - 0
Tests/Gr/GrCommon.h

@@ -97,6 +97,7 @@ inline void commonInit(Bool validation = true)
 	g_cvarWindowHeight = kHeight;
 	g_cvarGrVsync = false;
 	g_cvarGrDebugMarkers = true;
+	g_cvarWindowFullscreen = 0;
 	if(validation)
 	{
 		g_cvarGrValidation = true;