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.
9 // Developed by Minigraph
11 // Author(s): James Stanard
16 #include "TextureManager.h"
17 #include "FileUtility.h"
18 #include "DDSTextureLoader.h"
19 #include "GraphicsCore.h"
20 #include "CommandContext.h"
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
79 /*uint8_t imageTypeCode =*/ filePtr
++;
81 // Ignore another 9 bytes
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
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
;
104 for (uint32_t byteIdx
= 0; byteIdx
< numBytes
; byteIdx
+= 3)
106 *iter
++ = 0xff000000 | filePtr
[0] << 16 | filePtr
[1] << 8 | filePtr
[2];
111 for (uint32_t byteIdx
= 0; byteIdx
< numBytes
; byteIdx
+= 4)
113 *iter
++ = filePtr
[3] << 24 | filePtr
[0] << 16 | filePtr
[1] << 8 | filePtr
[2];
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
)
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
;
194 ManTex
->WaitForLoad();
198 uint32_t BlackPixel
= 0;
199 ManTex
->Create(1, 1, DXGI_FORMAT_R8G8B8A8_UNORM
, &BlackPixel
);
203 const Texture
& GetWhiteTex2D(void)
205 auto ManagedTex
= FindOrLoadTexture("DefaultWhiteTexture");
207 ManagedTexture
* ManTex
= ManagedTex
.first
;
208 const bool RequestsLoad
= ManagedTex
.second
;
212 ManTex
->WaitForLoad();
216 uint32_t WhitePixel
= 0xFFFFFFFFul
;
217 ManTex
->Create(1, 1, DXGI_FORMAT_R8G8B8A8_UNORM
, &WhitePixel
);
221 const Texture
& GetMagentaTex2D(void)
223 auto ManagedTex
= FindOrLoadTexture("DefaultMagentaTexture");
225 ManagedTexture
* ManTex
= ManagedTex
.first
;
226 const bool RequestsLoad
= ManagedTex
.second
;
230 ManTex
->WaitForLoad();
234 uint32_t MagentaPixel
= 0x00FF00FF;
235 ManTex
->Create(1, 1, DXGI_FORMAT_R8G8B8A8_UNORM
, &MagentaPixel
);
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();
255 const ManagedTexture
*TextureManager::LoadFromFile(const std::string
&fileName
, bool sRGB
)
257 std::string CatPath
= fileName
;
259 const ManagedTexture
*Tex
= LoadDDSFromFile(CatPath
+ ".dds", sRGB
);
261 Tex
= LoadTGAFromFile(CatPath
+ ".tga", sRGB
);
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
;
275 ManTex
->WaitForLoad();
279 Utility::ByteArray ba
= Utility::ReadFileSync( s_RootPath
+ fileName
);
280 if (ba
->size() == 0 || !ManTex
->CreateDDSFromMemory( ba
->data(), ba
->size(), sRGB
))
281 ManTex
->SetToInvalidTexture();
283 ManTex
->GetResource()->SetName(MakeWStr(fileName
).c_str());
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
;
297 ManTex
->WaitForLoad();
301 Utility::ByteArray ba
= Utility::ReadFileSync( s_RootPath
+ fileName
);
304 ManTex
->CreateTGAFromMemory( ba
->data(), ba
->size(), sRGB
);
305 ManTex
->GetResource()->SetName(MakeWStr(fileName
).c_str());
308 ManTex
->SetToInvalidTexture();
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
;
323 ManTex
->WaitForLoad();
327 Utility::ByteArray ba
= Utility::ReadFileSync( s_RootPath
+ fileName
);
330 ManTex
->CreatePIXImageFromMemory(ba
->data(), ba
->size());
331 ManTex
->GetResource()->SetName(MakeWStr(fileName
).c_str());
334 ManTex
->SetToInvalidTexture();