SleakEngine 0.1.0
C++23 multi-backend game engine
Loading...
Searching...
No Matches
DirectX12UploadRing.cpp
Go to the documentation of this file.
1#include <Core/Logger.hpp>
3#include <utility>
4
5namespace Sleak {
6namespace RenderEngine {
7
8namespace {
9constexpr uint64_t kAlignment = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
10
11uint64_t AlignUp(uint64_t value) {
12 return (value + kAlignment - 1) & ~(kAlignment - 1);
13}
14} // namespace
15
16void DirectX12UploadRing::Initialize(ID3D12Device* device, uint32_t frameCount,
17 uint64_t pageSize) {
18 Release();
19 m_device = device;
20 m_pageSize = AlignUp(pageSize);
21 m_frames.resize(frameCount);
22 m_current = 0;
23}
24
25void DirectX12UploadRing::BeginFrame(uint32_t frameIndex) {
26 if (frameIndex >= m_frames.size()) return;
27 m_current = frameIndex;
28 m_frames[frameIndex].page = 0;
29 m_frames[frameIndex].offset = 0;
30}
31
32bool DirectX12UploadRing::Allocate(uint64_t size, Allocation& out) {
33 if (!m_device || m_current >= m_frames.size() || size == 0) return false;
34
35 const uint64_t aligned = AlignUp(size);
36 Frame& frame = m_frames[m_current];
37
38 while (frame.page < frame.pages.size()) {
39 Page& page = frame.pages[frame.page];
40 if (frame.offset + aligned <= page.size) {
41 out.cpu = page.cpu + frame.offset;
42 out.gpu = page.gpu + frame.offset;
43 frame.offset += aligned;
44 return true;
45 }
46 ++frame.page;
47 frame.offset = 0;
48 }
49
50 Page page;
51 if (!CreatePage(aligned > m_pageSize ? aligned : m_pageSize, page))
52 return false;
53 frame.pages.push_back(std::move(page));
54 frame.page = frame.pages.size() - 1;
55
56 Page& fresh = frame.pages.back();
57 out.cpu = fresh.cpu;
58 out.gpu = fresh.gpu;
59 frame.offset = aligned;
60 return true;
61}
62
64 for (Frame& frame : m_frames) {
65 for (Page& page : frame.pages) {
66 if (page.resource && page.cpu) page.resource->Unmap(0, nullptr);
67 }
68 frame.pages.clear();
69 frame.page = 0;
70 frame.offset = 0;
71 }
72 m_frames.clear();
73 m_device = nullptr;
74 m_current = 0;
75}
76
77bool DirectX12UploadRing::CreatePage(uint64_t size, Page& out) {
78 D3D12_HEAP_PROPERTIES heapProps = {};
79 heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
80
81 D3D12_RESOURCE_DESC desc = {};
82 desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
83 desc.Width = size;
84 desc.Height = 1;
85 desc.DepthOrArraySize = 1;
86 desc.MipLevels = 1;
87 desc.Format = DXGI_FORMAT_UNKNOWN;
88 desc.SampleDesc.Count = 1;
89 desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
90
91 HRESULT hr = m_device->CreateCommittedResource(
92 &heapProps, D3D12_HEAP_FLAG_NONE, &desc,
93 D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
94 IID_PPV_ARGS(&out.resource));
95 if (FAILED(hr)) {
96 SLEAK_ERROR("Failed to create upload ring page! HRESULT: 0x{:08X}",
97 static_cast<unsigned int>(hr));
98 return false;
99 }
100 out.resource->SetName(L"UploadRingPage");
101
102 D3D12_RANGE noRead = {0, 0};
103 void* mapped = nullptr;
104 hr = out.resource->Map(0, &noRead, &mapped);
105 if (FAILED(hr)) {
106 SLEAK_ERROR("Failed to map upload ring page! HRESULT: 0x{:08X}",
107 static_cast<unsigned int>(hr));
108 out.resource.Reset();
109 return false;
110 }
111 out.cpu = static_cast<uint8_t*>(mapped);
112 out.gpu = out.resource->GetGPUVirtualAddress();
113 out.size = size;
114 return true;
115}
116
117} // namespace RenderEngine
118} // namespace Sleak
#define SLEAK_ERROR(...)
Definition Logger.hpp:22
void Release()
Unmaps and frees every page. The GPU must be idle.
void BeginFrame(uint32_t frameIndex)
Rewinds the frame's pages. The GPU must be done with that frame.
bool Allocate(uint64_t size, Allocation &out)
Returns 256-byte aligned memory valid until the frame is reused.
void Initialize(ID3D12Device *device, uint32_t frameCount, uint64_t pageSize)
Stores the device and sizes the ring. Pages are created on demand.
Backend-facing rendering layer shared by the four graphics backends.
Root namespace for everything the engine exposes.
Definition Camera.hpp:10
CPU write pointer and matching GPU address of one allocation.