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 //--------------------------------------------------------------------------------------
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 //--------------------------------------------------------------------------------------
23 #include "DDSTextureLoader.h"
26 #include "GpuResource.h"
27 #include "GraphicsCore.h"
28 #include "CommandContext.h"
31 //--------------------------------------------------------------------------------------
32 // Return the BPP for a particular format
33 //--------------------------------------------------------------------------------------
34 size_t BitsPerPixel( _In_ DXGI_FORMAT 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
:
44 case DXGI_FORMAT_R32G32B32_TYPELESS
:
45 case DXGI_FORMAT_R32G32B32_FLOAT
:
46 case DXGI_FORMAT_R32G32B32_UINT
:
47 case DXGI_FORMAT_R32G32B32_SINT
:
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
:
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
:
109 case DXGI_FORMAT_P010
:
110 case DXGI_FORMAT_P016
:
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
:
131 case DXGI_FORMAT_NV12
:
132 case DXGI_FORMAT_420_OPAQUE
:
133 case DXGI_FORMAT_NV11
:
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
:
147 case DXGI_FORMAT_R1_UNORM
:
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
:
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
:
181 //--------------------------------------------------------------------------------------
182 // Get surface information for a particular format
183 //--------------------------------------------------------------------------------------
184 static void GetSurfaceInfo( _In_
size_t width
,
186 _In_ DXGI_FORMAT fmt
,
187 _Out_opt_
size_t* outNumBytes
,
188 _Out_opt_
size_t* outRowBytes
,
189 _Out_opt_
size_t* outNumRows
)
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
:
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
:
230 case DXGI_FORMAT_R8G8_B8G8_UNORM
:
231 case DXGI_FORMAT_G8R8_G8B8_UNORM
:
232 case DXGI_FORMAT_YUY2
:
237 case DXGI_FORMAT_Y210
:
238 case DXGI_FORMAT_Y216
:
243 case DXGI_FORMAT_NV12
:
244 case DXGI_FORMAT_420_OPAQUE
:
249 case DXGI_FORMAT_P010
:
250 case DXGI_FORMAT_P016
:
260 size_t numBlocksWide
= 0;
263 numBlocksWide
= std::max
<size_t>( 1, (width
+ 3) / 4 );
265 size_t numBlocksHigh
= 0;
268 numBlocksHigh
= std::max
<size_t>( 1, (height
+ 3) / 4 );
270 rowBytes
= numBlocksWide
* bpe
;
271 numRows
= numBlocksHigh
;
272 numBytes
= rowBytes
* numBlocksHigh
;
276 rowBytes
= ( ( width
+ 1 ) >> 1 ) * bpe
;
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
;
288 rowBytes
= ( ( width
+ 1 ) >> 1 ) * bpe
;
289 numBytes
= ( rowBytes
* height
) + ( ( rowBytes
* height
+ 1 ) >> 1 );
290 numRows
= height
+ ( ( height
+ 1 ) >> 1 );
294 size_t bpp
= BitsPerPixel( fmt
);
295 rowBytes
= ( width
* bpp
+ 7 ) / 8; // round up to nearest byte
297 numBytes
= rowBytes
* height
;
302 *outNumBytes
= numBytes
;
306 *outRowBytes
= rowBytes
;
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
)
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
371 // No 24bpp DXGI formats aka D3DFMT_R8G8B8
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.
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
)
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
;
561 //--------------------------------------------------------------------------------------
562 static HRESULT
FillInitData( _In_
size_t width
,
565 _In_
size_t mipCount
,
566 _In_
size_t arraySize
,
567 _In_ DXGI_FORMAT format
,
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
)
589 const uint8_t* pSrcBits
= bitData
;
590 const uint8_t* pEndBits
= bitData
+ bitSize
;
593 for( size_t j
= 0; j
< arraySize
; j
++ )
598 for( size_t i
= 0; i
< mipCount
; i
++ )
608 if ( (mipCount
<= 1) || !maxsize
|| (w
<= maxsize
&& h
<= maxsize
&& d
<= maxsize
) )
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
);
626 // Count number of skipped mipmaps (first item only)
630 if (pSrcBits
+ (NumBytes
*d
) > pEndBits
)
632 return HRESULT_FROM_WIN32( ERROR_HANDLE_EOF
);
635 pSrcBits
+= NumBytes
* d
;
655 return (index
> 0) ? S_OK
: E_FAIL
;
659 //--------------------------------------------------------------------------------------
660 static HRESULT
CreateD3DResources( _In_ ID3D12Device
* d3dDevice
,
661 _In_
uint32_t resDim
,
665 _In_
size_t mipCount
,
666 _In_
size_t arraySize
,
667 _In_ DXGI_FORMAT format
,
670 _Outptr_opt_ ID3D12Resource
** texture
,
671 _In_ D3D12_CPU_DESCRIPTOR_HANDLE textureView
)
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
;
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
;
720 SRVDesc
.ViewDimension
= D3D12_SRV_DIMENSION_TEXTURE1DARRAY
;
721 SRVDesc
.Texture1DArray
.MipLevels
= (!mipCount
) ? -1 : ResourceDesc
.MipLevels
;
722 SRVDesc
.Texture1DArray
.ArraySize
= static_cast<UINT
>( arraySize
);
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)
738 tex
->SetName(L
"DDSTextureLoader");
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
;
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 );
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
);
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)
796 tex
->SetName(L
"DDSTextureLoader");
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)
830 tex
->SetName(L
"DDS Texture (3D)");
841 //--------------------------------------------------------------------------------------
842 static HRESULT
CreateTextureFromDDS( _In_ ID3D12Device
* d3dDevice
,
843 _In_
const DDS_HEADER
* header
,
844 _In_reads_bytes_(bitSize
) const uint8_t* bitData
,
848 _Outptr_opt_ ID3D12Resource
** texture
,
849 _In_ D3D12_CPU_DESCRIPTOR_HANDLE textureView
)
853 UINT width
= header
->width
;
854 UINT height
= header
->height
;
855 UINT depth
= header
->depth
;
857 uint32_t resDim
= D3D12_RESOURCE_DIMENSION_UNKNOWN
;
859 DXGI_FORMAT format
= DXGI_FORMAT_UNKNOWN
;
860 bool isCubeMap
= false;
862 size_t mipCount
= header
->mipMapCount
;
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
;
875 return HRESULT_FROM_WIN32( ERROR_INVALID_DATA
);
878 switch( d3d10ext
->dxgiFormat
)
880 case DXGI_FORMAT_AI44
:
881 case DXGI_FORMAT_IA44
:
883 case DXGI_FORMAT_A8P8
:
884 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED
);
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
);
906 case D3D12_RESOURCE_DIMENSION_TEXTURE2D
:
907 if (d3d10ext
->miscFlag
& DDS_RESOURCE_MISC_TEXTURECUBE
)
915 case D3D12_RESOURCE_DIMENSION_TEXTURE3D
:
916 if (!(header
->flags
& DDS_HEADER_FLAGS_VOLUME
))
918 return HRESULT_FROM_WIN32( ERROR_INVALID_DATA
);
923 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED
);
928 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED
);
931 resDim
= d3d10ext
->resourceDimension
;
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
;
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
);
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
);
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
);
985 case D3D12_RESOURCE_DIMENSION_TEXTURE2D
:
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
);
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
);
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
] );
1024 return E_OUTOFMEMORY
;
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
,
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
,
1053 isCubeMap
, texture
, textureView
);
1060 GpuResource
DestTexture(*texture
, D3D12_RESOURCE_STATE_COPY_DEST
);
1061 CommandContext::InitializeTexture(DestTexture
, subresourceCount
, initData
.get());
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
);
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
:
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
,
1106 ID3D12Resource
** texture
,
1107 D3D12_CPU_DESCRIPTOR_HANDLE textureView
,
1108 DDS_ALPHA_MODE
* 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
)))
1131 uint32_t dwMagicNumber
= *( const uint32_t* )( ddsData
);
1132 if (dwMagicNumber
!= DDS_MAGIC
)
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
))
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
)
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");
1170 *alphaMode
= GetAlphaMode( header
);