Refactor Vertex Shader input vertex layout to use GPUVertexLayout defined on Vertex Buffer rather than Vertex Shader

#3044 #2667
This commit is contained in:
Wojtek Figat
2024-12-15 22:10:45 +01:00
parent 666efb7675
commit b3f37ca041
66 changed files with 786 additions and 579 deletions

View File

@@ -9,6 +9,7 @@
#include "GPUTextureDX11.h"
#include "GPUBufferDX11.h"
#include "GPUSamplerDX11.h"
#include "GPUVertexLayoutDX11.h"
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
#include "Engine/Core/Math/Viewport.h"
#include "Engine/Core/Math/Rectangle.h"
@@ -82,9 +83,11 @@ void GPUContextDX11::FrameBegin()
_omDirtyFlag = false;
_uaDirtyFlag = false;
_cbDirtyFlag = false;
_iaInputLayoutDirtyFlag = false;
_srMaskDirtyGraphics = 0;
_srMaskDirtyCompute = 0;
_rtCount = 0;
_vertexLayout = nullptr;
_currentState = nullptr;
_rtDepth = nullptr;
Platform::MemoryClear(_rtHandles, sizeof(_rtHandles));
@@ -380,7 +383,7 @@ void GPUContextDX11::BindUA(int32 slot, GPUResourceView* view)
}
}
void GPUContextDX11::BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets)
void GPUContextDX11::BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets, GPUVertexLayout* vertexLayout)
{
ASSERT(vertexBuffers.Length() >= 0 && vertexBuffers.Length() <= GPU_MAX_VB_BINDED);
@@ -402,6 +405,13 @@ void GPUContextDX11::BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32*
{
_context->IASetVertexBuffers(0, vertexBuffers.Length(), _vbHandles, _vbStrides, _vbOffsets);
}
if (!vertexLayout)
vertexLayout = GPUVertexLayout::Get(vertexBuffers);
if (_vertexLayout != vertexLayout)
{
_vertexLayout = (GPUVertexLayoutDX11*)vertexLayout;
_iaInputLayoutDirtyFlag = true;
}
}
void GPUContextDX11::BindIB(GPUBuffer* indexBuffer)
@@ -610,7 +620,7 @@ void GPUContextDX11::SetState(GPUPipelineState* state)
#endif
CurrentVS = vs;
_context->VSSetShader(vs ? vs->GetBufferHandleDX11() : nullptr, nullptr, 0);
_context->IASetInputLayout(vs ? vs->GetInputLayoutDX11() : nullptr);
_iaInputLayoutDirtyFlag = true;
}
#if GPU_ALLOW_TESSELLATION_SHADERS
if (CurrentHS != hs)
@@ -720,6 +730,7 @@ void GPUContextDX11::FlushState()
flushCBs();
flushSRVs();
flushUAVs();
flushIA();
flushOM();
}
@@ -932,11 +943,28 @@ void GPUContextDX11::flushOM()
}
}
void GPUContextDX11::flushIA()
{
if (_iaInputLayoutDirtyFlag)
{
_iaInputLayoutDirtyFlag = false;
ID3D11InputLayout* inputLayout = CurrentVS ? CurrentVS->GetInputLayout(_vertexLayout) : nullptr;
#if GPU_ENABLE_ASSERTION_LOW_LAYERS
if (!inputLayout && CurrentVS && !_vertexLayout && _vbHandles[0])
{
LOG(Error, "Missing Vertex Layout (not assigned to GPUBuffer). Vertex Shader won't read valid data resulting incorrect visuals.");
}
#endif
_context->IASetInputLayout(inputLayout);
}
}
void GPUContextDX11::onDrawCall()
{
flushCBs();
flushSRVs();
flushUAVs();
flushIA();
flushOM();
}

View File

@@ -10,6 +10,7 @@
#if GRAPHICS_API_DIRECTX11
class GPUBufferDX11;
class GPUVertexLayoutDX11;
/// <summary>
/// GPU Context for DirectX 11 backend.
@@ -49,6 +50,8 @@ private:
ID3D11Buffer* _vbHandles[GPU_MAX_VB_BINDED];
UINT _vbStrides[GPU_MAX_VB_BINDED];
UINT _vbOffsets[GPU_MAX_VB_BINDED];
GPUVertexLayoutDX11* _vertexLayout;
bool _iaInputLayoutDirtyFlag;
// Pipeline State
GPUPipelineStateDX11* _currentState;
@@ -100,6 +103,7 @@ private:
void flushUAVs();
void flushCBs();
void flushOM();
void flushIA();
void onDrawCall();
public:
@@ -130,7 +134,7 @@ public:
void BindCB(int32 slot, GPUConstantBuffer* cb) override;
void BindSR(int32 slot, GPUResourceView* view) override;
void BindUA(int32 slot, GPUResourceView* view) override;
void BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override;
void BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr, GPUVertexLayout* vertexLayout = nullptr) override;
void BindIB(GPUBuffer* indexBuffer) override;
void BindSampler(int32 slot, GPUSampler* sampler) override;
void UpdateCB(GPUConstantBuffer* cb, const void* data) override;

View File

@@ -4,10 +4,33 @@
#include "GPUShaderDX11.h"
#include "GPUShaderProgramDX11.h"
#include "GPUVertexLayoutDX11.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "../RenderToolsDX.h"
GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream)
GPUShaderProgramVSDX11::~GPUShaderProgramVSDX11()
{
for (const auto& e : _cache)
e.Value->Release();
}
ID3D11InputLayout* GPUShaderProgramVSDX11::GetInputLayout(GPUVertexLayoutDX11* vertexLayout)
{
if (!vertexLayout)
vertexLayout = (GPUVertexLayoutDX11*)Layout;
ID3D11InputLayout* inputLayout = nullptr;
if (!_cache.TryGet(vertexLayout, inputLayout))
{
if (vertexLayout && vertexLayout->InputElementsCount)
{
VALIDATE_DIRECTX_CALL(vertexLayout->GetDevice()->GetDevice()->CreateInputLayout(vertexLayout->InputElements, vertexLayout->InputElementsCount, Bytecode.Get(), Bytecode.Length(), &inputLayout));
}
_cache.Add(vertexLayout, inputLayout);
}
return inputLayout;
}
GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span<byte> bytecode, MemoryReadStream& stream)
{
GPUShaderProgram* shader = nullptr;
HRESULT result;
@@ -16,80 +39,15 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
case ShaderStage::Vertex:
{
// Load Input Layout
byte inputLayoutSize;
stream.ReadByte(&inputLayoutSize);
ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS);
D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
for (int32 a = 0; a < inputLayoutSize; a++)
{
// Read description
GPUShaderProgramVS::InputElement inputElement;
stream.Read(inputElement);
// Get semantic name
const char* semanticName = nullptr;
// TODO: maybe use enum+mapping ?
switch (inputElement.Type)
{
case 1:
semanticName = "POSITION";
break;
case 2:
semanticName = "COLOR";
break;
case 3:
semanticName = "TEXCOORD";
break;
case 4:
semanticName = "NORMAL";
break;
case 5:
semanticName = "TANGENT";
break;
case 6:
semanticName = "BITANGENT";
break;
case 7:
semanticName = "ATTRIBUTE";
break;
case 8:
semanticName = "BLENDINDICES";
break;
case 9:
semanticName = "BLENDWEIGHT";
break;
default:
LOG(Fatal, "Invalid vertex shader element semantic type: {0}", inputElement.Type);
break;
}
// Set data
inputLayoutDesc[a] =
{
semanticName,
static_cast<UINT>(inputElement.Index),
static_cast<DXGI_FORMAT>(inputElement.Format),
static_cast<UINT>(inputElement.InputSlot),
static_cast<UINT>(inputElement.AlignedByteOffset),
static_cast<D3D11_INPUT_CLASSIFICATION>(inputElement.InputSlotClass),
static_cast<UINT>(inputElement.InstanceDataStepRate)
};
}
ID3D11InputLayout* inputLayout = nullptr;
if (inputLayoutSize > 0)
{
// Create input layout
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateInputLayout(inputLayoutDesc, inputLayoutSize, cacheBytes, cacheSize, &inputLayout));
}
GPUVertexLayout* vertexLayout = ReadVertexLayout(stream);
// Create shader
ID3D11VertexShader* buffer = nullptr;
result = _device->GetDevice()->CreateVertexShader(cacheBytes, cacheSize, nullptr, &buffer);
result = _device->GetDevice()->CreateVertexShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
shader = New<GPUShaderProgramVSDX11>(initializer, buffer, inputLayout, inputLayoutSize);
shader = New<GPUShaderProgramVSDX11>(initializer, buffer, vertexLayout, bytecode);
break;
}
#if GPU_ALLOW_TESSELLATION_SHADERS
@@ -101,7 +59,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
// Create shader
ID3D11HullShader* buffer = nullptr;
result = _device->GetDevice()->CreateHullShader(cacheBytes, cacheSize, nullptr, &buffer);
result = _device->GetDevice()->CreateHullShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
@@ -112,7 +70,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
{
// Create shader
ID3D11DomainShader* buffer = nullptr;
result = _device->GetDevice()->CreateDomainShader(cacheBytes, cacheSize, nullptr, &buffer);
result = _device->GetDevice()->CreateDomainShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
@@ -132,7 +90,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
{
// Create shader
ID3D11GeometryShader* buffer = nullptr;
result = _device->GetDevice()->CreateGeometryShader(cacheBytes, cacheSize, nullptr, &buffer);
result = _device->GetDevice()->CreateGeometryShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
@@ -144,7 +102,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
{
// Create shader
ID3D11PixelShader* buffer = nullptr;
result = _device->GetDevice()->CreatePixelShader(cacheBytes, cacheSize, nullptr, &buffer);
result = _device->GetDevice()->CreatePixelShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object
@@ -155,7 +113,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
{
// Create shader
ID3D11ComputeShader* buffer = nullptr;
result = _device->GetDevice()->CreateComputeShader(cacheBytes, cacheSize, nullptr, &buffer);
result = _device->GetDevice()->CreateComputeShader(bytecode.Get(), bytecode.Length(), nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object

View File

@@ -80,7 +80,7 @@ public:
protected:
// [GPUShader]
GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) override;
GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span<byte> bytecode, MemoryReadStream& stream) override;
void OnReleaseGPU() override;
public:

View File

@@ -3,6 +3,7 @@
#pragma once
#include "Engine/Graphics/Shaders/GPUShaderProgram.h"
#include "Engine/Core/Types/DataContainer.h"
#include "../IncludeDirectXHeaders.h"
#if GRAPHICS_API_DIRECTX11
@@ -17,11 +18,6 @@ protected:
BufferType* _buffer;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
GPUShaderProgramDX11(const GPUShaderProgramInitializer& initializer, BufferType* buffer)
: _buffer(buffer)
{
@@ -31,18 +27,11 @@ public:
#endif
}
/// <summary>
/// Finalizes an instance of the <see cref="GPUShaderProgramDX11"/> class.
/// </summary>
~GPUShaderProgramDX11()
{
DX_SAFE_RELEASE_CHECK(_buffer, 0);
}
public:
/// <summary>
/// Gets DirectX 11 buffer handle.
/// </summary>
FORCE_INLINE BufferType* GetBufferHandleDX11() const
{
return _buffer;
@@ -66,51 +55,21 @@ public:
class GPUShaderProgramVSDX11 : public GPUShaderProgramDX11<GPUShaderProgramVS, ID3D11VertexShader>
{
private:
byte _inputLayoutSize;
ID3D11InputLayout* _inputLayout;
Dictionary<class GPUVertexLayoutDX11*, ID3D11InputLayout*> _cache;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramVSDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
/// <param name="inputLayout">The input layout.</param>
/// <param name="inputLayoutSize">Size of the input layout.</param>
GPUShaderProgramVSDX11(const GPUShaderProgramInitializer& initializer, ID3D11VertexShader* buffer, ID3D11InputLayout* inputLayout, byte inputLayoutSize)
GPUShaderProgramVSDX11(const GPUShaderProgramInitializer& initializer, ID3D11VertexShader* buffer, GPUVertexLayout* vertexLayout, Span<byte> bytecode)
: GPUShaderProgramDX11(initializer, buffer)
, _inputLayoutSize(inputLayoutSize)
, _inputLayout(inputLayout)
{
Layout = vertexLayout;
Bytecode.Copy(bytecode);
}
/// <summary>
/// Finalizes an instance of the <see cref="GPUShaderProgramVSDX11"/> class.
/// </summary>
~GPUShaderProgramVSDX11()
{
DX_SAFE_RELEASE_CHECK(_inputLayout, 0);
}
~GPUShaderProgramVSDX11();
public:
/// <summary>
/// Gets the DirectX 11 input layout handle
/// </summary>
FORCE_INLINE ID3D11InputLayout* GetInputLayoutDX11() const
{
return _inputLayout;
}
BytesContainer Bytecode;
public:
// [GPUShaderProgramDX11]
void* GetInputLayout() const override
{
return (void*)_inputLayout;
}
byte GetInputLayoutSize() const override
{
return _inputLayoutSize;
}
ID3D11InputLayout* GetInputLayout(class GPUVertexLayoutDX11* vertexLayout);
};
#if GPU_ALLOW_TESSELLATION_SHADERS
@@ -120,12 +79,6 @@ public:
class GPUShaderProgramHSDX11 : public GPUShaderProgramDX11<GPUShaderProgramHS, ID3D11HullShader>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramHSDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
/// <param name="controlPointsCount">The control points used by the hull shader for processing.</param>
GPUShaderProgramHSDX11(const GPUShaderProgramInitializer& initializer, ID3D11HullShader* buffer, int32 controlPointsCount)
: GPUShaderProgramDX11(initializer, buffer)
{
@@ -139,11 +92,6 @@ public:
class GPUShaderProgramDSDX11 : public GPUShaderProgramDX11<GPUShaderProgramDS, ID3D11DomainShader>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramDSDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
GPUShaderProgramDSDX11(const GPUShaderProgramInitializer& initializer, ID3D11DomainShader* buffer)
: GPUShaderProgramDX11(initializer, buffer)
{
@@ -158,11 +106,6 @@ public:
class GPUShaderProgramGSDX11 : public GPUShaderProgramDX11<GPUShaderProgramGS, ID3D11GeometryShader>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramGSDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
GPUShaderProgramGSDX11(const GPUShaderProgramInitializer& initializer, ID3D11GeometryShader* buffer)
: GPUShaderProgramDX11(initializer, buffer)
{
@@ -176,11 +119,6 @@ public:
class GPUShaderProgramPSDX11 : public GPUShaderProgramDX11<GPUShaderProgramPS, ID3D11PixelShader>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramPSDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
GPUShaderProgramPSDX11(const GPUShaderProgramInitializer& initializer, ID3D11PixelShader* buffer)
: GPUShaderProgramDX11(initializer, buffer)
{
@@ -193,11 +131,6 @@ public:
class GPUShaderProgramCSDX11 : public GPUShaderProgramDX11<GPUShaderProgramCS, ID3D11ComputeShader>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramCSDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
GPUShaderProgramCSDX11(const GPUShaderProgramInitializer& initializer, ID3D11ComputeShader* buffer)
: GPUShaderProgramDX11(initializer, buffer)
{

View File

@@ -26,6 +26,7 @@
#include "GPUTextureDX12.h"
#include "GPUBufferDX12.h"
#include "GPUSamplerDX12.h"
#include "GPUVertexLayoutDX12.h"
#include "CommandQueueDX12.h"
#include "DescriptorHeapDX12.h"
#include "Engine/Graphics/RenderTask.h"
@@ -244,6 +245,7 @@ void GPUContextDX12::Reset()
Platform::MemoryClear(_srHandles, sizeof(_srHandles));
Platform::MemoryClear(_uaHandles, sizeof(_uaHandles));
Platform::MemoryClear(_vbHandles, sizeof(_vbHandles));
_vertexLayout = nullptr;
_ibHandle = nullptr;
Platform::MemoryClear(&_cbHandles, sizeof(_cbHandles));
Platform::MemoryClear(&_samplers, sizeof(_samplers));
@@ -560,7 +562,13 @@ void GPUContextDX12::flushPS()
// Change state
ASSERT(_currentState->IsValid());
_commandList->SetPipelineState(_currentState->GetState(_rtDepth, _rtCount, _rtHandles));
#if GPU_ENABLE_ASSERTION_LOW_LAYERS
if (!_vertexLayout && _vbHandles[0] && !_currentState->VertexLayout)
{
LOG(Error, "Missing Vertex Layout (not assigned to GPUBuffer). Vertex Shader won't read valid data resulting incorrect visuals.");
}
#endif
_commandList->SetPipelineState(_currentState->GetState(_rtDepth, _rtCount, _rtHandles, _vertexLayout));
if (_primitiveTopology != _currentState->PrimitiveTopology)
{
_primitiveTopology = _currentState->PrimitiveTopology;
@@ -946,7 +954,7 @@ void GPUContextDX12::BindUA(int32 slot, GPUResourceView* view)
*view->LastRenderTime = _lastRenderTime;
}
void GPUContextDX12::BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets)
void GPUContextDX12::BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets, GPUVertexLayout* vertexLayout)
{
ASSERT(vertexBuffers.Length() >= 0 && vertexBuffers.Length() <= GPU_MAX_VB_BINDED);
@@ -982,6 +990,7 @@ void GPUContextDX12::BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32*
#endif
_commandList->IASetVertexBuffers(0, vertexBuffers.Length(), views);
}
_vertexLayout = (GPUVertexLayoutDX12*)(vertexLayout ? vertexLayout : GPUVertexLayout::Get(vertexBuffers));
}
void GPUContextDX12::BindIB(GPUBuffer* indexBuffer)

View File

@@ -15,6 +15,7 @@ class GPUBufferDX12;
class GPUSamplerDX12;
class GPUConstantBufferDX12;
class GPUTextureViewDX12;
class GPUVertexLayoutDX12;
/// <summary>
/// Size of the resource barriers buffer size (will be flushed on overflow)
@@ -61,6 +62,7 @@ private:
GPUTextureViewDX12* _rtHandles[GPU_MAX_RT_BINDED];
IShaderResourceDX12* _srHandles[GPU_MAX_SR_BINDED];
IShaderResourceDX12* _uaHandles[GPU_MAX_UA_BINDED];
GPUVertexLayoutDX12* _vertexLayout;
GPUBufferDX12* _ibHandle;
GPUBufferDX12* _vbHandles[GPU_MAX_VB_BINDED];
D3D12_INDEX_BUFFER_VIEW _ibView;
@@ -176,7 +178,7 @@ public:
void BindCB(int32 slot, GPUConstantBuffer* cb) override;
void BindSR(int32 slot, GPUResourceView* view) override;
void BindUA(int32 slot, GPUResourceView* view) override;
void BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override;
void BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr, GPUVertexLayout* vertexLayout = nullptr) override;
void BindIB(GPUBuffer* indexBuffer) override;
void BindSampler(int32 slot, GPUSampler* sampler) override;
void UpdateCB(GPUConstantBuffer* cb, const void* data) override;

View File

@@ -4,6 +4,7 @@
#include "GPUPipelineStateDX12.h"
#include "GPUShaderProgramDX12.h"
#include "GPUVertexLayoutDX12.h"
#include "GPUTextureDX12.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
@@ -45,14 +46,16 @@ bool GPUPipelineStateDX12::IsValid() const
return !!_memoryUsage;
}
ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, int32 rtCount, GPUTextureViewDX12** rtHandles)
ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, int32 rtCount, GPUTextureViewDX12** rtHandles, GPUVertexLayoutDX12* vertexLayout)
{
// Validate
ASSERT(depth || rtCount);
if (!vertexLayout)
vertexLayout = VertexLayout;
// Prepare key
GPUPipelineStateKeyDX12 key;
key.RTsCount = rtCount;
key.VertexLayout = vertexLayout;
key.DepthFormat = depth ? depth->GetFormat() : PixelFormat::Unknown;
key.MSAA = depth ? depth->GetMSAA() : (rtCount ? rtHandles[0]->GetMSAA() : MSAALevel::None);
for (int32 i = 0; i < rtCount; i++)
@@ -72,7 +75,6 @@ ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, i
#endif
return state;
}
PROFILE_CPU_NAMED("Create Pipeline State");
// Update description to match the pipeline
@@ -83,6 +85,8 @@ ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, i
_desc.SampleDesc.Quality = key.MSAA == MSAALevel::None ? 0 : GPUDeviceDX12::GetMaxMSAAQuality((int32)key.MSAA);
_desc.SampleMask = D3D12_DEFAULT_SAMPLE_MASK;
_desc.DSVFormat = RenderToolsDX::ToDxgiFormat(PixelFormatExtensions::FindDepthStencilFormat(key.DepthFormat));
_desc.InputLayout.pInputElementDescs = vertexLayout ? vertexLayout->InputElements : nullptr;
_desc.InputLayout.NumElements = vertexLayout ? vertexLayout->InputElementsCount : 0;
// Create object
const HRESULT result = _device->GetDevice()->CreateGraphicsPipelineState(&_desc, IID_PPV_ARGS(&state));
@@ -96,6 +100,7 @@ ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, i
name.Add(*DebugDesc.VS->GetName(), DebugDesc.VS->GetName().Length());
name.Add('+');
}
#if GPU_ALLOW_TESSELLATION_SHADERS
if (DebugDesc.HS)
{
name.Add(*DebugDesc.HS->GetName(), DebugDesc.HS->GetName().Length());
@@ -106,11 +111,14 @@ ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, i
name.Add(*DebugDesc.DS->GetName(), DebugDesc.DS->GetName().Length());
name.Add('+');
}
#endif
#if GPU_ALLOW_GEOMETRY_SHADERS
if (DebugDesc.GS)
{
name.Add(*DebugDesc.GS->GetName(), DebugDesc.GS->GetName().Length());
name.Add('+');
}
#endif
if (DebugDesc.PS)
{
name.Add(*DebugDesc.PS->GetName(), DebugDesc.PS->GetName().Length());
@@ -148,7 +156,6 @@ bool GPUPipelineStateDX12::Init(const Description& desc)
// Shaders
Platform::MemoryClear(&Header, sizeof(Header));
psDesc.InputLayout = { static_cast<D3D12_INPUT_ELEMENT_DESC*>(desc.VS->GetInputLayout()), desc.VS->GetInputLayoutSize() };
#define INIT_SHADER_STAGE(stage, type) \
if (desc.stage) \
{ \
@@ -172,14 +179,17 @@ bool GPUPipelineStateDX12::Init(const Description& desc)
#endif
INIT_SHADER_STAGE(VS, GPUShaderProgramVSDX12);
INIT_SHADER_STAGE(PS, GPUShaderProgramPSDX12);
const static D3D12_PRIMITIVE_TOPOLOGY_TYPE primTypes1[] =
// Input Assembly
VertexLayout = desc.VS ? (GPUVertexLayoutDX12*)desc.VS->Layout : nullptr;
const D3D12_PRIMITIVE_TOPOLOGY_TYPE primTypes1[] =
{
D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED,
D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT,
D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
};
const static D3D_PRIMITIVE_TOPOLOGY primTypes2[] =
const D3D_PRIMITIVE_TOPOLOGY primTypes2[] =
{
D3D_PRIMITIVE_TOPOLOGY_UNDEFINED,
D3D_PRIMITIVE_TOPOLOGY_POINTLIST,

View File

@@ -11,11 +11,13 @@
#include "../IncludeDirectXHeaders.h"
class GPUTextureViewDX12;
class GPUVertexLayoutDX12;
struct GPUPipelineStateKeyDX12
{
int32 RTsCount;
MSAALevel MSAA;
GPUVertexLayout* VertexLayout;
PixelFormat DepthFormat;
PixelFormat RTVsFormats[GPU_MAX_RT_BINDED];
@@ -29,6 +31,7 @@ struct GPUPipelineStateKeyDX12
uint32 hash = (int32)key.MSAA * 11;
CombineHash(hash, (uint32)key.DepthFormat * 93473262);
CombineHash(hash, key.RTsCount * 136);
CombineHash(hash, GetHash(key.VertexLayout));
CombineHash(hash, (uint32)key.RTVsFormats[0]);
CombineHash(hash, (uint32)key.RTVsFormats[1]);
CombineHash(hash, (uint32)key.RTVsFormats[2]);
@@ -46,18 +49,16 @@ struct GPUPipelineStateKeyDX12
class GPUPipelineStateDX12 : public GPUResourceDX12<GPUPipelineState>
{
private:
Dictionary<GPUPipelineStateKeyDX12, ID3D12PipelineState*> _states;
D3D12_GRAPHICS_PIPELINE_STATE_DESC _desc;
public:
GPUPipelineStateDX12(GPUDeviceDX12* device);
public:
D3D_PRIMITIVE_TOPOLOGY PrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
DxShaderHeader Header;
GPUVertexLayoutDX12* VertexLayout;
/// <summary>
/// Gets DirectX 12 graphics pipeline state object for the given rendering state. Uses depth buffer and render targets formats and multi-sample levels to setup a proper PSO. Uses caching.
@@ -65,17 +66,16 @@ public:
/// <param name="depth">The depth buffer (can be null).</param>
/// <param name="rtCount">The render targets count (can be 0).</param>
/// <param name="rtHandles">The render target handles array.</param>
/// <param name="vertexLayout">The vertex buffers layout.</param>
/// <returns>DirectX 12 graphics pipeline state object</returns>
ID3D12PipelineState* GetState(GPUTextureViewDX12* depth, int32 rtCount, GPUTextureViewDX12** rtHandles);
ID3D12PipelineState* GetState(GPUTextureViewDX12* depth, int32 rtCount, GPUTextureViewDX12** rtHandles, GPUVertexLayoutDX12* vertexLayout);
public:
// [GPUPipelineState]
bool IsValid() const override;
bool Init(const Description& desc) override;
protected:
// [GPUResourceDX12]
void OnReleaseGPU() override;
};

View File

@@ -8,81 +8,19 @@
#include "Types.h"
#include "../RenderToolsDX.h"
GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream)
GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span<byte> bytecode, MemoryReadStream& stream)
{
// Extract the DX shader header from the cache
DxShaderHeader* header = (DxShaderHeader*)cacheBytes;
cacheBytes += sizeof(DxShaderHeader);
cacheSize -= sizeof(DxShaderHeader);
DxShaderHeader* header = (DxShaderHeader*)bytecode.Get();
bytecode = Span<byte>(bytecode.Get() + sizeof(DxShaderHeader), bytecode.Length() - sizeof(DxShaderHeader));
GPUShaderProgram* shader = nullptr;
switch (type)
{
case ShaderStage::Vertex:
{
// Load Input Layout (it may be empty)
byte inputLayoutSize;
stream.ReadByte(&inputLayoutSize);
ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS);
D3D12_INPUT_ELEMENT_DESC inputLayout[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
for (int32 a = 0; a < inputLayoutSize; a++)
{
// Read description
GPUShaderProgramVS::InputElement inputElement;
stream.Read(inputElement);
// Get semantic name
const char* semanticName = nullptr;
// TODO: maybe use enum+mapping ?
switch (inputElement.Type)
{
case 1:
semanticName = "POSITION";
break;
case 2:
semanticName = "COLOR";
break;
case 3:
semanticName = "TEXCOORD";
break;
case 4:
semanticName = "NORMAL";
break;
case 5:
semanticName = "TANGENT";
break;
case 6:
semanticName = "BITANGENT";
break;
case 7:
semanticName = "ATTRIBUTE";
break;
case 8:
semanticName = "BLENDINDICES";
break;
case 9:
semanticName = "BLENDWEIGHT";
break;
default:
LOG(Fatal, "Invalid vertex shader element semantic type: {0}", inputElement.Type);
break;
}
// Set data
inputLayout[a] =
{
semanticName,
static_cast<UINT>(inputElement.Index),
static_cast<DXGI_FORMAT>(inputElement.Format),
static_cast<UINT>(inputElement.InputSlot),
static_cast<UINT>(inputElement.AlignedByteOffset),
static_cast<D3D12_INPUT_CLASSIFICATION>(inputElement.InputSlotClass),
static_cast<UINT>(inputElement.InstanceDataStepRate)
};
}
// Create object
shader = New<GPUShaderProgramVSDX12>(initializer, header, cacheBytes, cacheSize, inputLayout, inputLayoutSize);
GPUVertexLayout* vertexLayout = ReadVertexLayout(stream);
shader = New<GPUShaderProgramVSDX12>(initializer, header, bytecode, vertexLayout);
break;
}
#if GPU_ALLOW_TESSELLATION_SHADERS
@@ -90,12 +28,12 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const
{
int32 controlPointsCount;
stream.ReadInt32(&controlPointsCount);
shader = New<GPUShaderProgramHSDX12>(initializer, header, cacheBytes, cacheSize, controlPointsCount);
shader = New<GPUShaderProgramHSDX12>(initializer, header, bytecode, controlPointsCount);
break;
}
case ShaderStage::Domain:
{
shader = New<GPUShaderProgramDSDX12>(initializer, header, cacheBytes, cacheSize);
shader = New<GPUShaderProgramDSDX12>(initializer, header, bytecode);
break;
}
#else
@@ -109,18 +47,18 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const
#if GPU_ALLOW_GEOMETRY_SHADERS
case ShaderStage::Geometry:
{
shader = New<GPUShaderProgramGSDX12>(initializer, header, cacheBytes, cacheSize);
shader = New<GPUShaderProgramGSDX12>(initializer, header, bytecode);
break;
}
#endif
case ShaderStage::Pixel:
{
shader = New<GPUShaderProgramPSDX12>(initializer, header, cacheBytes, cacheSize);
shader = New<GPUShaderProgramPSDX12>(initializer, header, bytecode);
break;
}
case ShaderStage::Compute:
{
shader = New<GPUShaderProgramCSDX12>(_device, initializer, header, cacheBytes, cacheSize);
shader = New<GPUShaderProgramCSDX12>(_device, initializer, header, bytecode);
break;
}
}

View File

@@ -46,7 +46,7 @@ public:
protected:
// [GPUShader]
GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) override;
GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span<byte> bytecode, MemoryReadStream& stream) override;
};
#endif

View File

@@ -5,6 +5,7 @@
#if GRAPHICS_API_DIRECTX12
#include "GPUDeviceDX12.h"
#include "Engine/Core/Types/DataContainer.h"
#include "Engine/Graphics/Shaders/GPUShaderProgram.h"
#include "Types.h"
#include "../IncludeDirectXHeaders.h"
@@ -15,30 +16,27 @@
template<typename BaseType>
class GPUShaderProgramDX12 : public BaseType
{
protected:
Array<byte> _data;
public:
GPUShaderProgramDX12(const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize)
GPUShaderProgramDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span<byte> bytecode)
: Header(*header)
{
BaseType::Init(initializer);
_data.Set(cacheBytes, cacheSize);
Bytecode.Copy(bytecode);
}
public:
BytesContainer Bytecode;
DxShaderHeader Header;
public:
// [BaseType]
void* GetBufferHandle() const override
{
return (void*)_data.Get();
return (void*)Bytecode.Get();
}
uint32 GetBufferSize() const override
{
return _data.Count();
return Bytecode.Length();
}
};
@@ -47,29 +45,11 @@ public:
/// </summary>
class GPUShaderProgramVSDX12 : public GPUShaderProgramDX12<GPUShaderProgramVS>
{
private:
byte _inputLayoutSize;
D3D12_INPUT_ELEMENT_DESC _inputLayout[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
public:
GPUShaderProgramVSDX12(const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize, D3D12_INPUT_ELEMENT_DESC* inputLayout, byte inputLayoutSize)
: GPUShaderProgramDX12(initializer, header, cacheBytes, cacheSize)
, _inputLayoutSize(inputLayoutSize)
GPUShaderProgramVSDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span<byte> bytecode, GPUVertexLayout* vertexLayout)
: GPUShaderProgramDX12(initializer, header, bytecode)
{
for (byte i = 0; i < inputLayoutSize; i++)
_inputLayout[i] = inputLayout[i];
}
public:
// [GPUShaderProgramDX12]
void* GetInputLayout() const override
{
return (void*)_inputLayout;
}
byte GetInputLayoutSize() const override
{
return _inputLayoutSize;
Layout = vertexLayout;
}
};
@@ -80,8 +60,8 @@ public:
class GPUShaderProgramHSDX12 : public GPUShaderProgramDX12<GPUShaderProgramHS>
{
public:
GPUShaderProgramHSDX12(const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize, int32 controlPointsCount)
: GPUShaderProgramDX12(initializer, header, cacheBytes, cacheSize)
GPUShaderProgramHSDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span<byte> bytecode, int32 controlPointsCount)
: GPUShaderProgramDX12(initializer, header, bytecode)
{
_controlPointsCount = controlPointsCount;
}
@@ -93,8 +73,8 @@ public:
class GPUShaderProgramDSDX12 : public GPUShaderProgramDX12<GPUShaderProgramDS>
{
public:
GPUShaderProgramDSDX12(const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize)
: GPUShaderProgramDX12(initializer, header, cacheBytes, cacheSize)
GPUShaderProgramDSDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span<byte> bytecode)
: GPUShaderProgramDX12(initializer, header, bytecode)
{
}
};
@@ -107,8 +87,8 @@ public:
class GPUShaderProgramGSDX12 : public GPUShaderProgramDX12<GPUShaderProgramGS>
{
public:
GPUShaderProgramGSDX12(const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize)
: GPUShaderProgramDX12(initializer, header, cacheBytes, cacheSize)
GPUShaderProgramGSDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span<byte> bytecode)
: GPUShaderProgramDX12(initializer, header, bytecode)
{
}
};
@@ -120,8 +100,8 @@ public:
class GPUShaderProgramPSDX12 : public GPUShaderProgramDX12<GPUShaderProgramPS>
{
public:
GPUShaderProgramPSDX12(const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize)
: GPUShaderProgramDX12(initializer, header, cacheBytes, cacheSize)
GPUShaderProgramPSDX12(const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span<byte> bytecode)
: GPUShaderProgramDX12(initializer, header, bytecode)
{
}
};
@@ -137,8 +117,8 @@ private:
ID3D12PipelineState* _state;
public:
GPUShaderProgramCSDX12(GPUDeviceDX12* device, const GPUShaderProgramInitializer& initializer, DxShaderHeader* header, byte* cacheBytes, uint32 cacheSize)
: GPUShaderProgramDX12(initializer, header, cacheBytes, cacheSize)
GPUShaderProgramCSDX12(GPUDeviceDX12* device, const GPUShaderProgramInitializer& initializer, const DxShaderHeader* header, Span<byte> bytecode)
: GPUShaderProgramDX12(initializer, header, bytecode)
, _device(device)
, _state(nullptr)
{

View File

@@ -17,8 +17,6 @@ struct DxShaderHeader
/// The UAV dimensions per-slot.
/// </summary>
byte UaDimensions[4];
// .. rest is just a actual data array
};
#endif

View File

@@ -116,7 +116,7 @@ public:
{
}
void BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override
void BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr, GPUVertexLayout* vertexLayout = nullptr) override
{
}

View File

@@ -14,7 +14,7 @@ class GPUShaderNull : public GPUShader
protected:
// [GPUShader]
GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) override
GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span<byte> bytecode, MemoryReadStream& stream) override
{
return nullptr;
}

View File

@@ -10,6 +10,7 @@
#include "GPUBufferVulkan.h"
#include "GPUShaderVulkan.h"
#include "GPUSamplerVulkan.h"
#include "GPUVertexLayoutVulkan.h"
#include "GPUPipelineStateVulkan.h"
#include "Engine/Profiler/RenderStats.h"
#include "GPUShaderProgramVulkan.h"
@@ -650,8 +651,14 @@ void GPUContextVulkan::OnDrawCall()
}
// Bind any missing vertex buffers to null if required by the current state
const auto vertexInputState = pipelineState->GetVertexInputState();
const int32 missingVBs = vertexInputState->vertexBindingDescriptionCount - _vbCount;
GPUVertexLayoutVulkan* vertexLayout = _vertexLayout ? _vertexLayout : pipelineState->VertexShaderLayout;
#if GPU_ENABLE_ASSERTION_LOW_LAYERS
if (!vertexLayout && pipelineState && !pipelineState->VertexShaderLayout && (pipelineState->UsedStagesMask & (1 << (int32)DescriptorSet::Vertex)) != 0 && !_vertexLayout && _vbCount)
{
LOG(Error, "Missing Vertex Layout (not assigned to GPUBuffer). Vertex Shader won't read valid data resulting incorrect visuals.");
}
#endif
const int32 missingVBs = vertexLayout ? (int32)vertexLayout->CreateInfo.vertexBindingDescriptionCount - _vbCount : 0;
if (missingVBs > 0)
{
VkBuffer buffers[GPU_MAX_VB_BINDED];
@@ -676,7 +683,7 @@ void GPUContextVulkan::OnDrawCall()
{
_psDirtyFlag = false;
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
const auto pipeline = pipelineState->GetState(_renderPass);
const auto pipeline = pipelineState->GetState(_renderPass, _vertexLayout);
vkCmdBindPipeline(cmdBuffer->GetHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
RENDER_STAT_PS_STATE_CHANGE();
}
@@ -715,6 +722,7 @@ void GPUContextVulkan::FrameBegin()
_stencilRef = 0;
_renderPass = nullptr;
_currentState = nullptr;
_vertexLayout = nullptr;
_rtDepth = nullptr;
Platform::MemoryClear(_rtHandles, sizeof(_rtHandles));
Platform::MemoryClear(_cbHandles, sizeof(_cbHandles));
@@ -1023,9 +1031,10 @@ void GPUContextVulkan::BindUA(int32 slot, GPUResourceView* view)
}
}
void GPUContextVulkan::BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets)
void GPUContextVulkan::BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets, GPUVertexLayout* vertexLayout)
{
_vbCount = vertexBuffers.Length();
_vertexLayout = (GPUVertexLayoutVulkan*)(vertexLayout ? vertexLayout : GPUVertexLayout::Get(vertexBuffers));
if (vertexBuffers.Length() == 0)
return;
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();

View File

@@ -14,6 +14,7 @@ class CmdBufferManagerVulkan;
class ResourceOwnerVulkan;
class GPUTextureViewVulkan;
class GPUBufferVulkan;
class GPUVertexLayoutVulkan;
class GPUPipelineStateVulkan;
class ComputePipelineStateVulkan;
class GPUConstantBufferVulkan;
@@ -82,6 +83,7 @@ private:
RenderPassVulkan* _renderPass;
GPUPipelineStateVulkan* _currentState;
GPUVertexLayoutVulkan* _vertexLayout;
GPUTextureViewVulkan* _rtDepth;
GPUTextureViewVulkan* _rtHandles[GPU_MAX_RT_BINDED];
DescriptorOwnerResourceVulkan* _cbHandles[GPU_MAX_CB_BINDED];
@@ -168,7 +170,7 @@ public:
void BindCB(int32 slot, GPUConstantBuffer* cb) override;
void BindSR(int32 slot, GPUResourceView* view) override;
void BindUA(int32 slot, GPUResourceView* view) override;
void BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override;
void BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr, GPUVertexLayout* vertexLayout = nullptr) override;
void BindIB(GPUBuffer* indexBuffer) override;
void BindSampler(int32 slot, GPUSampler* sampler) override;
void UpdateCB(GPUConstantBuffer* cb, const void* data) override;

View File

@@ -922,10 +922,10 @@ GPUTextureVulkan* HelperResourcesVulkan::GetDummyTexture(SpirvShaderResourceType
GPUBufferVulkan* HelperResourcesVulkan::GetDummyBuffer(PixelFormat format)
{
if (_dummyBuffers.IsEmpty())
if (!_dummyBuffers)
{
_dummyBuffers.Resize((int32)PixelFormat::MAX);
Platform::MemoryClear((void*)_dummyBuffers.Get(), (int32)PixelFormat::MAX * sizeof(void*));
_dummyBuffers = (GPUBufferVulkan**)Allocator::Allocate((int32)PixelFormat::MAX * sizeof(void*));
Platform::MemoryClear(_dummyBuffers, (int32)PixelFormat::MAX * sizeof(void*));
}
auto& dummyBuffer = _dummyBuffers[(int32)format];
if (!dummyBuffer)
@@ -941,7 +941,7 @@ GPUBufferVulkan* HelperResourcesVulkan::GetDummyVertexBuffer()
if (!_dummyVB)
{
_dummyVB = (GPUBufferVulkan*)_device->CreateBuffer(TEXT("DummyVertexBuffer"));
_dummyVB->Init(GPUBufferDescription::Vertex(sizeof(Color32), 1, &Color32::Transparent));
_dummyVB->Init(GPUBufferDescription::Vertex(nullptr, sizeof(Color32), 1, &Color32::Transparent));
}
return _dummyVB;
}
@@ -950,9 +950,16 @@ void HelperResourcesVulkan::Dispose()
{
SAFE_DELETE_GPU_RESOURCES(_dummyTextures);
SAFE_DELETE_GPU_RESOURCE(_dummyVB);
for (GPUBuffer* buffer : _dummyBuffers)
Delete(buffer);
_dummyBuffers.Clear();
if (_dummyBuffers)
{
for (int32 i = 0; i < (int32)PixelFormat::MAX; i++)
{
if (GPUBufferVulkan* buffer = _dummyBuffers[i])
Delete(buffer);
}
Allocator::Free(_dummyBuffers);
_dummyBuffers = nullptr;
}
for (int32 i = 0; i < ARRAY_COUNT(_staticSamplers); i++)
{

View File

@@ -308,7 +308,7 @@ class HelperResourcesVulkan
private:
GPUDeviceVulkan* _device;
GPUTextureVulkan* _dummyTextures[6];
Array<GPUBufferVulkan*> _dummyBuffers;
GPUBufferVulkan** _dummyBuffers = nullptr;
GPUBufferVulkan* _dummyVB;
VkSampler _staticSamplers[GPU_STATIC_SAMPLERS_COUNT];

View File

@@ -3,10 +3,12 @@
#if GRAPHICS_API_VULKAN
#include "GPUPipelineStateVulkan.h"
#include "GPUVertexLayoutVulkan.h"
#include "RenderToolsVulkan.h"
#include "DescriptorSetVulkan.h"
#include "GPUShaderProgramVulkan.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Types/Pair.h"
#include "Engine/Profiler/ProfilerCPU.h"
static VkStencilOp ToVulkanStencilOp(const StencilOperation value)
@@ -169,7 +171,6 @@ ComputePipelineStateVulkan::~ComputePipelineStateVulkan()
GPUPipelineStateVulkan::GPUPipelineStateVulkan(GPUDeviceVulkan* device)
: GPUResourceVulkan<GPUPipelineState>(device, StringView::Empty)
, _pipelines(16)
, _layout(nullptr)
{
}
@@ -201,25 +202,30 @@ PipelineLayoutVulkan* GPUPipelineStateVulkan::GetLayout()
return _layout;
}
VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass)
VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass, GPUVertexLayoutVulkan* vertexLayout)
{
ASSERT(renderPass);
if (!vertexLayout)
vertexLayout = VertexShaderLayout;
// Try reuse cached version
VkPipeline pipeline = VK_NULL_HANDLE;
if (_pipelines.TryGet(renderPass, pipeline))
const Pair<RenderPassVulkan*, GPUVertexLayoutVulkan*> key(renderPass, vertexLayout);
if (_pipelines.TryGet(key, pipeline))
{
#if BUILD_DEBUG
// Verify
RenderPassVulkan* refKey = nullptr;
Pair<RenderPassVulkan*, GPUVertexLayoutVulkan*> refKey(nullptr, nullptr);
_pipelines.KeyOf(pipeline, &refKey);
ASSERT(refKey == renderPass);
ASSERT(refKey == key);
#endif
return pipeline;
}
PROFILE_CPU_NAMED("Create Pipeline");
// Bind vertex input
_desc.pVertexInputState = vertexLayout ? &vertexLayout->CreateInfo : nullptr;
// Update description to match the pipeline
_descColorBlend.attachmentCount = renderPass->Layout.RTsCount;
_descMultisample.rasterizationSamples = (VkSampleCountFlagBits)renderPass->Layout.MSAA;
@@ -245,7 +251,7 @@ VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass)
}
// Cache it
_pipelines.Add(renderPass, pipeline);
_pipelines.Add(key, pipeline);
return pipeline;
}
@@ -278,12 +284,9 @@ bool GPUPipelineStateVulkan::Init(const Description& desc)
{
ASSERT(!IsValid());
// Create description
// Reset description
RenderToolsVulkan::ZeroStruct(_desc, VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO);
// Vertex Input
_desc.pVertexInputState = (VkPipelineVertexInputStateCreateInfo*)desc.VS->GetInputLayout();
// Stages
UsedStagesMask = 0;
HasDescriptorsPerStageMask = 0;
@@ -318,6 +321,7 @@ bool GPUPipelineStateVulkan::Init(const Description& desc)
_desc.pStages = _shaderStages;
// Input Assembly
VertexShaderLayout = desc.VS ? (GPUVertexLayoutVulkan*)desc.VS->Layout : nullptr;
RenderToolsVulkan::ZeroStruct(_descInputAssembly, VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO);;
switch (desc.PrimitiveTopology)
{

View File

@@ -9,6 +9,7 @@
#if GRAPHICS_API_VULKAN
class GPUVertexLayoutVulkan;
class PipelineLayoutVulkan;
class ComputePipelineStateVulkan
@@ -89,7 +90,7 @@ public:
class GPUPipelineStateVulkan : public GPUResourceVulkan<GPUPipelineState>
{
private:
Dictionary<RenderPassVulkan*, VkPipeline> _pipelines;
Dictionary<Pair<RenderPassVulkan*, GPUVertexLayoutVulkan*>, VkPipeline> _pipelines;
VkGraphicsPipelineCreateInfo _desc;
VkPipelineShaderStageCreateInfo _shaderStages[ShaderStage_Count - 1];
VkPipelineInputAssemblyStateCreateInfo _descInputAssembly;
@@ -140,18 +141,13 @@ public:
/// </summary>
const SpirvShaderDescriptorInfo* DescriptorInfoPerStage[DescriptorSet::GraphicsStagesCount];
const VkPipelineVertexInputStateCreateInfo* GetVertexInputState() const
{
return _desc.pVertexInputState;
}
DescriptorSetWriteContainerVulkan DSWriteContainer;
DescriptorSetWriterVulkan DSWriter[DescriptorSet::GraphicsStagesCount];
const DescriptorSetLayoutVulkan* DescriptorSetsLayout = nullptr;
TypedDescriptorPoolSetVulkan* CurrentTypedDescriptorPoolSet = nullptr;
GPUVertexLayoutVulkan* VertexShaderLayout = nullptr;
Array<VkDescriptorSet> DescriptorSetHandles;
Array<uint32> DynamicOffsets;
public:
@@ -184,8 +180,9 @@ public:
/// Gets the Vulkan graphics pipeline object for the given rendering state. Uses depth buffer and render targets formats and multi-sample levels to setup a proper PSO. Uses caching.
/// </summary>
/// <param name="renderPass">The render pass.</param>
/// <param name="vertexLayout">The vertex layout.</param>
/// <returns>Vulkan graphics pipeline object.</returns>
VkPipeline GetState(RenderPassVulkan* renderPass);
VkPipeline GetState(RenderPassVulkan* renderPass, GPUVertexLayoutVulkan* vertexLayout);
public:
// [GPUPipelineState]

View File

@@ -21,13 +21,6 @@ protected:
GPUDeviceVulkan* _device;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramVulkan"/> class.
/// </summary>
/// <param name="device">The graphics device.</param>
/// <param name="initializer">The program initialization data.</param>
/// <param name="descriptorInfo">The program descriptors usage info.</param>
/// <param name="shaderModule">The shader module object.</param>
GPUShaderProgramVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule)
: _device(device)
, ShaderModule(shaderModule)
@@ -36,9 +29,6 @@ public:
BaseType::Init(initializer);
}
/// <summary>
/// Finalizes an instance of the <see cref="GPUShaderProgramVulkan"/> class.
/// </summary>
~GPUShaderProgramVulkan()
{
if (ShaderModule)
@@ -64,7 +54,6 @@ public:
{
return 0;
}
void* GetBufferHandle() const override
{
return (void*)ShaderModule;
@@ -77,33 +66,10 @@ public:
class GPUShaderProgramVSVulkan : public GPUShaderProgramVulkan<GPUShaderProgramVS>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramVSVulkan"/> class.
/// </summary>
/// <param name="device">The graphics device.</param>
/// <param name="initializer">The program initialization data.</param>
/// <param name="descriptorInfo">The program descriptors usage info.</param>
/// <param name="shaderModule">The shader module object.</param>
GPUShaderProgramVSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule)
GPUShaderProgramVSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule, GPUVertexLayout* vertexLayout)
: GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule)
{
}
public:
VkPipelineVertexInputStateCreateInfo VertexInputState;
VkVertexInputBindingDescription VertexBindingDescriptions[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
VkVertexInputAttributeDescription VertexAttributeDescriptions[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
public:
// [GPUShaderProgramVulkan]
void* GetInputLayout() const override
{
return (void*)&VertexInputState;
}
byte GetInputLayoutSize() const override
{
return 0;
Layout = vertexLayout;
}
};
@@ -114,14 +80,6 @@ public:
class GPUShaderProgramHSVulkan : public GPUShaderProgramVulkan<GPUShaderProgramHS>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramHSVulkan"/> class.
/// </summary>
/// <param name="device">The graphics device.</param>
/// <param name="initializer">The program initialization data.</param>
/// <param name="descriptorInfo">The program descriptors usage info.</param>
/// <param name="shaderModule">The shader module object.</param>
/// <param name="controlPointsCount">The control points used by the hull shader for processing.</param>
GPUShaderProgramHSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule, int32 controlPointsCount)
: GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule)
{
@@ -135,13 +93,6 @@ public:
class GPUShaderProgramDSVulkan : public GPUShaderProgramVulkan<GPUShaderProgramDS>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramDSVulkan"/> class.
/// </summary>
/// <param name="device">The graphics device.</param>
/// <param name="initializer">The program initialization data.</param>
/// <param name="descriptorInfo">The program descriptors usage info.</param>
/// <param name="shaderModule">The shader module object.</param>
GPUShaderProgramDSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule)
: GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule)
{
@@ -156,13 +107,6 @@ public:
class GPUShaderProgramGSVulkan : public GPUShaderProgramVulkan<GPUShaderProgramGS>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramGSVulkan"/> class.
/// </summary>
/// <param name="device">The graphics device.</param>
/// <param name="initializer">The program initialization data.</param>
/// <param name="descriptorInfo">The program descriptors usage info.</param>
/// <param name="shaderModule">The shader module object.</param>
GPUShaderProgramGSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule)
: GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule)
{
@@ -176,13 +120,6 @@ public:
class GPUShaderProgramPSVulkan : public GPUShaderProgramVulkan<GPUShaderProgramPS>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramPSVulkan"/> class.
/// </summary>
/// <param name="device">The graphics device.</param>
/// <param name="initializer">The program initialization data.</param>
/// <param name="descriptorInfo">The program descriptors usage info.</param>
/// <param name="shaderModule">The shader module object.</param>
GPUShaderProgramPSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule)
: GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule)
{
@@ -198,29 +135,18 @@ private:
ComputePipelineStateVulkan* _pipelineState;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramCSVulkan"/> class.
/// </summary>
/// <param name="device">The graphics device.</param>
/// <param name="initializer">The program initialization data.</param>
/// <param name="descriptorInfo">The program descriptors usage info.</param>
/// <param name="shaderModule">The shader module object.</param>
GPUShaderProgramCSVulkan(GPUDeviceVulkan* device, const GPUShaderProgramInitializer& initializer, const SpirvShaderDescriptorInfo& descriptorInfo, VkShaderModule shaderModule)
: GPUShaderProgramVulkan(device, initializer, descriptorInfo, shaderModule)
, _pipelineState(nullptr)
{
}
/// <summary>
/// Finalizes an instance of the <see cref="GPUShaderProgramCSVulkan"/> class.
/// </summary>
~GPUShaderProgramCSVulkan();
public:
/// <summary>
/// Gets the state of the pipeline for the compute shader execution or creates a new one if missing.
/// </summary>
/// <returns>The compute pipeline state.</returns>
ComputePipelineStateVulkan* GetOrCreateState();
};

View File

@@ -98,17 +98,16 @@ void UniformBufferUploaderVulkan::OnReleaseGPU()
}
}
GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream)
GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span<byte> bytecode, MemoryReadStream& stream)
{
// Extract the SPIR-V shader header from the cache
SpirvShaderHeader* header = (SpirvShaderHeader*)cacheBytes;
cacheBytes += sizeof(SpirvShaderHeader);
cacheSize -= sizeof(SpirvShaderHeader);
SpirvShaderHeader* header = (SpirvShaderHeader*)bytecode.Get();
bytecode = Span<byte>(bytecode.Get() + sizeof(SpirvShaderHeader), bytecode.Length() - sizeof(SpirvShaderHeader));
// Extract the SPIR-V bytecode
BytesContainer spirv;
ASSERT(header->Type == SpirvShaderHeader::Types::Raw);
spirv.Link(cacheBytes, cacheSize);
spirv.Link(bytecode);
// Create shader module from SPIR-V bytecode
VkShaderModule shaderModule = VK_NULL_HANDLE;
@@ -139,59 +138,8 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons
{
case ShaderStage::Vertex:
{
// Create object
auto vsShader = New<GPUShaderProgramVSVulkan>(_device, initializer, header->DescriptorInfo, shaderModule);
shader = vsShader;
VkPipelineVertexInputStateCreateInfo& inputState = vsShader->VertexInputState;
VkVertexInputBindingDescription* vertexBindingDescriptions = vsShader->VertexBindingDescriptions;
VkVertexInputAttributeDescription* vertexAttributeDescriptions = vsShader->VertexAttributeDescriptions;
RenderToolsVulkan::ZeroStruct(inputState, VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO);
for (int32 i = 0; i < VERTEX_SHADER_MAX_INPUT_ELEMENTS; i++)
{
vertexBindingDescriptions[i].binding = i;
vertexBindingDescriptions[i].stride = 0;
vertexBindingDescriptions[i].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
}
// Load Input Layout (it may be empty)
byte inputLayoutSize;
stream.ReadByte(&inputLayoutSize);
ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS);
uint32 attributesCount = inputLayoutSize;
uint32 bindingsCount = 0;
int32 offset = 0;
for (int32 a = 0; a < inputLayoutSize; a++)
{
// Read description
GPUShaderProgramVS::InputElement inputElement;
stream.Read(inputElement);
const auto size = PixelFormatExtensions::SizeInBytes((PixelFormat)inputElement.Format);
if (inputElement.AlignedByteOffset != INPUT_LAYOUT_ELEMENT_ALIGN)
offset = inputElement.AlignedByteOffset;
auto& vertexBindingDescription = vertexBindingDescriptions[inputElement.InputSlot];
vertexBindingDescription.binding = inputElement.InputSlot;
vertexBindingDescription.stride = Math::Max(vertexBindingDescription.stride, (uint32_t)(offset + size));
vertexBindingDescription.inputRate = inputElement.InputSlotClass == INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
ASSERT(inputElement.InstanceDataStepRate == 0 || inputElement.InstanceDataStepRate == 1);
auto& vertexAttributeDescription = vertexAttributeDescriptions[a];
vertexAttributeDescription.location = a;
vertexAttributeDescription.binding = inputElement.InputSlot;
vertexAttributeDescription.format = RenderToolsVulkan::ToVulkanFormat((PixelFormat)inputElement.Format);
vertexAttributeDescription.offset = offset;
bindingsCount = Math::Max(bindingsCount, (uint32)inputElement.InputSlot + 1);
offset += size;
}
inputState.vertexBindingDescriptionCount = bindingsCount;
inputState.pVertexBindingDescriptions = vertexBindingDescriptions;
inputState.vertexAttributeDescriptionCount = attributesCount;
inputState.pVertexAttributeDescriptions = vertexAttributeDescriptions;
GPUVertexLayout* vertexLayout = ReadVertexLayout(stream);
shader = New<GPUShaderProgramVSVulkan>(_device, initializer, header->DescriptorInfo, shaderModule, vertexLayout);
break;
}
#if GPU_ALLOW_TESSELLATION_SHADERS

View File

@@ -130,7 +130,7 @@ public:
protected:
// [GPUShader]
GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) override;
GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span<byte> bytecode, MemoryReadStream& stream) override;
};
#endif