19DirectX12CubemapTexture::DirectX12CubemapTexture(
20 ID3D12Device* device, ID3D12CommandQueue* commandQueue,
22 : m_device(device), m_commandQueue(commandQueue), m_uploader(uploader) {}
24DirectX12CubemapTexture::~DirectX12CubemapTexture() {
25 DirectX12Buffer::DeferCleanup(std::move(m_srvHeap));
26 DirectX12Buffer::DeferCleanup(std::move(m_texture));
29bool DirectX12CubemapTexture::LoadCubemap(
30 const std::array<std::string, 6>& facePaths) {
31 stbi_set_flip_vertically_on_load(
false);
34 unsigned char* pixels =
nullptr;
37 std::array<FaceData, 6> faces;
39 for (
int i = 0; i < 6; i++) {
41 faces[i].pixels = stbi_load(facePaths[i].c_str(), &faces[i].w,
42 &faces[i].h, &channels, 4);
43 if (!faces[i].pixels) {
45 "DirectX12CubemapTexture: Failed to load face {}: {}", i,
47 for (
int j = 0; j < i; j++)
48 stbi_image_free(faces[j].pixels);
53 for (
int i = 1; i < 6; i++) {
54 if (faces[i].w != faces[0].w || faces[i].h != faces[0].h) {
56 "DirectX12CubemapTexture: Face {} size ({}x{}) doesn't match "
58 i, faces[i].w, faces[i].h, faces[0].w, faces[0].h);
59 for (
int j = 0; j < 6; j++)
60 stbi_image_free(faces[j].pixels);
65 uint32_t faceSize =
static_cast<uint32_t
>(faces[0].w);
66 std::vector<unsigned char*> facePointers;
67 for (
int i = 0; i < 6; i++)
68 facePointers.push_back(faces[i].pixels);
70 bool result = CreateCubemapFromFaces(facePointers, faceSize);
72 for (
int i = 0; i < 6; i++)
73 stbi_image_free(faces[i].pixels);
77 "DirectX12CubemapTexture: Loaded cubemap ({}x{}, 6 faces)",
83bool DirectX12CubemapTexture::LoadEquirectangular(
const std::string& path,
85 stbi_set_flip_vertically_on_load(
false);
87 int panW, panH, channels;
88 unsigned char* panorama =
89 stbi_load(path.c_str(), &panW, &panH, &channels, 4);
92 "DirectX12CubemapTexture: Failed to load panorama: {}", path);
96 size_t faceBytes =
static_cast<size_t>(faceSize) * faceSize * 4;
97 std::vector<std::vector<unsigned char>> allFaces(6);
98 for (
int i = 0; i < 6; i++)
99 allFaces[i].resize(faceBytes);
101 for (
int face = 0; face < 6; ++face) {
102 unsigned char* faceData = allFaces[face].data();
104 for (uint32_t y = 0; y < faceSize; ++y) {
105 for (uint32_t x = 0; x < faceSize; ++x) {
106 float u = (2.0f * (x + 0.5f) / faceSize) - 1.0f;
107 float v = (2.0f * (y + 0.5f) / faceSize) - 1.0f;
111 case 0: dx = 1.0f; dy = -v; dz = -u;
break;
112 case 1: dx = -1.0f; dy = -v; dz = u;
break;
113 case 2: dx = u; dy = 1.0f; dz = v;
break;
114 case 3: dx = u; dy = -1.0f; dz = -v;
break;
115 case 4: dx = u; dy = -v; dz = 1.0f;
break;
116 case 5: dx = -u; dy = -v; dz = -1.0f;
break;
117 default: dx = dy = dz = 0.0f;
break;
120 float len = std::sqrt(dx * dx + dy * dy + dz * dz);
121 dx /= len; dy /= len; dz /= len;
123 float lon = std::atan2(dz, dx);
124 float lat = std::asin(std::clamp(dy, -1.0f, 1.0f));
126 float panU = 0.5f + lon / (2.0f * 3.14159265f);
127 float panV = 0.5f - lat / 3.14159265f;
129 float srcX = panU * (panW - 1);
130 float srcY = panV * (panH - 1);
131 int x0 =
static_cast<int>(srcX);
132 int y0 =
static_cast<int>(srcY);
133 int x1 = std::min(x0 + 1, panW - 1);
134 int y1 = std::min(y0 + 1, panH - 1);
135 x0 = std::clamp(x0, 0, panW - 1);
136 y0 = std::clamp(y0, 0, panH - 1);
137 float fx = srcX - x0;
138 float fy = srcY - y0;
140 size_t idx = (y * faceSize + x) * 4;
141 for (
int c = 0; c < 4; ++c) {
142 float c00 = panorama[(y0 * panW + x0) * 4 + c];
143 float c10 = panorama[(y0 * panW + x1) * 4 + c];
144 float c01 = panorama[(y1 * panW + x0) * 4 + c];
145 float c11 = panorama[(y1 * panW + x1) * 4 + c];
146 float val = c00 * (1 - fx) * (1 - fy) +
147 c10 * fx * (1 - fy) +
148 c01 * (1 - fx) * fy +
150 faceData[idx + c] =
static_cast<unsigned char>(
151 std::clamp(val, 0.0f, 255.0f));
157 stbi_image_free(panorama);
159 std::vector<unsigned char*> facePointers;
160 for (
int i = 0; i < 6; i++)
161 facePointers.push_back(allFaces[i].data());
163 bool result = CreateCubemapFromFaces(facePointers, faceSize);
167 "DirectX12CubemapTexture: Loaded equirectangular panorama "
174bool DirectX12CubemapTexture::CreateCubemapFromFaces(
175 const std::vector<unsigned char*>& faceData, uint32_t faceSize) {
176 if (!m_device || faceData.size() != 6)
return false;
182 D3D12_RESOURCE_DESC texDesc = {};
183 texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
184 texDesc.Alignment = 0;
185 texDesc.Width = faceSize;
186 texDesc.Height = faceSize;
187 texDesc.DepthOrArraySize = 6;
188 texDesc.MipLevels = 1;
189 texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
190 texDesc.SampleDesc.Count = 1;
191 texDesc.SampleDesc.Quality = 0;
192 texDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
193 texDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
195 D3D12_HEAP_PROPERTIES heapProps = {};
196 heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
197 heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
198 heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
199 heapProps.CreationNodeMask = 1;
200 heapProps.VisibleNodeMask = 1;
202 HRESULT hr = m_device->CreateCommittedResource(
203 &heapProps, D3D12_HEAP_FLAG_NONE, &texDesc,
204 D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
205 IID_PPV_ARGS(&m_texture));
209 "DirectX12CubemapTexture: Failed to create texture resource "
211 static_cast<unsigned int>(hr));
216 D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprints[6];
218 UINT64 rowSizeInBytes[6];
220 m_device->GetCopyableFootprints(&texDesc, 0, 6, 0, footprints, numRows,
221 rowSizeInBytes, &totalBytes);
223 DirectX12UploadContext local;
224 DirectX12UploadContext* uploader = m_uploader;
226 if (!local.Initialize(m_device, m_commandQueue))
return false;
230 ID3D12Resource* staging =
nullptr;
232 static_cast<BYTE*
>(uploader->AllocateStaging(totalBytes, &staging));
235 "DirectX12CubemapTexture: Failed to allocate staging memory");
239 uint32_t srcRowPitch = faceSize * 4;
240 for (
int face = 0; face < 6; face++) {
241 BYTE* destBase = mapped + footprints[face].Offset;
242 const BYTE* srcData =
reinterpret_cast<const BYTE*
>(faceData[face]);
244 for (UINT row = 0; row < numRows[face]; row++) {
245 memcpy(destBase + row * footprints[face].Footprint.RowPitch,
246 srcData + row * srcRowPitch, srcRowPitch);
250 ID3D12GraphicsCommandList* cmdList = uploader->GetCommandList();
253 for (UINT face = 0; face < 6; face++) {
254 D3D12_TEXTURE_COPY_LOCATION dst = {};
255 dst.pResource = m_texture.Get();
256 dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
257 dst.SubresourceIndex = face;
259 D3D12_TEXTURE_COPY_LOCATION src = {};
260 src.pResource = staging;
261 src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
262 src.PlacedFootprint = footprints[face];
264 cmdList->CopyTextureRegion(&dst, 0, 0, 0, &src,
nullptr);
268 D3D12_RESOURCE_BARRIER barrier = {};
269 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
270 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
271 barrier.Transition.pResource = m_texture.Get();
272 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
273 barrier.Transition.StateAfter =
274 D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
275 barrier.Transition.Subresource =
276 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
277 cmdList->ResourceBarrier(1, &barrier);
279 if (uploader == &local) local.Flush();
282 D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
283 srvHeapDesc.NumDescriptors = 1;
284 srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
285 srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
287 hr = m_device->CreateDescriptorHeap(&srvHeapDesc,
288 IID_PPV_ARGS(&m_srvHeap));
291 "DirectX12CubemapTexture: Failed to create SRV descriptor heap");
296 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
297 srvDesc.Shader4ComponentMapping =
298 D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
299 srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
300 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
301 srvDesc.TextureCube.MipLevels = 1;
302 srvDesc.TextureCube.MostDetailedMip = 0;
303 srvDesc.TextureCube.ResourceMinLODClamp = 0.0f;
305 m_device->CreateShaderResourceView(
306 m_texture.Get(), &srvDesc,
307 m_srvHeap->GetCPUDescriptorHandleForHeapStart());
312bool DirectX12CubemapTexture::LoadFromMemory(
const void* data, uint32_t
width,
314 TextureFormat format) {
322bool DirectX12CubemapTexture::LoadFromFile(
const std::string& filePath) {
327void DirectX12CubemapTexture::Bind(uint32_t slot)
const {
332void DirectX12CubemapTexture::Unbind()
const {
336void DirectX12CubemapTexture::SetFilter(TextureFilter filter) {
340void DirectX12CubemapTexture::SetWrapMode(TextureWrapMode wrapMode) {
344void DirectX12CubemapTexture::BindToCommandList(
345 ID3D12GraphicsCommandList* cmdList, UINT rootParameterIndex)
const {
346 if (!cmdList)
return;
348 if (m_usesSharedHeap) {
350 cmdList->SetGraphicsRootDescriptorTable(rootParameterIndex, m_srvGpuHandle);
351 }
else if (m_srvHeap) {
353 ID3D12DescriptorHeap* heaps[] = {m_srvHeap.Get()};
354 cmdList->SetDescriptorHeaps(1, heaps);
355 cmdList->SetGraphicsRootDescriptorTable(
357 m_srvHeap->GetGPUDescriptorHandleForHeapStart());
361void DirectX12CubemapTexture::CreateSRVIntoHandle(
362 D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle) {
363 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
364 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
365 srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
366 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
367 srvDesc.TextureCube.MipLevels = 1;
368 srvDesc.TextureCube.MostDetailedMip = 0;
369 srvDesc.TextureCube.ResourceMinLODClamp = 0.0f;
370 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.