core: Define VK_USE_PLATFORM_XCB_KHR before including vkd3d_utils.h.
[vkmodelviewer.git] / Core / DDSTextureLoader.cpp
blob4de7d4875df6be30a7e1f5a57e7ba74470ecfa7b
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 //--------------------------------------------------------------------------------------
11 // Functions for loading a DDS texture and creating a Direct3D runtime resource for it
13 // Note these functions are useful as a light-weight runtime loader for DDS files. For
14 // a full-featured DDS file reader, writer, and texture processing pipeline see
15 // the 'Texconv' sample and the 'DirectXTex' library.
17 // http://go.microsoft.com/fwlink/?LinkId=248926
18 // http://go.microsoft.com/fwlink/?LinkId=248929
19 //--------------------------------------------------------------------------------------
21 #include "pch.h"
23 #include "DDSTextureLoader.h"
25 #include "dds.h"
26 #include "GpuResource.h"
27 #include "GraphicsCore.h"
28 #include "CommandContext.h"
29 #include "Utility.h"
31 //--------------------------------------------------------------------------------------
32 // Return the BPP for a particular format
33 //--------------------------------------------------------------------------------------
34 size_t BitsPerPixel( _In_ DXGI_FORMAT fmt )
36 switch( fmt )
38 case DXGI_FORMAT_R32G32B32A32_TYPELESS:
39 case DXGI_FORMAT_R32G32B32A32_FLOAT:
40 case DXGI_FORMAT_R32G32B32A32_UINT:
41 case DXGI_FORMAT_R32G32B32A32_SINT:
42 return 128;
44 case DXGI_FORMAT_R32G32B32_TYPELESS:
45 case DXGI_FORMAT_R32G32B32_FLOAT:
46 case DXGI_FORMAT_R32G32B32_UINT:
47 case DXGI_FORMAT_R32G32B32_SINT:
48 return 96;
50 case DXGI_FORMAT_R16G16B16A16_TYPELESS:
51 case DXGI_FORMAT_R16G16B16A16_FLOAT:
52 case DXGI_FORMAT_R16G16B16A16_UNORM:
53 case DXGI_FORMAT_R16G16B16A16_UINT:
54 case DXGI_FORMAT_R16G16B16A16_SNORM:
55 case DXGI_FORMAT_R16G16B16A16_SINT:
56 case DXGI_FORMAT_R32G32_TYPELESS:
57 case DXGI_FORMAT_R32G32_FLOAT:
58 case DXGI_FORMAT_R32G32_UINT:
59 case DXGI_FORMAT_R32G32_SINT:
60 case DXGI_FORMAT_R32G8X24_TYPELESS:
61 case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
62 case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
63 case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
64 case DXGI_FORMAT_Y416:
65 case DXGI_FORMAT_Y210:
66 case DXGI_FORMAT_Y216:
67 return 64;
69 case DXGI_FORMAT_R10G10B10A2_TYPELESS:
70 case DXGI_FORMAT_R10G10B10A2_UNORM:
71 case DXGI_FORMAT_R10G10B10A2_UINT:
72 case DXGI_FORMAT_R11G11B10_FLOAT:
73 case DXGI_FORMAT_R8G8B8A8_TYPELESS:
74 case DXGI_FORMAT_R8G8B8A8_UNORM:
75 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
76 case DXGI_FORMAT_R8G8B8A8_UINT:
77 case DXGI_FORMAT_R8G8B8A8_SNORM:
78 case DXGI_FORMAT_R8G8B8A8_SINT:
79 case DXGI_FORMAT_R16G16_TYPELESS:
80 case DXGI_FORMAT_R16G16_FLOAT:
81 case DXGI_FORMAT_R16G16_UNORM:
82 case DXGI_FORMAT_R16G16_UINT:
83 case DXGI_FORMAT_R16G16_SNORM:
84 case DXGI_FORMAT_R16G16_SINT:
85 case DXGI_FORMAT_R32_TYPELESS:
86 case DXGI_FORMAT_D32_FLOAT:
87 case DXGI_FORMAT_R32_FLOAT:
88 case DXGI_FORMAT_R32_UINT:
89 case DXGI_FORMAT_R32_SINT:
90 case DXGI_FORMAT_R24G8_TYPELESS:
91 case DXGI_FORMAT_D24_UNORM_S8_UINT:
92 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
93 case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
94 case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
95 case DXGI_FORMAT_R8G8_B8G8_UNORM:
96 case DXGI_FORMAT_G8R8_G8B8_UNORM:
97 case DXGI_FORMAT_B8G8R8A8_UNORM:
98 case DXGI_FORMAT_B8G8R8X8_UNORM:
99 case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
100 case DXGI_FORMAT_B8G8R8A8_TYPELESS:
101 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
102 case DXGI_FORMAT_B8G8R8X8_TYPELESS:
103 case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
104 case DXGI_FORMAT_AYUV:
105 case DXGI_FORMAT_Y410:
106 case DXGI_FORMAT_YUY2:
107 return 32;
109 case DXGI_FORMAT_P010:
110 case DXGI_FORMAT_P016:
111 return 24;
113 case DXGI_FORMAT_R8G8_TYPELESS:
114 case DXGI_FORMAT_R8G8_UNORM:
115 case DXGI_FORMAT_R8G8_UINT:
116 case DXGI_FORMAT_R8G8_SNORM:
117 case DXGI_FORMAT_R8G8_SINT:
118 case DXGI_FORMAT_R16_TYPELESS:
119 case DXGI_FORMAT_R16_FLOAT:
120 case DXGI_FORMAT_D16_UNORM:
121 case DXGI_FORMAT_R16_UNORM:
122 case DXGI_FORMAT_R16_UINT:
123 case DXGI_FORMAT_R16_SNORM:
124 case DXGI_FORMAT_R16_SINT:
125 case DXGI_FORMAT_B5G6R5_UNORM:
126 case DXGI_FORMAT_B5G5R5A1_UNORM:
127 case DXGI_FORMAT_A8P8:
128 case DXGI_FORMAT_B4G4R4A4_UNORM:
129 return 16;
131 case DXGI_FORMAT_NV12:
132 case DXGI_FORMAT_420_OPAQUE:
133 case DXGI_FORMAT_NV11:
134 return 12;
136 case DXGI_FORMAT_R8_TYPELESS:
137 case DXGI_FORMAT_R8_UNORM:
138 case DXGI_FORMAT_R8_UINT:
139 case DXGI_FORMAT_R8_SNORM:
140 case DXGI_FORMAT_R8_SINT:
141 case DXGI_FORMAT_A8_UNORM:
142 case DXGI_FORMAT_AI44:
143 case DXGI_FORMAT_IA44:
144 case DXGI_FORMAT_P8:
145 return 8;
147 case DXGI_FORMAT_R1_UNORM:
148 return 1;
150 case DXGI_FORMAT_BC1_TYPELESS:
151 case DXGI_FORMAT_BC1_UNORM:
152 case DXGI_FORMAT_BC1_UNORM_SRGB:
153 case DXGI_FORMAT_BC4_TYPELESS:
154 case DXGI_FORMAT_BC4_UNORM:
155 case DXGI_FORMAT_BC4_SNORM:
156 return 4;
158 case DXGI_FORMAT_BC2_TYPELESS:
159 case DXGI_FORMAT_BC2_UNORM:
160 case DXGI_FORMAT_BC2_UNORM_SRGB:
161 case DXGI_FORMAT_BC3_TYPELESS:
162 case DXGI_FORMAT_BC3_UNORM:
163 case DXGI_FORMAT_BC3_UNORM_SRGB:
164 case DXGI_FORMAT_BC5_TYPELESS:
165 case DXGI_FORMAT_BC5_UNORM:
166 case DXGI_FORMAT_BC5_SNORM:
167 case DXGI_FORMAT_BC6H_TYPELESS:
168 case DXGI_FORMAT_BC6H_UF16:
169 case DXGI_FORMAT_BC6H_SF16:
170 case DXGI_FORMAT_BC7_TYPELESS:
171 case DXGI_FORMAT_BC7_UNORM:
172 case DXGI_FORMAT_BC7_UNORM_SRGB:
173 return 8;
175 default:
176 return 0;
181 //--------------------------------------------------------------------------------------
182 // Get surface information for a particular format
183 //--------------------------------------------------------------------------------------
184 static void GetSurfaceInfo( _In_ size_t width,
185 _In_ size_t height,
186 _In_ DXGI_FORMAT fmt,
187 _Out_opt_ size_t* outNumBytes,
188 _Out_opt_ size_t* outRowBytes,
189 _Out_opt_ size_t* outNumRows )
191 size_t numBytes = 0;
192 size_t rowBytes = 0;
193 size_t numRows = 0;
195 bool bc = false;
196 bool packed = false;
197 bool planar = false;
198 size_t bpe = 0;
199 switch (fmt)
201 case DXGI_FORMAT_BC1_TYPELESS:
202 case DXGI_FORMAT_BC1_UNORM:
203 case DXGI_FORMAT_BC1_UNORM_SRGB:
204 case DXGI_FORMAT_BC4_TYPELESS:
205 case DXGI_FORMAT_BC4_UNORM:
206 case DXGI_FORMAT_BC4_SNORM:
207 bc=true;
208 bpe = 8;
209 break;
211 case DXGI_FORMAT_BC2_TYPELESS:
212 case DXGI_FORMAT_BC2_UNORM:
213 case DXGI_FORMAT_BC2_UNORM_SRGB:
214 case DXGI_FORMAT_BC3_TYPELESS:
215 case DXGI_FORMAT_BC3_UNORM:
216 case DXGI_FORMAT_BC3_UNORM_SRGB:
217 case DXGI_FORMAT_BC5_TYPELESS:
218 case DXGI_FORMAT_BC5_UNORM:
219 case DXGI_FORMAT_BC5_SNORM:
220 case DXGI_FORMAT_BC6H_TYPELESS:
221 case DXGI_FORMAT_BC6H_UF16:
222 case DXGI_FORMAT_BC6H_SF16:
223 case DXGI_FORMAT_BC7_TYPELESS:
224 case DXGI_FORMAT_BC7_UNORM:
225 case DXGI_FORMAT_BC7_UNORM_SRGB:
226 bc = true;
227 bpe = 16;
228 break;
230 case DXGI_FORMAT_R8G8_B8G8_UNORM:
231 case DXGI_FORMAT_G8R8_G8B8_UNORM:
232 case DXGI_FORMAT_YUY2:
233 packed = true;
234 bpe = 4;
235 break;
237 case DXGI_FORMAT_Y210:
238 case DXGI_FORMAT_Y216:
239 packed = true;
240 bpe = 8;
241 break;
243 case DXGI_FORMAT_NV12:
244 case DXGI_FORMAT_420_OPAQUE:
245 planar = true;
246 bpe = 2;
247 break;
249 case DXGI_FORMAT_P010:
250 case DXGI_FORMAT_P016:
251 planar = true;
252 bpe = 4;
253 break;
254 default:
255 break;
258 if (bc)
260 size_t numBlocksWide = 0;
261 if (width > 0)
263 numBlocksWide = std::max<size_t>( 1, (width + 3) / 4 );
265 size_t numBlocksHigh = 0;
266 if (height > 0)
268 numBlocksHigh = std::max<size_t>( 1, (height + 3) / 4 );
270 rowBytes = numBlocksWide * bpe;
271 numRows = numBlocksHigh;
272 numBytes = rowBytes * numBlocksHigh;
274 else if (packed)
276 rowBytes = ( ( width + 1 ) >> 1 ) * bpe;
277 numRows = height;
278 numBytes = rowBytes * height;
280 else if ( fmt == DXGI_FORMAT_NV11 )
282 rowBytes = ( ( width + 3 ) >> 2 ) * 4;
283 numRows = height * 2; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data
284 numBytes = rowBytes * numRows;
286 else if (planar)
288 rowBytes = ( ( width + 1 ) >> 1 ) * bpe;
289 numBytes = ( rowBytes * height ) + ( ( rowBytes * height + 1 ) >> 1 );
290 numRows = height + ( ( height + 1 ) >> 1 );
292 else
294 size_t bpp = BitsPerPixel( fmt );
295 rowBytes = ( width * bpp + 7 ) / 8; // round up to nearest byte
296 numRows = height;
297 numBytes = rowBytes * height;
300 if (outNumBytes)
302 *outNumBytes = numBytes;
304 if (outRowBytes)
306 *outRowBytes = rowBytes;
308 if (outNumRows)
310 *outNumRows = numRows;
315 //--------------------------------------------------------------------------------------
316 #define ISBITMASK( r,g,b,a ) ( ddpf.RBitMask == r && ddpf.GBitMask == g && ddpf.BBitMask == b && ddpf.ABitMask == a )
318 static DXGI_FORMAT GetDXGIFormat( const DDS_PIXELFORMAT& ddpf )
320 if (ddpf.flags & DDS_RGB)
322 // Note that sRGB formats are written using the "DX10" extended header
324 switch (ddpf.RGBBitCount)
326 case 32:
327 if (ISBITMASK(0x000000ff,0x0000ff00,0x00ff0000,0xff000000))
329 return DXGI_FORMAT_R8G8B8A8_UNORM;
332 if (ISBITMASK(0x00ff0000,0x0000ff00,0x000000ff,0xff000000))
334 return DXGI_FORMAT_B8G8R8A8_UNORM;
337 if (ISBITMASK(0x00ff0000,0x0000ff00,0x000000ff,0x00000000))
339 return DXGI_FORMAT_B8G8R8X8_UNORM;
342 // No DXGI format maps to ISBITMASK(0x000000ff,0x0000ff00,0x00ff0000,0x00000000) aka D3DFMT_X8B8G8R8
344 // Note that many common DDS reader/writers (including D3DX) swap the
345 // the RED/BLUE masks for 10:10:10:2 formats. We assumme
346 // below that the 'backwards' header mask is being used since it is most
347 // likely written by D3DX. The more robust solution is to use the 'DX10'
348 // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly
350 // For 'correct' writers, this should be 0x000003ff,0x000ffc00,0x3ff00000 for RGB data
351 if (ISBITMASK(0x3ff00000,0x000ffc00,0x000003ff,0xc0000000))
353 return DXGI_FORMAT_R10G10B10A2_UNORM;
356 // No DXGI format maps to ISBITMASK(0x000003ff,0x000ffc00,0x3ff00000,0xc0000000) aka D3DFMT_A2R10G10B10
358 if (ISBITMASK(0x0000ffff,0xffff0000,0x00000000,0x00000000))
360 return DXGI_FORMAT_R16G16_UNORM;
363 if (ISBITMASK(0xffffffff,0x00000000,0x00000000,0x00000000))
365 // Only 32-bit color channel format in D3D9 was R32F
366 return DXGI_FORMAT_R32_FLOAT; // D3DX writes this out as a FourCC of 114
368 break;
370 case 24:
371 // No 24bpp DXGI formats aka D3DFMT_R8G8B8
372 break;
374 case 16:
375 if (ISBITMASK(0x7c00,0x03e0,0x001f,0x8000))
377 return DXGI_FORMAT_B5G5R5A1_UNORM;
379 if (ISBITMASK(0xf800,0x07e0,0x001f,0x0000))
381 return DXGI_FORMAT_B5G6R5_UNORM;
384 // No DXGI format maps to ISBITMASK(0x7c00,0x03e0,0x001f,0x0000) aka D3DFMT_X1R5G5B5
386 if (ISBITMASK(0x0f00,0x00f0,0x000f,0xf000))
388 return DXGI_FORMAT_B4G4R4A4_UNORM;
391 // No DXGI format maps to ISBITMASK(0x0f00,0x00f0,0x000f,0x0000) aka D3DFMT_X4R4G4B4
393 // No 3:3:2, 3:3:2:8, or paletted DXGI formats aka D3DFMT_A8R3G3B2, D3DFMT_R3G3B2, D3DFMT_P8, D3DFMT_A8P8, etc.
394 break;
397 else if (ddpf.flags & DDS_LUMINANCE)
399 if (8 == ddpf.RGBBitCount)
401 if (ISBITMASK(0x000000ff,0x00000000,0x00000000,0x00000000))
403 return DXGI_FORMAT_R8_UNORM; // D3DX10/11 writes this out as DX10 extension
406 // No DXGI format maps to ISBITMASK(0x0f,0x00,0x00,0xf0) aka D3DFMT_A4L4
409 if (16 == ddpf.RGBBitCount)
411 if (ISBITMASK(0x0000ffff,0x00000000,0x00000000,0x00000000))
413 return DXGI_FORMAT_R16_UNORM; // D3DX10/11 writes this out as DX10 extension
415 if (ISBITMASK(0x000000ff,0x00000000,0x00000000,0x0000ff00))
417 return DXGI_FORMAT_R8G8_UNORM; // D3DX10/11 writes this out as DX10 extension
421 else if (ddpf.flags & DDS_ALPHA)
423 if (8 == ddpf.RGBBitCount)
425 return DXGI_FORMAT_A8_UNORM;
428 else if (ddpf.flags & DDS_FOURCC)
430 if (MAKEFOURCC( 'D', 'X', 'T', '1' ) == ddpf.fourCC)
432 return DXGI_FORMAT_BC1_UNORM;
434 if (MAKEFOURCC( 'D', 'X', 'T', '3' ) == ddpf.fourCC)
436 return DXGI_FORMAT_BC2_UNORM;
438 if (MAKEFOURCC( 'D', 'X', 'T', '5' ) == ddpf.fourCC)
440 return DXGI_FORMAT_BC3_UNORM;
443 // While pre-mulitplied alpha isn't directly supported by the DXGI formats,
444 // they are basically the same as these BC formats so they can be mapped
445 if (MAKEFOURCC( 'D', 'X', 'T', '2' ) == ddpf.fourCC)
447 return DXGI_FORMAT_BC2_UNORM;
449 if (MAKEFOURCC( 'D', 'X', 'T', '4' ) == ddpf.fourCC)
451 return DXGI_FORMAT_BC3_UNORM;
454 if (MAKEFOURCC( 'A', 'T', 'I', '1' ) == ddpf.fourCC)
456 return DXGI_FORMAT_BC4_UNORM;
458 if (MAKEFOURCC( 'B', 'C', '4', 'U' ) == ddpf.fourCC)
460 return DXGI_FORMAT_BC4_UNORM;
462 if (MAKEFOURCC( 'B', 'C', '4', 'S' ) == ddpf.fourCC)
464 return DXGI_FORMAT_BC4_SNORM;
467 if (MAKEFOURCC( 'A', 'T', 'I', '2' ) == ddpf.fourCC)
469 return DXGI_FORMAT_BC5_UNORM;
471 if (MAKEFOURCC( 'B', 'C', '5', 'U' ) == ddpf.fourCC)
473 return DXGI_FORMAT_BC5_UNORM;
475 if (MAKEFOURCC( 'B', 'C', '5', 'S' ) == ddpf.fourCC)
477 return DXGI_FORMAT_BC5_SNORM;
480 // BC6H and BC7 are written using the "DX10" extended header
482 if (MAKEFOURCC( 'R', 'G', 'B', 'G' ) == ddpf.fourCC)
484 return DXGI_FORMAT_R8G8_B8G8_UNORM;
486 if (MAKEFOURCC( 'G', 'R', 'G', 'B' ) == ddpf.fourCC)
488 return DXGI_FORMAT_G8R8_G8B8_UNORM;
491 if (MAKEFOURCC('Y','U','Y','2') == ddpf.fourCC)
493 return DXGI_FORMAT_YUY2;
496 // Check for D3DFORMAT enums being set here
497 switch( ddpf.fourCC )
499 case 36: // D3DFMT_A16B16G16R16
500 return DXGI_FORMAT_R16G16B16A16_UNORM;
502 case 110: // D3DFMT_Q16W16V16U16
503 return DXGI_FORMAT_R16G16B16A16_SNORM;
505 case 111: // D3DFMT_R16F
506 return DXGI_FORMAT_R16_FLOAT;
508 case 112: // D3DFMT_G16R16F
509 return DXGI_FORMAT_R16G16_FLOAT;
511 case 113: // D3DFMT_A16B16G16R16F
512 return DXGI_FORMAT_R16G16B16A16_FLOAT;
514 case 114: // D3DFMT_R32F
515 return DXGI_FORMAT_R32_FLOAT;
517 case 115: // D3DFMT_G32R32F
518 return DXGI_FORMAT_R32G32_FLOAT;
520 case 116: // D3DFMT_A32B32G32R32F
521 return DXGI_FORMAT_R32G32B32A32_FLOAT;
525 return DXGI_FORMAT_UNKNOWN;
529 //--------------------------------------------------------------------------------------
530 static DXGI_FORMAT MakeSRGB( _In_ DXGI_FORMAT format )
532 switch( format )
534 case DXGI_FORMAT_R8G8B8A8_UNORM:
535 return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
537 case DXGI_FORMAT_BC1_UNORM:
538 return DXGI_FORMAT_BC1_UNORM_SRGB;
540 case DXGI_FORMAT_BC2_UNORM:
541 return DXGI_FORMAT_BC2_UNORM_SRGB;
543 case DXGI_FORMAT_BC3_UNORM:
544 return DXGI_FORMAT_BC3_UNORM_SRGB;
546 case DXGI_FORMAT_B8G8R8A8_UNORM:
547 return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
549 case DXGI_FORMAT_B8G8R8X8_UNORM:
550 return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB;
552 case DXGI_FORMAT_BC7_UNORM:
553 return DXGI_FORMAT_BC7_UNORM_SRGB;
555 default:
556 return format;
561 //--------------------------------------------------------------------------------------
562 static HRESULT FillInitData( _In_ size_t width,
563 _In_ size_t height,
564 _In_ size_t depth,
565 _In_ size_t mipCount,
566 _In_ size_t arraySize,
567 _In_ DXGI_FORMAT format,
568 _In_ size_t maxsize,
569 _In_ size_t bitSize,
570 _In_reads_bytes_(bitSize) const uint8_t* bitData,
571 _Out_ size_t& twidth,
572 _Out_ size_t& theight,
573 _Out_ size_t& tdepth,
574 _Out_ size_t& skipMip,
575 _Out_writes_(mipCount*arraySize) D3D12_SUBRESOURCE_DATA* initData )
577 if ( !bitData || !initData )
579 return E_POINTER;
582 skipMip = 0;
583 twidth = 0;
584 theight = 0;
585 tdepth = 0;
587 size_t NumBytes = 0;
588 size_t RowBytes = 0;
589 const uint8_t* pSrcBits = bitData;
590 const uint8_t* pEndBits = bitData + bitSize;
592 size_t index = 0;
593 for( size_t j = 0; j < arraySize; j++ )
595 size_t w = width;
596 size_t h = height;
597 size_t d = depth;
598 for( size_t i = 0; i < mipCount; i++ )
600 GetSurfaceInfo( w,
602 format,
603 &NumBytes,
604 &RowBytes,
605 nullptr
608 if ( (mipCount <= 1) || !maxsize || (w <= maxsize && h <= maxsize && d <= maxsize) )
610 if ( !twidth )
612 twidth = w;
613 theight = h;
614 tdepth = d;
617 assert(index < mipCount * arraySize);
618 _Analysis_assume_(index < mipCount * arraySize);
619 initData[index].pData = ( const void* )pSrcBits;
620 initData[index].RowPitch = static_cast<UINT>( RowBytes );
621 initData[index].SlicePitch = static_cast<UINT>( NumBytes );
622 ++index;
624 else if ( !j )
626 // Count number of skipped mipmaps (first item only)
627 ++skipMip;
630 if (pSrcBits + (NumBytes*d) > pEndBits)
632 return HRESULT_FROM_WIN32( ERROR_HANDLE_EOF );
635 pSrcBits += NumBytes * d;
637 w = w >> 1;
638 h = h >> 1;
639 d = d >> 1;
640 if (w == 0)
642 w = 1;
644 if (h == 0)
646 h = 1;
648 if (d == 0)
650 d = 1;
655 return (index > 0) ? S_OK : E_FAIL;
659 //--------------------------------------------------------------------------------------
660 static HRESULT CreateD3DResources( _In_ ID3D12Device* d3dDevice,
661 _In_ uint32_t resDim,
662 _In_ size_t width,
663 _In_ size_t height,
664 _In_ size_t depth,
665 _In_ size_t mipCount,
666 _In_ size_t arraySize,
667 _In_ DXGI_FORMAT format,
668 _In_ bool forceSRGB,
669 _In_ bool isCubeMap,
670 _Outptr_opt_ ID3D12Resource** texture,
671 _In_ D3D12_CPU_DESCRIPTOR_HANDLE textureView )
673 if ( !d3dDevice )
674 return E_POINTER;
676 HRESULT hr = E_FAIL;
678 if ( forceSRGB )
680 format = MakeSRGB( format );
683 D3D12_HEAP_PROPERTIES HeapProps;
684 HeapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
685 HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
686 HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
687 HeapProps.CreationNodeMask = 1;
688 HeapProps.VisibleNodeMask = 1;
690 D3D12_RESOURCE_DESC ResourceDesc;
691 ResourceDesc.Alignment = 0;
692 ResourceDesc.Width = static_cast<UINT64>( width );
693 ResourceDesc.Height = static_cast<UINT>( height );
694 ResourceDesc.DepthOrArraySize = static_cast<UINT16>( arraySize );
695 ResourceDesc.MipLevels = static_cast<UINT16>( mipCount );
696 ResourceDesc.Format = format;
697 ResourceDesc.SampleDesc.Count = 1;
698 ResourceDesc.SampleDesc.Quality = 0;
699 ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
700 ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
702 switch ( resDim )
704 case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
706 ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D;
708 ID3D12Resource* tex = nullptr;
709 hr = d3dDevice->CreateCommittedResource( &HeapProps, D3D12_HEAP_FLAG_NONE, &ResourceDesc,
710 D3D12_RESOURCE_STATE_COPY_DEST, nullptr, MY_IID_PPV_ARGS(&tex));
712 if (SUCCEEDED( hr ) && tex != nullptr)
714 D3D12_SHADER_RESOURCE_VIEW_DESC SRVDesc = {};
715 SRVDesc.Format = format;
716 SRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
718 if (arraySize > 1)
720 SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
721 SRVDesc.Texture1DArray.MipLevels = (!mipCount) ? -1 : ResourceDesc.MipLevels;
722 SRVDesc.Texture1DArray.ArraySize = static_cast<UINT>( arraySize );
724 else
726 SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
727 SRVDesc.Texture1D.MipLevels = (!mipCount) ? -1 : ResourceDesc.MipLevels;
730 d3dDevice->CreateShaderResourceView( tex, &SRVDesc, textureView );
732 if (texture != nullptr)
734 *texture = tex;
736 else
738 tex->SetName(L"DDSTextureLoader");
739 tex->Release();
743 break;
745 case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
747 ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
749 ID3D12Resource* tex = nullptr;
750 hr = d3dDevice->CreateCommittedResource( &HeapProps, D3D12_HEAP_FLAG_NONE, &ResourceDesc,
751 D3D12_RESOURCE_STATE_COPY_DEST, nullptr, MY_IID_PPV_ARGS(&tex));
753 if (SUCCEEDED( hr ) && tex != 0)
755 D3D12_SHADER_RESOURCE_VIEW_DESC SRVDesc = {};
756 SRVDesc.Format = format;
757 SRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
759 if ( isCubeMap )
761 if (arraySize > 6)
763 SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
764 SRVDesc.TextureCubeArray.MipLevels = (!mipCount) ? -1 : ResourceDesc.MipLevels;
766 // Earlier we set arraySize to (NumCubes * 6)
767 SRVDesc.TextureCubeArray.NumCubes = static_cast<UINT>( arraySize / 6 );
769 else
771 SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
772 SRVDesc.TextureCube.MipLevels = (!mipCount) ? -1 : ResourceDesc.MipLevels;
775 else if (arraySize > 1)
777 SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
778 SRVDesc.Texture2DArray.MipLevels = (!mipCount) ? -1 : ResourceDesc.MipLevels;
779 SRVDesc.Texture2DArray.ArraySize = static_cast<UINT>( arraySize );
781 else
783 SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
784 SRVDesc.Texture2D.MipLevels = (!mipCount) ? -1 : ResourceDesc.MipLevels;
785 SRVDesc.Texture2D.MostDetailedMip = 0;
788 d3dDevice->CreateShaderResourceView( tex, &SRVDesc, textureView );
790 if (texture != nullptr)
792 *texture = tex;
794 else
796 tex->SetName(L"DDSTextureLoader");
797 tex->Release();
801 break;
803 case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
805 ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;
806 ResourceDesc.DepthOrArraySize = static_cast<UINT16>( depth );
808 ID3D12Resource* tex = nullptr;
809 hr = d3dDevice->CreateCommittedResource( &HeapProps, D3D12_HEAP_FLAG_NONE, &ResourceDesc,
810 D3D12_RESOURCE_STATE_COPY_DEST, nullptr, MY_IID_PPV_ARGS(&tex));
812 if (SUCCEEDED( hr ) && tex != nullptr)
814 D3D12_SHADER_RESOURCE_VIEW_DESC SRVDesc = {};
815 SRVDesc.Format = format;
816 SRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
818 SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
819 SRVDesc.Texture3D.MipLevels = (!mipCount) ? -1 : ResourceDesc.MipLevels;
820 SRVDesc.Texture3D.MostDetailedMip = 0;
822 d3dDevice->CreateShaderResourceView( tex, &SRVDesc, textureView );
824 if (texture != nullptr)
826 *texture = tex;
828 else
830 tex->SetName(L"DDS Texture (3D)");
831 tex->Release();
835 break;
838 return hr;
841 //--------------------------------------------------------------------------------------
842 static HRESULT CreateTextureFromDDS( _In_ ID3D12Device* d3dDevice,
843 _In_ const DDS_HEADER* header,
844 _In_reads_bytes_(bitSize) const uint8_t* bitData,
845 _In_ size_t bitSize,
846 _In_ size_t maxsize,
847 _In_ bool forceSRGB,
848 _Outptr_opt_ ID3D12Resource** texture,
849 _In_ D3D12_CPU_DESCRIPTOR_HANDLE textureView )
851 HRESULT hr = S_OK;
853 UINT width = header->width;
854 UINT height = header->height;
855 UINT depth = header->depth;
857 uint32_t resDim = D3D12_RESOURCE_DIMENSION_UNKNOWN;
858 UINT arraySize = 1;
859 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
860 bool isCubeMap = false;
862 size_t mipCount = header->mipMapCount;
863 if (0 == mipCount)
865 mipCount = 1;
868 if ((header->ddspf.flags & DDS_FOURCC) && (MAKEFOURCC( 'D', 'X', '1', '0' ) == header->ddspf.fourCC ))
870 auto d3d10ext = reinterpret_cast<const DDS_HEADER_DXT10*>( (const char*)header + sizeof(DDS_HEADER) );
872 arraySize = d3d10ext->arraySize;
873 if (arraySize == 0)
875 return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
878 switch( d3d10ext->dxgiFormat )
880 case DXGI_FORMAT_AI44:
881 case DXGI_FORMAT_IA44:
882 case DXGI_FORMAT_P8:
883 case DXGI_FORMAT_A8P8:
884 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
886 default:
887 if ( BitsPerPixel( d3d10ext->dxgiFormat ) == 0 )
889 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
893 format = d3d10ext->dxgiFormat;
895 switch ( d3d10ext->resourceDimension )
897 case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
898 // D3DX writes 1D textures with a fixed Height of 1
899 if ((header->flags & DDS_HEIGHT) && height != 1)
901 return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
903 height = depth = 1;
904 break;
906 case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
907 if (d3d10ext->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE)
909 arraySize *= 6;
910 isCubeMap = true;
912 depth = 1;
913 break;
915 case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
916 if (!(header->flags & DDS_HEADER_FLAGS_VOLUME))
918 return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
921 if (arraySize > 1)
923 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
925 break;
927 default:
928 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
931 resDim = d3d10ext->resourceDimension;
933 else
935 format = GetDXGIFormat( header->ddspf );
937 if (format == DXGI_FORMAT_UNKNOWN)
939 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
942 if (header->flags & DDS_HEADER_FLAGS_VOLUME)
944 resDim = D3D12_RESOURCE_DIMENSION_TEXTURE3D;
946 else
948 if (header->caps2 & DDS_CUBEMAP)
950 // We require all six faces to be defined
951 if ((header->caps2 & DDS_CUBEMAP_ALLFACES ) != DDS_CUBEMAP_ALLFACES)
953 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
956 arraySize = 6;
957 isCubeMap = true;
960 depth = 1;
961 resDim = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
963 // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture
966 assert( BitsPerPixel( format ) != 0 );
969 // Bound sizes (for security purposes we don't trust DDS file metadata larger than the D3D 11.x hardware requirements)
970 if (mipCount > D3D12_REQ_MIP_LEVELS)
972 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
975 switch ( resDim )
977 case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
978 if ((arraySize > D3D12_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION) ||
979 (width > D3D12_REQ_TEXTURE1D_U_DIMENSION) )
981 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
983 break;
985 case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
986 if ( isCubeMap )
988 // This is the right bound because we set arraySize to (NumCubes*6) above
989 if ((arraySize > D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||
990 (width > D3D12_REQ_TEXTURECUBE_DIMENSION) ||
991 (height > D3D12_REQ_TEXTURECUBE_DIMENSION))
993 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
996 else if ((arraySize > D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||
997 (width > D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION) ||
998 (height > D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION))
1000 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
1002 break;
1004 case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
1005 if ((arraySize > 1) ||
1006 (width > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||
1007 (height > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||
1008 (depth > D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) )
1010 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
1012 break;
1014 default:
1015 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
1019 // Create the texture
1020 UINT subresourceCount = static_cast<UINT>(mipCount) * arraySize;
1021 std::unique_ptr<D3D12_SUBRESOURCE_DATA[]> initData( new (std::nothrow) D3D12_SUBRESOURCE_DATA[subresourceCount] );
1022 if ( !initData )
1024 return E_OUTOFMEMORY;
1027 size_t skipMip = 0;
1028 size_t twidth = 0;
1029 size_t theight = 0;
1030 size_t tdepth = 0;
1031 hr = FillInitData( width, height, depth, mipCount, arraySize, format, maxsize, bitSize, bitData,
1032 twidth, theight, tdepth, skipMip, initData.get() );
1034 if ( SUCCEEDED(hr) )
1036 hr = CreateD3DResources( d3dDevice, resDim, twidth, theight, tdepth, mipCount - skipMip, arraySize,
1037 format, forceSRGB,
1038 isCubeMap, texture, textureView );
1040 if ( FAILED(hr) && !maxsize && (mipCount > 1) )
1042 // Retry with a maxsize determined by feature level
1043 maxsize = (resDim == D3D12_RESOURCE_DIMENSION_TEXTURE3D)
1044 ? 2048 /*D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION*/
1045 : 8192 /*D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION*/;
1047 hr = FillInitData( width, height, depth, mipCount, arraySize, format, maxsize, bitSize, bitData,
1048 twidth, theight, tdepth, skipMip, initData.get() );
1049 if ( SUCCEEDED(hr) )
1051 hr = CreateD3DResources( d3dDevice, resDim, twidth, theight, tdepth, mipCount - skipMip, arraySize,
1052 format, forceSRGB,
1053 isCubeMap, texture, textureView );
1058 if (SUCCEEDED(hr))
1060 GpuResource DestTexture(*texture, D3D12_RESOURCE_STATE_COPY_DEST);
1061 CommandContext::InitializeTexture(DestTexture, subresourceCount, initData.get());
1065 return hr;
1069 //--------------------------------------------------------------------------------------
1070 static DDS_ALPHA_MODE GetAlphaMode( _In_ const DDS_HEADER* header )
1072 if ( header->ddspf.flags & DDS_FOURCC )
1074 if ( MAKEFOURCC( 'D', 'X', '1', '0' ) == header->ddspf.fourCC )
1076 auto d3d10ext = reinterpret_cast<const DDS_HEADER_DXT10*>( (const char*)header + sizeof(DDS_HEADER) );
1077 auto mode = static_cast<DDS_ALPHA_MODE>( d3d10ext->miscFlags2 & DDS_MISC_FLAGS2_ALPHA_MODE_MASK );
1078 switch( mode )
1080 case DDS_ALPHA_MODE_STRAIGHT:
1081 case DDS_ALPHA_MODE_PREMULTIPLIED:
1082 case DDS_ALPHA_MODE_OPAQUE:
1083 case DDS_ALPHA_MODE_CUSTOM:
1084 case DDS_ALPHA_MODE_UNKNOWN:
1085 return mode;
1088 else if ( ( MAKEFOURCC( 'D', 'X', 'T', '2' ) == header->ddspf.fourCC )
1089 || ( MAKEFOURCC( 'D', 'X', 'T', '4' ) == header->ddspf.fourCC ) )
1091 return DDS_ALPHA_MODE_PREMULTIPLIED;
1095 return DDS_ALPHA_MODE_UNKNOWN;
1099 _Use_decl_annotations_
1100 HRESULT CreateDDSTextureFromMemory(
1101 ID3D12Device* d3dDevice,
1102 const uint8_t* ddsData,
1103 size_t ddsDataSize,
1104 size_t maxsize,
1105 bool forceSRGB,
1106 ID3D12Resource** texture,
1107 D3D12_CPU_DESCRIPTOR_HANDLE textureView,
1108 DDS_ALPHA_MODE* alphaMode )
1110 if ( texture )
1112 *texture = nullptr;
1115 if ( alphaMode )
1117 *alphaMode = DDS_ALPHA_MODE_UNKNOWN;
1120 if (!d3dDevice || !ddsData)
1122 return E_INVALIDARG;
1125 // Validate DDS file in memory
1126 if (ddsDataSize < (sizeof(uint32_t) + sizeof(DDS_HEADER)))
1128 return E_FAIL;
1131 uint32_t dwMagicNumber = *( const uint32_t* )( ddsData );
1132 if (dwMagicNumber != DDS_MAGIC)
1134 return E_FAIL;
1137 auto header = reinterpret_cast<const DDS_HEADER*>( ddsData + sizeof( uint32_t ) );
1139 // Verify header to validate DDS file
1140 if (header->size != sizeof(DDS_HEADER) ||
1141 header->ddspf.size != sizeof(DDS_PIXELFORMAT))
1143 return E_FAIL;
1146 size_t offset = sizeof(DDS_HEADER) + sizeof(uint32_t);
1148 // Check for extensions
1149 if (header->ddspf.flags & DDS_FOURCC)
1151 if (MAKEFOURCC( 'D', 'X', '1', '0' ) == header->ddspf.fourCC)
1152 offset += sizeof(DDS_HEADER_DXT10);
1155 // Must be long enough for all headers and magic value
1156 if (ddsDataSize < offset)
1157 return E_FAIL;
1159 HRESULT hr = CreateTextureFromDDS( d3dDevice,
1160 header, ddsData + offset, ddsDataSize - offset, maxsize,
1161 forceSRGB, texture, textureView );
1162 if ( SUCCEEDED(hr) )
1164 if (texture != nullptr && *texture != nullptr)
1166 (*texture)->SetName(L"DDSTextureLoader");
1169 if ( alphaMode )
1170 *alphaMode = GetAlphaMode( header );
1173 return hr;