Add vertex shader input layout reading via shader compiler reflection to handle missing vertex elements binding when explicit layout got deprecated

This commit is contained in:
Wojtek Figat
2025-01-07 23:26:06 +01:00
parent 7f0d852f49
commit 7aa240e5eb
20 changed files with 350 additions and 232 deletions

View File

@@ -177,22 +177,28 @@ GPUShaderProgram* GPUShader::GetShader(ShaderStage stage, const StringAnsiView&
return shader; return shader;
} }
GPUVertexLayout* GPUShader::ReadVertexLayout(MemoryReadStream& stream) void GPUShader::ReadVertexLayout(MemoryReadStream& stream, GPUVertexLayout*& inputLayout, GPUVertexLayout*& vertexLayout)
{ {
inputLayout = vertexLayout = nullptr;
// Read input layout (based on shader reflection)
GPUVertexLayout::Elements elements;
stream.Read(elements);
inputLayout = GPUVertexLayout::Get(elements);
// [Deprecated in v1.10] // [Deprecated in v1.10]
byte inputLayoutSize; byte inputLayoutSize;
stream.ReadByte(&inputLayoutSize); stream.ReadByte(&inputLayoutSize);
if (inputLayoutSize == 0) if (inputLayoutSize == 0)
return nullptr; return;
void* elementsData = stream.Move(sizeof(VertexElement) * inputLayoutSize); void* elementsData = stream.Move(sizeof(VertexElement) * inputLayoutSize);
if (inputLayoutSize > GPU_MAX_VS_ELEMENTS) if (inputLayoutSize > GPU_MAX_VS_ELEMENTS)
{ {
LOG(Error, "Incorrect input layout size."); LOG(Error, "Incorrect input layout size.");
return nullptr; return;
} }
GPUVertexLayout::Elements elements;
elements.Set((VertexElement*)elementsData, inputLayoutSize); elements.Set((VertexElement*)elementsData, inputLayoutSize);
return GPUVertexLayout::Get(elements); vertexLayout = GPUVertexLayout::Get(elements);
} }
GPUResourceType GPUShader::GetResourceType() const GPUResourceType GPUShader::GetResourceType() const

View File

@@ -12,7 +12,7 @@ class GPUShaderProgram;
/// <summary> /// <summary>
/// The runtime version of the shaders cache supported by the all graphics back-ends. The same for all the shader cache formats (easier to sync and validate). /// The runtime version of the shaders cache supported by the all graphics back-ends. The same for all the shader cache formats (easier to sync and validate).
/// </summary> /// </summary>
#define GPU_SHADER_CACHE_VERSION 11 #define GPU_SHADER_CACHE_VERSION 12
/// <summary> /// <summary>
/// The GPU resource with shader programs that can run on the GPU and are able to perform rendering calculation using textures, vertices and other resources. /// The GPU resource with shader programs that can run on the GPU and are able to perform rendering calculation using textures, vertices and other resources.
@@ -135,7 +135,7 @@ public:
protected: protected:
GPUShaderProgram* GetShader(ShaderStage stage, const StringAnsiView& name, int32 permutationIndex) const; GPUShaderProgram* GetShader(ShaderStage stage, const StringAnsiView& name, int32 permutationIndex) const;
virtual GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span<byte> bytecode, MemoryReadStream& stream) = 0; virtual GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span<byte> bytecode, MemoryReadStream& stream) = 0;
static GPUVertexLayout* ReadVertexLayout(MemoryReadStream& stream); static void ReadVertexLayout(MemoryReadStream& stream, GPUVertexLayout*& inputLayout, GPUVertexLayout*& vertexLayout);
public: public:
// [GPUResource] // [GPUResource]

View File

@@ -136,6 +136,9 @@ public:
// [Deprecated in v1.10] // [Deprecated in v1.10]
GPUVertexLayout* Layout = nullptr; GPUVertexLayout* Layout = nullptr;
// Vertex shader inputs layout. Used to ensure that binded vertex buffers provide all required elements.
GPUVertexLayout* InputLayout = nullptr;
public: public:
// [GPUShaderProgram] // [GPUShaderProgram]
ShaderStage GetStage() const override ShaderStage GetStage() const override

View File

@@ -26,7 +26,7 @@ ID3D11InputLayout* GPUShaderProgramVSDX11::GetInputLayout(GPUVertexLayoutDX11* v
{ {
if (vertexLayout && vertexLayout->InputElementsCount) if (vertexLayout && vertexLayout->InputElementsCount)
{ {
auto mergedVertexLayout = (GPUVertexLayoutDX11*)GPUVertexLayout::Merge(vertexLayout, Layout); auto mergedVertexLayout = (GPUVertexLayoutDX11*)GPUVertexLayout::Merge(vertexLayout, Layout ? Layout : InputLayout);
LOG_DIRECTX_RESULT(vertexLayout->GetDevice()->GetDevice()->CreateInputLayout(mergedVertexLayout->InputElements, mergedVertexLayout->InputElementsCount, Bytecode.Get(), Bytecode.Length(), &inputLayout)); LOG_DIRECTX_RESULT(vertexLayout->GetDevice()->GetDevice()->CreateInputLayout(mergedVertexLayout->InputElements, mergedVertexLayout->InputElementsCount, Bytecode.Get(), Bytecode.Length(), &inputLayout));
} }
_cache.Add(vertexLayout, inputLayout); _cache.Add(vertexLayout, inputLayout);
@@ -42,42 +42,30 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
{ {
case ShaderStage::Vertex: case ShaderStage::Vertex:
{ {
// Load Input Layout GPUVertexLayout* inputLayout, *vertexLayout;
GPUVertexLayout* vertexLayout = ReadVertexLayout(stream); ReadVertexLayout(stream, inputLayout, vertexLayout);
// Create shader
ID3D11VertexShader* buffer = nullptr; ID3D11VertexShader* buffer = nullptr;
result = _device->GetDevice()->CreateVertexShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer); result = _device->GetDevice()->CreateVertexShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr); LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
shader = New<GPUShaderProgramVSDX11>(initializer, buffer, inputLayout, vertexLayout, bytecode);
// Create object
shader = New<GPUShaderProgramVSDX11>(initializer, buffer, vertexLayout, bytecode);
break; break;
} }
#if GPU_ALLOW_TESSELLATION_SHADERS #if GPU_ALLOW_TESSELLATION_SHADERS
case ShaderStage::Hull: case ShaderStage::Hull:
{ {
// Read control points
int32 controlPointsCount; int32 controlPointsCount;
stream.ReadInt32(&controlPointsCount); stream.ReadInt32(&controlPointsCount);
// Create shader
ID3D11HullShader* buffer = nullptr; ID3D11HullShader* buffer = nullptr;
result = _device->GetDevice()->CreateHullShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer); result = _device->GetDevice()->CreateHullShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr); LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
shader = New<GPUShaderProgramHSDX11>(initializer, buffer, controlPointsCount); shader = New<GPUShaderProgramHSDX11>(initializer, buffer, controlPointsCount);
break; break;
} }
case ShaderStage::Domain: case ShaderStage::Domain:
{ {
// Create shader
ID3D11DomainShader* buffer = nullptr; ID3D11DomainShader* buffer = nullptr;
result = _device->GetDevice()->CreateDomainShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer); result = _device->GetDevice()->CreateDomainShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr); LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
shader = New<GPUShaderProgramDSDX11>(initializer, buffer); shader = New<GPUShaderProgramDSDX11>(initializer, buffer);
break; break;
} }
@@ -92,35 +80,26 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
#if GPU_ALLOW_GEOMETRY_SHADERS #if GPU_ALLOW_GEOMETRY_SHADERS
case ShaderStage::Geometry: case ShaderStage::Geometry:
{ {
// Create shader
ID3D11GeometryShader* buffer = nullptr; ID3D11GeometryShader* buffer = nullptr;
result = _device->GetDevice()->CreateGeometryShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer); result = _device->GetDevice()->CreateGeometryShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr); LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
shader = New<GPUShaderProgramGSDX11>(initializer, buffer); shader = New<GPUShaderProgramGSDX11>(initializer, buffer);
break; break;
} }
#endif #endif
case ShaderStage::Pixel: case ShaderStage::Pixel:
{ {
// Create shader
ID3D11PixelShader* buffer = nullptr; ID3D11PixelShader* buffer = nullptr;
result = _device->GetDevice()->CreatePixelShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer); result = _device->GetDevice()->CreatePixelShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr); LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
shader = New<GPUShaderProgramPSDX11>(initializer, buffer); shader = New<GPUShaderProgramPSDX11>(initializer, buffer);
break; break;
} }
case ShaderStage::Compute: case ShaderStage::Compute:
{ {
// Create shader
ID3D11ComputeShader* buffer = nullptr; ID3D11ComputeShader* buffer = nullptr;
result = _device->GetDevice()->CreateComputeShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer); result = _device->GetDevice()->CreateComputeShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr); LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
shader = New<GPUShaderProgramCSDX11>(initializer, buffer); shader = New<GPUShaderProgramCSDX11>(initializer, buffer);
break; break;
} }

View File

@@ -58,9 +58,10 @@ private:
Dictionary<class GPUVertexLayoutDX11*, ID3D11InputLayout*> _cache; Dictionary<class GPUVertexLayoutDX11*, ID3D11InputLayout*> _cache;
public: public:
GPUShaderProgramVSDX11(const GPUShaderProgramInitializer& initializer, ID3D11VertexShader* buffer, GPUVertexLayout* vertexLayout, Span<byte> bytecode) GPUShaderProgramVSDX11(const GPUShaderProgramInitializer& initializer, ID3D11VertexShader* buffer, GPUVertexLayout* inputLayout, GPUVertexLayout* vertexLayout, Span<byte> bytecode)
: GPUShaderProgramDX11(initializer, buffer) : GPUShaderProgramDX11(initializer, buffer)
{ {
InputLayout = inputLayout;
Layout = vertexLayout; Layout = vertexLayout;
Bytecode.Copy(bytecode); Bytecode.Copy(bytecode);
} }

View File

@@ -124,7 +124,7 @@ void DescriptorHeapWithSlotsDX12::ReleaseSlot(uint32 index)
{ {
uint32& value = _usage[index / 32]; uint32& value = _usage[index / 32];
const uint32 mask = 1 << (index & 31); const uint32 mask = 1 << (index & 31);
ASSERT_LOW_LAYER((value & mask) == mask); //ASSERT_LOW_LAYER((value & mask) == mask);
value &= ~mask; value &= ~mask;
} }

View File

@@ -180,7 +180,7 @@ bool GPUPipelineStateDX12::Init(const Description& desc)
INIT_SHADER_STAGE(PS, GPUShaderProgramPSDX12); INIT_SHADER_STAGE(PS, GPUShaderProgramPSDX12);
// Input Assembly // Input Assembly
VertexLayout = desc.VS ? (GPUVertexLayoutDX12*)desc.VS->Layout : nullptr; VertexLayout = desc.VS ? (GPUVertexLayoutDX12*)(desc.VS->Layout ? desc.VS->Layout : desc.VS->InputLayout) : nullptr;
const D3D12_PRIMITIVE_TOPOLOGY_TYPE primTypes1[] = const D3D12_PRIMITIVE_TOPOLOGY_TYPE primTypes1[] =
{ {
D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED, D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED,

View File

@@ -19,8 +19,9 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const
{ {
case ShaderStage::Vertex: case ShaderStage::Vertex:
{ {
GPUVertexLayout* vertexLayout = ReadVertexLayout(stream); GPUVertexLayout* inputLayout, *vertexLayout;
shader = New<GPUShaderProgramVSDX12>(initializer, header, bytecode, vertexLayout); ReadVertexLayout(stream, inputLayout, vertexLayout);
shader = New<GPUShaderProgramVSDX12>(initializer, header, bytecode, inputLayout, vertexLayout);
break; break;
} }
#if GPU_ALLOW_TESSELLATION_SHADERS #if GPU_ALLOW_TESSELLATION_SHADERS

View File

@@ -46,9 +46,10 @@ public:
class GPUShaderProgramVSDX12 : public GPUShaderProgramDX12<GPUShaderProgramVS> class GPUShaderProgramVSDX12 : public GPUShaderProgramDX12<GPUShaderProgramVS>
{ {
public: public:
GPUShaderProgramVSDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span<byte> bytecode, GPUVertexLayout* vertexLayout) GPUShaderProgramVSDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span<byte> bytecode, GPUVertexLayout* inputLayout, GPUVertexLayout* vertexLayout)
: GPUShaderProgramDX12(initializer, header, bytecode) : GPUShaderProgramDX12(initializer, header, bytecode)
{ {
InputLayout = inputLayout;
Layout = vertexLayout; Layout = vertexLayout;
} }
}; };

View File

@@ -320,7 +320,7 @@ bool GPUPipelineStateVulkan::Init(const Description& desc)
_desc.pStages = _shaderStages; _desc.pStages = _shaderStages;
// Input Assembly // Input Assembly
VertexShaderLayout = desc.VS ? (GPUVertexLayoutVulkan*)desc.VS->Layout : nullptr; VertexShaderLayout = desc.VS ? (GPUVertexLayoutVulkan*)(desc.VS->Layout ? desc.VS->Layout : desc.VS->InputLayout) : nullptr;
RenderToolsVulkan::ZeroStruct(_descInputAssembly, VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO);; RenderToolsVulkan::ZeroStruct(_descInputAssembly, VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO);;
switch (desc.PrimitiveTopology) switch (desc.PrimitiveTopology)
{ {

View File

@@ -66,9 +66,10 @@ public:
class GPUShaderProgramVSVulkan : public GPUShaderProgramVulkan<GPUShaderProgramVS> class GPUShaderProgramVSVulkan : public GPUShaderProgramVulkan<GPUShaderProgramVS>
{ {
public: public:
GPUShaderProgramVSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule, GPUVertexLayout* vertexLayout) GPUShaderProgramVSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule, GPUVertexLayout* inputLayout, GPUVertexLayout* vertexLayout)
: GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule) : GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule)
{ {
InputLayout = inputLayout;
Layout = vertexLayout; Layout = vertexLayout;
} }
}; };

View File

@@ -138,8 +138,9 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons
{ {
case ShaderStage::Vertex: case ShaderStage::Vertex:
{ {
GPUVertexLayout* vertexLayout = ReadVertexLayout(stream); GPUVertexLayout* inputLayout, *vertexLayout;
shader = New<GPUShaderProgramVSVulkan>(_device, initializer, header->DescriptorInfo, shaderModule, vertexLayout); ReadVertexLayout(stream, inputLayout, vertexLayout);
shader = New<GPUShaderProgramVSVulkan>(_device, initializer, header->DescriptorInfo, shaderModule, inputLayout, vertexLayout);
break; break;
} }
#if GPU_ALLOW_TESSELLATION_SHADERS #if GPU_ALLOW_TESSELLATION_SHADERS

View File

@@ -16,11 +16,9 @@
class IncludeD3D : public ID3DInclude class IncludeD3D : public ID3DInclude
{ {
private: private:
ShaderCompilationContext* _context; ShaderCompilationContext* _context;
public: public:
IncludeD3D(ShaderCompilationContext* context) IncludeD3D(ShaderCompilationContext* context)
{ {
_context = context; _context = context;
@@ -84,14 +82,9 @@ namespace
// Extract constant buffers usage information // Extract constant buffers usage information
for (uint32 a = 0; a < desc.ConstantBuffers; a++) for (uint32 a = 0; a < desc.ConstantBuffers; a++)
{ {
// Get CB
auto cb = reflector->GetConstantBufferByIndex(a); auto cb = reflector->GetConstantBufferByIndex(a);
// Get CB description
D3D11_SHADER_BUFFER_DESC cbDesc; D3D11_SHADER_BUFFER_DESC cbDesc;
cb->GetDesc(&cbDesc); cb->GetDesc(&cbDesc);
// Check buffer type
if (cbDesc.Type == D3D_CT_CBUFFER) if (cbDesc.Type == D3D_CT_CBUFFER)
{ {
// Find CB slot index // Find CB slot index
@@ -132,22 +125,20 @@ namespace
// Extract resources usage // Extract resources usage
for (uint32 i = 0; i < desc.BoundResources; i++) for (uint32 i = 0; i < desc.BoundResources; i++)
{ {
// Get resource description
D3D11_SHADER_INPUT_BIND_DESC resDesc; D3D11_SHADER_INPUT_BIND_DESC resDesc;
reflector->GetResourceBindingDesc(i, &resDesc); reflector->GetResourceBindingDesc(i, &resDesc);
switch (resDesc.Type) switch (resDesc.Type)
{ {
// Sampler // Sampler
case D3D_SIT_SAMPLER: case D3D_SIT_SAMPLER:
break; break;
// Constant Buffer // Constant Buffer
case D3D_SIT_CBUFFER: case D3D_SIT_CBUFFER:
case D3D_SIT_TBUFFER: case D3D_SIT_TBUFFER:
break; break;
// Shader Resource // Shader Resource
case D3D_SIT_TEXTURE: case D3D_SIT_TEXTURE:
case D3D_SIT_STRUCTURED: case D3D_SIT_STRUCTURED:
case D3D_SIT_BYTEADDRESS: case D3D_SIT_BYTEADDRESS:
@@ -155,7 +146,7 @@ namespace
bindings.UsedSRsMask |= 1 << (resDesc.BindPoint + shift); bindings.UsedSRsMask |= 1 << (resDesc.BindPoint + shift);
break; break;
// Unordered Access // Unordered Access
case D3D_SIT_UAV_RWTYPED: case D3D_SIT_UAV_RWTYPED:
case D3D_SIT_UAV_RWSTRUCTURED: case D3D_SIT_UAV_RWSTRUCTURED:
case D3D_SIT_UAV_RWBYTEADDRESS: case D3D_SIT_UAV_RWBYTEADDRESS:
@@ -212,7 +203,6 @@ bool ShaderCompilerD3D::CompileShader(ShaderFunctionMeta& meta, WritePermutation
else else
{ {
profileName += "_4_0"; profileName += "_4_0";
if (type == ShaderStage::Domain || type == ShaderStage::Hull) if (type == ShaderStage::Domain || type == ShaderStage::Hull)
{ {
_context->OnError("Tessellation is not supported on DirectX 10"); _context->OnError("Tessellation is not supported on DirectX 10");
@@ -221,6 +211,7 @@ bool ShaderCompilerD3D::CompileShader(ShaderFunctionMeta& meta, WritePermutation
} }
// Compile all shader function permutations // Compile all shader function permutations
AdditionalDataVS additionalDataVS;
for (int32 permutationIndex = 0; permutationIndex < meta.Permutations.Count(); permutationIndex++) for (int32 permutationIndex = 0; permutationIndex < meta.Permutations.Count(); permutationIndex++)
{ {
_macros.Clear(); _macros.Clear();
@@ -253,8 +244,6 @@ bool ShaderCompilerD3D::CompileShader(ShaderFunctionMeta& meta, WritePermutation
0, 0,
&shader, &shader,
&errors); &errors);
// Check compilation result
if (FAILED(result)) if (FAILED(result))
{ {
const auto msg = static_cast<const char*>(errors->GetBufferPointer()); const auto msg = static_cast<const char*>(errors->GetBufferPointer());
@@ -279,24 +268,68 @@ bool ShaderCompilerD3D::CompileShader(ShaderFunctionMeta& meta, WritePermutation
reflector->GetDesc(&desc); reflector->GetDesc(&desc);
// Process shader reflection data // Process shader reflection data
void* additionalData = nullptr;
if (type == ShaderStage::Vertex)
{
additionalData = &additionalDataVS;
additionalDataVS.Inputs.Clear();
for (UINT inputIdx = 0; inputIdx < desc.InputParameters; inputIdx++)
{
D3D11_SIGNATURE_PARAMETER_DESC inputDesc;
reflector->GetInputParameterDesc(inputIdx, &inputDesc);
if (inputDesc.ReadWriteMask == 0 || inputDesc.SystemValueType != D3D10_NAME_UNDEFINED)
continue;
auto format = PixelFormat::Unknown;
switch (inputDesc.ComponentType)
{
case D3D_REGISTER_COMPONENT_UINT32:
if (inputDesc.Mask >= 0b1111)
format = PixelFormat::R32G32B32A32_UInt;
else if (inputDesc.Mask >= 0b111)
format = PixelFormat::R32G32B32_UInt;
else if (inputDesc.Mask >= 0b11)
format = PixelFormat::R32G32_UInt;
else
format = PixelFormat::R32_UInt;
break;
case D3D_REGISTER_COMPONENT_SINT32:
if (inputDesc.Mask >= 0b1111)
format = PixelFormat::R32G32B32A32_SInt;
else if (inputDesc.Mask >= 0b111)
format = PixelFormat::R32G32B32_SInt;
else if (inputDesc.Mask >= 0b11)
format = PixelFormat::R32G32_SInt;
else
format = PixelFormat::R32_SInt;
break;
case D3D_REGISTER_COMPONENT_FLOAT32:
if (inputDesc.Mask >= 0b1111)
format = PixelFormat::R32G32B32A32_Float;
else if (inputDesc.Mask >= 0b111)
format = PixelFormat::R32G32B32_Float;
else if (inputDesc.Mask >= 0b11)
format = PixelFormat::R32G32_Float;
else
format = PixelFormat::R32_Float;
break;
}
additionalDataVS.Inputs.Add({ ParseVertexElementType(inputDesc.SemanticName, inputDesc.SemanticIndex), 0, 0, 0, format });
}
}
ShaderBindings bindings = { desc.InstructionCount, 0, 0, 0 }; ShaderBindings bindings = { desc.InstructionCount, 0, 0, 0 };
if (ProcessShader(_context, _constantBuffers, reflector.Get(), desc, bindings)) if (ProcessShader(_context, _constantBuffers, reflector.Get(), desc, bindings))
return true; return true;
#ifdef GPU_USE_SHADERS_DEBUG_LAYER #ifdef GPU_USE_SHADERS_DEBUG_LAYER
// Generate debug information // Generate debug information
if (ProcessDebugInfo(_context, meta, permutationIndex, shaderBuffer, shaderBufferSize)) if (ProcessDebugInfo(_context, meta, permutationIndex, shaderBuffer, shaderBufferSize))
return true; return true;
#endif #endif
// Strip shader bytecode for an optimization // Strip shader bytecode for an optimization
ComPtr<ID3DBlob> shaderStripped; ComPtr<ID3DBlob> shaderStripped;
if (!options->GenerateDebugData) if (!options->GenerateDebugData)
{ {
//auto prevShaderBufferSize = shaderBufferSize;
// Strip shader bytes // Strip shader bytes
result = D3DStripShader( result = D3DStripShader(
shaderBuffer, shaderBuffer,
@@ -312,15 +345,12 @@ bool ShaderCompilerD3D::CompileShader(ShaderFunctionMeta& meta, WritePermutation
// Set new buffer // Set new buffer
shaderBuffer = shaderStripped->GetBufferPointer(); shaderBuffer = shaderStripped->GetBufferPointer();
shaderBufferSize = static_cast<int32>(shaderStripped->GetBufferSize()); shaderBufferSize = static_cast<int32>(shaderStripped->GetBufferSize());
//auto strippedBytes = prevShaderBufferSize - shaderBufferSize;
//auto strippedBytesPercentage = Math::FloorToInt(strippedBytes * 100.0f / prevShaderBufferSize);
} }
if (WriteShaderFunctionPermutation(_context, meta, permutationIndex, bindings, shaderBuffer, shaderBufferSize)) if (WriteShaderFunctionPermutation(_context, meta, permutationIndex, bindings, shaderBuffer, shaderBufferSize))
return true; return true;
if (customDataWrite && customDataWrite(_context, meta, permutationIndex, _macros)) if (customDataWrite && customDataWrite(_context, meta, permutationIndex, _macros, additionalData))
return true; return true;
} }

View File

@@ -12,12 +12,10 @@
class ShaderCompilerD3D : public ShaderCompiler class ShaderCompilerD3D : public ShaderCompiler
{ {
private: private:
Array<char> _funcNameDefineBuffer; Array<char> _funcNameDefineBuffer;
uint32 _flags; uint32 _flags;
public: public:
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ShaderCompilerD3D"/> class. /// Initializes a new instance of the <see cref="ShaderCompilerD3D"/> class.
/// </summary> /// </summary>
@@ -25,7 +23,6 @@ public:
ShaderCompilerD3D(ShaderProfile profile); ShaderCompilerD3D(ShaderProfile profile);
protected: protected:
// [ShaderCompiler] // [ShaderCompiler]
bool CompileShader(ShaderFunctionMeta& meta, WritePermutationData customDataWrite = nullptr) override; bool CompileShader(ShaderFunctionMeta& meta, WritePermutationData customDataWrite = nullptr) override;
bool OnCompileBegin() override; bool OnCompileBegin() override;

View File

@@ -4,7 +4,6 @@
#include "ShaderCompilerDX.h" #include "ShaderCompilerDX.h"
#include "Engine/Core/Log.h" #include "Engine/Core/Log.h"
#include "Engine/Threading/Threading.h"
#include "Engine/Engine/Globals.h" #include "Engine/Engine/Globals.h"
#include "Engine/Graphics/Config.h" #include "Engine/Graphics/Config.h"
#include "Engine/GraphicsDevice/DirectX/DX12/Types.h" #include "Engine/GraphicsDevice/DirectX/DX12/Types.h"
@@ -22,12 +21,10 @@
class IncludeDX : public IDxcIncludeHandler class IncludeDX : public IDxcIncludeHandler
{ {
private: private:
ShaderCompilationContext* _context; ShaderCompilationContext* _context;
IDxcLibrary* _library; IDxcLibrary* _library;
public: public:
IncludeDX(ShaderCompilationContext* context, IDxcLibrary* library) IncludeDX(ShaderCompilationContext* context, IDxcLibrary* library)
{ {
_context = context; _context = context;
@@ -185,6 +182,7 @@ bool ShaderCompilerDX::CompileShader(ShaderFunctionMeta& meta, WritePermutationD
} }
// Compile all shader function permutations // Compile all shader function permutations
AdditionalDataVS additionalDataVS;
for (int32 permutationIndex = 0; permutationIndex < meta.Permutations.Count(); permutationIndex++) for (int32 permutationIndex = 0; permutationIndex < meta.Permutations.Count(); permutationIndex++)
{ {
_macros.Clear(); _macros.Clear();
@@ -320,6 +318,54 @@ bool ShaderCompilerDX::CompileShader(ShaderFunctionMeta& meta, WritePermutationD
shaderReflection->GetDesc(&desc); shaderReflection->GetDesc(&desc);
// Process shader reflection data // Process shader reflection data
void* additionalData = nullptr;
if (type == ShaderStage::Vertex)
{
additionalData = &additionalDataVS;
additionalDataVS.Inputs.Clear();
for (UINT inputIdx = 0; inputIdx < desc.InputParameters; inputIdx++)
{
D3D12_SIGNATURE_PARAMETER_DESC inputDesc;
shaderReflection->GetInputParameterDesc(inputIdx, &inputDesc);
if (inputDesc.ReadWriteMask == 0 || inputDesc.SystemValueType != D3D10_NAME_UNDEFINED)
continue;
auto format = PixelFormat::Unknown;
switch (inputDesc.ComponentType)
{
case D3D_REGISTER_COMPONENT_UINT32:
if (inputDesc.Mask >= 0b1111)
format = PixelFormat::R32G32B32A32_UInt;
else if (inputDesc.Mask >= 0b111)
format = PixelFormat::R32G32B32_UInt;
else if (inputDesc.Mask >= 0b11)
format = PixelFormat::R32G32_UInt;
else
format = PixelFormat::R32_UInt;
break;
case D3D_REGISTER_COMPONENT_SINT32:
if (inputDesc.Mask >= 0b1111)
format = PixelFormat::R32G32B32A32_SInt;
else if (inputDesc.Mask >= 0b111)
format = PixelFormat::R32G32B32_SInt;
else if (inputDesc.Mask >= 0b11)
format = PixelFormat::R32G32_SInt;
else
format = PixelFormat::R32_SInt;
break;
case D3D_REGISTER_COMPONENT_FLOAT32:
if (inputDesc.Mask >= 0b1111)
format = PixelFormat::R32G32B32A32_Float;
else if (inputDesc.Mask >= 0b111)
format = PixelFormat::R32G32B32_Float;
else if (inputDesc.Mask >= 0b11)
format = PixelFormat::R32G32_Float;
else
format = PixelFormat::R32_Float;
break;
}
additionalDataVS.Inputs.Add({ ParseVertexElementType(inputDesc.SemanticName, inputDesc.SemanticIndex), 0, 0, 0, format });
}
}
DxShaderHeader header; DxShaderHeader header;
Platform::MemoryClear(&header, sizeof(header)); Platform::MemoryClear(&header, sizeof(header));
ShaderBindings bindings = { desc.InstructionCount, 0, 0, 0 }; ShaderBindings bindings = { desc.InstructionCount, 0, 0, 0 };
@@ -370,16 +416,16 @@ bool ShaderCompilerDX::CompileShader(ShaderFunctionMeta& meta, WritePermutationD
shaderReflection->GetResourceBindingDesc(i, &resDesc); shaderReflection->GetResourceBindingDesc(i, &resDesc);
switch (resDesc.Type) switch (resDesc.Type)
{ {
// Sampler // Sampler
case D3D_SIT_SAMPLER: case D3D_SIT_SAMPLER:
break; break;
// Constant Buffer // Constant Buffer
case D3D_SIT_CBUFFER: case D3D_SIT_CBUFFER:
case D3D_SIT_TBUFFER: case D3D_SIT_TBUFFER:
break; break;
// Shader Resource // Shader Resource
case D3D_SIT_TEXTURE: case D3D_SIT_TEXTURE:
for (UINT shift = 0; shift < resDesc.BindCount; shift++) for (UINT shift = 0; shift < resDesc.BindCount; shift++)
{ {
@@ -396,7 +442,7 @@ bool ShaderCompilerDX::CompileShader(ShaderFunctionMeta& meta, WritePermutationD
} }
break; break;
// Unordered Access // Unordered Access
case D3D_SIT_UAV_RWTYPED: case D3D_SIT_UAV_RWTYPED:
case D3D_SIT_UAV_RWSTRUCTURED: case D3D_SIT_UAV_RWSTRUCTURED:
case D3D_SIT_UAV_RWBYTEADDRESS: case D3D_SIT_UAV_RWBYTEADDRESS:
@@ -415,7 +461,7 @@ bool ShaderCompilerDX::CompileShader(ShaderFunctionMeta& meta, WritePermutationD
if (WriteShaderFunctionPermutation(_context, meta, permutationIndex, bindings, &header, sizeof(header), shaderBuffer->GetBufferPointer(), (int32)shaderBuffer->GetBufferSize())) if (WriteShaderFunctionPermutation(_context, meta, permutationIndex, bindings, &header, sizeof(header), shaderBuffer->GetBufferPointer(), (int32)shaderBuffer->GetBufferSize()))
return true; return true;
if (customDataWrite && customDataWrite(_context, meta, permutationIndex, _macros)) if (customDataWrite && customDataWrite(_context, meta, permutationIndex, _macros, additionalData))
return true; return true;
} }

View File

@@ -12,14 +12,12 @@
class ShaderCompilerDX : public ShaderCompiler class ShaderCompilerDX : public ShaderCompiler
{ {
private: private:
Array<char> _funcNameDefineBuffer; Array<char> _funcNameDefineBuffer;
void* _compiler; void* _compiler;
void* _library; void* _library;
void* _containerReflection; void* _containerReflection;
public: public:
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ShaderCompilerDX"/> class. /// Initializes a new instance of the <see cref="ShaderCompilerDX"/> class.
/// </summary> /// </summary>
@@ -32,7 +30,6 @@ public:
~ShaderCompilerDX(); ~ShaderCompilerDX();
protected: protected:
// [ShaderCompiler] // [ShaderCompiler]
bool CompileShader(ShaderFunctionMeta& meta, WritePermutationData customDataWrite = nullptr) override; bool CompileShader(ShaderFunctionMeta& meta, WritePermutationData customDataWrite = nullptr) override;
bool OnCompileBegin() override; bool OnCompileBegin() override;

View File

@@ -271,7 +271,6 @@ bool ShaderCompiler::WriteShaderFunctionBegin(ShaderCompilationContext* context,
bool ShaderCompiler::WriteShaderFunctionPermutation(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const ShaderBindings& bindings, const void* header, int32 headerSize, const void* cache, int32 cacheSize) bool ShaderCompiler::WriteShaderFunctionPermutation(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const ShaderBindings& bindings, const void* header, int32 headerSize, const void* cache, int32 cacheSize)
{ {
auto output = context->Output; auto output = context->Output;
output->Write((uint32)(cacheSize + headerSize)); output->Write((uint32)(cacheSize + headerSize));
output->WriteBytes(header, headerSize); output->WriteBytes(header, headerSize);
output->WriteBytes(cache, cacheSize); output->WriteBytes(cache, cacheSize);
@@ -293,18 +292,22 @@ bool ShaderCompiler::WriteShaderFunctionEnd(ShaderCompilationContext* context, S
return false; return false;
} }
bool ShaderCompiler::WriteCustomDataVS(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const Array<ShaderMacro>& macros) bool ShaderCompiler::WriteCustomDataVS(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const Array<ShaderMacro>& macros, void* additionalData)
{ {
// [Deprecated in v1.10]
auto output = context->Output; auto output = context->Output;
// Write vertex shader inputs (based on compiled shader reflection) to bind any missing vertex buffer streaming at runtime (during drawing - see usage of GPUVertexLayout::Merge)
if (auto* additionalDataVS = (AdditionalDataVS*)additionalData)
output->Write(additionalDataVS->Inputs);
else
output->WriteInt32(0);
// [Deprecated in v1.10]
auto& metaVS = *(VertexShaderMeta*)&meta; auto& metaVS = *(VertexShaderMeta*)&meta;
auto& layout = metaVS.InputLayout; auto& layout = metaVS.InputLayout;
#if FLAXENGINE_VERSION_MAJOR > 2 || (FLAXENGINE_VERSION_MAJOR == 2 && FLAXENGINE_VERSION_MINOR >= 1) #if FLAXENGINE_VERSION_MAJOR > 2 || (FLAXENGINE_VERSION_MAJOR == 2 && FLAXENGINE_VERSION_MINOR >= 1)
if (layout.HasItems()) if (layout.HasItems())
LOG(Warning, "Vertex Shader '{}' (asset '{}') uses explicit vertex layout via 'META_VS_IN_ELEMENT' macros which has been deprecated. Remove this code and migrate to GPUVertexLayout with VertexElement array in code (assigned to vertex buffer).", String(meta.Name), context->Options->TargetName); LOG(Warning, "Vertex Shader '{}' (asset '{}') uses explicit vertex layout via 'META_VS_IN_ELEMENT' macros which has been deprecated. Remove this code and migrate to GPUVertexLayout with VertexElement array in code (assigned to vertex buffer).", String(meta.Name), context->Options->TargetName);
#elif FLAXENGINE_VERSION_MAJOR == 1 && FLAXENGINE_VERSION_MINOR >= 11
if (layout.HasItems())
LOG(Warning, "Vertex Shader '{}' (asset '{}') uses explicit vertex layout via 'META_VS_IN_ELEMENT' macros which has been deprecated. Remove this code and migrate to GPUVertexLayout with VertexElement array in code (assigned to vertex buffer).", String(meta.Name), context->Options->TargetName);
#endif #endif
// Get visible entries (based on `visible` flag switch) // Get visible entries (based on `visible` flag switch)
@@ -443,7 +446,7 @@ bool ShaderCompiler::WriteCustomDataVS(ShaderCompilationContext* context, Shader
return false; return false;
} }
bool ShaderCompiler::WriteCustomDataHS(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const Array<ShaderMacro>& macros) bool ShaderCompiler::WriteCustomDataHS(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const Array<ShaderMacro>& macros, void* additionalData)
{ {
auto output = context->Output; auto output = context->Output;
auto& metaHS = *(HullShaderMeta*)&meta; auto& metaHS = *(HullShaderMeta*)&meta;
@@ -457,7 +460,7 @@ bool ShaderCompiler::WriteCustomDataHS(ShaderCompilationContext* context, Shader
void ShaderCompiler::GetDefineForFunction(ShaderFunctionMeta& meta, Array<ShaderMacro>& macros) void ShaderCompiler::GetDefineForFunction(ShaderFunctionMeta& meta, Array<ShaderMacro>& macros)
{ {
auto& functionName = meta.Name; auto& functionName = meta.Name;
const int32 functionNameLength = static_cast<int32>(functionName.Length()); const int32 functionNameLength = functionName.Length();
_funcNameDefineBuffer.Clear(); _funcNameDefineBuffer.Clear();
_funcNameDefineBuffer.EnsureCapacity(functionNameLength + 2); _funcNameDefineBuffer.EnsureCapacity(functionNameLength + 2);
_funcNameDefineBuffer.Add('_'); _funcNameDefineBuffer.Add('_');
@@ -466,4 +469,35 @@ void ShaderCompiler::GetDefineForFunction(ShaderFunctionMeta& meta, Array<Shader
macros.Add({ _funcNameDefineBuffer.Get(), "1" }); macros.Add({ _funcNameDefineBuffer.Get(), "1" });
} }
VertexElement::Types ShaderCompiler::ParseVertexElementType(StringAnsiView semantic, uint32 index)
{
if (semantic.HasChars() && StringUtils::IsDigit(semantic[semantic.Length() - 1]))
{
// Get index from end of the name
index = semantic[semantic.Length() - 1] - '0';
semantic = StringAnsiView(semantic.Get(), semantic.Length() - 1);
}
if (semantic == "POSITION")
return VertexElement::Types::Position;
if (semantic == "COLOR")
return VertexElement::Types::Color;
if (semantic == "NORMAL")
return VertexElement::Types::Normal;
if (semantic == "TANGENT")
return VertexElement::Types::Tangent;
if (semantic == "BLENDINDICES")
return VertexElement::Types::BlendIndices;
if (semantic == "BLENDWEIGHTS" ||
semantic == "BLENDWEIGHT") // [Deprecated in v1.10]
return VertexElement::Types::BlendWeights;
if (semantic == "TEXCOORD" && index < 8)
return (VertexElement::Types)((int32)VertexElement::Types::TexCoord0 + index);
if (semantic == "ATTRIBUTE" && index < 4)
return (VertexElement::Types)((int32)VertexElement::Types::Attribute0 + index);
LOG(Warning, "Unsupported vertex shader input element semantic {}{}", semantic.ToString(), index);
return VertexElement::Types::Unknown;;
}
#endif #endif

View File

@@ -7,6 +7,7 @@
#include "ShaderCompilationContext.h" #include "ShaderCompilationContext.h"
#include "Parser/ShaderMeta.h" #include "Parser/ShaderMeta.h"
#include "Engine/Graphics/Shaders/GPUShaderProgram.h" #include "Engine/Graphics/Shaders/GPUShaderProgram.h"
#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
/// <summary> /// <summary>
/// Base class for the objects that can compile shaders source code. /// Base class for the objects that can compile shaders source code.
@@ -14,7 +15,6 @@
class ShaderCompiler class ShaderCompiler
{ {
public: public:
struct ShaderResourceBuffer struct ShaderResourceBuffer
{ {
byte Slot; byte Slot;
@@ -23,11 +23,9 @@ public:
}; };
private: private:
Array<char> _funcNameDefineBuffer; Array<char> _funcNameDefineBuffer;
protected: protected:
ShaderProfile _profile; ShaderProfile _profile;
ShaderCompilationContext* _context = nullptr; ShaderCompilationContext* _context = nullptr;
Array<ShaderMacro> _globalMacros; Array<ShaderMacro> _globalMacros;
@@ -35,7 +33,6 @@ protected:
Array<ShaderResourceBuffer> _constantBuffers; Array<ShaderResourceBuffer> _constantBuffers;
public: public:
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ShaderCompiler"/> class. /// Initializes a new instance of the <see cref="ShaderCompiler"/> class.
/// </summary> /// </summary>
@@ -51,7 +48,6 @@ public:
virtual ~ShaderCompiler() = default; virtual ~ShaderCompiler() = default;
public: public:
/// <summary> /// <summary>
/// Gets shader profile supported by this compiler. /// Gets shader profile supported by this compiler.
/// </summary> /// </summary>
@@ -85,8 +81,13 @@ public:
static void DisposeIncludedFilesCache(); static void DisposeIncludedFilesCache();
protected: protected:
// Input elements read from reflection after shader compilation. Rough approx or attributes without exact format nor bind slot (only semantics and value dimensions match).
struct AdditionalDataVS
{
GPUVertexLayout::Elements Inputs;
};
typedef bool (*WritePermutationData)(ShaderCompilationContext*, ShaderFunctionMeta&, int32, const Array<ShaderMacro>&); typedef bool (*WritePermutationData)(ShaderCompilationContext*, ShaderFunctionMeta&, int32, const Array<ShaderMacro>&, void*);
virtual bool CompileShader(ShaderFunctionMeta& meta, WritePermutationData customDataWrite = nullptr) = 0; virtual bool CompileShader(ShaderFunctionMeta& meta, WritePermutationData customDataWrite = nullptr) = 0;
@@ -99,9 +100,11 @@ protected:
static bool WriteShaderFunctionPermutation(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const ShaderBindings& bindings, const void* header, int32 headerSize, const void* cache, int32 cacheSize); static bool WriteShaderFunctionPermutation(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const ShaderBindings& bindings, const void* header, int32 headerSize, const void* cache, int32 cacheSize);
static bool WriteShaderFunctionPermutation(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const ShaderBindings& bindings, const void* cache, int32 cacheSize); static bool WriteShaderFunctionPermutation(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const ShaderBindings& bindings, const void* cache, int32 cacheSize);
static bool WriteShaderFunctionEnd(ShaderCompilationContext* context, ShaderFunctionMeta& meta); static bool WriteShaderFunctionEnd(ShaderCompilationContext* context, ShaderFunctionMeta& meta);
static bool WriteCustomDataVS(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const Array<ShaderMacro>& macros); static bool WriteCustomDataVS(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const Array<ShaderMacro>& macros, void* additionalData);
static bool WriteCustomDataHS(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const Array<ShaderMacro>& macros); static bool WriteCustomDataHS(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const Array<ShaderMacro>& macros, void* additionalData);
void GetDefineForFunction(ShaderFunctionMeta& meta, Array<ShaderMacro>& macros); void GetDefineForFunction(ShaderFunctionMeta& meta, Array<ShaderMacro>& macros);
static VertexElement::Types ParseVertexElementType(StringAnsiView semantic, uint32 index = 0);
}; };
#endif #endif

View File

@@ -234,14 +234,14 @@ SpirvShaderResourceType GetTextureType(const glslang::TSampler& sampler)
} }
} }
PixelFormat GetResourceFormat(const glslang::TSampler& sampler) PixelFormat GetResourceFormat(glslang::TBasicType basicType, uint32 vectorSize)
{ {
switch (sampler.type) switch (basicType)
{ {
case glslang::EbtVoid: case glslang::EbtVoid:
return PixelFormat::Unknown; return PixelFormat::Unknown;
case glslang::EbtFloat: case glslang::EbtFloat:
switch (sampler.vectorSize) switch (vectorSize)
{ {
case 1: case 1:
return PixelFormat::R32_Float; return PixelFormat::R32_Float;
@@ -254,7 +254,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
} }
break; break;
case glslang::EbtFloat16: case glslang::EbtFloat16:
switch (sampler.vectorSize) switch (vectorSize)
{ {
case 1: case 1:
return PixelFormat::R16_Float; return PixelFormat::R16_Float;
@@ -265,7 +265,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
} }
break; break;
case glslang::EbtUint: case glslang::EbtUint:
switch (sampler.vectorSize) switch (vectorSize)
{ {
case 1: case 1:
return PixelFormat::R32_UInt; return PixelFormat::R32_UInt;
@@ -278,7 +278,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
} }
break; break;
case glslang::EbtInt: case glslang::EbtInt:
switch (sampler.vectorSize) switch (vectorSize)
{ {
case 1: case 1:
return PixelFormat::R32_SInt; return PixelFormat::R32_SInt;
@@ -291,7 +291,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
} }
break; break;
case glslang::EbtUint8: case glslang::EbtUint8:
switch (sampler.vectorSize) switch (vectorSize)
{ {
case 1: case 1:
return PixelFormat::R8_UInt; return PixelFormat::R8_UInt;
@@ -302,7 +302,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
} }
break; break;
case glslang::EbtInt8: case glslang::EbtInt8:
switch (sampler.vectorSize) switch (vectorSize)
{ {
case 1: case 1:
return PixelFormat::R8_SInt; return PixelFormat::R8_SInt;
@@ -313,7 +313,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
} }
break; break;
case glslang::EbtUint16: case glslang::EbtUint16:
switch (sampler.vectorSize) switch (vectorSize)
{ {
case 1: case 1:
return PixelFormat::R16_UInt; return PixelFormat::R16_UInt;
@@ -324,7 +324,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
} }
break; break;
case glslang::EbtInt16: case glslang::EbtInt16:
switch (sampler.vectorSize) switch (vectorSize)
{ {
case 1: case 1:
return PixelFormat::R16_SInt; return PixelFormat::R16_SInt;
@@ -340,6 +340,16 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
return PixelFormat::Unknown; return PixelFormat::Unknown;
} }
PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
{
return GetResourceFormat(sampler.type, sampler.vectorSize);
}
PixelFormat GetResourceFormat(const glslang::TType& type)
{
return GetResourceFormat(type.getBasicType(), type.getVectorSize());
}
bool IsUavType(const glslang::TType& type) bool IsUavType(const glslang::TType& type)
{ {
if (type.getQualifier().isReadOnly()) if (type.getQualifier().isReadOnly())
@@ -611,6 +621,7 @@ bool ShaderCompilerVulkan::CompileShader(ShaderFunctionMeta& meta, WritePermutat
EShMessages messages = (EShMessages)(EShMsgReadHlsl | EShMsgSpvRules | EShMsgVulkanRules); EShMessages messages = (EShMessages)(EShMsgReadHlsl | EShMsgSpvRules | EShMsgVulkanRules);
// Compile all shader function permutations // Compile all shader function permutations
AdditionalDataVS additionalDataVS;
for (int32 permutationIndex = 0; permutationIndex < meta.Permutations.Count(); permutationIndex++) for (int32 permutationIndex = 0; permutationIndex < meta.Permutations.Count(); permutationIndex++)
{ {
#if PRINT_DESCRIPTORS #if PRINT_DESCRIPTORS
@@ -721,157 +732,167 @@ bool ShaderCompilerVulkan::CompileShader(ShaderFunctionMeta& meta, WritePermutat
} }
// Process shader reflection data // Process shader reflection data
void* additionalData = nullptr;
SpirvShaderHeader header; SpirvShaderHeader header;
Platform::MemoryClear(&header, sizeof(header)); Platform::MemoryClear(&header, sizeof(header));
ShaderBindings bindings = { 0, 0, 0, 0 }; ShaderBindings bindings = { 0, 0, 0, 0 };
if (type == ShaderStage::Vertex)
{ {
// Extract constant buffers usage information additionalData = &additionalDataVS;
for (int blockIndex = 0; blockIndex < program.getNumLiveUniformBlocks(); blockIndex++) additionalDataVS.Inputs.Clear();
for (int inputIndex = 0; inputIndex < program.getNumPipeInputs(); inputIndex++)
{ {
auto size = program.getUniformBlockSize(blockIndex); const glslang::TObjectReflection& input = program.getPipeInput(inputIndex);
auto uniform = program.getUniformBlockTType(blockIndex); if (!input.getType() || input.getType()->containsBuiltIn())
auto& qualifier = uniform->getQualifier();
auto binding = (int32)qualifier.layoutBinding;
if (!qualifier.hasBinding())
{
// Each uniform must have a valid binding
//LOG(Warning, "Found a uniform block \'{0}\' without a binding qualifier. Each uniform block must have an explicitly defined binding number.", String(uniform->getTypeName().c_str()));
continue; continue;
} additionalDataVS.Inputs.Add({ ParseVertexElementType(input.getType()->getQualifier().semanticName), 0, 0, 0, GetResourceFormat(*input.getType()) });
}
}
for (int blockIndex = 0; blockIndex < program.getNumLiveUniformBlocks(); blockIndex++)
{
auto size = program.getUniformBlockSize(blockIndex);
auto uniform = program.getUniformBlockTType(blockIndex);
auto& qualifier = uniform->getQualifier();
auto binding = (int32)qualifier.layoutBinding;
// Shared storage buffer if (!qualifier.hasBinding())
if (qualifier.storage == glslang::EvqBuffer) {
// Each uniform must have a valid binding
//LOG(Warning, "Found a uniform block \'{0}\' without a binding qualifier. Each uniform block must have an explicitly defined binding number.", String(uniform->getTypeName().c_str()));
continue;
}
// Shared storage buffer
if (qualifier.storage == glslang::EvqBuffer)
{
// RWBuffer
}
else
{
// Uniform buffer
bool found = false;
for (int32 i = 0; i < descriptorsCollector.DescriptorsCount; i++)
{ {
// RWBuffer auto& descriptor = descriptorsCollector.Descriptors[i];
if (descriptor.BindingType == SpirvShaderResourceBindingType::CB && descriptor.Binding == binding)
{
found = true;
descriptor.Size = size;
break;
}
} }
else if (!found)
{ {
// Uniform buffer LOG(Warning, "Failed to find descriptor for the uniform block \'{0}\' of size {1} (bytes), binding: {2}.", String(uniform->getTypeName().c_str()), size, binding);
bool found = false;
for (int32 i = 0; i < descriptorsCollector.DescriptorsCount; i++)
{
auto& descriptor = descriptorsCollector.Descriptors[i];
if (descriptor.BindingType == SpirvShaderResourceBindingType::CB && descriptor.Binding == binding)
{
found = true;
descriptor.Size = size;
break;
}
}
if (!found)
{
LOG(Warning, "Failed to find descriptor for the uniform block \'{0}\' of size {1} (bytes), binding: {2}.", String(uniform->getTypeName().c_str()), size, binding);
}
} }
} }
}
#if PRINT_UNIFORMS #if PRINT_UNIFORMS
// Debug printing all uniforms // Debug printing all uniforms
for (int32 index = 0; index < program.getNumLiveUniformVariables(); index++) for (int32 index = 0; index < program.getNumLiveUniformVariables(); index++)
{ {
auto uniform = program.getUniformTType(index); auto uniform = program.getUniformTType(index);
auto qualifier = uniform->getQualifier(); auto qualifier = uniform->getQualifier();
if (!uniform->isArray()) if (!uniform->isArray())
LOG(Warning, "Shader {0}:{1} - uniform: {2} {3} at binding {4}", LOG(Warning, "Shader {0}:{1} - uniform: {2} {3} at binding {4}",
_context->TargetNameAnsi, _context->TargetNameAnsi,
String(meta.Name), String(meta.Name),
uniform->getCompleteString().c_str(), uniform->getCompleteString().c_str(),
program.getUniformName(index), program.getUniformName(index),
qualifier.layoutBinding qualifier.layoutBinding
); );
} }
#endif #endif
// Process all descriptors // Process all descriptors
header.DescriptorInfo.ImageInfosCount = descriptorsCollector.Images; header.DescriptorInfo.ImageInfosCount = descriptorsCollector.Images;
header.DescriptorInfo.BufferInfosCount = descriptorsCollector.Buffers; header.DescriptorInfo.BufferInfosCount = descriptorsCollector.Buffers;
header.DescriptorInfo.TexelBufferViewsCount = descriptorsCollector.TexelBuffers; header.DescriptorInfo.TexelBufferViewsCount = descriptorsCollector.TexelBuffers;
for (int32 i = 0; i < descriptorsCollector.DescriptorsCount; i++) for (int32 i = 0; i < descriptorsCollector.DescriptorsCount; i++)
{
auto& descriptor = descriptorsCollector.Descriptors[i];
// Skip cases (eg. AppendStructuredBuffer counter buffer)
if (descriptor.Slot == MAX_uint16)
continue;
auto& d = header.DescriptorInfo.DescriptorTypes[header.DescriptorInfo.DescriptorTypesCount++];
d.Binding = descriptor.Binding;
d.Set = stageSet;
d.Slot = descriptor.Slot;
d.BindingType = descriptor.BindingType;
d.DescriptorType = descriptor.DescriptorType;
d.ResourceType = descriptor.ResourceType;
d.ResourceFormat = descriptor.ResourceFormat;
d.Count = descriptor.Count;
switch (descriptor.BindingType)
{ {
auto& descriptor = descriptorsCollector.Descriptors[i]; case SpirvShaderResourceBindingType::CB:
ASSERT_LOW_LAYER(descriptor.Slot >= 0 && descriptor.Slot < GPU_MAX_CB_BINDED);
bindings.UsedCBsMask |= 1 << descriptor.Slot;
break;
case SpirvShaderResourceBindingType::SRV:
ASSERT_LOW_LAYER(descriptor.Slot >= 0 && descriptor.Slot < GPU_MAX_SR_BINDED);
bindings.UsedSRsMask |= 1 << descriptor.Slot;
break;
case SpirvShaderResourceBindingType::UAV:
ASSERT_LOW_LAYER(descriptor.Slot >= 0 && descriptor.Slot < GPU_MAX_UA_BINDED);
bindings.UsedUAsMask |= 1 << descriptor.Slot;
break;
}
// Skip cases (eg. AppendStructuredBuffer counter buffer) if (descriptor.BindingType == SpirvShaderResourceBindingType::CB)
if (descriptor.Slot == MAX_uint16) {
if (descriptor.Size == -1)
{
// Skip unused constant buffers
continue; continue;
}
auto& d = header.DescriptorInfo.DescriptorTypes[header.DescriptorInfo.DescriptorTypesCount++]; if (descriptor.Size == 0)
d.Binding = descriptor.Binding;
d.Set = stageSet;
d.Slot = descriptor.Slot;
d.BindingType = descriptor.BindingType;
d.DescriptorType = descriptor.DescriptorType;
d.ResourceType = descriptor.ResourceType;
d.ResourceFormat = descriptor.ResourceFormat;
d.Count = descriptor.Count;
switch (descriptor.BindingType)
{ {
case SpirvShaderResourceBindingType::CB: LOG(Warning, "Found constant buffer \'{1}\' at slot {0} but it's not used or has no valid size.", descriptor.Slot, String(descriptor.Name.c_str()));
ASSERT_LOW_LAYER(descriptor.Slot >= 0 && descriptor.Slot < GPU_MAX_CB_BINDED); continue;
bindings.UsedCBsMask |= 1 << descriptor.Slot;
break;
case SpirvShaderResourceBindingType::SRV:
ASSERT_LOW_LAYER(descriptor.Slot >= 0 && descriptor.Slot < GPU_MAX_SR_BINDED);
bindings.UsedSRsMask |= 1 << descriptor.Slot;
break;
case SpirvShaderResourceBindingType::UAV:
ASSERT_LOW_LAYER(descriptor.Slot >= 0 && descriptor.Slot < GPU_MAX_UA_BINDED);
bindings.UsedUAsMask |= 1 << descriptor.Slot;
break;
} }
if (descriptor.BindingType == SpirvShaderResourceBindingType::CB) for (int32 b = 0; b < _constantBuffers.Count(); b++)
{ {
if (descriptor.Size == -1) auto& cc = _constantBuffers[b];
if (cc.Slot == descriptor.Slot)
{ {
// Skip unused constant buffers // Mark as used and cache some data
continue; cc.IsUsed = true;
} cc.Size = descriptor.Size;
if (descriptor.Size == 0) break;
{
LOG(Warning, "Found constant buffer \'{1}\' at slot {0} but it's not used or has no valid size.", descriptor.Slot, String(descriptor.Name.c_str()));
continue;
}
for (int32 b = 0; b < _constantBuffers.Count(); b++)
{
auto& cc = _constantBuffers[b];
if (cc.Slot == descriptor.Slot)
{
// Mark as used and cache some data
cc.IsUsed = true;
cc.Size = descriptor.Size;
break;
}
} }
} }
}
#if PRINT_DESCRIPTORS #if PRINT_DESCRIPTORS
String type; String type;
switch (descriptor.BindingType) switch (descriptor.BindingType)
{ {
case SpirvShaderResourceBindingType::INVALID: case SpirvShaderResourceBindingType::INVALID:
type = TEXT("INVALID"); type = TEXT("INVALID");
break; break;
case SpirvShaderResourceBindingType::CB: case SpirvShaderResourceBindingType::CB:
type = TEXT("CB"); type = TEXT("CB");
break; break;
case SpirvShaderResourceBindingType::SAMPLER: case SpirvShaderResourceBindingType::SAMPLER:
type = TEXT("SAMPLER"); type = TEXT("SAMPLER");
break; break;
case SpirvShaderResourceBindingType::SRV: case SpirvShaderResourceBindingType::SRV:
type = TEXT("SRV"); type = TEXT("SRV");
break; break;
case SpirvShaderResourceBindingType::UAV: case SpirvShaderResourceBindingType::UAV:
type = TEXT("UAV"); type = TEXT("UAV");
break; break;
default: default:
type = TEXT("?"); type = TEXT("?");
}
LOG(Warning, "VULKAN SHADER RESOURCE: slot: {1}, binding: {2}, name: {0}, type: {3}", String(descriptor.Name.c_str()), descriptor.Slot, descriptor.Binding, type);
#endif
} }
LOG(Warning, "VULKAN SHADER RESOURCE: slot: {1}, binding: {2}, name: {0}, type: {3}", String(descriptor.Name.c_str()), descriptor.Slot, descriptor.Binding, type);
#endif
} }
// Generate SPIR-V (optimize it at the same time) // Generate SPIR-V (optimize it at the same time)
@@ -916,7 +937,7 @@ bool ShaderCompilerVulkan::CompileShader(ShaderFunctionMeta& meta, WritePermutat
if (WriteShaderFunctionPermutation(_context, meta, permutationIndex, bindings, &header, sizeof(header), &spirv[0], spirvBytesCount)) if (WriteShaderFunctionPermutation(_context, meta, permutationIndex, bindings, &header, sizeof(header), &spirv[0], spirvBytesCount))
return true; return true;
if (customDataWrite && customDataWrite(_context, meta, permutationIndex, _macros)) if (customDataWrite && customDataWrite(_context, meta, permutationIndex, _macros, additionalData))
return true; return true;
} }

View File

@@ -12,11 +12,9 @@
class ShaderCompilerVulkan : public ShaderCompiler class ShaderCompilerVulkan : public ShaderCompiler
{ {
private: private:
Array<char> _funcNameDefineBuffer; Array<char> _funcNameDefineBuffer;
public: public:
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ShaderCompilerVulkan"/> class. /// Initializes a new instance of the <see cref="ShaderCompilerVulkan"/> class.
/// </summary> /// </summary>
@@ -29,7 +27,6 @@ public:
~ShaderCompilerVulkan(); ~ShaderCompilerVulkan();
protected: protected:
// [ShaderCompiler] // [ShaderCompiler]
bool CompileShader(ShaderFunctionMeta& meta, WritePermutationData customDataWrite = nullptr) override; bool CompileShader(ShaderFunctionMeta& meta, WritePermutationData customDataWrite = nullptr) override;
bool OnCompileBegin() override; bool OnCompileBegin() override;