浏览代码

More D3D compiler work

Panagiotis Christopoulos Charitos 1 年之前
父节点
当前提交
4d5d13ecc0

+ 2 - 0
.gitignore

@@ -4,3 +4,5 @@ out/*
 CMakeSettings.json
 *.TMP
 AndroidProject_*
+*.diff
+*.patch

+ 7 - 2
AnKi/Config.h.cmake

@@ -143,8 +143,13 @@
 #endif
 
 // Graphics backend
-#define ANKI_GR_BACKEND_GL 0
-#define ANKI_GR_BACKEND_VULKAN 1
+#if ${_ANKI_GR_BACKEND} == 0
+#	define ANKI_GR_BACKEND_VULKAN 1
+#	define ANKI_GR_BACKEND_DIRECT3D 0
+#else
+#	define ANKI_GR_BACKEND_VULKAN 0
+#	define ANKI_GR_BACKEND_DIRECT3D 1
+#endif
 
 // Windowing system
 #if ${_ANKI_WINDOWING_SYSTEM} == 0

+ 39 - 3
AnKi/Gr/Common.h

@@ -895,7 +895,7 @@ public:
 		: m_class(c)
 		, m_number(U16(n))
 	{
-		ANKI_ASSERT(c == 'c' || c == 'b' || c == 'u' || c == 's');
+		ANKI_ASSERT(c == 't' || c == 'b' || c == 'u' || c == 's');
 		ANKI_ASSERT(n < kMaxU16);
 	}
 
@@ -903,7 +903,7 @@ public:
 	BindingSemantic(const Char* str)
 	{
 		ANKI_ASSERT(str);
-		ANKI_ASSERT(str[0] == 'c' || str[0] == 'b' || str[0] == 'u' || str[0] == 's');
+		ANKI_ASSERT(str[0] == 't' || str[0] == 'b' || str[0] == 'u' || str[0] == 's');
 		m_class = str[0];
 		m_number = 0;
 		while(*str != '\0')
@@ -914,16 +914,51 @@ public:
 			++str;
 		}
 	}
+
+	Bool operator<(const BindingSemantic& b) const
+	{
+		return (m_class == b.m_class) ? m_number < b.m_number : m_class < b.m_class;
+	}
+
+	Bool operator==(const BindingSemantic& b) const
+	{
+		return m_class == b.m_class && m_number == b.m_number;
+	}
 };
 
 class ShaderReflectionBinding
 {
 public:
-	BindingSemantic m_semantic = {'c', 1};
+	BindingSemantic m_semantic = {'t', 1};
 	DescriptorType m_type = DescriptorType::kCount;
 	DescriptorFlag m_flags = DescriptorFlag::kNone;
 	U16 m_arraySize = 0;
 	U16 m_vkBinding = kMaxU8;
+
+	Bool operator<(const ShaderReflectionBinding& b) const
+	{
+#define ANKI_LESS(member) \
+	if(member != b.member) \
+	{ \
+		return member < b.member; \
+	}
+
+		ANKI_LESS(m_semantic)
+		ANKI_LESS(m_type)
+		ANKI_LESS(m_flags)
+		ANKI_LESS(m_arraySize)
+		ANKI_LESS(m_vkBinding)
+#undef ANKI_LESS
+		return false;
+	}
+
+	void validate() const
+	{
+		ANKI_ASSERT(m_type < DescriptorType::kCount);
+		ANKI_ASSERT(m_flags != DescriptorFlag::kNone);
+		ANKI_ASSERT(m_arraySize > 0);
+		ANKI_ASSERT(ANKI_GR_BACKEND_DIRECT3D || m_vkBinding != kMaxU8);
+	}
 };
 
 class ShaderReflection
@@ -945,6 +980,7 @@ public:
 	BitSet<kMaxColorRenderTargets, U8> m_colorAttachmentWritemask = {false};
 
 	U8 m_pushConstantsSize = 0;
+
 	Bool m_discards = false;
 
 	ShaderReflection()

+ 109 - 0
AnKi/Gr/D3D/D3DDescriptor.cpp

@@ -0,0 +1,109 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Gr/D3D/D3DDescriptor.h>
+
+namespace anki {
+
+Error RootSignatureFactory::getOrCreateRootSignature(const ShaderReflection& refl, RootSignature*& signature)
+{
+	// Compute the hash
+	// TODO
+	U64 hash = 0;
+
+	// Search if exists
+	LockGuard lock(m_mtx);
+
+	for(RootSignature* s : m_signatures)
+	{
+		if(s->m_hash == hash)
+		{
+			signature = s;
+			return Error::kNone;
+		}
+	}
+
+	// Not found, create one
+
+	const U32 spaceCount = (refl.m_descriptorSetMask.getMostSignificantBit() < kMaxU32) ? refl.m_descriptorSetMask.getMostSignificantBit() + 1 : 0;
+	GrDynamicArray<D3D12_ROOT_PARAMETER> rootParameters;
+
+	// Create the tables
+	Array<GrDynamicArray<D3D12_DESCRIPTOR_RANGE>, kMaxBindingsPerDescriptorSet * 2> tableRanges; // One per descriptor table
+	U32 tableRangesCount = 0;
+	for(U32 space = 0; space < spaceCount; ++space)
+	{
+		GrDynamicArray<D3D12_DESCRIPTOR_RANGE>& nonSamplerRanges = tableRanges[tableRangesCount++];
+		GrDynamicArray<D3D12_DESCRIPTOR_RANGE>& samplerRanges = tableRanges[tableRangesCount++];
+
+		// Create the ranges
+		for(U32 bindingIdx = 0; bindingIdx < refl.m_bindingCounts[space]; ++bindingIdx)
+		{
+			const ShaderReflectionBinding& akBinding = refl.m_bindings[space][bindingIdx];
+			akBinding.validate();
+			D3D12_DESCRIPTOR_RANGE& range =
+				(akBinding.m_type == DescriptorType::kSampler) ? *samplerRanges.emplaceBack() : *nonSamplerRanges.emplaceBack();
+
+			range.NumDescriptors = akBinding.m_arraySize;
+			range.BaseShaderRegister = akBinding.m_semantic.m_number;
+			range.RegisterSpace = space;
+			range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+
+			if(akBinding.m_type == DescriptorType::kUniformBuffer)
+			{
+				ANKI_ASSERT(akBinding.m_semantic.m_class == 'b');
+				range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
+			}
+			else if(akBinding.m_type == DescriptorType::kSampler)
+			{
+				ANKI_ASSERT(akBinding.m_semantic.m_class == 's');
+				range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
+			}
+			else if(!(akBinding.m_flags & DescriptorFlag::kWrite))
+			{
+				ANKI_ASSERT(akBinding.m_semantic.m_class == 't');
+				range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+			}
+			else
+			{
+				ANKI_ASSERT(akBinding.m_semantic.m_class == 'u');
+				range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
+			}
+		}
+
+		if(nonSamplerRanges.getSize())
+		{
+			D3D12_ROOT_PARAMETER& table = *rootParameters.emplaceBack();
+			table.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+			table.DescriptorTable.NumDescriptorRanges = nonSamplerRanges.getSize();
+			table.DescriptorTable.pDescriptorRanges = nonSamplerRanges.getBegin();
+		}
+
+		if(samplerRanges.getSize())
+		{
+			D3D12_ROOT_PARAMETER& table = *rootParameters.emplaceBack();
+			table.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+			table.DescriptorTable.NumDescriptorRanges = samplerRanges.getSize();
+			table.DescriptorTable.pDescriptorRanges = samplerRanges.getBegin();
+		}
+	}
+
+	// Root constants
+	if(refl.m_pushConstantsSize)
+	{
+		D3D12_ROOT_PARAMETER& rootParam = *rootParameters.emplaceBack();
+		rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
+		ANKI_ASSERT((refl.m_pushConstantsSize % 4) == 0);
+		rootParam.Constants.Num32BitValues = refl.m_pushConstantsSize / 4;
+		rootParam.Constants.RegisterSpace = ANKI_PUSH_CONSTANTS_D3D_BINDING;
+		rootParam.Constants.ShaderRegister = ANKI_PUSH_CONSTANTS_D3D_SPACE;
+	}
+
+	D3D12_ROOT_SIGNATURE_DESC sigDesc = {};
+
+	return Error::kNone;
+}
+
+} // end namespace anki

+ 20 - 3
AnKi/Gr/D3D/D3DDescriptorHeap.h → AnKi/Gr/D3D/D3DDescriptor.h

@@ -9,9 +9,6 @@
 
 namespace anki {
 
-// Forward
-class DescriptorHeap;
-
 /// @addtogroup directx
 /// @{
 
@@ -157,6 +154,26 @@ public:
 private:
 	Array<DescriptorHeap, D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES> m_heaps;
 };
+
+/// @memberof RootSignatureFactory
+class RootSignature
+{
+	friend class RootSignatureFactory;
+
+public:
+	ID3D12RootSignature* m_rootSignature = nullptr;
+	U64 m_hash = 0;
+};
+
+class RootSignatureFactory : public MakeSingleton<RootSignatureFactory>
+{
+public:
+	Error getOrCreateRootSignature(const ShaderReflection& refl, RootSignature*& signature);
+
+private:
+	GrDynamicArray<RootSignature*> m_signatures;
+	Mutex m_mtx;
+};
 /// @}
 
 } // end namespace anki

+ 1 - 1
AnKi/Gr/D3D/D3DFrameGarbageCollector.h

@@ -5,7 +5,7 @@
 
 #pragma once
 
-#include <AnKi/Gr/D3D/D3DDescriptorHeap.h>
+#include <AnKi/Gr/D3D/D3DDescriptor.h>
 #include <AnKi/Gr/D3D/D3DFence.h>
 #include <AnKi/Util/List.h>
 

+ 1 - 1
AnKi/Gr/D3D/D3DGrManager.cpp

@@ -4,7 +4,7 @@
 // http://www.anki3d.org/LICENSE
 
 #include <AnKi/Gr/D3D/D3DGrManager.h>
-#include <AnKi/Gr/D3D/D3DDescriptorHeap.h>
+#include <AnKi/Gr/D3D/D3DDescriptor.h>
 #include <AnKi/Gr/D3D/D3DFrameGarbageCollector.h>
 
 #include <AnKi/Gr/D3D/D3DAccelerationStructure.h>

+ 1 - 1
AnKi/Gr/D3D/D3DSwapchainFactory.cpp

@@ -4,7 +4,7 @@
 // http://www.anki3d.org/LICENSE
 
 #include <AnKi/Gr/D3D/D3DSwapchainFactory.h>
-#include <AnKi/Gr/D3D/D3DDescriptorHeap.h>
+#include <AnKi/Gr/D3D/D3DDescriptor.h>
 #include <AnKi/Gr/D3D/D3DTexture.h>
 #include <AnKi/Gr/D3D/D3DGrManager.h>
 #include <AnKi/Window/NativeWindowSdl.h>

+ 1 - 1
AnKi/Gr/D3D/D3DTexture.h

@@ -6,7 +6,7 @@
 #pragma once
 
 #include <AnKi/Gr/Texture.h>
-#include <AnKi/Gr/D3D/D3DDescriptorHeap.h>
+#include <AnKi/Gr/D3D/D3DDescriptor.h>
 #include <AnKi/Util/HashMap.h>
 
 namespace anki {

+ 4 - 0
AnKi/ShaderCompiler/Dxc.cpp

@@ -97,6 +97,10 @@ static Error compileHlsl(CString src, ShaderType shaderType, Bool compileWith16b
 	dxcArgs.emplaceBack("main");
 	dxcArgs.emplaceBack("-T");
 	dxcArgs.emplaceBack(profile(shaderType));
+	if(ANKI_COMPILER_MSVC)
+	{
+		dxcArgs.emplaceBack("-fdiagnostics-format=msvc"); // Make errors clickable in visual studio
+	}
 	if(spirv)
 	{
 		dxcArgs.emplaceBack("-spirv");

+ 83 - 10
AnKi/ShaderCompiler/ShaderProgramCompiler.cpp

@@ -326,6 +326,7 @@ static Error doReflectionSpirv(ConstWeakArray<U8> spirv, ShaderType type, Shader
 }
 
 #if ANKI_DIXL_REFLECTION
+
 #	define ANKI_REFL_CHECK(x) \
 		do \
 		{ \
@@ -341,20 +342,64 @@ static Error doReflectionDxil(ConstWeakArray<U8> dxil, ShaderType type, ShaderRe
 {
 	using Microsoft::WRL::ComPtr;
 
+	const Bool isRayTracing = type >= ShaderType::kFirstRayTracing && type <= ShaderType::kLastRayTracing;
+	if(isRayTracing)
+	{
+		// TODO: Skip for now. RT shaders require explicity register()
+		return Error::kNone;
+	}
+
 	ComPtr<IDxcUtils> utils;
 	ANKI_REFL_CHECK(g_DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(&utils)));
 
-	const DxcBuffer buff = {dxil.getBegin(), dxil.getSizeInBytes(), 0};
 	ComPtr<ID3D12ShaderReflection> dxRefl;
-	ANKI_REFL_CHECK(utils->CreateReflection(&buff, IID_PPV_ARGS(&dxRefl)));
-
+	ComPtr<ID3D12LibraryReflection> libRefl;
+	ID3D12FunctionReflection* funcRefl = nullptr;
 	D3D12_SHADER_DESC shaderDesc = {};
-	dxRefl->GetDesc(&shaderDesc);
+	U32 bindingCount = 0;
+
+	if(!isRayTracing)
+	{
+		const DxcBuffer buff = {dxil.getBegin(), dxil.getSizeInBytes(), 0};
+		ANKI_REFL_CHECK(utils->CreateReflection(&buff, IID_PPV_ARGS(&dxRefl)));
+
+		ANKI_REFL_CHECK(dxRefl->GetDesc(&shaderDesc));
+
+		bindingCount = shaderDesc.BoundResources;
+	}
+	else
+	{
+		const DxcBuffer buff = {dxil.getBegin(), dxil.getSizeInBytes(), 0};
+		ANKI_REFL_CHECK(utils->CreateReflection(&buff, IID_PPV_ARGS(&libRefl)));
+
+		D3D12_LIBRARY_DESC libDesc = {};
+		libRefl->GetDesc(&libDesc);
+
+		if(libDesc.FunctionCount != 1)
+		{
+			errorStr.sprintf("Expecting 1 in D3D12_LIBRARY_DESC::FunctionCount");
+			return Error::kUserData;
+		}
+
+		funcRefl = libRefl->GetFunctionByIndex(0);
+
+		D3D12_FUNCTION_DESC funcDesc;
+		ANKI_REFL_CHECK(funcRefl->GetDesc(&funcDesc));
+
+		bindingCount = funcDesc.BoundResources;
+	}
 
-	for(U32 i = 0; i < shaderDesc.BoundResources; ++i)
+	for(U32 i = 0; i < bindingCount; ++i)
 	{
 		D3D12_SHADER_INPUT_BIND_DESC bind;
-		ANKI_REFL_CHECK(dxRefl->GetResourceBindingDesc(i, &bind));
+		if(dxRefl.Get() != nullptr)
+		{
+			ANKI_REFL_CHECK(dxRefl->GetResourceBindingDesc(i, &bind));
+		}
+		else
+		{
+			ANKI_REFL_CHECK(funcRefl->GetResourceBindingDesc(i, &bind));
+		}
 
 		ShaderReflectionBinding akBinding;
 
@@ -365,6 +410,14 @@ static Error doReflectionDxil(ConstWeakArray<U8> dxil, ShaderType type, ShaderRe
 		if(bind.Type == D3D_SIT_CBUFFER)
 		{
 			// ConstantBuffer
+
+			if(bind.BindPoint == ANKI_PUSH_CONSTANTS_D3D_BINDING && bind.Space == ANKI_PUSH_CONSTANTS_D3D_SPACE)
+			{
+				// It's push/root constants
+				ANKI_ASSERT(!"TODO");
+				continue;
+			}
+
 			akBinding.m_type = DescriptorType::kUniformBuffer;
 			akBinding.m_flags = DescriptorFlag::kRead;
 			akBinding.m_semantic = BindingSemantic('b', bind.BindPoint);
@@ -425,15 +478,34 @@ static Error doReflectionDxil(ConstWeakArray<U8> dxil, ShaderType type, ShaderRe
 			akBinding.m_flags = DescriptorFlag::kRead;
 			akBinding.m_semantic = BindingSemantic('t', bind.BindPoint);
 		}
+		else if(bind.Type == D3D_SIT_STRUCTURED)
+		{
+			// StructuredBuffer
+			akBinding.m_type = DescriptorType::kStorageBuffer;
+			akBinding.m_flags = DescriptorFlag::kRead;
+			akBinding.m_semantic = BindingSemantic('t', bind.BindPoint);
+		}
+		else if(bind.Type == D3D_SIT_UAV_RWSTRUCTURED)
+		{
+			// RWStructuredBuffer
+			akBinding.m_type = DescriptorType::kStorageBuffer;
+			akBinding.m_flags = DescriptorFlag::kReadWrite;
+			akBinding.m_semantic = BindingSemantic('u', bind.BindPoint);
+		}
 		else
 		{
-			ANKI_SHADER_COMPILER_LOGE("Unrecognized type for binding: %s", bind.Name);
+			errorStr.sprintf("Unrecognized type for binding: %s", bind.Name);
 			return Error::kUserData;
 		}
 
 		refl.m_bindings[bind.Space][refl.m_bindingCounts[bind.Space++]] = akBinding;
 	}
 
+	for(U32 i = 0; i < kMaxDescriptorSets; ++i)
+	{
+		std::sort(refl.m_bindings[i].getBegin(), refl.m_bindings[i].getBegin() + refl.m_bindingCounts[i]);
+	}
+
 	if(type == ShaderType::kVertex)
 	{
 		for(U32 i = 0; i < shaderDesc.InputParameters; ++i)
@@ -475,9 +547,10 @@ static Error doReflectionDxil(ConstWeakArray<U8> dxil, ShaderType type, ShaderRe
 			{
 				a = VertexAttributeSemantic::kMisc3;
 			}
-			else if(ANKI_ATTRIB_NAME(SV_VERTEXID, 0))
+			else if(ANKI_ATTRIB_NAME(SV_VERTEXID, 0) || ANKI_ATTRIB_NAME(SV_INSTANCEID, 0))
 			{
 				// Ignore
+				continue;
 			}
 			else
 			{
@@ -766,8 +839,8 @@ static Error compileShaderProgramInternal(CString fname, Bool spirv, ShaderProgr
 	{
 		defines.emplaceBack(d);
 	}
-	defines.emplaceBack(ShaderCompilerDefine{"ANKI_TARGET_SPIRV", spirv});
-	defines.emplaceBack(ShaderCompilerDefine{"ANKI_TARGET_DXIL", !spirv});
+	defines.emplaceBack(ShaderCompilerDefine{"ANKI_GR_BACKEND_VULKAN", spirv});
+	defines.emplaceBack(ShaderCompilerDefine{"ANKI_GR_BACKEND_DIRECT3D", !spirv});
 
 	// Initialize the binary
 	binary = newInstance<ShaderProgramBinary>(memPool);

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

@@ -756,6 +756,17 @@ constexpr U32 kMeshletGroupSize = ANKI_TASK_SHADER_THREADGROUP_SIZE;
 #define ANKI_MESH_SHADER_THREADGROUP_SIZE 32u
 static_assert(kMaxVerticesPerMeshlet % ANKI_MESH_SHADER_THREADGROUP_SIZE == 0);
 
+// Push constant stuff. In VK is simply defined but in D3D it's a special register() used to identify it
+#define ANKI_PUSH_CONSTANTS_D3D_BINDING 2000
+#define ANKI_PUSH_CONSTANTS_D3D_SPACE 100
+#if ANKI_GR_BACKEND_VULKAN
+#	define ANKI_PUSH_CONSTANTS_BEGIN [[vk::push_constants]]
+#	define ANKI_PUSH_CONSTANTS_END
+#else
+#	define ANKI_PUSH_CONSTANTS_BEGIN
+	#define ANKI_PUSH_CONSTANTS_END register(b2000, space100)
+#endif
+
 struct DrawIndirectArgs
 {
 	U32 m_vertexCount;

+ 7 - 1
CMakeLists.txt

@@ -176,10 +176,10 @@ set(ANKI_GR_BACKEND "VULKAN" CACHE STRING "The graphics API to use (VULKAN or DI
 if(${ANKI_GR_BACKEND} STREQUAL "DIRECTX")
 	set(DIRECTX TRUE)
 	set(VULKAN FALSE)
-	set(VIDEO_VULKAN TRUE) # Set for the SDL2 to pick up
 elseif(${ANKI_GR_BACKEND} STREQUAL "VULKAN")
 	set(DIRECTX FALSE)
 	set(VULKAN TRUE)
+	set(VIDEO_VULKAN TRUE) # Set for the SDL2 to pick up
 else()
 	message(FATAL_ERROR "Wrong ANKI_GR_BACKEND")
 endif()
@@ -426,6 +426,12 @@ else()
 	set(_ANKI_PLATFORM_MOBILE 0)
 endif()
 
+if(VULKAN)
+	set(_ANKI_GR_BACKEND 0)
+else()
+	set(_ANKI_GR_BACKEND 1)
+endif()
+
 configure_file("AnKi/Config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/AnKi/Config.h")
 
 # Include & lib directories