SleakEngine 1.0.0
C++23 multi-backend game engine
Loading...
Searching...
No Matches
DirectX11Buffer.cpp
Go to the documentation of this file.
3#include <cassert>
5#include <Math/Matrix.hpp>
6
7namespace Sleak {
8namespace RenderEngine {
9
10/// Derives usage/bind/CPU-access flags from the buffer type via ConfigureFromBufferType.
11DirectX11Buffer::DirectX11Buffer(ID3D11Device* device, size_t size, BufferType type)
12 : BufferBase()
13{
14 assert(device != nullptr);
15 m_device = device;
16 device->GetImmediateContext(m_deviceContext.GetAddressOf());
17 Size = size;
18 ConfigureFromBufferType(type);
19 this->Type = type;
20}
21
22DirectX11Buffer::DirectX11Buffer(ID3D11Device* device, size_t size,
23 D3D11_USAGE usage, UINT bindFlags, UINT cpuAccessFlags)
24 : BufferBase(),
25 m_usage(usage),
26 m_bindFlags(bindFlags),
27 m_cpuAccessFlags(cpuAccessFlags)
28{
29 assert(device != nullptr);
30 m_device = device;
31 device->GetImmediateContext(m_deviceContext.GetAddressOf());
32 Size = size;
33}
34
36 : BufferBase(std::move(other)),
37 m_device(std::move(other.m_device)),
38 m_deviceContext(std::move(other.m_deviceContext)),
39 m_buffer(std::move(other.m_buffer)),
40 m_usage(other.m_usage),
41 m_bindFlags(other.m_bindFlags),
42 m_cpuAccessFlags(other.m_cpuAccessFlags),
43 m_mappedResource(other.m_mappedResource)
44{
45 other.m_mappedResource = {};
46}
47
49{
50 if (this != &other) {
51 Cleanup();
52
53 BufferBase::operator=(std::move(other));
54 m_device = std::move(other.m_device);
55 m_deviceContext = std::move(other.m_deviceContext);
56 m_buffer = std::move(other.m_buffer);
57 m_usage = other.m_usage;
58 m_bindFlags = other.m_bindFlags;
59 m_cpuAccessFlags = other.m_cpuAccessFlags;
60 m_mappedResource = other.m_mappedResource;
61
62 other.m_mappedResource = {};
63 }
64 return *this;
65}
66
71
72void DirectX11Buffer::ConfigureFromBufferType(BufferType type)
73{
74 switch (type) {
76 m_usage = D3D11_USAGE_DEFAULT;
77 m_bindFlags = D3D11_BIND_VERTEX_BUFFER;
78 m_cpuAccessFlags = 0;
79 break;
80
82 m_usage = D3D11_USAGE_DEFAULT;
83 m_bindFlags = D3D11_BIND_INDEX_BUFFER;
84 m_cpuAccessFlags = 0;
85 break;
86
88 m_usage = D3D11_USAGE_DEFAULT;
89 m_bindFlags = D3D11_BIND_CONSTANT_BUFFER;
90 m_cpuAccessFlags = 0;
91 break;
92
93 default:
94 m_usage = D3D11_USAGE_DYNAMIC;
95 m_bindFlags = D3D11_BIND_SHADER_RESOURCE;
96 m_cpuAccessFlags = D3D11_CPU_ACCESS_WRITE;
97 break;
98 }
99}
100
101D3D11_BUFFER_DESC DirectX11Buffer::CreateBufferDesc() const
102{
103 D3D11_BUFFER_DESC desc = {};
104 desc.ByteWidth = static_cast<UINT>(Size);
105 desc.Usage = m_usage;
106 desc.BindFlags = m_bindFlags;
107 desc.CPUAccessFlags = m_cpuAccessFlags;
108 desc.MiscFlags = 0;
109 desc.StructureByteStride = 0;
110 return desc;
111}
112
114 return Initialize(Data,Size);
115}
116
117bool DirectX11Buffer::Initialize(const void* data, uint16_t size)
118{
119 if (!m_device || Size == 0)
120 return false;
121
122 if (m_buffer)
123 Cleanup();
124
125 D3D11_SUBRESOURCE_DATA resource;
126 resource.pSysMem = data;
127
128 auto desc = CreateBufferDesc();
129 HRESULT hr = m_device->CreateBuffer(&desc, data != nullptr ? &resource : nullptr, m_buffer.GetAddressOf());
130
131 if (FAILED(hr)) {
132 SLEAK_ERROR("Failed to create DirectX11 buffer! HRESULT: 0x{:08X}", static_cast<unsigned int>(hr));
133 return false;
134 }
135
136 bIsInitialized = true;
137 return true;
138}
139
141 UINT stride = sizeof(Sleak::Vertex);
142 UINT offset = 0;
143
144 switch (Type) {
146 m_deviceContext->IASetVertexBuffers(Slot, 1, m_buffer.GetAddressOf(), &stride, &offset);
147 break;
149 m_deviceContext->IASetIndexBuffer(m_buffer.Get(),DXGI_FORMAT_R32_UINT,0);
150 break;
152 m_deviceContext->VSSetConstantBuffers(Slot,1,m_buffer.GetAddressOf());
153 m_deviceContext->PSSetConstantBuffers(Slot,1,m_buffer.GetAddressOf());
154 break;
155 default:
156 SLEAK_ERROR("Unknown buffer type passed!");
157 }
158}
159
161{
162 if (bIsMapped) {
163 Unmap();
164 }
165
166 m_buffer.Reset();
167 bIsInitialized = false;
168 Size = 0;
169 Data = nullptr;
170 bIsMapped = false;
171}
172
174{
175 if (!m_buffer || !m_deviceContext || bIsMapped)
176 return false;
177
178 D3D11_MAP mapType = (m_cpuAccessFlags & D3D11_CPU_ACCESS_READ)
179 ? D3D11_MAP_READ
180 : (m_usage == D3D11_USAGE_DYNAMIC ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE);
181
182 HRESULT hr = m_deviceContext->Map(m_buffer.Get(), 0, mapType, 0, &m_mappedResource);
183
184 if (FAILED(hr)) {
185 SLEAK_ERROR("Failed to map DirectX11 buffer! HRESULT: 0x{:08X}", static_cast<unsigned int>(hr));
186 return false;
187 }
188
189 Data = m_mappedResource.pData;
190 bIsMapped = true;
191 return true;
192}
193
195{
196 if (m_buffer && m_deviceContext && bIsMapped) {
197 m_deviceContext->Unmap(m_buffer.Get(), 0);
198 Data = nullptr;
199 bIsMapped = false;
200 }
201}
202
203void DirectX11Buffer::Update(void* data, size_t size)
204{
205 if (!m_buffer || !m_deviceContext || size > Size || !data)
206 return;
207
208 // Store CPU shadow copy for transform CBs (needed by shadow pass)
209 if (Type == BufferType::Constant && size <= 128) {
210 StoreCPUShadowCopy(data, size);
211 }
212
213 if (m_cpuAccessFlags != 0) {
214 // CPU-accessible buffer
215 if (!bIsMapped && !Map())
216 return;
217
218 memcpy(Data, data, size);
219 Unmap();
220 }
221 else {
222 // GPU-only buffer
223 m_deviceContext->UpdateSubresource(m_buffer.Get(), 0, nullptr, data, 0, 0);
224 }
225}
226
227/// Returns CPU-visible data directly for readable buffers, or round-trips GPU-only buffers through a staging copy.
229 if (!m_buffer || !m_deviceContext) {
230 SLEAK_ERROR("Buffer or device context is null!");
231 return nullptr;
232 }
233
234 // If the buffer is CPU-readable, map it and return the data
235 if (m_cpuAccessFlags & D3D11_CPU_ACCESS_READ) {
236 if (!bIsMapped && !Map()) {
237 SLEAK_ERROR("Failed to map buffer for reading!");
238 return nullptr;
239 }
240
241 // Return the mapped data
242 return Data;
243 }
244
245 // If the buffer is GPU-only, create a staging buffer to copy the data
246 else {
247 // Create a staging buffer description
248 D3D11_BUFFER_DESC stagingDesc = {};
249 stagingDesc.ByteWidth = static_cast<UINT>(Size);
250 stagingDesc.Usage = D3D11_USAGE_STAGING;
251 stagingDesc.BindFlags = 0; // No bind flags for staging buffers
252 stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
253 stagingDesc.MiscFlags = 0;
254 stagingDesc.StructureByteStride = 0;
255
256 // Create the staging buffer
257 Microsoft::WRL::ComPtr<ID3D11Buffer> stagingBuffer;
258 HRESULT hr =
259 m_device->CreateBuffer(&stagingDesc, nullptr, &stagingBuffer);
260 if (FAILED(hr)) {
261 SLEAK_ERROR("Failed to create staging buffer! HRESULT: 0x{:08X}",
262 static_cast<unsigned int>(hr));
263 return nullptr;
264 }
265
266 // Copy the data from the GPU buffer to the staging buffer
267 m_deviceContext->CopyResource(stagingBuffer.Get(), m_buffer.Get());
268
269 // Map the staging buffer to read the data
270 D3D11_MAPPED_SUBRESOURCE mappedResource;
271 hr = m_deviceContext->Map(stagingBuffer.Get(), 0, D3D11_MAP_READ, 0,
272 &mappedResource);
273 if (FAILED(hr)) {
274 SLEAK_ERROR("Failed to map staging buffer! HRESULT: 0x{:08X}",
275 static_cast<unsigned int>(hr));
276 return nullptr;
277 }
278
279 // Allocate memory to store the data
280 void* data = malloc(Size);
281 if (!data) {
282 SLEAK_ERROR("Failed to allocate memory for buffer data!");
283 m_deviceContext->Unmap(stagingBuffer.Get(), 0);
284 return nullptr;
285 }
286
287 // Copy the data from the staging buffer to the allocated memory
288 memcpy(data, mappedResource.pData, Size);
289
290 // Unmap the staging buffer
291 m_deviceContext->Unmap(stagingBuffer.Get(), 0);
292
293 // Return the copied data
294 return data;
295 }
296}
297
298} // namespace RenderEngine
299} // namespace Sleak
#define SLEAK_ERROR(...)
Definition Logger.hpp:22
Backend-agnostic GPU buffer: vertex, index, constant, or resource view target.
void StoreCPUShadowCopy(const void *data, size_t size)
Copies up to 128 bytes into the inline shadow-copy storage, clamping oversized input.
void * GetData() override
Returns CPU-visible data directly for readable buffers, or round-trips GPU-only buffers through a sta...
bool Map() override
Maps the buffer for CPU writes (dynamic usage only).
DirectX11Buffer & operator=(const DirectX11Buffer &)=delete
DirectX11Buffer(ID3D11Device *device, size_t size, BufferType type)
Derives usage/bind/CPU-access flags from the buffer type via ConfigureFromBufferType.
bool Initialize(void *Data) override
Creates the D3D11 buffer resource and uploads initial data, if any.
Backend-facing rendering layer shared by the four graphics backends.
BufferType
GPU buffer usage kind, drives backend binding flags and layout.
Root namespace for everything the engine exposes.
Definition Camera.hpp:10