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:
@@ -177,22 +177,28 @@ GPUShaderProgram* GPUShader::GetShader(ShaderStage stage, const StringAnsiView&
|
||||
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]
|
||||
byte inputLayoutSize;
|
||||
stream.ReadByte(&inputLayoutSize);
|
||||
if (inputLayoutSize == 0)
|
||||
return nullptr;
|
||||
return;
|
||||
void* elementsData = stream.Move(sizeof(VertexElement) * inputLayoutSize);
|
||||
if (inputLayoutSize > GPU_MAX_VS_ELEMENTS)
|
||||
{
|
||||
LOG(Error, "Incorrect input layout size.");
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
GPUVertexLayout::Elements elements;
|
||||
elements.Set((VertexElement*)elementsData, inputLayoutSize);
|
||||
return GPUVertexLayout::Get(elements);
|
||||
vertexLayout = GPUVertexLayout::Get(elements);
|
||||
}
|
||||
|
||||
GPUResourceType GPUShader::GetResourceType() const
|
||||
|
||||
@@ -12,7 +12,7 @@ class GPUShaderProgram;
|
||||
/// <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).
|
||||
/// </summary>
|
||||
#define GPU_SHADER_CACHE_VERSION 11
|
||||
#define GPU_SHADER_CACHE_VERSION 12
|
||||
|
||||
/// <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.
|
||||
@@ -135,7 +135,7 @@ public:
|
||||
protected:
|
||||
GPUShaderProgram* GetShader(ShaderStage stage, const StringAnsiView& name, int32 permutationIndex) const;
|
||||
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:
|
||||
// [GPUResource]
|
||||
|
||||
@@ -136,6 +136,9 @@ public:
|
||||
// [Deprecated in v1.10]
|
||||
GPUVertexLayout* Layout = nullptr;
|
||||
|
||||
// Vertex shader inputs layout. Used to ensure that binded vertex buffers provide all required elements.
|
||||
GPUVertexLayout* InputLayout = nullptr;
|
||||
|
||||
public:
|
||||
// [GPUShaderProgram]
|
||||
ShaderStage GetStage() const override
|
||||
|
||||
@@ -26,7 +26,7 @@ ID3D11InputLayout* GPUShaderProgramVSDX11::GetInputLayout(GPUVertexLayoutDX11* v
|
||||
{
|
||||
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));
|
||||
}
|
||||
_cache.Add(vertexLayout, inputLayout);
|
||||
@@ -42,42 +42,30 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
|
||||
{
|
||||
case ShaderStage::Vertex:
|
||||
{
|
||||
// Load Input Layout
|
||||
GPUVertexLayout* vertexLayout = ReadVertexLayout(stream);
|
||||
|
||||
// Create shader
|
||||
GPUVertexLayout* inputLayout, *vertexLayout;
|
||||
ReadVertexLayout(stream, inputLayout, vertexLayout);
|
||||
ID3D11VertexShader* buffer = nullptr;
|
||||
result = _device->GetDevice()->CreateVertexShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
|
||||
|
||||
// Create object
|
||||
shader = New<GPUShaderProgramVSDX11>(initializer, buffer, vertexLayout, bytecode);
|
||||
shader = New<GPUShaderProgramVSDX11>(initializer, buffer, inputLayout, vertexLayout, bytecode);
|
||||
break;
|
||||
}
|
||||
#if GPU_ALLOW_TESSELLATION_SHADERS
|
||||
case ShaderStage::Hull:
|
||||
{
|
||||
// Read control points
|
||||
int32 controlPointsCount;
|
||||
stream.ReadInt32(&controlPointsCount);
|
||||
|
||||
// Create shader
|
||||
ID3D11HullShader* buffer = nullptr;
|
||||
result = _device->GetDevice()->CreateHullShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
|
||||
|
||||
// Create object
|
||||
shader = New<GPUShaderProgramHSDX11>(initializer, buffer, controlPointsCount);
|
||||
break;
|
||||
}
|
||||
case ShaderStage::Domain:
|
||||
{
|
||||
// Create shader
|
||||
ID3D11DomainShader* buffer = nullptr;
|
||||
result = _device->GetDevice()->CreateDomainShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
|
||||
|
||||
// Create object
|
||||
shader = New<GPUShaderProgramDSDX11>(initializer, buffer);
|
||||
break;
|
||||
}
|
||||
@@ -92,35 +80,26 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
|
||||
#if GPU_ALLOW_GEOMETRY_SHADERS
|
||||
case ShaderStage::Geometry:
|
||||
{
|
||||
// Create shader
|
||||
ID3D11GeometryShader* buffer = nullptr;
|
||||
result = _device->GetDevice()->CreateGeometryShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
|
||||
|
||||
// Create object
|
||||
shader = New<GPUShaderProgramGSDX11>(initializer, buffer);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case ShaderStage::Pixel:
|
||||
{
|
||||
// Create shader
|
||||
ID3D11PixelShader* buffer = nullptr;
|
||||
result = _device->GetDevice()->CreatePixelShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
|
||||
|
||||
// Create object
|
||||
shader = New<GPUShaderProgramPSDX11>(initializer, buffer);
|
||||
break;
|
||||
}
|
||||
case ShaderStage::Compute:
|
||||
{
|
||||
// Create shader
|
||||
ID3D11ComputeShader* buffer = nullptr;
|
||||
result = _device->GetDevice()->CreateComputeShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
|
||||
|
||||
// Create object
|
||||
shader = New<GPUShaderProgramCSDX11>(initializer, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -58,9 +58,10 @@ private:
|
||||
Dictionary<class GPUVertexLayoutDX11*, ID3D11InputLayout*> _cache;
|
||||
|
||||
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)
|
||||
{
|
||||
InputLayout = inputLayout;
|
||||
Layout = vertexLayout;
|
||||
Bytecode.Copy(bytecode);
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ void DescriptorHeapWithSlotsDX12::ReleaseSlot(uint32 index)
|
||||
{
|
||||
uint32& value = _usage[index / 32];
|
||||
const uint32 mask = 1 << (index & 31);
|
||||
ASSERT_LOW_LAYER((value & mask) == mask);
|
||||
//ASSERT_LOW_LAYER((value & mask) == mask);
|
||||
value &= ~mask;
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ bool GPUPipelineStateDX12::Init(const Description& desc)
|
||||
INIT_SHADER_STAGE(PS, GPUShaderProgramPSDX12);
|
||||
|
||||
// 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[] =
|
||||
{
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED,
|
||||
|
||||
@@ -19,8 +19,9 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const
|
||||
{
|
||||
case ShaderStage::Vertex:
|
||||
{
|
||||
GPUVertexLayout* vertexLayout = ReadVertexLayout(stream);
|
||||
shader = New<GPUShaderProgramVSDX12>(initializer, header, bytecode, vertexLayout);
|
||||
GPUVertexLayout* inputLayout, *vertexLayout;
|
||||
ReadVertexLayout(stream, inputLayout, vertexLayout);
|
||||
shader = New<GPUShaderProgramVSDX12>(initializer, header, bytecode, inputLayout, vertexLayout);
|
||||
break;
|
||||
}
|
||||
#if GPU_ALLOW_TESSELLATION_SHADERS
|
||||
|
||||
@@ -46,9 +46,10 @@ public:
|
||||
class GPUShaderProgramVSDX12 : public GPUShaderProgramDX12<GPUShaderProgramVS>
|
||||
{
|
||||
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)
|
||||
{
|
||||
InputLayout = inputLayout;
|
||||
Layout = vertexLayout;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -320,7 +320,7 @@ bool GPUPipelineStateVulkan::Init(const Description& desc)
|
||||
_desc.pStages = _shaderStages;
|
||||
|
||||
// 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);;
|
||||
switch (desc.PrimitiveTopology)
|
||||
{
|
||||
|
||||
@@ -66,9 +66,10 @@ public:
|
||||
class GPUShaderProgramVSVulkan : public GPUShaderProgramVulkan<GPUShaderProgramVS>
|
||||
{
|
||||
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)
|
||||
{
|
||||
InputLayout = inputLayout;
|
||||
Layout = vertexLayout;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -138,8 +138,9 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons
|
||||
{
|
||||
case ShaderStage::Vertex:
|
||||
{
|
||||
GPUVertexLayout* vertexLayout = ReadVertexLayout(stream);
|
||||
shader = New<GPUShaderProgramVSVulkan>(_device, initializer, header->DescriptorInfo, shaderModule, vertexLayout);
|
||||
GPUVertexLayout* inputLayout, *vertexLayout;
|
||||
ReadVertexLayout(stream, inputLayout, vertexLayout);
|
||||
shader = New<GPUShaderProgramVSVulkan>(_device, initializer, header->DescriptorInfo, shaderModule, inputLayout, vertexLayout);
|
||||
break;
|
||||
}
|
||||
#if GPU_ALLOW_TESSELLATION_SHADERS
|
||||
|
||||
@@ -16,11 +16,9 @@
|
||||
class IncludeD3D : public ID3DInclude
|
||||
{
|
||||
private:
|
||||
|
||||
ShaderCompilationContext* _context;
|
||||
|
||||
public:
|
||||
|
||||
IncludeD3D(ShaderCompilationContext* context)
|
||||
{
|
||||
_context = context;
|
||||
@@ -84,14 +82,9 @@ namespace
|
||||
// Extract constant buffers usage information
|
||||
for (uint32 a = 0; a < desc.ConstantBuffers; a++)
|
||||
{
|
||||
// Get CB
|
||||
auto cb = reflector->GetConstantBufferByIndex(a);
|
||||
|
||||
// Get CB description
|
||||
D3D11_SHADER_BUFFER_DESC cbDesc;
|
||||
cb->GetDesc(&cbDesc);
|
||||
|
||||
// Check buffer type
|
||||
if (cbDesc.Type == D3D_CT_CBUFFER)
|
||||
{
|
||||
// Find CB slot index
|
||||
@@ -132,22 +125,20 @@ namespace
|
||||
// Extract resources usage
|
||||
for (uint32 i = 0; i < desc.BoundResources; i++)
|
||||
{
|
||||
// Get resource description
|
||||
D3D11_SHADER_INPUT_BIND_DESC resDesc;
|
||||
reflector->GetResourceBindingDesc(i, &resDesc);
|
||||
|
||||
switch (resDesc.Type)
|
||||
{
|
||||
// Sampler
|
||||
// Sampler
|
||||
case D3D_SIT_SAMPLER:
|
||||
break;
|
||||
|
||||
// Constant Buffer
|
||||
// Constant Buffer
|
||||
case D3D_SIT_CBUFFER:
|
||||
case D3D_SIT_TBUFFER:
|
||||
break;
|
||||
|
||||
// Shader Resource
|
||||
// Shader Resource
|
||||
case D3D_SIT_TEXTURE:
|
||||
case D3D_SIT_STRUCTURED:
|
||||
case D3D_SIT_BYTEADDRESS:
|
||||
@@ -155,7 +146,7 @@ namespace
|
||||
bindings.UsedSRsMask |= 1 << (resDesc.BindPoint + shift);
|
||||
break;
|
||||
|
||||
// Unordered Access
|
||||
// Unordered Access
|
||||
case D3D_SIT_UAV_RWTYPED:
|
||||
case D3D_SIT_UAV_RWSTRUCTURED:
|
||||
case D3D_SIT_UAV_RWBYTEADDRESS:
|
||||
@@ -212,7 +203,6 @@ bool ShaderCompilerD3D::CompileShader(ShaderFunctionMeta& meta, WritePermutation
|
||||
else
|
||||
{
|
||||
profileName += "_4_0";
|
||||
|
||||
if (type == ShaderStage::Domain || type == ShaderStage::Hull)
|
||||
{
|
||||
_context->OnError("Tessellation is not supported on DirectX 10");
|
||||
@@ -221,6 +211,7 @@ bool ShaderCompilerD3D::CompileShader(ShaderFunctionMeta& meta, WritePermutation
|
||||
}
|
||||
|
||||
// Compile all shader function permutations
|
||||
AdditionalDataVS additionalDataVS;
|
||||
for (int32 permutationIndex = 0; permutationIndex < meta.Permutations.Count(); permutationIndex++)
|
||||
{
|
||||
_macros.Clear();
|
||||
@@ -253,8 +244,6 @@ bool ShaderCompilerD3D::CompileShader(ShaderFunctionMeta& meta, WritePermutation
|
||||
0,
|
||||
&shader,
|
||||
&errors);
|
||||
|
||||
// Check compilation result
|
||||
if (FAILED(result))
|
||||
{
|
||||
const auto msg = static_cast<const char*>(errors->GetBufferPointer());
|
||||
@@ -279,24 +268,68 @@ bool ShaderCompilerD3D::CompileShader(ShaderFunctionMeta& meta, WritePermutation
|
||||
reflector->GetDesc(&desc);
|
||||
|
||||
// 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 };
|
||||
if (ProcessShader(_context, _constantBuffers, reflector.Get(), desc, bindings))
|
||||
return true;
|
||||
|
||||
#ifdef GPU_USE_SHADERS_DEBUG_LAYER
|
||||
|
||||
// Generate debug information
|
||||
if (ProcessDebugInfo(_context, meta, permutationIndex, shaderBuffer, shaderBufferSize))
|
||||
return true;
|
||||
|
||||
#endif
|
||||
|
||||
// Strip shader bytecode for an optimization
|
||||
ComPtr<ID3DBlob> shaderStripped;
|
||||
if (!options->GenerateDebugData)
|
||||
{
|
||||
//auto prevShaderBufferSize = shaderBufferSize;
|
||||
|
||||
// Strip shader bytes
|
||||
result = D3DStripShader(
|
||||
shaderBuffer,
|
||||
@@ -312,15 +345,12 @@ bool ShaderCompilerD3D::CompileShader(ShaderFunctionMeta& meta, WritePermutation
|
||||
// Set new buffer
|
||||
shaderBuffer = shaderStripped->GetBufferPointer();
|
||||
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))
|
||||
return true;
|
||||
|
||||
if (customDataWrite && customDataWrite(_context, meta, permutationIndex, _macros))
|
||||
if (customDataWrite && customDataWrite(_context, meta, permutationIndex, _macros, additionalData))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,12 +12,10 @@
|
||||
class ShaderCompilerD3D : public ShaderCompiler
|
||||
{
|
||||
private:
|
||||
|
||||
Array<char> _funcNameDefineBuffer;
|
||||
uint32 _flags;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ShaderCompilerD3D"/> class.
|
||||
/// </summary>
|
||||
@@ -25,7 +23,6 @@ public:
|
||||
ShaderCompilerD3D(ShaderProfile profile);
|
||||
|
||||
protected:
|
||||
|
||||
// [ShaderCompiler]
|
||||
bool CompileShader(ShaderFunctionMeta& meta, WritePermutationData customDataWrite = nullptr) override;
|
||||
bool OnCompileBegin() override;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "ShaderCompilerDX.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Graphics/Config.h"
|
||||
#include "Engine/GraphicsDevice/DirectX/DX12/Types.h"
|
||||
@@ -22,12 +21,10 @@
|
||||
class IncludeDX : public IDxcIncludeHandler
|
||||
{
|
||||
private:
|
||||
|
||||
ShaderCompilationContext* _context;
|
||||
IDxcLibrary* _library;
|
||||
|
||||
public:
|
||||
|
||||
IncludeDX(ShaderCompilationContext* context, IDxcLibrary* library)
|
||||
{
|
||||
_context = context;
|
||||
@@ -185,6 +182,7 @@ bool ShaderCompilerDX::CompileShader(ShaderFunctionMeta& meta, WritePermutationD
|
||||
}
|
||||
|
||||
// Compile all shader function permutations
|
||||
AdditionalDataVS additionalDataVS;
|
||||
for (int32 permutationIndex = 0; permutationIndex < meta.Permutations.Count(); permutationIndex++)
|
||||
{
|
||||
_macros.Clear();
|
||||
@@ -320,6 +318,54 @@ bool ShaderCompilerDX::CompileShader(ShaderFunctionMeta& meta, WritePermutationD
|
||||
shaderReflection->GetDesc(&desc);
|
||||
|
||||
// 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;
|
||||
Platform::MemoryClear(&header, sizeof(header));
|
||||
ShaderBindings bindings = { desc.InstructionCount, 0, 0, 0 };
|
||||
@@ -370,16 +416,16 @@ bool ShaderCompilerDX::CompileShader(ShaderFunctionMeta& meta, WritePermutationD
|
||||
shaderReflection->GetResourceBindingDesc(i, &resDesc);
|
||||
switch (resDesc.Type)
|
||||
{
|
||||
// Sampler
|
||||
// Sampler
|
||||
case D3D_SIT_SAMPLER:
|
||||
break;
|
||||
|
||||
// Constant Buffer
|
||||
// Constant Buffer
|
||||
case D3D_SIT_CBUFFER:
|
||||
case D3D_SIT_TBUFFER:
|
||||
break;
|
||||
|
||||
// Shader Resource
|
||||
// Shader Resource
|
||||
case D3D_SIT_TEXTURE:
|
||||
for (UINT shift = 0; shift < resDesc.BindCount; shift++)
|
||||
{
|
||||
@@ -396,7 +442,7 @@ bool ShaderCompilerDX::CompileShader(ShaderFunctionMeta& meta, WritePermutationD
|
||||
}
|
||||
break;
|
||||
|
||||
// Unordered Access
|
||||
// Unordered Access
|
||||
case D3D_SIT_UAV_RWTYPED:
|
||||
case D3D_SIT_UAV_RWSTRUCTURED:
|
||||
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()))
|
||||
return true;
|
||||
|
||||
if (customDataWrite && customDataWrite(_context, meta, permutationIndex, _macros))
|
||||
if (customDataWrite && customDataWrite(_context, meta, permutationIndex, _macros, additionalData))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,14 +12,12 @@
|
||||
class ShaderCompilerDX : public ShaderCompiler
|
||||
{
|
||||
private:
|
||||
|
||||
Array<char> _funcNameDefineBuffer;
|
||||
void* _compiler;
|
||||
void* _library;
|
||||
void* _containerReflection;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ShaderCompilerDX"/> class.
|
||||
/// </summary>
|
||||
@@ -32,7 +30,6 @@ public:
|
||||
~ShaderCompilerDX();
|
||||
|
||||
protected:
|
||||
|
||||
// [ShaderCompiler]
|
||||
bool CompileShader(ShaderFunctionMeta& meta, WritePermutationData customDataWrite = nullptr) override;
|
||||
bool OnCompileBegin() override;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
auto output = context->Output;
|
||||
|
||||
output->Write((uint32)(cacheSize + headerSize));
|
||||
output->WriteBytes(header, headerSize);
|
||||
output->WriteBytes(cache, cacheSize);
|
||||
@@ -293,18 +292,22 @@ bool ShaderCompiler::WriteShaderFunctionEnd(ShaderCompilationContext* context, S
|
||||
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;
|
||||
|
||||
// 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& layout = metaVS.InputLayout;
|
||||
#if FLAXENGINE_VERSION_MAJOR > 2 || (FLAXENGINE_VERSION_MAJOR == 2 && FLAXENGINE_VERSION_MINOR >= 1)
|
||||
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);
|
||||
#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
|
||||
|
||||
// Get visible entries (based on `visible` flag switch)
|
||||
@@ -443,7 +446,7 @@ bool ShaderCompiler::WriteCustomDataVS(ShaderCompilationContext* context, Shader
|
||||
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& metaHS = *(HullShaderMeta*)&meta;
|
||||
@@ -457,7 +460,7 @@ bool ShaderCompiler::WriteCustomDataHS(ShaderCompilationContext* context, Shader
|
||||
void ShaderCompiler::GetDefineForFunction(ShaderFunctionMeta& meta, Array<ShaderMacro>& macros)
|
||||
{
|
||||
auto& functionName = meta.Name;
|
||||
const int32 functionNameLength = static_cast<int32>(functionName.Length());
|
||||
const int32 functionNameLength = functionName.Length();
|
||||
_funcNameDefineBuffer.Clear();
|
||||
_funcNameDefineBuffer.EnsureCapacity(functionNameLength + 2);
|
||||
_funcNameDefineBuffer.Add('_');
|
||||
@@ -466,4 +469,35 @@ void ShaderCompiler::GetDefineForFunction(ShaderFunctionMeta& meta, Array<Shader
|
||||
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
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "ShaderCompilationContext.h"
|
||||
#include "Parser/ShaderMeta.h"
|
||||
#include "Engine/Graphics/Shaders/GPUShaderProgram.h"
|
||||
#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
|
||||
|
||||
/// <summary>
|
||||
/// Base class for the objects that can compile shaders source code.
|
||||
@@ -14,7 +15,6 @@
|
||||
class ShaderCompiler
|
||||
{
|
||||
public:
|
||||
|
||||
struct ShaderResourceBuffer
|
||||
{
|
||||
byte Slot;
|
||||
@@ -23,11 +23,9 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Array<char> _funcNameDefineBuffer;
|
||||
|
||||
protected:
|
||||
|
||||
ShaderProfile _profile;
|
||||
ShaderCompilationContext* _context = nullptr;
|
||||
Array<ShaderMacro> _globalMacros;
|
||||
@@ -35,7 +33,6 @@ protected:
|
||||
Array<ShaderResourceBuffer> _constantBuffers;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ShaderCompiler"/> class.
|
||||
/// </summary>
|
||||
@@ -51,7 +48,6 @@ public:
|
||||
virtual ~ShaderCompiler() = default;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets shader profile supported by this compiler.
|
||||
/// </summary>
|
||||
@@ -85,8 +81,13 @@ public:
|
||||
static void DisposeIncludedFilesCache();
|
||||
|
||||
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;
|
||||
|
||||
@@ -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* cache, int32 cacheSize);
|
||||
static bool WriteShaderFunctionEnd(ShaderCompilationContext* context, ShaderFunctionMeta& meta);
|
||||
static bool WriteCustomDataVS(ShaderCompilationContext* context, ShaderFunctionMeta& meta, int32 permutationIndex, const Array<ShaderMacro>& macros);
|
||||
static bool WriteCustomDataHS(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, void* additionalData);
|
||||
void GetDefineForFunction(ShaderFunctionMeta& meta, Array<ShaderMacro>& macros);
|
||||
|
||||
static VertexElement::Types ParseVertexElementType(StringAnsiView semantic, uint32 index = 0);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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:
|
||||
return PixelFormat::Unknown;
|
||||
case glslang::EbtFloat:
|
||||
switch (sampler.vectorSize)
|
||||
switch (vectorSize)
|
||||
{
|
||||
case 1:
|
||||
return PixelFormat::R32_Float;
|
||||
@@ -254,7 +254,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
|
||||
}
|
||||
break;
|
||||
case glslang::EbtFloat16:
|
||||
switch (sampler.vectorSize)
|
||||
switch (vectorSize)
|
||||
{
|
||||
case 1:
|
||||
return PixelFormat::R16_Float;
|
||||
@@ -265,7 +265,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
|
||||
}
|
||||
break;
|
||||
case glslang::EbtUint:
|
||||
switch (sampler.vectorSize)
|
||||
switch (vectorSize)
|
||||
{
|
||||
case 1:
|
||||
return PixelFormat::R32_UInt;
|
||||
@@ -278,7 +278,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
|
||||
}
|
||||
break;
|
||||
case glslang::EbtInt:
|
||||
switch (sampler.vectorSize)
|
||||
switch (vectorSize)
|
||||
{
|
||||
case 1:
|
||||
return PixelFormat::R32_SInt;
|
||||
@@ -291,7 +291,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
|
||||
}
|
||||
break;
|
||||
case glslang::EbtUint8:
|
||||
switch (sampler.vectorSize)
|
||||
switch (vectorSize)
|
||||
{
|
||||
case 1:
|
||||
return PixelFormat::R8_UInt;
|
||||
@@ -302,7 +302,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
|
||||
}
|
||||
break;
|
||||
case glslang::EbtInt8:
|
||||
switch (sampler.vectorSize)
|
||||
switch (vectorSize)
|
||||
{
|
||||
case 1:
|
||||
return PixelFormat::R8_SInt;
|
||||
@@ -313,7 +313,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
|
||||
}
|
||||
break;
|
||||
case glslang::EbtUint16:
|
||||
switch (sampler.vectorSize)
|
||||
switch (vectorSize)
|
||||
{
|
||||
case 1:
|
||||
return PixelFormat::R16_UInt;
|
||||
@@ -324,7 +324,7 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
|
||||
}
|
||||
break;
|
||||
case glslang::EbtInt16:
|
||||
switch (sampler.vectorSize)
|
||||
switch (vectorSize)
|
||||
{
|
||||
case 1:
|
||||
return PixelFormat::R16_SInt;
|
||||
@@ -340,6 +340,16 @@ PixelFormat GetResourceFormat(const glslang::TSampler& sampler)
|
||||
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)
|
||||
{
|
||||
if (type.getQualifier().isReadOnly())
|
||||
@@ -611,6 +621,7 @@ bool ShaderCompilerVulkan::CompileShader(ShaderFunctionMeta& meta, WritePermutat
|
||||
EShMessages messages = (EShMessages)(EShMsgReadHlsl | EShMsgSpvRules | EShMsgVulkanRules);
|
||||
|
||||
// Compile all shader function permutations
|
||||
AdditionalDataVS additionalDataVS;
|
||||
for (int32 permutationIndex = 0; permutationIndex < meta.Permutations.Count(); permutationIndex++)
|
||||
{
|
||||
#if PRINT_DESCRIPTORS
|
||||
@@ -721,157 +732,167 @@ bool ShaderCompilerVulkan::CompileShader(ShaderFunctionMeta& meta, WritePermutat
|
||||
}
|
||||
|
||||
// Process shader reflection data
|
||||
void* additionalData = nullptr;
|
||||
SpirvShaderHeader header;
|
||||
Platform::MemoryClear(&header, sizeof(header));
|
||||
ShaderBindings bindings = { 0, 0, 0, 0 };
|
||||
if (type == ShaderStage::Vertex)
|
||||
{
|
||||
// Extract constant buffers usage information
|
||||
for (int blockIndex = 0; blockIndex < program.getNumLiveUniformBlocks(); blockIndex++)
|
||||
additionalData = &additionalDataVS;
|
||||
additionalDataVS.Inputs.Clear();
|
||||
for (int inputIndex = 0; inputIndex < program.getNumPipeInputs(); inputIndex++)
|
||||
{
|
||||
auto size = program.getUniformBlockSize(blockIndex);
|
||||
auto uniform = program.getUniformBlockTType(blockIndex);
|
||||
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()));
|
||||
const glslang::TObjectReflection& input = program.getPipeInput(inputIndex);
|
||||
if (!input.getType() || input.getType()->containsBuiltIn())
|
||||
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.storage == glslang::EvqBuffer)
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
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);
|
||||
}
|
||||
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
|
||||
// Debug printing all uniforms
|
||||
for (int32 index = 0; index < program.getNumLiveUniformVariables(); index++)
|
||||
{
|
||||
auto uniform = program.getUniformTType(index);
|
||||
auto qualifier = uniform->getQualifier();
|
||||
if (!uniform->isArray())
|
||||
LOG(Warning, "Shader {0}:{1} - uniform: {2} {3} at binding {4}",
|
||||
_context->TargetNameAnsi,
|
||||
String(meta.Name),
|
||||
uniform->getCompleteString().c_str(),
|
||||
program.getUniformName(index),
|
||||
qualifier.layoutBinding
|
||||
);
|
||||
}
|
||||
// Debug printing all uniforms
|
||||
for (int32 index = 0; index < program.getNumLiveUniformVariables(); index++)
|
||||
{
|
||||
auto uniform = program.getUniformTType(index);
|
||||
auto qualifier = uniform->getQualifier();
|
||||
if (!uniform->isArray())
|
||||
LOG(Warning, "Shader {0}:{1} - uniform: {2} {3} at binding {4}",
|
||||
_context->TargetNameAnsi,
|
||||
String(meta.Name),
|
||||
uniform->getCompleteString().c_str(),
|
||||
program.getUniformName(index),
|
||||
qualifier.layoutBinding
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Process all descriptors
|
||||
header.DescriptorInfo.ImageInfosCount = descriptorsCollector.Images;
|
||||
header.DescriptorInfo.BufferInfosCount = descriptorsCollector.Buffers;
|
||||
header.DescriptorInfo.TexelBufferViewsCount = descriptorsCollector.TexelBuffers;
|
||||
for (int32 i = 0; i < descriptorsCollector.DescriptorsCount; i++)
|
||||
// Process all descriptors
|
||||
header.DescriptorInfo.ImageInfosCount = descriptorsCollector.Images;
|
||||
header.DescriptorInfo.BufferInfosCount = descriptorsCollector.Buffers;
|
||||
header.DescriptorInfo.TexelBufferViewsCount = descriptorsCollector.TexelBuffers;
|
||||
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.Slot == MAX_uint16)
|
||||
if (descriptor.BindingType == SpirvShaderResourceBindingType::CB)
|
||||
{
|
||||
if (descriptor.Size == -1)
|
||||
{
|
||||
// Skip unused constant buffers
|
||||
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)
|
||||
}
|
||||
if (descriptor.Size == 0)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
continue;
|
||||
}
|
||||
if (descriptor.Size == 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
// Mark as used and cache some data
|
||||
cc.IsUsed = true;
|
||||
cc.Size = descriptor.Size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if PRINT_DESCRIPTORS
|
||||
String type;
|
||||
switch (descriptor.BindingType)
|
||||
{
|
||||
case SpirvShaderResourceBindingType::INVALID:
|
||||
type = TEXT("INVALID");
|
||||
break;
|
||||
case SpirvShaderResourceBindingType::CB:
|
||||
type = TEXT("CB");
|
||||
break;
|
||||
case SpirvShaderResourceBindingType::SAMPLER:
|
||||
type = TEXT("SAMPLER");
|
||||
break;
|
||||
case SpirvShaderResourceBindingType::SRV:
|
||||
type = TEXT("SRV");
|
||||
break;
|
||||
case SpirvShaderResourceBindingType::UAV:
|
||||
type = TEXT("UAV");
|
||||
break;
|
||||
default:
|
||||
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
|
||||
String type;
|
||||
switch (descriptor.BindingType)
|
||||
{
|
||||
case SpirvShaderResourceBindingType::INVALID:
|
||||
type = TEXT("INVALID");
|
||||
break;
|
||||
case SpirvShaderResourceBindingType::CB:
|
||||
type = TEXT("CB");
|
||||
break;
|
||||
case SpirvShaderResourceBindingType::SAMPLER:
|
||||
type = TEXT("SAMPLER");
|
||||
break;
|
||||
case SpirvShaderResourceBindingType::SRV:
|
||||
type = TEXT("SRV");
|
||||
break;
|
||||
case SpirvShaderResourceBindingType::UAV:
|
||||
type = TEXT("UAV");
|
||||
break;
|
||||
default:
|
||||
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
|
||||
}
|
||||
|
||||
// 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))
|
||||
return true;
|
||||
|
||||
if (customDataWrite && customDataWrite(_context, meta, permutationIndex, _macros))
|
||||
if (customDataWrite && customDataWrite(_context, meta, permutationIndex, _macros, additionalData))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,9 @@
|
||||
class ShaderCompilerVulkan : public ShaderCompiler
|
||||
{
|
||||
private:
|
||||
|
||||
Array<char> _funcNameDefineBuffer;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ShaderCompilerVulkan"/> class.
|
||||
/// </summary>
|
||||
@@ -29,7 +27,6 @@ public:
|
||||
~ShaderCompilerVulkan();
|
||||
|
||||
protected:
|
||||
|
||||
// [ShaderCompiler]
|
||||
bool CompileShader(ShaderFunctionMeta& meta, WritePermutationData customDataWrite = nullptr) override;
|
||||
bool OnCompileBegin() override;
|
||||
|
||||
Reference in New Issue
Block a user