blob: 62f40634b9d432d7c8f2badc9a871be1ee912f90 [file] [log] [blame] [edit]
/*
* Copyright 2025 Rive
*/
#include "rive/renderer/d3d12/d3d12_utils.hpp"
namespace rive::gpu
{
void print_sig_descriptor(LPCVOID data, SIZE_T size)
{
ComPtr<ID3D12RootSignatureDeserializer> descS;
D3D12CreateRootSignatureDeserializer(data, size, IID_PPV_ARGS(&descS));
auto desc = descS->GetRootSignatureDesc();
printf("desc {\n");
for (size_t i = 0; i < desc->NumParameters; ++i)
{
const char* type;
switch (desc->pParameters[i].ParameterType)
{
case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
type = "table";
break;
case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
type = "constant";
break;
case D3D12_ROOT_PARAMETER_TYPE_CBV:
type = "cbv";
break;
case D3D12_ROOT_PARAMETER_TYPE_SRV:
type = "srv";
break;
case D3D12_ROOT_PARAMETER_TYPE_UAV:
type = "uav";
break;
default:
type = "unkown";
}
printf("root desc name %s\n", type);
}
printf("}\n");
}
#if defined(DEBUG)
void SetName(D3D12Resource* pObject, LPCWSTR name) { pObject->SetName(name); }
#else
void printDescriptor(LPCVOID data, SIZE_T size) {}
void SetName(ID3D12Object*, LPCWSTR) {}
#endif
D3D12DescriptorHeap::D3D12DescriptorHeap(rcp<GPUResourceManager> manager,
ID3D12Device* device,
UINT numDescriptors,
D3D12_DESCRIPTOR_HEAP_TYPE type,
D3D12_DESCRIPTOR_HEAP_FLAGS flags) :
GPUResource(std::move(manager)),
#ifndef NDEBUG
m_type(type),
m_flags(flags),
#endif
m_heapDescriptorSize(device->GetDescriptorHandleIncrementSize(type))
{
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
desc.Type = type;
desc.NumDescriptors = numDescriptors;
desc.Flags = flags;
VERIFY_OK(device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&m_heap)));
}
void D3D12DescriptorHeap::markSamplerToIndex(ID3D12Device* device,
const D3D12_SAMPLER_DESC& desc,
UINT index)
{
assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
CD3DX12_CPU_DESCRIPTOR_HANDLE samplerHandle(
m_heap->GetCPUDescriptorHandleForHeapStart(),
index,
m_heapDescriptorSize);
device->CreateSampler(&desc, samplerHandle);
}
void D3D12DescriptorHeap::markCbvToIndex(ID3D12Device* device,
D3D12Buffer* resource,
UINT index,
UINT sizeInBytes,
SIZE_T offset)
{
assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc;
cbvDesc.SizeInBytes = sizeInBytes;
cbvDesc.BufferLocation =
resource->resource()->GetGPUVirtualAddress() + offset;
CD3DX12_CPU_DESCRIPTOR_HANDLE cbvHandle(
m_heap->GetCPUDescriptorHandleForHeapStart(),
index,
m_heapDescriptorSize);
device->CreateConstantBufferView(&cbvDesc, cbvHandle);
}
void D3D12DescriptorHeap::markSrvToIndex(ID3D12Device* device,
D3D12Buffer* resource,
UINT index,
UINT numElements,
UINT elementByteStride,
UINT64 firstElement)
{
assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
srvDesc.Buffer.FirstElement = firstElement;
srvDesc.Buffer.NumElements = numElements;
srvDesc.Buffer.StructureByteStride = elementByteStride;
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
srvDesc.Format = resource->desc().Format;
CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle(
m_heap->GetCPUDescriptorHandleForHeapStart(),
index,
m_heapDescriptorSize);
device->CreateShaderResourceView(resource->resource(), &srvDesc, srvHandle);
}
void D3D12DescriptorHeap::markUavToIndex(ID3D12Device* device,
D3D12Buffer* resource,
DXGI_FORMAT format,
UINT index,
UINT numElements,
UINT elementByteStride)
{
assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
uavDesc.Buffer.CounterOffsetInBytes = 0;
uavDesc.Buffer.FirstElement = 0;
uavDesc.Buffer.NumElements = numElements;
uavDesc.Buffer.StructureByteStride = elementByteStride;
uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
uavDesc.Format = format;
CD3DX12_CPU_DESCRIPTOR_HANDLE uavHandle(
m_heap->GetCPUDescriptorHandleForHeapStart(),
index,
m_heapDescriptorSize);
device->CreateUnorderedAccessView(resource->resource(),
nullptr,
&uavDesc,
uavHandle);
}
void D3D12DescriptorHeap::markSrvToIndex(ID3D12Device* device,
D3D12Texture* resource,
UINT index)
{
assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = resource->desc().MipLevels;
srvDesc.Texture2D.PlaneSlice = 0;
srvDesc.Format = resource->desc().Format;
CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle(
m_heap->GetCPUDescriptorHandleForHeapStart(),
index,
m_heapDescriptorSize);
device->CreateShaderResourceView(resource->resource(), &srvDesc, srvHandle);
}
void D3D12DescriptorHeap::markSrvToIndex(ID3D12Device* device,
D3D12TextureArray* resource,
UINT index)
{
assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
srvDesc.Texture1DArray.MipLevels = resource->desc().MipLevels;
srvDesc.Texture1DArray.ArraySize = resource->length();
srvDesc.Texture1DArray.FirstArraySlice = 0;
srvDesc.Format = resource->desc().Format;
CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle(
m_heap->GetCPUDescriptorHandleForHeapStart(),
index,
m_heapDescriptorSize);
device->CreateShaderResourceView(resource->resource(), &srvDesc, srvHandle);
}
void D3D12DescriptorHeap::markUavToIndex(ID3D12Device* device,
D3D12Texture* resource,
DXGI_FORMAT format,
UINT index)
{
assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
uavDesc.Texture2D.MipSlice = 0;
uavDesc.Texture2D.PlaneSlice = 0;
uavDesc.Format = format;
CD3DX12_CPU_DESCRIPTOR_HANDLE uavHandle(
m_heap->GetCPUDescriptorHandleForHeapStart(),
index,
m_heapDescriptorSize);
device->CreateUnorderedAccessView(resource->resource(),
nullptr,
&uavDesc,
uavHandle);
}
void D3D12DescriptorHeap::markRtvToIndex(ID3D12Device* device,
D3D12Texture* resource,
UINT index)
{
assert(m_type == D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_RENDER_TARGET_VIEW_DESC RTVDesc = {};
RTVDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
RTVDesc.Texture2D.MipSlice = 0;
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(
m_heap->GetCPUDescriptorHandleForHeapStart(),
index,
m_heapDescriptorSize);
device->CreateRenderTargetView(resource->resource(), &RTVDesc, rtvHandle);
}
D3D12Resource::D3D12Resource(rcp<GPUResourceManager> manager,
ComPtr<ID3D12Resource> resource,
D3D12_RESOURCE_STATES initialState) :
GPUResource(std::move(manager)),
m_resource(resource),
m_lastState(initialState),
m_desc(m_resource->GetDesc()),
m_heapPropeties(D3D12_HEAP_TYPE_DEFAULT),
m_heapFlags(D3D12_HEAP_FLAG_NONE)
{}
D3D12Resource::D3D12Resource(rcp<GPUResourceManager> manager,
ID3D12Device* device,
D3D12_RESOURCE_STATES initialState,
D3D12_HEAP_FLAGS heapFlags,
const D3D12_RESOURCE_DESC& resourceDesc,
const D3D12_CLEAR_VALUE* clearValue) :
GPUResource(std::move(manager)),
m_lastState(initialState),
m_desc(std::move(resourceDesc)),
m_heapFlags(heapFlags)
{
m_heapPropeties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
VERIFY_OK(device->CreateCommittedResource(&m_heapPropeties,
heapFlags,
&m_desc,
m_lastState,
clearValue,
IID_PPV_ARGS(&m_resource)));
}
D3D12Resource::D3D12Resource(rcp<GPUResourceManager> manager,
ID3D12Device* device,
D3D12_RESOURCE_STATES initialState,
D3D12_HEAP_FLAGS heapFlags,
CD3DX12_HEAP_PROPERTIES heapPropeties,
const D3D12_RESOURCE_DESC& desc,
const D3D12_CLEAR_VALUE* clearValue) :
GPUResource(std::move(manager)),
m_lastState(initialState),
m_desc(std::move(desc)),
m_heapPropeties(heapPropeties),
m_heapFlags(heapFlags)
{
VERIFY_OK(device->CreateCommittedResource(&m_heapPropeties,
heapFlags,
&m_desc,
m_lastState,
clearValue,
IID_PPV_ARGS(&m_resource)));
}
void* D3D12Buffer::map()
{
assert(m_sizeInBytes);
assert(!m_isMapped);
assert(m_heapPropeties.IsCPUAccessible());
void* data = nullptr;
VERIFY_OK(m_resource->Map(0, nullptr, &data));
#ifndef NDEBUG
m_isMapped = true;
#endif
return data;
}
void D3D12Buffer::unmap()
{
assert(m_isMapped);
assert(m_heapPropeties.IsCPUAccessible());
m_resource->Unmap(0, nullptr);
#ifndef NDEBUG
m_isMapped = false;
#endif
}
D3D12VolatileBuffer::D3D12VolatileBuffer(rcp<D3D12ResourceManager> manager,
UINT initialSize,
D3D12_RESOURCE_FLAGS bindFlags,
D3D12_HEAP_FLAGS heapFlags) :
GPUResource(std::move(manager)),
m_bindFlags(bindFlags),
m_heapFlags(heapFlags)
{
assert(initialSize > 0);
resizeBuffers(initialSize);
}
D3D12ResourceManager* D3D12VolatileBuffer::d3d() const
{
return static_cast<D3D12ResourceManager*>(m_manager.get());
}
void D3D12VolatileBuffer::sync(ID3D12GraphicsCommandList* cmdList,
UINT64 offsetBytes)
{
assert(m_uploadBuffer->sizeInBytes() == m_gpuBuffer->sizeInBytes());
sync(cmdList, offsetBytes, m_uploadBuffer->sizeInBytes());
}
void D3D12VolatileBuffer::sync(ID3D12GraphicsCommandList* cmdList,
UINT64 offsetBytes,
UINT64 bytesToSync)
{
assert(bytesToSync);
d3d()->transition(cmdList,
m_gpuBuffer.get(),
D3D12_RESOURCE_STATE_COPY_DEST);
cmdList->CopyBufferRegion(m_gpuBuffer->resource(),
0,
m_uploadBuffer->resource(),
offsetBytes,
bytesToSync);
d3d()->transition(cmdList, m_gpuBuffer.get(), D3D12_RESOURCE_STATE_COMMON);
}
void D3D12VolatileBuffer::syncToBuffer(ID3D12GraphicsCommandList* cmdList,
D3D12Buffer* buffer,
UINT64 offsetBytes,
UINT64 bytesToSync) const
{
assert(buffer->sizeInBytes() >= bytesToSync);
cmdList->CopyBufferRegion(buffer->resource(),
0,
m_uploadBuffer->resource(),
offsetBytes,
bytesToSync);
}
void D3D12VolatileBuffer::resizeBuffers(UINT newSize)
{
m_uploadBuffer = d3d()->makeUploadBuffer(newSize,
D3D12_RESOURCE_FLAG_NONE,
D3D12_RESOURCE_STATE_COPY_SOURCE);
m_gpuBuffer = d3d()->makeBuffer(newSize,
m_bindFlags,
D3D12_RESOURCE_STATE_COMMON,
m_heapFlags);
}
rcp<D3D12Buffer> D3D12ResourceManager::makeBuffer(
UINT size,
D3D12_RESOURCE_FLAGS bindFlags,
D3D12_RESOURCE_STATES initialState,
D3D12_HEAP_FLAGS heapFlags)
{
auto desc = CD3DX12_RESOURCE_DESC::Buffer(size);
return make_rcp<D3D12Buffer>(ref_rcp(this),
m_device.Get(),
initialState,
heapFlags,
size,
desc);
}
rcp<D3D12Buffer> D3D12ResourceManager::makeUploadBuffer(
UINT size,
D3D12_RESOURCE_FLAGS bindFlags,
D3D12_RESOURCE_STATES initialState,
D3D12_HEAP_FLAGS heapFlags)
{
auto desc = CD3DX12_RESOURCE_DESC::Buffer(size);
return make_rcp<D3D12Buffer>(
ref_rcp(this),
m_device.Get(),
initialState,
heapFlags,
CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
size,
desc);
}
rcp<D3D12VolatileBuffer> D3D12ResourceManager::makeVolatileBuffer(
UINT size,
D3D12_RESOURCE_FLAGS bindFlags,
D3D12_HEAP_FLAGS heapFlags)
{
return make_rcp<D3D12VolatileBuffer>(ref_rcp(this),
size,
bindFlags,
heapFlags);
}
rcp<D3D12DescriptorHeap> D3D12ResourceManager::makeHeap(
UINT numDescriptors,
D3D12_DESCRIPTOR_HEAP_TYPE type,
D3D12_DESCRIPTOR_HEAP_FLAGS flags)
{
return make_rcp<D3D12DescriptorHeap>(ref_rcp(this),
m_device.Get(),
numDescriptors,
type,
flags);
}
rcp<D3D12TextureArray> D3D12ResourceManager::make1DTextureArray(
UINT width,
UINT16 length,
UINT mipLevelCount,
DXGI_FORMAT format,
D3D12_RESOURCE_FLAGS bindFlags,
D3D12_RESOURCE_STATES initialState,
D3D12_HEAP_FLAGS heapFlags)
{
D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Tex1D(format,
width,
length,
mipLevelCount,
bindFlags);
return make_rcp<D3D12TextureArray>(ref_rcp(this),
m_device.Get(),
initialState,
heapFlags,
desc);
}
rcp<D3D12Texture> D3D12ResourceManager::make2DTexture(
UINT width,
UINT height,
UINT mipLevelCount,
DXGI_FORMAT format,
D3D12_RESOURCE_FLAGS bindFlags,
D3D12_RESOURCE_STATES initialState,
D3D12_HEAP_FLAGS heapFlags,
const D3D12_CLEAR_VALUE* clearValue)
{
D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Tex2D(format,
width,
height,
1,
mipLevelCount,
1,
0,
bindFlags);
return make_rcp<D3D12Texture>(ref_rcp(this),
m_device.Get(),
initialState,
heapFlags,
desc,
clearValue);
}
rcp<D3D12Texture> D3D12ResourceManager::makeExternalTexture(
ComPtr<ID3D12Resource> externalTexture,
D3D12_RESOURCE_STATES lastState)
{
return make_rcp<D3D12Texture>(ref_rcp(this), externalTexture, lastState);
}
void D3D12ResourceManager::transition(ID3D12GraphicsCommandList* cmdList,
D3D12Resource* resource,
D3D12_RESOURCE_STATES toState)
{
assert(resource->m_lastState != toState);
auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(resource->resource(),
resource->m_lastState,
toState);
cmdList->ResourceBarrier(1, &barrier);
resource->m_lastState = toState;
}
void D3D12ResourceManager::clearUAV(ID3D12GraphicsCommandList* cmdList,
ID3D12Resource* resource,
CD3DX12_GPU_DESCRIPTOR_HANDLE& gpuHandle,
CD3DX12_CPU_DESCRIPTOR_HANDLE& cpuHandle,
const UINT clearColor[4],
bool needsBarrier)
{
if (needsBarrier)
{
D3D12_RESOURCE_BARRIER barriers[] = {
CD3DX12_RESOURCE_BARRIER::UAV(resource)};
cmdList->ResourceBarrier(1, barriers);
}
cmdList->ClearUnorderedAccessViewUint(gpuHandle,
cpuHandle,
resource,
clearColor,
0,
nullptr);
if (needsBarrier)
{
D3D12_RESOURCE_BARRIER barriers[] = {
CD3DX12_RESOURCE_BARRIER::UAV(resource)};
cmdList->ResourceBarrier(1, barriers);
}
}
void D3D12ResourceManager::clearUAV(ID3D12GraphicsCommandList* cmdList,
ID3D12Resource* resource,
CD3DX12_GPU_DESCRIPTOR_HANDLE& gpuHandle,
CD3DX12_CPU_DESCRIPTOR_HANDLE& cpuHandle,
const float clearColor[4],
bool needsBarrier)
{
if (needsBarrier)
{
D3D12_RESOURCE_BARRIER barriers[] = {
CD3DX12_RESOURCE_BARRIER::UAV(resource)};
cmdList->ResourceBarrier(1, barriers);
}
cmdList->ClearUnorderedAccessViewFloat(gpuHandle,
cpuHandle,
resource,
clearColor,
0,
nullptr);
if (needsBarrier)
{
D3D12_RESOURCE_BARRIER barriers[] = {
CD3DX12_RESOURCE_BARRIER::UAV(resource)};
cmdList->ResourceBarrier(1, barriers);
}
}
D3D12VolatileBufferPool::D3D12VolatileBufferPool(
rcp<D3D12ResourceManager> manager,
UINT alignment,
UINT size) :
GPUResourcePool(std::move(manager), MAX_POOL_SIZE),
m_targetSize(std::max<UINT>(size, m_alignment)),
m_alignment(alignment)
{}
inline D3D12ResourceManager* D3D12VolatileBufferPool::d3d() const
{
return static_cast<D3D12ResourceManager*>(m_manager.get());
}
void D3D12VolatileBufferPool::setTargetSize(size_t size)
{
m_targetSize = std::max<UINT>(static_cast<UINT>(size), m_alignment);
assert(m_targetSize % m_alignment == 0);
}
rcp<D3D12VolatileBuffer> D3D12VolatileBufferPool::acquire()
{
auto buffer =
static_rcp_cast<D3D12VolatileBuffer>(GPUResourcePool::acquire());
if (buffer == nullptr)
{
buffer = d3d()->makeVolatileBuffer(m_targetSize);
}
else if (buffer->sizeInBytes() != m_targetSize)
{
buffer->resizeBuffers(m_targetSize);
}
return buffer;
}
D3D12DescriptorHeapPool::D3D12DescriptorHeapPool(
rcp<D3D12ResourceManager> manager,
UINT numDescriptors,
D3D12_DESCRIPTOR_HEAP_TYPE type,
D3D12_DESCRIPTOR_HEAP_FLAGS flags) :
GPUResourcePool(std::move(manager), MAX_POOL_SIZE),
m_numDescriptors(numDescriptors),
m_type(type),
m_flags(flags)
{}
rcp<D3D12DescriptorHeap> D3D12DescriptorHeapPool::acquire()
{
auto heap =
static_rcp_cast<D3D12DescriptorHeap>(GPUResourcePool::acquire());
if (heap == nullptr)
{
heap = d3d()->makeHeap(m_numDescriptors, m_type, m_flags);
}
return heap;
}
inline D3D12ResourceManager* D3D12DescriptorHeapPool::d3d() const
{
return static_cast<D3D12ResourceManager*>(m_manager.get());
}
}; // namespace rive::gpu