duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

d3d12_descriptor_heap_manager.cpp (4781B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR PolyForm-Strict-1.0.0)
      3 
      4 #include "d3d12_descriptor_heap_manager.h"
      5 
      6 #include "common/assert.h"
      7 #include "common/error.h"
      8 
      9 D3D12DescriptorHeapManager::D3D12DescriptorHeapManager() = default;
     10 D3D12DescriptorHeapManager::~D3D12DescriptorHeapManager() = default;
     11 
     12 bool D3D12DescriptorHeapManager::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors,
     13                                         bool shader_visible, Error* error)
     14 {
     15   D3D12_DESCRIPTOR_HEAP_DESC desc = {
     16     type, static_cast<UINT>(num_descriptors),
     17     shader_visible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 0u};
     18 
     19   HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(m_descriptor_heap.ReleaseAndGetAddressOf()));
     20   if (FAILED(hr)) [[unlikely]]
     21   {
     22     Error::SetHResult(error, "CreateDescriptorHeap() failed: ", hr);
     23     return false;
     24   }
     25 
     26   m_heap_base_cpu = m_descriptor_heap->GetCPUDescriptorHandleForHeapStart();
     27   if (shader_visible)
     28     m_heap_base_gpu = m_descriptor_heap->GetGPUDescriptorHandleForHeapStart();
     29 
     30   m_num_descriptors = num_descriptors;
     31   m_descriptor_increment_size = device->GetDescriptorHandleIncrementSize(type);
     32   m_shader_visible = shader_visible;
     33 
     34   // Set all slots to unallocated (1)
     35   const u32 bitset_count = num_descriptors / BITSET_SIZE + (((num_descriptors % BITSET_SIZE) != 0) ? 1 : 0);
     36   m_free_slots.resize(bitset_count);
     37   for (BitSetType& bs : m_free_slots)
     38     bs.flip();
     39 
     40   return true;
     41 }
     42 
     43 void D3D12DescriptorHeapManager::Destroy()
     44 {
     45 #ifdef _DEBUG
     46   for (BitSetType& bs : m_free_slots)
     47   {
     48     DebugAssert(bs.all());
     49   }
     50 #endif
     51 
     52   m_shader_visible = false;
     53   m_num_descriptors = 0;
     54   m_descriptor_increment_size = 0;
     55   m_heap_base_cpu = {};
     56   m_heap_base_gpu = {};
     57   m_descriptor_heap.Reset();
     58   m_free_slots.clear();
     59 }
     60 
     61 bool D3D12DescriptorHeapManager::Allocate(D3D12DescriptorHandle* handle)
     62 {
     63   // Start past the temporary slots, no point in searching those.
     64   for (u32 group = 0; group < m_free_slots.size(); group++)
     65   {
     66     BitSetType& bs = m_free_slots[group];
     67     if (bs.none())
     68       continue;
     69 
     70     u32 bit = 0;
     71     for (; bit < BITSET_SIZE; bit++)
     72     {
     73       if (bs[bit])
     74         break;
     75     }
     76 
     77     u32 index = group * BITSET_SIZE + bit;
     78     bs[bit] = false;
     79 
     80     handle->index = index;
     81     handle->cpu_handle.ptr = m_heap_base_cpu.ptr + index * m_descriptor_increment_size;
     82     handle->gpu_handle.ptr = m_shader_visible ? (m_heap_base_gpu.ptr + index * m_descriptor_increment_size) : 0;
     83     return true;
     84   }
     85 
     86   Panic("Out of fixed descriptors");
     87   return false;
     88 }
     89 
     90 void D3D12DescriptorHeapManager::Free(u32 index)
     91 {
     92   DebugAssert(index < m_num_descriptors);
     93 
     94   u32 group = index / BITSET_SIZE;
     95   u32 bit = index % BITSET_SIZE;
     96   m_free_slots[group][bit] = true;
     97 }
     98 
     99 void D3D12DescriptorHeapManager::Free(D3D12DescriptorHandle* handle)
    100 {
    101   if (handle->index == D3D12DescriptorHandle::INVALID_INDEX)
    102     return;
    103 
    104   Free(handle->index);
    105   handle->Clear();
    106 }
    107 
    108 D3D12DescriptorAllocator::D3D12DescriptorAllocator() = default;
    109 D3D12DescriptorAllocator::~D3D12DescriptorAllocator() = default;
    110 
    111 bool D3D12DescriptorAllocator::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors, Error* error)
    112 {
    113   const D3D12_DESCRIPTOR_HEAP_DESC desc = {type, static_cast<UINT>(num_descriptors),
    114                                            D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, 0u};
    115   const HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(m_descriptor_heap.ReleaseAndGetAddressOf()));
    116   if (FAILED(hr))
    117   {
    118     Error::SetHResult(error, "CreateDescriptorHeap() failed: ", hr);
    119     return false;
    120   }
    121 
    122   m_num_descriptors = num_descriptors;
    123   m_descriptor_increment_size = device->GetDescriptorHandleIncrementSize(type);
    124   m_heap_base_cpu = m_descriptor_heap->GetCPUDescriptorHandleForHeapStart();
    125   m_heap_base_gpu = m_descriptor_heap->GetGPUDescriptorHandleForHeapStart();
    126   return true;
    127 }
    128 
    129 void D3D12DescriptorAllocator::Destroy()
    130 {
    131   m_descriptor_heap.Reset();
    132   m_descriptor_increment_size = 0;
    133   m_num_descriptors = 0;
    134   m_current_offset = 0;
    135   m_heap_base_cpu = {};
    136   m_heap_base_gpu = {};
    137 }
    138 
    139 bool D3D12DescriptorAllocator::Allocate(u32 num_handles, D3D12DescriptorHandle* out_base_handle)
    140 {
    141   if ((m_current_offset + num_handles) > m_num_descriptors)
    142     return false;
    143 
    144   out_base_handle->index = m_current_offset;
    145   out_base_handle->cpu_handle.ptr = m_heap_base_cpu.ptr + m_current_offset * m_descriptor_increment_size;
    146   out_base_handle->gpu_handle.ptr = m_heap_base_gpu.ptr + m_current_offset * m_descriptor_increment_size;
    147   m_current_offset += num_handles;
    148   return true;
    149 }
    150 
    151 void D3D12DescriptorAllocator::Reset()
    152 {
    153   m_current_offset = 0;
    154 }