Add support for programmable samplers in shaders

This commit is contained in:
Wojtek Figat
2021-06-28 15:56:32 +02:00
parent 971449bef1
commit 3c1fd427eb
31 changed files with 866 additions and 121 deletions

View File

@@ -8,6 +8,7 @@
#include "GPUPipelineStateDX11.h"
#include "GPUTextureDX11.h"
#include "GPUBufferDX11.h"
#include "GPUSamplerDX11.h"
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
#include "Engine/Core/Math/Viewport.h"
#include "Engine/Core/Math/Rectangle.h"
@@ -384,6 +385,15 @@ void GPUContextDX11::BindIB(GPUBuffer* indexBuffer)
}
}
void GPUContextDX11::BindSampler(int32 slot, GPUSampler* sampler)
{
const auto samplerDX11 = sampler ? static_cast<GPUSamplerDX11*>(sampler)->SamplerState : nullptr;
_context->VSSetSamplers(slot, 1, &samplerDX11);
_context->DSSetSamplers(slot, 1, &samplerDX11);
_context->PSSetSamplers(slot, 1, &samplerDX11);
_context->CSSetSamplers(slot, 1, &samplerDX11);
}
void GPUContextDX11::UpdateCB(GPUConstantBuffer* cb, const void* data)
{
ASSERT(data && cb);

View File

@@ -122,6 +122,7 @@ public:
void BindUA(int32 slot, GPUResourceView* view) override;
void BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override;
void BindIB(GPUBuffer* indexBuffer) override;
void BindSampler(int32 slot, GPUSampler* sampler) override;
void UpdateCB(GPUConstantBuffer* cb, const void* data) override;
void Dispatch(GPUShaderProgramCS* shader, uint32 threadGroupCountX, uint32 threadGroupCountY, uint32 threadGroupCountZ) override;
void DispatchIndirect(GPUShaderProgramCS* shader, GPUBuffer* bufferForArgs, uint32 offsetForArgs) override;

View File

@@ -9,6 +9,7 @@
#include "GPUTextureDX11.h"
#include "GPUTimerQueryDX11.h"
#include "GPUBufferDX11.h"
#include "GPUSamplerDX11.h"
#include "GPUSwapChainDX11.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Utilities.h"
@@ -324,6 +325,7 @@ bool GPUDeviceDX11::Init()
limits.MaximumTexture2DArraySize = D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
limits.MaximumTexture3DSize = D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;
limits.MaximumTextureCubeSize = D3D11_REQ_TEXTURECUBE_DIMENSION;
limits.MaximumSamplerAnisotropy = D3D11_DEFAULT_MAX_ANISOTROPY;
}
else
{
@@ -346,6 +348,7 @@ bool GPUDeviceDX11::Init()
limits.MaximumTexture2DArraySize = D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
limits.MaximumTexture3DSize = D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;
limits.MaximumTextureCubeSize = D3D10_REQ_TEXTURECUBE_DIMENSION;
limits.MaximumSamplerAnisotropy = D3D10_DEFAULT_MAX_ANISOTROPY;
}
for (int32 i = 0; i < static_cast<int32>(PixelFormat::MAX); i++)
@@ -685,6 +688,11 @@ GPUBuffer* GPUDeviceDX11::CreateBuffer(const StringView& name)
return New<GPUBufferDX11>(this, name);
}
GPUSampler* GPUDeviceDX11::CreateSampler()
{
return New<GPUSamplerDX11>(this);
}
GPUSwapChain* GPUDeviceDX11::CreateSwapChain(Window* window)
{
return New<GPUSwapChainDX11>(this, window);

View File

@@ -99,6 +99,7 @@ public:
GPUPipelineState* CreatePipelineState() override;
GPUTimerQuery* CreateTimerQuery() override;
GPUBuffer* CreateBuffer(const StringView& name) override;
GPUSampler* CreateSampler() override;
GPUSwapChain* CreateSwapChain(Window* window) override;
};

View File

@@ -0,0 +1,128 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#if GRAPHICS_API_DIRECTX11
#include "GPUSamplerDX11.h"
D3D11_TEXTURE_ADDRESS_MODE ToDX11(GPUSamplerAddressMode value)
{
switch (value)
{
case GPUSamplerAddressMode::Wrap:
return D3D11_TEXTURE_ADDRESS_WRAP;
case GPUSamplerAddressMode::Clamp:
return D3D11_TEXTURE_ADDRESS_CLAMP;
case GPUSamplerAddressMode::Mirror:
return D3D11_TEXTURE_ADDRESS_MIRROR;
case GPUSamplerAddressMode::Border:
return D3D11_TEXTURE_ADDRESS_BORDER;
default:
return (D3D11_TEXTURE_ADDRESS_MODE)-1;
}
}
bool GPUSamplerDX11::OnInit()
{
D3D11_SAMPLER_DESC samplerDesc;
if (_desc.ComparisonFunction == GPUSamplerCompareFunction::Never)
{
switch (_desc.Filter)
{
case GPUSamplerFilter::Point:
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
break;
case GPUSamplerFilter::Bilinear:
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
break;
case GPUSamplerFilter::Trilinear:
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
break;
case GPUSamplerFilter::Anisotropic:
samplerDesc.Filter = D3D11_FILTER_ANISOTROPIC;
break;
default:
return true;
}
}
else
{
switch (_desc.Filter)
{
case GPUSamplerFilter::Point:
samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT;
break;
case GPUSamplerFilter::Bilinear:
samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT;
break;
case GPUSamplerFilter::Trilinear:
samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR;
break;
case GPUSamplerFilter::Anisotropic:
samplerDesc.Filter = D3D11_FILTER_COMPARISON_ANISOTROPIC;
break;
default:
return true;
}
}
samplerDesc.AddressU = ToDX11(_desc.AddressU);
samplerDesc.AddressV = ToDX11(_desc.AddressV);
samplerDesc.AddressW = ToDX11(_desc.AddressW);
samplerDesc.MipLODBias = _desc.MipBias;
samplerDesc.MaxAnisotropy = _desc.MaxAnisotropy;
switch (_desc.ComparisonFunction)
{
case GPUSamplerCompareFunction::Never:
samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
break;
case GPUSamplerCompareFunction::Less:
samplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS;
break;
default:
return true;
}
switch (_desc.BorderColor)
{
case GPUSamplerBorderColor::TransparentBlack:
samplerDesc.BorderColor[0] = 0;
samplerDesc.BorderColor[1] = 0;
samplerDesc.BorderColor[2] = 0;
samplerDesc.BorderColor[3] = 0;
break;
case GPUSamplerBorderColor::OpaqueBlack:
samplerDesc.BorderColor[0] = 0;
samplerDesc.BorderColor[1] = 0;
samplerDesc.BorderColor[2] = 0;
samplerDesc.BorderColor[3] = 1.0f;
break;
case GPUSamplerBorderColor::OpaqueWhite:
samplerDesc.BorderColor[0] = 1.0f;
samplerDesc.BorderColor[1] = 1.0f;
samplerDesc.BorderColor[2] = 1.0f;
samplerDesc.BorderColor[3] = 1.0f;
break;
default:
return true;
}
samplerDesc.MinLOD = _desc.MinMipLevel;
samplerDesc.MaxLOD = _desc.MaxMipLevel;
HRESULT result = _device->GetDevice()->CreateSamplerState(&samplerDesc, &SamplerState);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
ASSERT(SamplerState != nullptr);
_memoryUsage = sizeof(D3D11_SAMPLER_DESC);
return false;
}
void GPUSamplerDX11::OnReleaseGPU()
{
if (SamplerState)
{
SamplerState->Release();
SamplerState = nullptr;
}
// Base
GPUSampler::OnReleaseGPU();
}
#endif

View File

@@ -0,0 +1,31 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Graphics/Textures/GPUSampler.h"
#include "GPUDeviceDX11.h"
#if GRAPHICS_API_DIRECTX11
/// <summary>
/// Sampler object for DirectX 11 backend.
/// </summary>
class GPUSamplerDX11 : public GPUResourceBase<GPUDeviceDX11, GPUSampler>
{
public:
GPUSamplerDX11(GPUDeviceDX11* device)
: GPUResourceBase<GPUDeviceDX11, GPUSampler>(device, StringView::Empty)
{
}
ID3D11SamplerState* SamplerState = nullptr;
protected:
// [GPUSampler]
bool OnInit() override;
void OnReleaseGPU() override;
};
#endif

View File

@@ -11,6 +11,7 @@
#include "UploadBufferDX12.h"
#include "GPUTextureDX12.h"
#include "GPUBufferDX12.h"
#include "GPUSamplerDX12.h"
#include "CommandQueueDX12.h"
#include "DescriptorHeapDX12.h"
#include "Engine/Graphics/RenderTask.h"
@@ -74,6 +75,7 @@ GPUContextDX12::GPUContextDX12(GPUDeviceDX12* device, D3D12_COMMAND_LIST_TYPE ty
, _rtDirtyFlag(0)
, _psDirtyFlag(0)
, _cbDirtyFlag(0)
, _samplersDirtyFlag(0)
, _rtDepth(nullptr)
, _ibHandle(nullptr)
{
@@ -213,6 +215,7 @@ void GPUContextDX12::Reset()
_currentState = nullptr;
_rtDirtyFlag = false;
_cbDirtyFlag = false;
_samplersDirtyFlag = false;
_rtCount = 0;
_rtDepth = nullptr;
_srMaskDirtyGraphics = 0;
@@ -226,8 +229,9 @@ void GPUContextDX12::Reset()
Platform::MemoryClear(_srHandles, sizeof(_srHandles));
Platform::MemoryClear(_uaHandles, sizeof(_uaHandles));
Platform::MemoryClear(_vbHandles, sizeof(_vbHandles));
Platform::MemoryClear(&_ibHandle, sizeof(_ibHandle));
_ibHandle = nullptr;
Platform::MemoryClear(&_cbHandles, sizeof(_cbHandles));
Platform::MemoryClear(&_samplers, sizeof(_samplers));
_swapChainsUsed = 0;
// Bind Root Signature
@@ -235,7 +239,7 @@ void GPUContextDX12::Reset()
_commandList->SetComputeRootSignature(_device->GetRootSignature());
// Bind heaps
ID3D12DescriptorHeap* ppHeaps[] = { _device->RingHeap_CBV_SRV_UAV.GetHeap() };
ID3D12DescriptorHeap* ppHeaps[] = { _device->RingHeap_CBV_SRV_UAV.GetHeap(), _device->RingHeap_Sampler.GetHeap() };
_commandList->SetDescriptorHeaps(ARRAY_COUNT(ppHeaps), ppHeaps);
}
@@ -449,28 +453,58 @@ void GPUContextDX12::flushUAVs()
void GPUContextDX12::flushCBs()
{
// Check if need to flush constant buffers
if (_cbDirtyFlag)
if (!_cbDirtyFlag)
return;
_cbDirtyFlag = false;
for (uint32 slotIndex = 0; slotIndex < ARRAY_COUNT(_cbHandles); slotIndex++)
{
// Clear flag
_cbDirtyFlag = false;
// Flush with the driver
for (uint32 slotIndex = 0; slotIndex < ARRAY_COUNT(_cbHandles); slotIndex++)
auto cb = _cbHandles[slotIndex];
if (cb)
{
auto cb = _cbHandles[slotIndex];
if (cb)
{
ASSERT(cb->GPUAddress != 0);
if (_isCompute)
_commandList->SetComputeRootConstantBufferView(slotIndex, cb->GPUAddress);
else
_commandList->SetGraphicsRootConstantBufferView(slotIndex, cb->GPUAddress);
}
ASSERT(cb->GPUAddress != 0);
if (_isCompute)
_commandList->SetComputeRootConstantBufferView(slotIndex, cb->GPUAddress);
else
_commandList->SetGraphicsRootConstantBufferView(slotIndex, cb->GPUAddress);
}
}
}
void GPUContextDX12::flushSamplers()
{
if (!_samplersDirtyFlag)
return;
_samplersDirtyFlag = false;
int32 lastSlot = -1;
for (int32 slotIndex = ARRAY_COUNT(_samplers) - 1; slotIndex >= 0; slotIndex--)
{
auto sampler = _samplers[slotIndex];
if (sampler)
{
lastSlot = slotIndex;
break;
}
}
if (lastSlot < 0)
return;
const uint32 samplersCount = lastSlot + 1;
D3D12_CPU_DESCRIPTOR_HANDLE srcDescriptorRangeStarts[ARRAY_COUNT(_samplers)];
for (uint32 i = 0; i < samplersCount; i++)
{
const auto handle = _samplers[i];
if (handle != nullptr)
{
srcDescriptorRangeStarts[i] = handle->HandleCPU;
}
}
auto allocation = _device->RingHeap_Sampler.AllocateTable(samplersCount);
_device->GetDevice()->CopyDescriptors(1, &allocation.CPU, &samplersCount, samplersCount, srcDescriptorRangeStarts, nullptr, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
if (_isCompute)
_commandList->SetComputeRootDescriptorTable(4, allocation.GPU);
else
_commandList->SetGraphicsRootDescriptorTable(4, allocation.GPU);
}
void GPUContextDX12::flushRBs()
{
#if DX12_ENABLE_RESOURCE_BARRIERS_BATCHING
@@ -563,6 +597,7 @@ void GPUContextDX12::OnDrawCall()
flushRBs();
flushPS();
flushCBs();
flushSamplers();
#if BUILD_DEBUG
// Additional verification of the state
@@ -835,8 +870,8 @@ void GPUContextDX12::BindUA(int32 slot, GPUResourceView* view)
{
ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED);
_uaHandles[slot] = view ? (IShaderResourceDX12*)view->GetNativePtr() : nullptr;
if (view)
*view->LastRenderTime = _lastRenderTime;
if (view)
*view->LastRenderTime = _lastRenderTime;
}
void GPUContextDX12::BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets)
@@ -890,6 +925,17 @@ void GPUContextDX12::BindIB(GPUBuffer* indexBuffer)
}
}
void GPUContextDX12::BindSampler(int32 slot, GPUSampler* sampler)
{
ASSERT(slot >= GPU_STATIC_SAMPLERS_COUNT && slot < GPU_MAX_SAMPLER_BINDED);
const auto handle = sampler ? static_cast<GPUSamplerDX12*>(sampler) : nullptr;
if (_samplers[slot - GPU_STATIC_SAMPLERS_COUNT] != handle)
{
_samplersDirtyFlag = true;
_samplers[slot - GPU_STATIC_SAMPLERS_COUNT] = handle;
}
}
void GPUContextDX12::UpdateCB(GPUConstantBuffer* cb, const void* data)
{
ASSERT(data && cb);
@@ -927,6 +973,7 @@ void GPUContextDX12::Dispatch(GPUShaderProgramCS* shader, uint32 threadGroupCoun
flushUAVs();
flushRBs();
flushCBs();
flushSamplers();
auto shaderDX12 = (GPUShaderProgramCSDX12*)shader;
auto computeState = shaderDX12->GetOrCreateState();
@@ -959,6 +1006,7 @@ void GPUContextDX12::DispatchIndirect(GPUShaderProgramCS* shader, GPUBuffer* buf
flushUAVs();
flushRBs();
flushCBs();
flushSamplers();
auto shaderDX12 = (GPUShaderProgramCSDX12*)shader;
auto computeState = shaderDX12->GetOrCreateState();

View File

@@ -12,6 +12,7 @@
class GPUDeviceDX12;
class GPUPipelineStateDX12;
class GPUBufferDX12;
class GPUSamplerDX12;
class GPUConstantBufferDX12;
class GPUTextureViewDX12;
@@ -51,6 +52,7 @@ private:
int32 _rtDirtyFlag : 1;
int32 _psDirtyFlag : 1;
int32 _cbDirtyFlag : 1;
int32 _samplersDirtyFlag : 1;
GPUTextureViewDX12* _rtDepth;
GPUTextureViewDX12* _rtHandles[GPU_MAX_RT_BINDED];
@@ -62,6 +64,7 @@ private:
D3D12_VERTEX_BUFFER_VIEW _vbViews[GPU_MAX_VB_BINDED];
D3D12_RESOURCE_BARRIER _rbBuffer[DX12_RB_BUFFER_SIZE];
GPUConstantBufferDX12* _cbHandles[GPU_MAX_CB_BINDED];
GPUSamplerDX12* _samplers[GPU_MAX_SAMPLER_BINDED - GPU_STATIC_SAMPLERS_COUNT];
public:
@@ -136,6 +139,7 @@ private:
void flushRTVs();
void flushUAVs();
void flushCBs();
void flushSamplers();
void flushRBs();
void flushPS();
void OnDrawCall();
@@ -167,6 +171,7 @@ public:
void BindUA(int32 slot, GPUResourceView* view) override;
void BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override;
void BindIB(GPUBuffer* indexBuffer) override;
void BindSampler(int32 slot, GPUSampler* sampler) override;
void UpdateCB(GPUConstantBuffer* cb, const void* data) override;
void Dispatch(GPUShaderProgramCS* shader, uint32 threadGroupCountX, uint32 threadGroupCountY, uint32 threadGroupCountZ) override;
void DispatchIndirect(GPUShaderProgramCS* shader, GPUBuffer* bufferForArgs, uint32 offsetForArgs) override;

View File

@@ -9,6 +9,7 @@
#include "GPUTextureDX12.h"
#include "GPUTimerQueryDX12.h"
#include "GPUBufferDX12.h"
#include "GPUSamplerDX12.h"
#include "GPUSwapChainDX12.h"
#include "Engine/Engine/Engine.h"
#include "Engine/Engine/CommandLine.h"
@@ -191,7 +192,9 @@ GPUDeviceDX12::GPUDeviceDX12(IDXGIFactory4* dxgiFactory, GPUAdapterDX* adapter)
, Heap_CBV_SRV_UAV(this, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 4 * 1024, false)
, Heap_RTV(this, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1 * 1024, false)
, Heap_DSV(this, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 64, false)
, Heap_Sampler(this, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 128, false)
, RingHeap_CBV_SRV_UAV(this, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 512 * 1024, true)
, RingHeap_Sampler(this, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 1 * 1024, true)
{
}
@@ -350,6 +353,7 @@ bool GPUDeviceDX12::Init()
limits.MaximumTexture2DArraySize = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
limits.MaximumTexture3DSize = D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;
limits.MaximumTextureCubeSize = D3D12_REQ_TEXTURECUBE_DIMENSION;
limits.MaximumSamplerAnisotropy = D3D12_DEFAULT_MAX_ANISOTROPY;
for (int32 i = 0; i < static_cast<int32>(PixelFormat::MAX); i++)
{
@@ -379,6 +383,8 @@ bool GPUDeviceDX12::Init()
_mainContext = New<GPUContextDX12>(this, D3D12_COMMAND_LIST_TYPE_DIRECT);
if (RingHeap_CBV_SRV_UAV.Init())
return true;
if (RingHeap_Sampler.Init())
return true;
// Create empty views
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
@@ -458,7 +464,7 @@ bool GPUDeviceDX12::Init()
// TODO: maybe create set of different root signatures? for UAVs, for compute, for simple drawing, for post fx?
{
// Descriptor tables
D3D12_DESCRIPTOR_RANGE r[2];
D3D12_DESCRIPTOR_RANGE r[3];
// TODO: separate ranges for pixel/vertex visibility and one shared for all?
{
D3D12_DESCRIPTOR_RANGE& range = r[0];
@@ -476,9 +482,17 @@ bool GPUDeviceDX12::Init()
range.RegisterSpace = 0;
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
{
D3D12_DESCRIPTOR_RANGE& range = r[2];
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
range.NumDescriptors = GPU_MAX_SAMPLER_BINDED - GPU_STATIC_SAMPLERS_COUNT;
range.BaseShaderRegister = GPU_STATIC_SAMPLERS_COUNT;
range.RegisterSpace = 0;
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
}
// Root parameters
D3D12_ROOT_PARAMETER rootParameters[4];
D3D12_ROOT_PARAMETER rootParameters[5];
{
D3D12_ROOT_PARAMETER& rootParam = rootParameters[0];
rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
@@ -507,11 +521,18 @@ bool GPUDeviceDX12::Init()
rootParam.DescriptorTable.NumDescriptorRanges = 1;
rootParam.DescriptorTable.pDescriptorRanges = &r[1];
}
// TODO: describe visibilities for the static samples, maybe use all pixel? or again pixel + all combo?
{
D3D12_ROOT_PARAMETER& rootParam = rootParameters[4];
rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
rootParam.DescriptorTable.NumDescriptorRanges = 1;
rootParam.DescriptorTable.pDescriptorRanges = &r[2];
}
// Static samplers
D3D12_STATIC_SAMPLER_DESC staticSamplers[6];
static_assert(GPU_STATIC_SAMPLERS_COUNT == ARRAY_COUNT(staticSamplers), "Update static samplers setup.");
// TODO: describe visibilities for the static samples, maybe use all pixel? or again pixel + all combo?
// Linear Clamp
staticSamplers[0].Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
staticSamplers[0].AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
@@ -718,7 +739,9 @@ void GPUDeviceDX12::Dispose()
Heap_CBV_SRV_UAV.ReleaseGPU();
Heap_RTV.ReleaseGPU();
Heap_DSV.ReleaseGPU();
Heap_Sampler.ReleaseGPU();
RingHeap_CBV_SRV_UAV.ReleaseGPU();
RingHeap_Sampler.ReleaseGPU();
SAFE_DELETE(UploadBuffer);
SAFE_DELETE(DrawIndirectCommandSignature);
SAFE_DELETE(_mainContext);
@@ -766,6 +789,11 @@ GPUBuffer* GPUDeviceDX12::CreateBuffer(const StringView& name)
return New<GPUBufferDX12>(this, name);
}
GPUSampler* GPUDeviceDX12::CreateSampler()
{
return New<GPUSamplerDX12>(this);
}
GPUSwapChain* GPUDeviceDX12::CreateSwapChain(Window* window)
{
return New<GPUSwapChainDX12>(this, window);

View File

@@ -141,7 +141,9 @@ public:
DescriptorHeapPoolDX12 Heap_CBV_SRV_UAV;
DescriptorHeapPoolDX12 Heap_RTV;
DescriptorHeapPoolDX12 Heap_DSV;
DescriptorHeapPoolDX12 Heap_Sampler;
DescriptorHeapRingBufferDX12 RingHeap_CBV_SRV_UAV;
DescriptorHeapRingBufferDX12 RingHeap_Sampler;
public:
@@ -188,6 +190,7 @@ public:
GPUPipelineState* CreatePipelineState() override;
GPUTimerQuery* CreateTimerQuery() override;
GPUBuffer* CreateBuffer(const StringView& name) override;
GPUSampler* CreateSampler() override;
GPUSwapChain* CreateSwapChain(Window* window) override;
};

View File

@@ -0,0 +1,124 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#if GRAPHICS_API_DIRECTX12
#include "GPUSamplerDX12.h"
D3D12_TEXTURE_ADDRESS_MODE ToDX12(GPUSamplerAddressMode value)
{
switch (value)
{
case GPUSamplerAddressMode::Wrap:
return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
case GPUSamplerAddressMode::Clamp:
return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
case GPUSamplerAddressMode::Mirror:
return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
case GPUSamplerAddressMode::Border:
return D3D12_TEXTURE_ADDRESS_MODE_BORDER;
default:
return (D3D12_TEXTURE_ADDRESS_MODE)-1;
}
}
bool GPUSamplerDX12::OnInit()
{
D3D12_SAMPLER_DESC samplerDesc;
if (_desc.ComparisonFunction == GPUSamplerCompareFunction::Never)
{
switch (_desc.Filter)
{
case GPUSamplerFilter::Point:
samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
break;
case GPUSamplerFilter::Bilinear:
samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
break;
case GPUSamplerFilter::Trilinear:
samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
break;
case GPUSamplerFilter::Anisotropic:
samplerDesc.Filter = D3D12_FILTER_ANISOTROPIC;
break;
default:
return true;
}
}
else
{
switch (_desc.Filter)
{
case GPUSamplerFilter::Point:
samplerDesc.Filter = D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT;
break;
case GPUSamplerFilter::Bilinear:
samplerDesc.Filter = D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT;
break;
case GPUSamplerFilter::Trilinear:
samplerDesc.Filter = D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR;
break;
case GPUSamplerFilter::Anisotropic:
samplerDesc.Filter = D3D12_FILTER_COMPARISON_ANISOTROPIC;
break;
default:
return true;
}
}
samplerDesc.AddressU = ToDX12(_desc.AddressU);
samplerDesc.AddressV = ToDX12(_desc.AddressV);
samplerDesc.AddressW = ToDX12(_desc.AddressW);
samplerDesc.MipLODBias = _desc.MipBias;
samplerDesc.MaxAnisotropy = _desc.MaxAnisotropy;
switch (_desc.ComparisonFunction)
{
case GPUSamplerCompareFunction::Never:
samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
break;
case GPUSamplerCompareFunction::Less:
samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_LESS;
break;
default:
return true;
}
switch (_desc.BorderColor)
{
case GPUSamplerBorderColor::TransparentBlack:
samplerDesc.BorderColor[0] = 0;
samplerDesc.BorderColor[1] = 0;
samplerDesc.BorderColor[2] = 0;
samplerDesc.BorderColor[3] = 0;
break;
case GPUSamplerBorderColor::OpaqueBlack:
samplerDesc.BorderColor[0] = 0;
samplerDesc.BorderColor[1] = 0;
samplerDesc.BorderColor[2] = 0;
samplerDesc.BorderColor[3] = 1.0f;
break;
case GPUSamplerBorderColor::OpaqueWhite:
samplerDesc.BorderColor[0] = 1.0f;
samplerDesc.BorderColor[1] = 1.0f;
samplerDesc.BorderColor[2] = 1.0f;
samplerDesc.BorderColor[3] = 1.0f;
break;
default:
return true;
}
samplerDesc.MinLOD = _desc.MinMipLevel;
samplerDesc.MaxLOD = _desc.MaxMipLevel;
_device->Heap_Sampler.AllocateSlot(Slot.Heap, Slot.Index);
HandleCPU = Slot.CPU();
_device->GetDevice()->CreateSampler(&samplerDesc, HandleCPU);
_memoryUsage = sizeof(D3D12_SAMPLER_DESC);
return false;
}
void GPUSamplerDX12::OnReleaseGPU()
{
Slot.Release();
// Base
GPUSampler::OnReleaseGPU();
}
#endif

View File

@@ -0,0 +1,32 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Graphics/Textures/GPUSampler.h"
#include "GPUDeviceDX12.h"
#if GRAPHICS_API_DIRECTX12
/// <summary>
/// Sampler object for DirectX 12 backend.
/// </summary>
class GPUSamplerDX12 : public GPUResourceDX12<GPUSampler>
{
public:
GPUSamplerDX12(GPUDeviceDX12* device)
: GPUResourceDX12<GPUSampler>(device, StringView::Empty)
{
}
DescriptorHeapWithSlotsDX12::Slot Slot;
D3D12_CPU_DESCRIPTOR_HANDLE HandleCPU;
protected:
// [GPUSampler]
bool OnInit() override;
void OnReleaseGPU() override;
};
#endif

View File

@@ -108,6 +108,10 @@ public:
{
}
void BindSampler(int32 slot, GPUSampler* sampler) override
{
}
void UpdateCB(GPUConstantBuffer* cb, const void* data) override
{
}

View File

@@ -10,6 +10,7 @@
#include "GPUPipelineStateNull.h"
#include "GPUTimerQueryNull.h"
#include "GPUBufferNull.h"
#include "GPUSamplerNull.h"
#include "GPUSwapChainNull.h"
GPUDeviceNull::GPUDeviceNull()
@@ -66,6 +67,7 @@ bool GPUDeviceNull::Init()
limits.MaximumTexture2DArraySize = 512;
limits.MaximumTexture3DSize = 2048;
limits.MaximumTextureCubeSize = 16384;
limits.MaximumSamplerAnisotropy = 0;
for (int32 i = 0; i < static_cast<int32>(PixelFormat::MAX); i++)
{
@@ -177,6 +179,11 @@ GPUBuffer* GPUDeviceNull::CreateBuffer(const StringView& name)
return New<GPUBufferNull>();
}
GPUSampler* GPUDeviceNull::CreateSampler()
{
return New<GPUSamplerNull>();
}
GPUSwapChain* GPUDeviceNull::CreateSwapChain(Window* window)
{
return New<GPUSwapChainNull>(window);

View File

@@ -46,6 +46,7 @@ public:
GPUPipelineState* CreatePipelineState() override;
GPUTimerQuery* CreateTimerQuery() override;
GPUBuffer* CreateBuffer(const StringView& name) override;
GPUSampler* CreateSampler() override;
GPUSwapChain* CreateSwapChain(Window* window) override;
};

View File

@@ -0,0 +1,23 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#if GRAPHICS_API_NULL
#include "Engine/Graphics/Textures/GPUSampler.h"
/// <summary>
/// Sampler object for Null backend.
/// </summary>
class GPUSamplerNull : public GPUSampler
{
protected:
// [GPUSampler]
bool OnInit() override
{
return false;
}
};
#endif

View File

@@ -8,6 +8,7 @@
#include "Engine/Core/Math/Color.h"
#include "GPUBufferVulkan.h"
#include "GPUShaderVulkan.h"
#include "GPUSamplerVulkan.h"
#include "GPUPipelineStateVulkan.h"
#include "Engine/Profiler/RenderStats.h"
#include "GPUShaderProgramVulkan.h"
@@ -447,7 +448,8 @@ void GPUContextVulkan::UpdateDescriptorSets(const SpirvShaderDescriptorInfo& des
case VK_DESCRIPTOR_TYPE_SAMPLER:
{
// Sampler
const VkSampler sampler = _device->HelperResources.GetStaticSampler((HelperResourcesVulkan::StaticSamplers)descriptor.Slot);
const VkSampler sampler = _samplerHandles[descriptor.Slot];
ASSERT(sampler);
needsWrite |= dsWriter.WriteSampler(descriptorIndex, sampler);
break;
}
@@ -715,8 +717,6 @@ void GPUContextVulkan::FrameBegin()
_psDirtyFlag = 0;
_rtDirtyFlag = 0;
_cbDirtyFlag = 0;
_srDirtyFlag = 0;
_uaDirtyFlag = 0;
_rtCount = 0;
_vbCount = 0;
_renderPass = nullptr;
@@ -726,6 +726,8 @@ void GPUContextVulkan::FrameBegin()
Platform::MemoryClear(_cbHandles, sizeof(_cbHandles));
Platform::MemoryClear(_srHandles, sizeof(_srHandles));
Platform::MemoryClear(_uaHandles, sizeof(_uaHandles));
Platform::MemoryCopy(_samplerHandles, _device->HelperResources.GetStaticSamplers(), sizeof(VkSampler) * GPU_STATIC_SAMPLERS_COUNT);
Platform::MemoryClear(_samplerHandles + GPU_STATIC_SAMPLERS_COUNT, sizeof(_samplerHandles) - sizeof(VkSampler) * GPU_STATIC_SAMPLERS_COUNT);
#if VULKAN_RESET_QUERY_POOLS
// Reset pending queries
@@ -916,13 +918,11 @@ void GPUContextVulkan::SetRenderTarget(GPUTextureView* rt, GPUBuffer* uaOutput)
void GPUContextVulkan::ResetSR()
{
_srDirtyFlag = false;
Platform::MemoryClear(_srHandles, sizeof(_srHandles));
}
void GPUContextVulkan::ResetUA()
{
_uaDirtyFlag = false;
Platform::MemoryClear(_uaHandles, sizeof(_uaHandles));
}
@@ -951,7 +951,6 @@ void GPUContextVulkan::BindSR(int32 slot, GPUResourceView* view)
const auto handle = view ? (DescriptorOwnerResourceVulkan*)view->GetNativePtr() : nullptr;
if (_srHandles[slot] != handle)
{
_srDirtyFlag = true;
_srHandles[slot] = handle;
if (view)
*view->LastRenderTime = _lastRenderTime;
@@ -964,7 +963,6 @@ void GPUContextVulkan::BindUA(int32 slot, GPUResourceView* view)
const auto handle = view ? (DescriptorOwnerResourceVulkan*)view->GetNativePtr() : nullptr;
if (_uaHandles[slot] != handle)
{
_uaDirtyFlag = true;
_uaHandles[slot] = handle;
if (view)
*view->LastRenderTime = _lastRenderTime;
@@ -997,6 +995,16 @@ void GPUContextVulkan::BindIB(GPUBuffer* indexBuffer)
vkCmdBindIndexBuffer(cmdBuffer->GetHandle(), ibVulkan, 0, indexBuffer->GetFormat() == PixelFormat::R32_UInt ? VK_INDEX_TYPE_UINT32 : VK_INDEX_TYPE_UINT16);
}
void GPUContextVulkan::BindSampler(int32 slot, GPUSampler* sampler)
{
ASSERT(slot >= 0 && slot < GPU_MAX_SR_BINDED);
const auto handle = sampler ? ((GPUSamplerVulkan*)sampler)->Sampler : nullptr;
if (_samplerHandles[slot] != handle)
{
_samplerHandles[slot] = handle;
}
}
void GPUContextVulkan::UpdateCB(GPUConstantBuffer* cb, const void* data)
{
ASSERT(data && cb);

View File

@@ -94,8 +94,6 @@ private:
int32 _psDirtyFlag : 1;
int32 _rtDirtyFlag : 1;
int32 _cbDirtyFlag : 1;
int32 _srDirtyFlag : 1;
int32 _uaDirtyFlag : 1;
int32 _rtCount;
int32 _vbCount;
@@ -107,6 +105,7 @@ private:
DescriptorOwnerResourceVulkan* _cbHandles[GPU_MAX_CB_BINDED];
DescriptorOwnerResourceVulkan* _srHandles[GPU_MAX_SR_BINDED];
DescriptorOwnerResourceVulkan* _uaHandles[GPU_MAX_UA_BINDED];
VkSampler _samplerHandles[GPU_MAX_SAMPLER_BINDED];
DescriptorOwnerResourceVulkan** _handles[(int32)SpirvShaderResourceBindingType::MAX];
typedef Array<DescriptorPoolVulkan*> DescriptorPoolArray;
@@ -188,6 +187,7 @@ public:
void BindUA(int32 slot, GPUResourceView* view) override;
void BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override;
void BindIB(GPUBuffer* indexBuffer) override;
void BindSampler(int32 slot, GPUSampler* sampler) override;
void UpdateCB(GPUConstantBuffer* cb, const void* data) override;
void Dispatch(GPUShaderProgramCS* shader, uint32 threadGroupCountX, uint32 threadGroupCountY, uint32 threadGroupCountZ) override;
void DispatchIndirect(GPUShaderProgramCS* shader, GPUBuffer* bufferForArgs, uint32 offsetForArgs) override;

View File

@@ -13,6 +13,7 @@
#include "GPUTextureVulkan.h"
#include "GPUTimerQueryVulkan.h"
#include "GPUBufferVulkan.h"
#include "GPUSamplerVulkan.h"
#include "GPUSwapChainVulkan.h"
#include "RenderToolsVulkan.h"
#include "QueueVulkan.h"
@@ -369,7 +370,7 @@ void DeferredDeletionQueueVulkan::ReleaseResources(bool deleteImmediately)
#undef SWITCH_CASE
default:
#if !BUILD_RELEASE
CRASH;
CRASH;
#endif
break;
}
@@ -730,8 +731,9 @@ void InitSampler(VkSamplerCreateInfo& createInfo, bool supportsMirrorClampToEdge
createInfo.compareOp = RenderToolsVulkan::ToVulkanSamplerCompareFunction(compareFunction);
}
VkSampler HelperResourcesVulkan::GetStaticSampler(StaticSamplers type)
VkSampler* HelperResourcesVulkan::GetStaticSamplers()
{
static_assert(GPU_STATIC_SAMPLERS_COUNT == 6, "Update static samplers setup.");
if (!_staticSamplers[0])
{
const bool supportsMirrorClampToEdge = GPUDeviceVulkan::OptionalDeviceExtensions.HasMirrorClampToEdge;
@@ -769,8 +771,7 @@ VkSampler HelperResourcesVulkan::GetStaticSampler(StaticSamplers type)
InitSampler(createInfo, supportsMirrorClampToEdge, GPUSamplerFilter::Trilinear, GPUSamplerAddressMode::Clamp, GPUSamplerAddressMode::Clamp, GPUSamplerAddressMode::Clamp, GPUSamplerCompareFunction::Less);
VALIDATE_VULKAN_RESULT(vkCreateSampler(_device->Device, &createInfo, nullptr, &_staticSamplers[5]));
}
return _staticSamplers[static_cast<int32>(type)];
return _staticSamplers;
}
GPUTextureVulkan* HelperResourcesVulkan::GetDummyTexture(SpirvShaderResourceType type)
@@ -797,7 +798,7 @@ GPUTextureVulkan* HelperResourcesVulkan::GetDummyTexture(SpirvShaderResourceType
index = 5;
break;
default:
CRASH;
CRASH;
return nullptr;
}
@@ -1172,7 +1173,7 @@ GPUDevice* GPUDeviceVulkan::Create()
volkLoadInstance(Instance);
#endif
// Setup debug layer
// Setup debug layer
#if VULKAN_USE_DEBUG_LAYER
SetupDebugLayerCallback();
#endif
@@ -1692,6 +1693,7 @@ bool GPUDeviceVulkan::Init()
limits.MaximumTexture2DArraySize = PhysicalDeviceLimits.maxImageArrayLayers;
limits.MaximumTexture3DSize = PhysicalDeviceLimits.maxImageDimension3D;
limits.MaximumTextureCubeSize = PhysicalDeviceLimits.maxImageDimensionCube;
limits.MaximumSamplerAnisotropy = PhysicalDeviceLimits.maxSamplerAnisotropy;
for (int32 i = 0; i < static_cast<int32>(PixelFormat::MAX); i++)
{
@@ -1957,6 +1959,11 @@ GPUBuffer* GPUDeviceVulkan::CreateBuffer(const StringView& name)
return New<GPUBufferVulkan>(this, name);
}
GPUSampler* GPUDeviceVulkan::CreateSampler()
{
return New<GPUSamplerVulkan>(this);
}
GPUSwapChain* GPUDeviceVulkan::CreateSwapChain(Window* window)
{
return New<GPUSwapChainVulkan>(this, window);

View File

@@ -385,46 +385,24 @@ public:
/// </summary>
class HelperResourcesVulkan
{
public:
enum class StaticSamplers
{
SamplerLinearClamp =0,
SamplerPointClamp = 1,
SamplerLinearWrap = 2,
SamplerPointWrap = 3,
ShadowSampler = 4,
ShadowSamplerPCF = 5,
MAX
};
private:
GPUDeviceVulkan* _device;
GPUTextureVulkan* _dummyTextures[6];
GPUBufferVulkan* _dummyBuffer;
GPUBufferVulkan* _dummyVB;
VkSampler _staticSamplers[static_cast<int32>(StaticSamplers::MAX)];
VkSampler _staticSamplers[GPU_STATIC_SAMPLERS_COUNT];
public:
/// <summary>
/// Initializes a new instance of the <see cref="DummyResourcesVulkan"/> class.
/// </summary>
/// <param name="device">The graphics device.</param>
HelperResourcesVulkan(GPUDeviceVulkan* device);
public:
VkSampler GetStaticSampler(StaticSamplers type);
VkSampler* GetStaticSamplers();
GPUTextureVulkan* GetDummyTexture(SpirvShaderResourceType type);
GPUBufferVulkan* GetDummyBuffer();
GPUBufferVulkan* GetDummyVertexBuffer();
void Dispose();
};
@@ -739,6 +717,7 @@ public:
GPUPipelineState* CreatePipelineState() override;
GPUTimerQuery* CreateTimerQuery() override;
GPUBuffer* CreateBuffer(const StringView& name) override;
GPUSampler* CreateSampler() override;
GPUSwapChain* CreateSwapChain(Window* window) override;
};

View File

@@ -0,0 +1,56 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#if GRAPHICS_API_VULKAN
#include "GPUSamplerVulkan.h"
#include "RenderToolsVulkan.h"
bool GPUSamplerVulkan::OnInit()
{
VkSamplerCreateInfo createInfo;
RenderToolsVulkan::ZeroStruct(createInfo, VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
createInfo.magFilter = RenderToolsVulkan::ToVulkanMagFilterMode(_desc.Filter);
createInfo.minFilter = RenderToolsVulkan::ToVulkanMinFilterMode(_desc.Filter);
createInfo.mipmapMode = RenderToolsVulkan::ToVulkanMipFilterMode(_desc.Filter);
const bool supportsMirrorClampToEdge = GPUDeviceVulkan::OptionalDeviceExtensions.HasMirrorClampToEdge;
createInfo.addressModeU = RenderToolsVulkan::ToVulkanWrapMode(_desc.AddressU, supportsMirrorClampToEdge);
createInfo.addressModeV = RenderToolsVulkan::ToVulkanWrapMode(_desc.AddressV, supportsMirrorClampToEdge);
createInfo.addressModeW = RenderToolsVulkan::ToVulkanWrapMode(_desc.AddressW, supportsMirrorClampToEdge);
createInfo.mipLodBias = _desc.MipBias;
createInfo.anisotropyEnable = _desc.Filter == GPUSamplerFilter::Anisotropic ? VK_TRUE : VK_FALSE;
createInfo.maxAnisotropy = (float)_desc.MaxAnisotropy;
createInfo.compareEnable = _desc.ComparisonFunction != GPUSamplerCompareFunction::Never ? VK_TRUE : VK_FALSE;
createInfo.compareOp = RenderToolsVulkan::ToVulkanSamplerCompareFunction(_desc.ComparisonFunction);
createInfo.minLod = _desc.MinMipLevel;
createInfo.maxLod = _desc.MaxMipLevel;
switch (_desc.BorderColor)
{
case GPUSamplerBorderColor::TransparentBlack:
createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
break;
case GPUSamplerBorderColor::OpaqueBlack:
createInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
break;
case GPUSamplerBorderColor::OpaqueWhite:
createInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
break;
default:
return true;
}
VALIDATE_VULKAN_RESULT(vkCreateSampler(_device->Device, &createInfo, nullptr, &Sampler));
return false;
}
void GPUSamplerVulkan::OnReleaseGPU()
{
if (Sampler != VK_NULL_HANDLE)
{
_device->DeferredDeletionQueue.EnqueueResource(DeferredDeletionQueueVulkan::Buffer, Sampler);
Sampler = VK_NULL_HANDLE;
}
// Base
GPUSampler::OnReleaseGPU();
}
#endif

View File

@@ -0,0 +1,31 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#if GRAPHICS_API_VULKAN
#include "Engine/Graphics/Textures/GPUSampler.h"
#include "GPUDeviceVulkan.h"
/// <summary>
/// Sampler object for Vulkan backend.
/// </summary>
class GPUSamplerVulkan : public GPUResourceVulkan<GPUSampler>
{
public:
GPUSamplerVulkan(GPUDeviceVulkan* device)
: GPUResourceVulkan<GPUSampler>(device, StringView::Empty)
{
}
VkSampler Sampler = VK_NULL_HANDLE;
protected:
// [GPUSamplerVulkan]
bool OnInit() override;
void OnReleaseGPU() override;
};
#endif