15DirectX12CubemapTexture::DirectX12CubemapTexture(
16 ID3D12Device* device, ID3D12CommandQueue* commandQueue)
17 : m_device(device), m_commandQueue(commandQueue) {}
19DirectX12CubemapTexture::~DirectX12CubemapTexture() {
20 m_uploadBuffer.Reset();
25bool DirectX12CubemapTexture::LoadCubemap(
26 const std::array<std::string, 6>& facePaths) {
27 stbi_set_flip_vertically_on_load(
false);
30 unsigned char* pixels =
nullptr;
33 std::array<FaceData, 6> faces;
35 for (
int i = 0; i < 6; i++) {
37 faces[i].pixels = stbi_load(facePaths[i].c_str(), &faces[i].w,
38 &faces[i].h, &channels, 4);
39 if (!faces[i].pixels) {
41 "DirectX12CubemapTexture: Failed to load face {}: {}", i,
43 for (
int j = 0; j < i; j++)
44 stbi_image_free(faces[j].pixels);
49 for (
int i = 1; i < 6; i++) {
50 if (faces[i].w != faces[0].w || faces[i].h != faces[0].h) {
52 "DirectX12CubemapTexture: Face {} size ({}x{}) doesn't match "
54 i, faces[i].w, faces[i].h, faces[0].w, faces[0].h);
55 for (
int j = 0; j < 6; j++)
56 stbi_image_free(faces[j].pixels);
61 uint32_t faceSize =
static_cast<uint32_t
>(faces[0].w);
62 std::vector<unsigned char*> facePointers;
63 for (
int i = 0; i < 6; i++)
64 facePointers.push_back(faces[i].pixels);
66 bool result = CreateCubemapFromFaces(facePointers, faceSize);
68 for (
int i = 0; i < 6; i++)
69 stbi_image_free(faces[i].pixels);
73 "DirectX12CubemapTexture: Loaded cubemap ({}x{}, 6 faces)",
79bool DirectX12CubemapTexture::LoadEquirectangular(
const std::string& path,
81 stbi_set_flip_vertically_on_load(
false);
83 int panW, panH, channels;
84 unsigned char* panorama =
85 stbi_load(path.c_str(), &panW, &panH, &channels, 4);
88 "DirectX12CubemapTexture: Failed to load panorama: {}", path);
92 size_t faceBytes =
static_cast<size_t>(faceSize) * faceSize * 4;
93 std::vector<std::vector<unsigned char>> allFaces(6);
94 for (
int i = 0; i < 6; i++)
95 allFaces[i].resize(faceBytes);
97 for (
int face = 0; face < 6; ++face) {
98 unsigned char* faceData = allFaces[face].data();
100 for (uint32_t y = 0; y < faceSize; ++y) {
101 for (uint32_t x = 0; x < faceSize; ++x) {
102 float u = (2.0f * (x + 0.5f) / faceSize) - 1.0f;
103 float v = (2.0f * (y + 0.5f) / faceSize) - 1.0f;
107 case 0: dx = 1.0f; dy = -v; dz = -u;
break;
108 case 1: dx = -1.0f; dy = -v; dz = u;
break;
109 case 2: dx = u; dy = 1.0f; dz = v;
break;
110 case 3: dx = u; dy = -1.0f; dz = -v;
break;
111 case 4: dx = u; dy = -v; dz = 1.0f;
break;
112 case 5: dx = -u; dy = -v; dz = -1.0f;
break;
113 default: dx = dy = dz = 0.0f;
break;
116 float len = std::sqrt(dx * dx + dy * dy + dz * dz);
117 dx /= len; dy /= len; dz /= len;
119 float lon = std::atan2(dz, dx);
120 float lat = std::asin(std::clamp(dy, -1.0f, 1.0f));
122 float panU = 0.5f + lon / (2.0f * 3.14159265f);
123 float panV = 0.5f - lat / 3.14159265f;
125 float srcX = panU * (panW - 1);
126 float srcY = panV * (panH - 1);
127 int x0 =
static_cast<int>(srcX);
128 int y0 =
static_cast<int>(srcY);
129 int x1 = std::min(x0 + 1, panW - 1);
130 int y1 = std::min(y0 + 1, panH - 1);
131 x0 = std::clamp(x0, 0, panW - 1);
132 y0 = std::clamp(y0, 0, panH - 1);
133 float fx = srcX - x0;
134 float fy = srcY - y0;
136 size_t idx = (y * faceSize + x) * 4;
137 for (
int c = 0; c < 4; ++c) {
138 float c00 = panorama[(y0 * panW + x0) * 4 + c];
139 float c10 = panorama[(y0 * panW + x1) * 4 + c];
140 float c01 = panorama[(y1 * panW + x0) * 4 + c];
141 float c11 = panorama[(y1 * panW + x1) * 4 + c];
142 float val = c00 * (1 - fx) * (1 - fy) +
143 c10 * fx * (1 - fy) +
144 c01 * (1 - fx) * fy +
146 faceData[idx + c] =
static_cast<unsigned char>(
147 std::clamp(val, 0.0f, 255.0f));
153 stbi_image_free(panorama);
155 std::vector<unsigned char*> facePointers;
156 for (
int i = 0; i < 6; i++)
157 facePointers.push_back(allFaces[i].data());
159 bool result = CreateCubemapFromFaces(facePointers, faceSize);
163 "DirectX12CubemapTexture: Loaded equirectangular panorama "
170bool DirectX12CubemapTexture::CreateCubemapFromFaces(
171 const std::vector<unsigned char*>& faceData, uint32_t faceSize) {
172 if (!m_device || faceData.size() != 6)
return false;
178 D3D12_RESOURCE_DESC texDesc = {};
179 texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
180 texDesc.Alignment = 0;
181 texDesc.Width = faceSize;
182 texDesc.Height = faceSize;
183 texDesc.DepthOrArraySize = 6;
184 texDesc.MipLevels = 1;
185 texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
186 texDesc.SampleDesc.Count = 1;
187 texDesc.SampleDesc.Quality = 0;
188 texDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
189 texDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
191 D3D12_HEAP_PROPERTIES heapProps = {};
192 heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
193 heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
194 heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
195 heapProps.CreationNodeMask = 1;
196 heapProps.VisibleNodeMask = 1;
198 HRESULT hr = m_device->CreateCommittedResource(
199 &heapProps, D3D12_HEAP_FLAG_NONE, &texDesc,
200 D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
201 IID_PPV_ARGS(&m_texture));
205 "DirectX12CubemapTexture: Failed to create texture resource "
207 static_cast<unsigned int>(hr));
212 D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprints[6];
214 UINT64 rowSizeInBytes[6];
216 m_device->GetCopyableFootprints(&texDesc, 0, 6, 0, footprints, numRows,
217 rowSizeInBytes, &totalBytes);
220 D3D12_HEAP_PROPERTIES uploadHeapProps = {};
221 uploadHeapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
222 uploadHeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
223 uploadHeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
224 uploadHeapProps.CreationNodeMask = 1;
225 uploadHeapProps.VisibleNodeMask = 1;
227 D3D12_RESOURCE_DESC uploadDesc = {};
228 uploadDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
229 uploadDesc.Alignment = 0;
230 uploadDesc.Width = totalBytes;
231 uploadDesc.Height = 1;
232 uploadDesc.DepthOrArraySize = 1;
233 uploadDesc.MipLevels = 1;
234 uploadDesc.Format = DXGI_FORMAT_UNKNOWN;
235 uploadDesc.SampleDesc.Count = 1;
236 uploadDesc.SampleDesc.Quality = 0;
237 uploadDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
238 uploadDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
240 hr = m_device->CreateCommittedResource(
241 &uploadHeapProps, D3D12_HEAP_FLAG_NONE, &uploadDesc,
242 D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
243 IID_PPV_ARGS(&m_uploadBuffer));
247 "DirectX12CubemapTexture: Failed to create upload buffer");
252 BYTE* mapped =
nullptr;
253 hr = m_uploadBuffer->Map(0,
nullptr,
reinterpret_cast<void**
>(&mapped));
255 SLEAK_ERROR(
"DirectX12CubemapTexture: Failed to map upload buffer");
259 uint32_t srcRowPitch = faceSize * 4;
260 for (
int face = 0; face < 6; face++) {
261 BYTE* destBase = mapped + footprints[face].Offset;
262 const BYTE* srcData =
reinterpret_cast<const BYTE*
>(faceData[face]);
264 for (UINT row = 0; row < numRows[face]; row++) {
265 memcpy(destBase + row * footprints[face].Footprint.RowPitch,
266 srcData + row * srcRowPitch, srcRowPitch);
270 m_uploadBuffer->Unmap(0,
nullptr);
273 Microsoft::WRL::ComPtr<ID3D12CommandAllocator> cmdAllocator;
274 Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> cmdList;
276 hr = m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,
277 IID_PPV_ARGS(&cmdAllocator));
278 if (FAILED(hr))
return false;
280 hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,
281 cmdAllocator.Get(),
nullptr,
282 IID_PPV_ARGS(&cmdList));
283 if (FAILED(hr))
return false;
286 for (UINT face = 0; face < 6; face++) {
287 D3D12_TEXTURE_COPY_LOCATION dst = {};
288 dst.pResource = m_texture.Get();
289 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
290 dst.SubresourceIndex = face;
292 D3D12_TEXTURE_COPY_LOCATION src = {};
293 src.pResource = m_uploadBuffer.Get();
294 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
295 src.PlacedFootprint = footprints[face];
297 cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src,
nullptr);
301 D3D12_RESOURCE_BARRIER barrier = {};
302 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
303 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
304 barrier.Transition.pResource = m_texture.Get();
305 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
306 barrier.Transition.StateAfter =
307 D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
308 barrier.Transition.Subresource =
309 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
310 cmdList->ResourceBarrier(1, &barrier);
314 ID3D12CommandList* ppCmdLists[] = {cmdList.Get()};
315 m_commandQueue->ExecuteCommandLists(1, ppCmdLists);
319 D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
320 srvHeapDesc.NumDescriptors = 1;
321 srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
322 srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
324 hr = m_device->CreateDescriptorHeap(&srvHeapDesc,
325 IID_PPV_ARGS(&m_srvHeap));
328 "DirectX12CubemapTexture: Failed to create SRV descriptor heap");
333 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
334 srvDesc.Shader4ComponentMapping =
335 D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
336 srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
337 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
338 srvDesc.TextureCube.MipLevels = 1;
339 srvDesc.TextureCube.MostDetailedMip = 0;
340 srvDesc.TextureCube.ResourceMinLODClamp = 0.0f;
342 m_device->CreateShaderResourceView(
343 m_texture.Get(), &srvDesc,
344 m_srvHeap->GetCPUDescriptorHandleForHeapStart());
349void DirectX12CubemapTexture::WaitForUpload() {
350 Microsoft::WRL::ComPtr<ID3D12Fence> fence;
351 HRESULT hr = m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE,
352 IID_PPV_ARGS(&fence));
353 if (FAILED(hr))
return;
355 HANDLE
event = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
358 m_commandQueue->Signal(fence.Get(), 1);
359 if (fence->GetCompletedValue() < 1) {
360 fence->SetEventOnCompletion(1, event);
361 WaitForSingleObject(event, INFINITE);
367bool DirectX12CubemapTexture::LoadFromMemory(
const void* data, uint32_t
width,
369 TextureFormat format) {
377bool DirectX12CubemapTexture::LoadFromFile(
const std::string& filePath) {
382void DirectX12CubemapTexture::Bind(uint32_t slot)
const {
387void DirectX12CubemapTexture::Unbind()
const {
391void DirectX12CubemapTexture::SetFilter(TextureFilter filter) {
395void DirectX12CubemapTexture::SetWrapMode(TextureWrapMode wrapMode) {
399void DirectX12CubemapTexture::BindToCommandList(
400 ID3D12GraphicsCommandList* cmdList, UINT rootParameterIndex)
const {
401 if (!cmdList)
return;
403 if (m_usesSharedHeap) {
405 cmdList->SetGraphicsRootDescriptorTable(rootParameterIndex, m_srvGpuHandle);
406 }
else if (m_srvHeap) {
408 ID3D12DescriptorHeap* heaps[] = {m_srvHeap.Get()};
409 cmdList->SetDescriptorHeaps(1, heaps);
410 cmdList->SetGraphicsRootDescriptorTable(
412 m_srvHeap->GetGPUDescriptorHandleForHeapStart());
416void DirectX12CubemapTexture::CreateSRVIntoHandle(
417 D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle) {
418 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
419 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
420 srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
421 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
422 srvDesc.TextureCube.MipLevels = 1;
423 srvDesc.TextureCube.MostDetailedMip = 0;
424 srvDesc.TextureCube.ResourceMinLODClamp = 0.0f;
425 m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, cpuHandle);
Backend-facing rendering layer shared by the four graphics backends.
Root namespace for everything the engine exposes.