Files
OptiScaler/CyberXeSS/cs/CS_Dx12.cpp
T
2024-03-31 21:45:18 +03:00

375 lines
11 KiB
C++

#include "CS_Dx12.h"
static ID3DBlob* CompileShader(const char* shaderCode, const char* entryPoint, const char* target)
{
ID3DBlob* shaderBlob = nullptr;
ID3DBlob* errorBlob = nullptr;
HRESULT hr = D3DCompile(shaderCode, strlen(shaderCode), nullptr, nullptr, nullptr, entryPoint, target, 0, 0, &shaderBlob, &errorBlob);
if (FAILED(hr))
{
spdlog::error("CompileShader error while compiling shader");
if (errorBlob)
{
spdlog::error("CompileShader error while compiling shader : {0}", (char*)errorBlob->GetBufferPointer());
errorBlob->Release();
}
if (shaderBlob)
shaderBlob->Release();
return nullptr;
}
if (errorBlob)
errorBlob->Release();
return shaderBlob;
}
static bool CreateComputeShader(ID3D12Device* device, ID3D12RootSignature* rootSignature, ID3D12PipelineState** pipelineState, ID3DBlob* shaderBlob)
{
D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.pRootSignature = rootSignature;
psoDesc.CS = CD3DX12_SHADER_BYTECODE(const_cast<void*>(shaderBlob->GetBufferPointer()), shaderBlob->GetBufferSize());
psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
HRESULT hr = device->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(pipelineState));
if (FAILED(hr))
{
spdlog::error("CreateComputeShader CreateComputePipelineState error {0:x}", hr);
return false;
}
return true;
}
bool CS_Dx12::CreateBufferResource(ID3D12Device* InDevice, ID3D12Resource* InSource, D3D12_RESOURCE_STATES InState)
{
if (InDevice == nullptr || InSource == nullptr)
return false;
D3D12_RESOURCE_DESC texDesc = InSource->GetDesc();
if (_buffer != nullptr)
{
auto bufDesc = _buffer->GetDesc();
if (bufDesc.Width != texDesc.Width || bufDesc.Height != texDesc.Height || bufDesc.Format != texDesc.Format)
{
_buffer->Release();
_buffer = nullptr;
}
else
return true;
}
spdlog::debug("CS_Dx12::CreateBufferResource [{0}] Start!", _name);
D3D12_HEAP_PROPERTIES heapProperties;
D3D12_HEAP_FLAGS heapFlags;
HRESULT hr = InSource->GetHeapProperties(&heapProperties, &heapFlags);
if (hr != S_OK)
{
spdlog::error("CS_Dx12::CreateBufferResource [{0}] GetHeapProperties result: {1:x}", _name.c_str(), hr);
return false;
}
texDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS | D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS;
hr = InDevice->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &texDesc, InState, nullptr, IID_PPV_ARGS(&_buffer));
if (hr != S_OK)
{
spdlog::error("CS_Dx12::CreateBufferResource [{0}] CreateCommittedResource result: {1:x}", _name, hr);
return false;
}
_buffer->SetName(L"CS_Buffer");
_bufferState = InState;
return true;
}
void CS_Dx12::SetBufferState(ID3D12GraphicsCommandList* InCommandList, D3D12_RESOURCE_STATES InState)
{
if (_bufferState == InState)
return;
D3D12_RESOURCE_BARRIER barrier = {};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Transition.pResource = _buffer;
barrier.Transition.StateBefore = _bufferState;
barrier.Transition.StateAfter = InState;
barrier.Transition.Subresource = 0;
InCommandList->ResourceBarrier(1, &barrier);
_bufferState = InState;
}
bool CS_Dx12::Dispatch(ID3D12Device* InDevice, ID3D12GraphicsCommandList* InCmdList, ID3D12Resource* InResource, ID3D12Resource* OutResource, uint32_t InNumThreadsX, uint32_t InNumThreadsY)
{
if (!_init || InDevice == nullptr || InCmdList == nullptr || InResource == nullptr || OutResource == nullptr || InNumThreadsX == 0 || InNumThreadsY == 0)
return false;
spdlog::debug("CS_Dx12::Dispatch [{0}] Start!", _name);
_counter++;
_counter = _counter % 2;
if (_cpuSrvHandle[_counter].ptr == NULL)
_cpuSrvHandle[_counter] = _srvHeap[_counter]->GetCPUDescriptorHandleForHeapStart();
if (_cpuUavHandle[_counter].ptr == NULL)
{
_cpuUavHandle[_counter] = _cpuSrvHandle[_counter];
_cpuUavHandle[_counter].ptr += InDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
if (_gpuSrvHandle[_counter].ptr == NULL)
_gpuSrvHandle[_counter] = _srvHeap[_counter]->GetGPUDescriptorHandleForHeapStart();
if (_gpuUavHandle[_counter].ptr == NULL)
{
_gpuUavHandle[_counter] = _gpuSrvHandle[_counter];
_gpuUavHandle[_counter].ptr += InDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
// Create SRV for Input Texture
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.Format = InResource->GetDesc().Format;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = 1;
InDevice->CreateShaderResourceView(InResource, &srvDesc, _cpuSrvHandle[_counter]);
// Create UAV for Output Texture
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
uavDesc.Format = OutResource->GetDesc().Format;
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
uavDesc.Texture2D.MipSlice = 0;
InDevice->CreateUnorderedAccessView(OutResource, nullptr, &uavDesc, _cpuUavHandle[_counter]);
ID3D12DescriptorHeap* heaps[] = { _srvHeap[_counter] };
InCmdList->SetDescriptorHeaps(_countof(heaps), heaps);
InCmdList->SetComputeRootSignature(_rootSignature);
InCmdList->SetPipelineState(_pipelineState);
InCmdList->SetComputeRootDescriptorTable(0, _gpuSrvHandle[_counter]);
InCmdList->SetComputeRootDescriptorTable(1, _gpuUavHandle[_counter]);
UINT dispatchWidth = (InResource->GetDesc().Width + InNumThreadsX - 1) / InNumThreadsX;
UINT dispatchHeight = (InResource->GetDesc().Height + InNumThreadsY - 1) / InNumThreadsY;
InCmdList->Dispatch(dispatchWidth, dispatchHeight, 1);
return true;
}
CS_Dx12::CS_Dx12(std::string InName, ID3D12Device* InDevice, std::string InShaderCode, std::string InEntry, std::string InTarget) : _name(InName), _device(InDevice)
{
if (InDevice == nullptr)
{
spdlog::error("CS_Dx12::CS_Dx12 InDevice is nullptr!");
return;
}
spdlog::debug("CS_Dx12::CS_Dx12 {0} start!", _name);
// Describe and create the root signature
// ---------------------------------------------------
D3D12_DESCRIPTOR_RANGE descriptorRange[2];
// SRV Range (Input Texture)
descriptorRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
descriptorRange[0].NumDescriptors = 1;
descriptorRange[0].BaseShaderRegister = 0; // Assuming t0 register in HLSL for SRV
descriptorRange[0].RegisterSpace = 0;
descriptorRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
// UAV Range (Output Texture)
descriptorRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
descriptorRange[1].NumDescriptors = 1;
descriptorRange[1].BaseShaderRegister = 0; // Assuming u0 register in HLSL for UAV
descriptorRange[1].RegisterSpace = 0;
descriptorRange[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
// Define the root parameter (descriptor table)
// ---------------------------------------------------
D3D12_ROOT_PARAMETER rootParameters[2];
// Root Parameter for SRV
rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
rootParameters[0].DescriptorTable.NumDescriptorRanges = 1; // One range (SRV)
rootParameters[0].DescriptorTable.pDescriptorRanges = &descriptorRange[0]; // Point to the SRV range
rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
// Root Parameter for UAV
rootParameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
rootParameters[1].DescriptorTable.NumDescriptorRanges = 1; // One range (UAV)
rootParameters[1].DescriptorTable.pDescriptorRanges = &descriptorRange[1]; // Point to the UAV range
rootParameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
// A root signature is an array of root parameters
// ---------------------------------------------------
D3D12_ROOT_SIGNATURE_DESC rootSigDesc;
rootSigDesc.NumParameters = 2; // Two root parameters
rootSigDesc.pParameters = rootParameters;
rootSigDesc.NumStaticSamplers = 0;
rootSigDesc.pStaticSamplers = nullptr;
rootSigDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
ID3DBlob* errorBlob;
ID3DBlob* signatureBlob;
do
{
auto hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signatureBlob, &errorBlob);
if (FAILED(hr))
{
spdlog::error("CS_Dx12::CS_Dx12 [{0}] D3D12SerializeRootSignature error {1:x}", _name, hr);
break;
}
hr = InDevice->CreateRootSignature(0, signatureBlob->GetBufferPointer(), signatureBlob->GetBufferSize(), IID_PPV_ARGS(&_rootSignature));
if (FAILED(hr))
{
spdlog::error("CS_Dx12::CS_Dx12 [{0}] CreateRootSignature error {1:x}", _name, hr);
break;
}
} while (false);
if (errorBlob != nullptr)
{
errorBlob->Release();
errorBlob = nullptr;
}
if (signatureBlob != nullptr)
{
signatureBlob->Release();
signatureBlob = nullptr;
}
if (_rootSignature == nullptr)
{
spdlog::error("CS_Dx12::CS_Dx12 [{0}] _rootSignature is null!", _name);
return;
}
// Compile shader blobs
auto _recEncodeShader = CompileShader(InShaderCode.c_str(), InEntry.c_str(), InTarget.c_str());
if (_recEncodeShader == nullptr)
{
spdlog::error("CS_Dx12::CS_Dx12 [{0}] CompileShader error!", _name);
return;
}
// create pso objects
if (!CreateComputeShader(InDevice, _rootSignature, &_pipelineState, _recEncodeShader))
{
spdlog::error("CS_Dx12::CS_Dx12 [{0}] CreateComputeShader error!", _name);
return;
}
if (_recEncodeShader != nullptr)
{
_recEncodeShader->Release();
_recEncodeShader = nullptr;
}
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
heapDesc.NumDescriptors = 2; // One for SRV and one for UAV
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
auto hr = InDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&_srvHeap[0]));
if (FAILED(hr))
{
spdlog::error("CS_Dx12::CS_Dx12 [{0}] CreateDescriptorHeap[0] error {1:x}", _name, hr);
return;
}
hr = InDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&_srvHeap[1]));
if (FAILED(hr))
{
spdlog::error("CS_Dx12::CS_Dx12 [{0}] CreateDescriptorHeap[1] error {1:x}", _name, hr);
return;
}
_init = _srvHeap[1] != nullptr;
}
CS_Dx12::~CS_Dx12()
{
if (!_init)
return;
ID3D12Fence* d3d12Fence = nullptr;
do
{
if (_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3d12Fence)) != S_OK)
break;
d3d12Fence->Signal(999);
HANDLE fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (fenceEvent != NULL && d3d12Fence->SetEventOnCompletion(999, fenceEvent) == S_OK)
{
WaitForSingleObject(fenceEvent, INFINITE);
CloseHandle(fenceEvent);
}
} while (false);
if (d3d12Fence != nullptr)
{
d3d12Fence->Release();
d3d12Fence = nullptr;
}
if (_rootSignature != nullptr)
{
_rootSignature->Release();
_rootSignature = nullptr;
}
if (_pipelineState != nullptr)
{
_pipelineState->Release();
_pipelineState = nullptr;
}
if (_srvHeap[0] != nullptr)
{
_srvHeap[0]->Release();
_srvHeap[0] = nullptr;
}
if (_srvHeap[1] != nullptr)
{
_srvHeap[1]->Release();
_srvHeap[1] = nullptr;
}
if (_buffer != nullptr)
{
_buffer->Release();
_buffer = nullptr;
}
}