core: Define VK_USE_PLATFORM_XCB_KHR before including vkd3d_utils.h.
[vkmodelviewer.git] / Core / TextureManager.cpp
blobff9a33fa40c9da28c055079a9269f058548cc8e5
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // This code is licensed under the MIT License (MIT).
4 // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
5 // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
6 // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
7 // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
8 //
9 // Developed by Minigraph
11 // Author(s): James Stanard
12 // Alex Nankervis
15 #include "pch.h"
16 #include "TextureManager.h"
17 #include "FileUtility.h"
18 #include "DDSTextureLoader.h"
19 #include "GraphicsCore.h"
20 #include "CommandContext.h"
21 #include <map>
22 #include <thread>
24 using namespace std;
25 using namespace Graphics;
27 static UINT BytesPerPixel( DXGI_FORMAT Format )
29 return (UINT)BitsPerPixel(Format) / 8;
32 void Texture::Create( size_t Pitch, size_t Width, size_t Height, DXGI_FORMAT Format, const void* InitialData )
34 m_UsageState = D3D12_RESOURCE_STATE_COPY_DEST;
36 D3D12_RESOURCE_DESC texDesc = {};
37 texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
38 texDesc.Width = Width;
39 texDesc.Height = (UINT)Height;
40 texDesc.DepthOrArraySize = 1;
41 texDesc.MipLevels = 1;
42 texDesc.Format = Format;
43 texDesc.SampleDesc.Count = 1;
44 texDesc.SampleDesc.Quality = 0;
45 texDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
46 texDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
48 D3D12_HEAP_PROPERTIES HeapProps;
49 HeapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
50 HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
51 HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
52 HeapProps.CreationNodeMask = 1;
53 HeapProps.VisibleNodeMask = 1;
55 ASSERT_SUCCEEDED(g_Device->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, &texDesc,
56 m_UsageState, nullptr, MY_IID_PPV_ARGS(m_pResource.ReleaseAndGetAddressOf())));
58 m_pResource->SetName(L"Texture");
60 D3D12_SUBRESOURCE_DATA texResource;
61 texResource.pData = InitialData;
62 texResource.RowPitch = Pitch * BytesPerPixel(Format);
63 texResource.SlicePitch = texResource.RowPitch * Height;
65 CommandContext::InitializeTexture(*this, 1, &texResource);
67 if (m_hCpuDescriptorHandle.ptr == D3D12_GPU_VIRTUAL_ADDRESS_UNKNOWN)
68 m_hCpuDescriptorHandle = AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
69 g_Device->CreateShaderResourceView(m_pResource.Get(), nullptr, m_hCpuDescriptorHandle);
72 void Texture::CreateTGAFromMemory( const void* _filePtr, size_t, bool sRGB )
74 const uint8_t* filePtr = (const uint8_t*)_filePtr;
76 // Skip first two bytes
77 filePtr += 2;
79 /*uint8_t imageTypeCode =*/ filePtr++;
81 // Ignore another 9 bytes
82 filePtr += 9;
84 uint16_t imageWidth = *(uint16_t*)filePtr;
85 filePtr += sizeof(uint16_t);
86 uint16_t imageHeight = *(uint16_t*)filePtr;
87 filePtr += sizeof(uint16_t);
88 uint8_t bitCount = *filePtr++;
90 // Ignore another byte
91 filePtr++;
93 uint32_t* formattedData = new uint32_t[imageWidth * imageHeight];
94 uint32_t* iter = formattedData;
96 uint8_t numChannels = bitCount / 8;
97 uint32_t numBytes = imageWidth * imageHeight * numChannels;
99 switch (numChannels)
101 default:
102 break;
103 case 3:
104 for (uint32_t byteIdx = 0; byteIdx < numBytes; byteIdx += 3)
106 *iter++ = 0xff000000 | filePtr[0] << 16 | filePtr[1] << 8 | filePtr[2];
107 filePtr += 3;
109 break;
110 case 4:
111 for (uint32_t byteIdx = 0; byteIdx < numBytes; byteIdx += 4)
113 *iter++ = filePtr[3] << 24 | filePtr[0] << 16 | filePtr[1] << 8 | filePtr[2];
114 filePtr += 4;
116 break;
119 Create( imageWidth, imageHeight, sRGB ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM, formattedData );
121 delete [] formattedData;
124 bool Texture::CreateDDSFromMemory( const void* filePtr, size_t fileSize, bool sRGB )
126 if (m_hCpuDescriptorHandle.ptr == D3D12_GPU_VIRTUAL_ADDRESS_UNKNOWN)
127 m_hCpuDescriptorHandle = AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
129 HRESULT hr = CreateDDSTextureFromMemory( Graphics::g_Device,
130 (const uint8_t*)filePtr, fileSize, 0, sRGB, &m_pResource, m_hCpuDescriptorHandle );
132 return SUCCEEDED(hr);
135 void Texture::CreatePIXImageFromMemory( const void* memBuffer, size_t fileSize )
137 struct Header
139 DXGI_FORMAT Format;
140 uint32_t Pitch;
141 uint32_t Width;
142 uint32_t Height;
144 const Header& header = *(Header*)memBuffer;
146 ASSERT(fileSize >= header.Pitch * BytesPerPixel(header.Format) * header.Height + sizeof(Header),
147 "Raw PIX image dump has an invalid file size");
149 Create(header.Pitch, header.Width, header.Height, header.Format, (uint8_t*)memBuffer + sizeof(Header));
152 namespace TextureManager
154 string s_RootPath = "";
155 map<string, unique_ptr<ManagedTexture>> s_TextureCache;
157 void Initialize(const std::string &TextureLibRoot)
159 s_RootPath = TextureLibRoot;
162 void Shutdown( void )
164 s_TextureCache.clear();
167 pair<ManagedTexture *, bool> FindOrLoadTexture(const string &fileName)
169 static mutex s_Mutex;
170 lock_guard<mutex> Guard(s_Mutex);
172 auto iter = s_TextureCache.find(fileName);
174 // If it's found, it has already been loaded or the load process has begun
175 if (iter != s_TextureCache.end())
176 return make_pair(iter->second.get(), false);
178 ManagedTexture* NewTexture = new ManagedTexture(fileName);
179 s_TextureCache[fileName].reset( NewTexture );
181 // This was the first time it was requested, so indicate that the caller must read the file
182 return make_pair(NewTexture, true);
185 const Texture& GetBlackTex2D(void)
187 auto ManagedTex = FindOrLoadTexture("DefaultBlackTexture");
189 ManagedTexture* ManTex = ManagedTex.first;
190 const bool RequestsLoad = ManagedTex.second;
192 if (!RequestsLoad)
194 ManTex->WaitForLoad();
195 return *ManTex;
198 uint32_t BlackPixel = 0;
199 ManTex->Create(1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, &BlackPixel);
200 return *ManTex;
203 const Texture& GetWhiteTex2D(void)
205 auto ManagedTex = FindOrLoadTexture("DefaultWhiteTexture");
207 ManagedTexture* ManTex = ManagedTex.first;
208 const bool RequestsLoad = ManagedTex.second;
210 if (!RequestsLoad)
212 ManTex->WaitForLoad();
213 return *ManTex;
216 uint32_t WhitePixel = 0xFFFFFFFFul;
217 ManTex->Create(1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, &WhitePixel);
218 return *ManTex;
221 const Texture& GetMagentaTex2D(void)
223 auto ManagedTex = FindOrLoadTexture("DefaultMagentaTexture");
225 ManagedTexture* ManTex = ManagedTex.first;
226 const bool RequestsLoad = ManagedTex.second;
228 if (!RequestsLoad)
230 ManTex->WaitForLoad();
231 return *ManTex;
234 uint32_t MagentaPixel = 0x00FF00FF;
235 ManTex->Create(1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, &MagentaPixel);
236 return *ManTex;
239 } // namespace TextureManager
241 void ManagedTexture::WaitForLoad( void ) const
243 volatile D3D12_CPU_DESCRIPTOR_HANDLE& VolHandle = (volatile D3D12_CPU_DESCRIPTOR_HANDLE&)m_hCpuDescriptorHandle;
244 volatile bool& VolValid = (volatile bool&)m_IsValid;
245 while (VolHandle.ptr == D3D12_GPU_VIRTUAL_ADDRESS_UNKNOWN && VolValid)
246 this_thread::yield();
249 void ManagedTexture::SetToInvalidTexture( void )
251 m_hCpuDescriptorHandle = TextureManager::GetMagentaTex2D().GetSRV();
252 m_IsValid = false;
255 const ManagedTexture *TextureManager::LoadFromFile(const std::string &fileName, bool sRGB)
257 std::string CatPath = fileName;
259 const ManagedTexture *Tex = LoadDDSFromFile(CatPath + ".dds", sRGB);
260 if (!Tex->IsValid())
261 Tex = LoadTGAFromFile(CatPath + ".tga", sRGB);
263 return Tex;
266 const ManagedTexture *TextureManager::LoadDDSFromFile(const std::string &fileName, bool sRGB)
268 auto ManagedTex = FindOrLoadTexture(fileName);
270 ManagedTexture* ManTex = ManagedTex.first;
271 const bool RequestsLoad = ManagedTex.second;
273 if (!RequestsLoad)
275 ManTex->WaitForLoad();
276 return ManTex;
279 Utility::ByteArray ba = Utility::ReadFileSync( s_RootPath + fileName );
280 if (ba->size() == 0 || !ManTex->CreateDDSFromMemory( ba->data(), ba->size(), sRGB ))
281 ManTex->SetToInvalidTexture();
282 else
283 ManTex->GetResource()->SetName(MakeWStr(fileName).c_str());
285 return ManTex;
288 const ManagedTexture *TextureManager::LoadTGAFromFile(const std::string &fileName, bool sRGB)
290 auto ManagedTex = FindOrLoadTexture(fileName);
292 ManagedTexture* ManTex = ManagedTex.first;
293 const bool RequestsLoad = ManagedTex.second;
295 if (!RequestsLoad)
297 ManTex->WaitForLoad();
298 return ManTex;
301 Utility::ByteArray ba = Utility::ReadFileSync( s_RootPath + fileName );
302 if (ba->size() > 0)
304 ManTex->CreateTGAFromMemory( ba->data(), ba->size(), sRGB );
305 ManTex->GetResource()->SetName(MakeWStr(fileName).c_str());
307 else
308 ManTex->SetToInvalidTexture();
310 return ManTex;
314 const ManagedTexture *TextureManager::LoadPIXImageFromFile(const std::string &fileName)
316 auto ManagedTex = FindOrLoadTexture(fileName);
318 ManagedTexture* ManTex = ManagedTex.first;
319 const bool RequestsLoad = ManagedTex.second;
321 if (!RequestsLoad)
323 ManTex->WaitForLoad();
324 return ManTex;
327 Utility::ByteArray ba = Utility::ReadFileSync( s_RootPath + fileName );
328 if (ba->size() > 0)
330 ManTex->CreatePIXImageFromMemory(ba->data(), ba->size());
331 ManTex->GetResource()->SetName(MakeWStr(fileName).c_str());
333 else
334 ManTex->SetToInvalidTexture();
336 return ManTex;