OSDN Git Service

バックバッファを作ってみた。
[shooting3/shootinggame.git] / ShootingGame / DDSTextureLoader.cpp
1 //--------------------------------------------------------------------------------------
2 // File: DDSTextureLoader.cpp
3 //
4 // Function for loading a DDS texture and creating a Direct3D 11 runtime resource for it
5 //
6 // Note this function is useful as a light-weight runtime loader for DDS files. For
7 // a full-featured DDS file reader, writer, and texture processing pipeline see
8 // the 'Texconv' sample and the 'DirectXTex' library.
9 //
10 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
11 // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
12 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
13 // PARTICULAR PURPOSE.
14 //
15 // Copyright (c) Microsoft Corporation. All rights reserved.
16 //--------------------------------------------------------------------------------------
17
18 #include "pch.h"
19 #include <dxgiformat.h>
20 #include <assert.h>
21 #include <memory>
22 #include "DDSTextureLoader.h"
23 #include "DirectXSample.h"
24
25 using namespace Microsoft::WRL;
26
27 //--------------------------------------------------------------------------------------
28 // Macros
29 //--------------------------------------------------------------------------------------
30 #ifndef MAKEFOURCC
31     #define MAKEFOURCC(ch0, ch1, ch2, ch3)                              \
32                 ((uint32)(byte)(ch0) | ((uint32)(byte)(ch1) << 8) |       \
33                 ((uint32)(byte)(ch2) << 16) | ((uint32)(byte)(ch3) << 24 ))
34 #endif /* defined(MAKEFOURCC) */
35
36 //--------------------------------------------------------------------------------------
37 // DDS file structure definitions
38 //
39 // See DDS.h in the 'Texconv' sample and the 'DirectXTex' library
40 //--------------------------------------------------------------------------------------
41 #pragma pack(push,1)
42
43 #define DDS_MAGIC 0x20534444 // "DDS "
44
45 struct DDS_PIXELFORMAT
46 {
47     uint32  size;
48     uint32  flags;
49     uint32  fourCC;
50     uint32  RGBBitCount;
51     uint32  RBitMask;
52     uint32  GBitMask;
53     uint32  BBitMask;
54     uint32  ABitMask;
55 };
56
57 #define DDS_FOURCC      0x00000004  // DDPF_FOURCC
58 #define DDS_RGB         0x00000040  // DDPF_RGB
59 #define DDS_RGBA        0x00000041  // DDPF_RGB | DDPF_ALPHAPIXELS
60 #define DDS_LUMINANCE   0x00020000  // DDPF_LUMINANCE
61 #define DDS_LUMINANCEA  0x00020001  // DDPF_LUMINANCE | DDPF_ALPHAPIXELS
62 #define DDS_ALPHA       0x00000002  // DDPF_ALPHA
63 #define DDS_PAL8        0x00000020  // DDPF_PALETTEINDEXED8
64
65 #define DDS_HEADER_FLAGS_TEXTURE        0x00001007  // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT 
66 #define DDS_HEADER_FLAGS_MIPMAP         0x00020000  // DDSD_MIPMAPCOUNT
67 #define DDS_HEADER_FLAGS_VOLUME         0x00800000  // DDSD_DEPTH
68 #define DDS_HEADER_FLAGS_PITCH          0x00000008  // DDSD_PITCH
69 #define DDS_HEADER_FLAGS_LINEARSIZE     0x00080000  // DDSD_LINEARSIZE
70
71 #define DDS_HEIGHT 0x00000002 // DDSD_HEIGHT
72 #define DDS_WIDTH  0x00000004 // DDSD_WIDTH
73
74 #define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE
75 #define DDS_SURFACE_FLAGS_MIPMAP  0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP
76 #define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX
77
78 #define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX
79 #define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX
80 #define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY
81 #define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY
82 #define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ
83 #define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ
84
85 #define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\
86                                DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\
87                                DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ )
88
89 #define DDS_CUBEMAP 0x00000200 // DDSCAPS2_CUBEMAP
90
91 #define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME
92
93 typedef struct
94 {
95     uint32          size;
96     uint32          flags;
97     uint32          height;
98     uint32          width;
99     uint32          pitchOrLinearSize;
100     uint32          depth; // only if DDS_HEADER_FLAGS_VOLUME is set in flags
101     uint32          mipMapCount;
102     uint32          reserved1[11];
103     DDS_PIXELFORMAT ddspf;
104     uint32          caps;
105     uint32          caps2;
106     uint32          caps3;
107     uint32          caps4;
108     uint32          reserved2;
109 } DDS_HEADER;
110
111 typedef struct
112 {
113     DXGI_FORMAT dxgiFormat;
114     uint32      resourceDimension;
115     uint32      miscFlag; // see D3D11_RESOURCE_MISC_FLAG
116     uint32      arraySize;
117     uint32      reserved;
118 } DDS_HEADER_DXT10;
119
120 #pragma pack(pop)
121
122 //--------------------------------------------------------------------------------------
123 // Return the BPP for a particular format
124 //--------------------------------------------------------------------------------------
125 static size_t BitsPerPixel( _In_ DXGI_FORMAT fmt )
126 {
127     switch( fmt )
128     {
129     case DXGI_FORMAT_R32G32B32A32_TYPELESS:
130     case DXGI_FORMAT_R32G32B32A32_FLOAT:
131     case DXGI_FORMAT_R32G32B32A32_UINT:
132     case DXGI_FORMAT_R32G32B32A32_SINT:
133         return 128;
134
135     case DXGI_FORMAT_R32G32B32_TYPELESS:
136     case DXGI_FORMAT_R32G32B32_FLOAT:
137     case DXGI_FORMAT_R32G32B32_UINT:
138     case DXGI_FORMAT_R32G32B32_SINT:
139         return 96;
140
141     case DXGI_FORMAT_R16G16B16A16_TYPELESS:
142     case DXGI_FORMAT_R16G16B16A16_FLOAT:
143     case DXGI_FORMAT_R16G16B16A16_UNORM:
144     case DXGI_FORMAT_R16G16B16A16_UINT:
145     case DXGI_FORMAT_R16G16B16A16_SNORM:
146     case DXGI_FORMAT_R16G16B16A16_SINT:
147     case DXGI_FORMAT_R32G32_TYPELESS:
148     case DXGI_FORMAT_R32G32_FLOAT:
149     case DXGI_FORMAT_R32G32_UINT:
150     case DXGI_FORMAT_R32G32_SINT:
151     case DXGI_FORMAT_R32G8X24_TYPELESS:
152     case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
153     case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
154     case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
155         return 64;
156
157     case DXGI_FORMAT_R10G10B10A2_TYPELESS:
158     case DXGI_FORMAT_R10G10B10A2_UNORM:
159     case DXGI_FORMAT_R10G10B10A2_UINT:
160     case DXGI_FORMAT_R11G11B10_FLOAT:
161     case DXGI_FORMAT_R8G8B8A8_TYPELESS:
162     case DXGI_FORMAT_R8G8B8A8_UNORM:
163     case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
164     case DXGI_FORMAT_R8G8B8A8_UINT:
165     case DXGI_FORMAT_R8G8B8A8_SNORM:
166     case DXGI_FORMAT_R8G8B8A8_SINT:
167     case DXGI_FORMAT_R16G16_TYPELESS:
168     case DXGI_FORMAT_R16G16_FLOAT:
169     case DXGI_FORMAT_R16G16_UNORM:
170     case DXGI_FORMAT_R16G16_UINT:
171     case DXGI_FORMAT_R16G16_SNORM:
172     case DXGI_FORMAT_R16G16_SINT:
173     case DXGI_FORMAT_R32_TYPELESS:
174     case DXGI_FORMAT_D32_FLOAT:
175     case DXGI_FORMAT_R32_FLOAT:
176     case DXGI_FORMAT_R32_UINT:
177     case DXGI_FORMAT_R32_SINT:
178     case DXGI_FORMAT_R24G8_TYPELESS:
179     case DXGI_FORMAT_D24_UNORM_S8_UINT:
180     case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
181     case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
182     case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
183     case DXGI_FORMAT_R8G8_B8G8_UNORM:
184     case DXGI_FORMAT_G8R8_G8B8_UNORM:
185     case DXGI_FORMAT_B8G8R8A8_UNORM:
186     case DXGI_FORMAT_B8G8R8X8_UNORM:
187     case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
188     case DXGI_FORMAT_B8G8R8A8_TYPELESS:
189     case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
190     case DXGI_FORMAT_B8G8R8X8_TYPELESS:
191     case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
192         return 32;
193
194     case DXGI_FORMAT_R8G8_TYPELESS:
195     case DXGI_FORMAT_R8G8_UNORM:
196     case DXGI_FORMAT_R8G8_UINT:
197     case DXGI_FORMAT_R8G8_SNORM:
198     case DXGI_FORMAT_R8G8_SINT:
199     case DXGI_FORMAT_R16_TYPELESS:
200     case DXGI_FORMAT_R16_FLOAT:
201     case DXGI_FORMAT_D16_UNORM:
202     case DXGI_FORMAT_R16_UNORM:
203     case DXGI_FORMAT_R16_UINT:
204     case DXGI_FORMAT_R16_SNORM:
205     case DXGI_FORMAT_R16_SINT:
206     case DXGI_FORMAT_B5G6R5_UNORM:
207     case DXGI_FORMAT_B5G5R5A1_UNORM:
208     case DXGI_FORMAT_B4G4R4A4_UNORM:
209         return 16;
210
211     case DXGI_FORMAT_R8_TYPELESS:
212     case DXGI_FORMAT_R8_UNORM:
213     case DXGI_FORMAT_R8_UINT:
214     case DXGI_FORMAT_R8_SNORM:
215     case DXGI_FORMAT_R8_SINT:
216     case DXGI_FORMAT_A8_UNORM:
217         return 8;
218
219     case DXGI_FORMAT_R1_UNORM:
220         return 1;
221
222     case DXGI_FORMAT_BC1_TYPELESS:
223     case DXGI_FORMAT_BC1_UNORM:
224     case DXGI_FORMAT_BC1_UNORM_SRGB:
225     case DXGI_FORMAT_BC4_TYPELESS:
226     case DXGI_FORMAT_BC4_UNORM:
227     case DXGI_FORMAT_BC4_SNORM:
228         return 4;
229
230     case DXGI_FORMAT_BC2_TYPELESS:
231     case DXGI_FORMAT_BC2_UNORM:
232     case DXGI_FORMAT_BC2_UNORM_SRGB:
233     case DXGI_FORMAT_BC3_TYPELESS:
234     case DXGI_FORMAT_BC3_UNORM:
235     case DXGI_FORMAT_BC3_UNORM_SRGB:
236     case DXGI_FORMAT_BC5_TYPELESS:
237     case DXGI_FORMAT_BC5_UNORM:
238     case DXGI_FORMAT_BC5_SNORM:
239     case DXGI_FORMAT_BC6H_TYPELESS:
240     case DXGI_FORMAT_BC6H_UF16:
241     case DXGI_FORMAT_BC6H_SF16:
242     case DXGI_FORMAT_BC7_TYPELESS:
243     case DXGI_FORMAT_BC7_UNORM:
244     case DXGI_FORMAT_BC7_UNORM_SRGB:
245         return 8;
246
247     default:
248         return 0;
249     }
250 }
251
252
253 //--------------------------------------------------------------------------------------
254 // Get surface information for a particular format
255 //--------------------------------------------------------------------------------------
256 static void GetSurfaceInfo( _In_ size_t width,
257                             _In_ size_t height,
258                             _In_ DXGI_FORMAT fmt,
259                             _Out_opt_ size_t* outNumBytes,
260                             _Out_opt_ size_t* outRowBytes,
261                             _Out_opt_ size_t* outNumRows )
262 {
263     size_t numBytes = 0;
264     size_t rowBytes = 0;
265     size_t numRows = 0;
266
267     bool bc = false;
268     bool packed  = false;
269     size_t bcnumBytesPerBlock = 0;
270     switch (fmt)
271     {
272     case DXGI_FORMAT_BC1_TYPELESS:
273     case DXGI_FORMAT_BC1_UNORM:
274     case DXGI_FORMAT_BC1_UNORM_SRGB:
275     case DXGI_FORMAT_BC4_TYPELESS:
276     case DXGI_FORMAT_BC4_UNORM:
277     case DXGI_FORMAT_BC4_SNORM:
278         bc=true;
279         bcnumBytesPerBlock = 8;
280         break;
281
282     case DXGI_FORMAT_BC2_TYPELESS:
283     case DXGI_FORMAT_BC2_UNORM:
284     case DXGI_FORMAT_BC2_UNORM_SRGB:
285     case DXGI_FORMAT_BC3_TYPELESS:
286     case DXGI_FORMAT_BC3_UNORM:
287     case DXGI_FORMAT_BC3_UNORM_SRGB:
288     case DXGI_FORMAT_BC5_TYPELESS:
289     case DXGI_FORMAT_BC5_UNORM:
290     case DXGI_FORMAT_BC5_SNORM:
291     case DXGI_FORMAT_BC6H_TYPELESS:
292     case DXGI_FORMAT_BC6H_UF16:
293     case DXGI_FORMAT_BC6H_SF16:
294     case DXGI_FORMAT_BC7_TYPELESS:
295     case DXGI_FORMAT_BC7_UNORM:
296     case DXGI_FORMAT_BC7_UNORM_SRGB:
297         bc = true;
298         bcnumBytesPerBlock = 16;
299         break;
300
301     case DXGI_FORMAT_R8G8_B8G8_UNORM:
302     case DXGI_FORMAT_G8R8_G8B8_UNORM:
303         packed = true;
304         break;
305     }
306
307     if (bc)
308     {
309         size_t numBlocksWide = 0;
310         if (width > 0)
311         {
312             numBlocksWide = max( 1, (width + 3) / 4 );
313         }
314         size_t numBlocksHigh = 0;
315         if (height > 0)
316         {
317             numBlocksHigh = max( 1, (height + 3) / 4 );
318         }
319         rowBytes = numBlocksWide * bcnumBytesPerBlock;
320         numRows = numBlocksHigh;
321     }
322     else if (packed)
323     {
324         rowBytes = ( ( width + 1 ) >> 1 ) * 4;
325         numRows = height;
326     }
327     else
328     {
329         size_t bpp = BitsPerPixel( fmt );
330         rowBytes = ( width * bpp + 7 ) / 8; // round up to nearest byte
331         numRows = height;
332     }
333
334     numBytes = rowBytes * numRows;
335     if (outNumBytes)
336     {
337         *outNumBytes = numBytes;
338     }
339     if (outRowBytes)
340     {
341         *outRowBytes = rowBytes;
342     }
343     if (outNumRows)
344     {
345         *outNumRows = numRows;
346     }
347 }
348
349
350 //--------------------------------------------------------------------------------------
351 #define ISBITMASK( r,g,b,a ) ( ddpf.RBitMask == r && ddpf.GBitMask == g && ddpf.BBitMask == b && ddpf.ABitMask == a )
352
353 static DXGI_FORMAT GetDXGIFormat( const DDS_PIXELFORMAT& ddpf )
354 {
355     if (ddpf.flags & DDS_RGB)
356     {
357         // Note that sRGB formats are written using the "DX10" extended header
358
359         switch (ddpf.RGBBitCount)
360         {
361         case 32:
362             if (ISBITMASK(0x000000ff,0x0000ff00,0x00ff0000,0xff000000))
363             {
364                 return DXGI_FORMAT_R8G8B8A8_UNORM;
365             }
366
367             if (ISBITMASK(0x00ff0000,0x0000ff00,0x000000ff,0xff000000))
368             {
369                 return DXGI_FORMAT_B8G8R8A8_UNORM;
370             }
371
372             if (ISBITMASK(0x00ff0000,0x0000ff00,0x000000ff,0x00000000))
373             {
374                 return DXGI_FORMAT_B8G8R8X8_UNORM;
375             }
376
377             // No DXGI format maps to ISBITMASK(0x000000ff,0x0000ff00,0x00ff0000,0x00000000) aka D3DFMT_X8B8G8R8
378
379             // Note that many common DDS reader/writers (including D3DX) swap the
380             // the RED/BLUE masks for 10:10:10:2 formats. We assumme
381             // below that the 'backwards' header mask is being used since it is most
382             // likely written by D3DX. The more robust solution is to use the 'DX10'
383             // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly
384
385             // For 'correct' writers, this should be 0x000003ff,0x000ffc00,0x3ff00000 for RGB data
386             if (ISBITMASK(0x3ff00000,0x000ffc00,0x000003ff,0xc0000000))
387             {
388                 return DXGI_FORMAT_R10G10B10A2_UNORM;
389             }
390
391             // No DXGI format maps to ISBITMASK(0x000003ff,0x000ffc00,0x3ff00000,0xc0000000) aka D3DFMT_A2R10G10B10
392
393             if (ISBITMASK(0x0000ffff,0xffff0000,0x00000000,0x00000000))
394             {
395                 return DXGI_FORMAT_R16G16_UNORM;
396             }
397
398             if (ISBITMASK(0xffffffff,0x00000000,0x00000000,0x00000000))
399             {
400                 // Only 32-bit color channel format in D3D9 was R32F
401                 return DXGI_FORMAT_R32_FLOAT; // D3DX writes this out as a FourCC of 114
402             }
403             break;
404
405         case 24:
406             // No 24bpp DXGI formats aka D3DFMT_R8G8B8
407             break;
408
409         case 16:
410             if (ISBITMASK(0x7c00,0x03e0,0x001f,0x8000))
411             {
412                 return DXGI_FORMAT_B5G5R5A1_UNORM;
413             }
414             if (ISBITMASK(0xf800,0x07e0,0x001f,0x0000))
415             {
416                 return DXGI_FORMAT_B5G6R5_UNORM;
417             }
418
419             // No DXGI format maps to ISBITMASK(0x7c00,0x03e0,0x001f,0x0000) aka D3DFMT_X1R5G5B5
420             if (ISBITMASK(0x0f00,0x00f0,0x000f,0xf000))
421             {
422                 return DXGI_FORMAT_B4G4R4A4_UNORM;
423             }
424
425             // No DXGI format maps to ISBITMASK(0x0f00,0x00f0,0x000f,0x0000) aka D3DFMT_X4R4G4B4
426
427             // No 3:3:2, 3:3:2:8, or paletted DXGI formats aka D3DFMT_A8R3G3B2, D3DFMT_R3G3B2, D3DFMT_P8, D3DFMT_A8P8, etc.
428             break;
429         }
430     }
431     else if (ddpf.flags & DDS_LUMINANCE)
432     {
433         if (8 == ddpf.RGBBitCount)
434         {
435             if (ISBITMASK(0x000000ff,0x00000000,0x00000000,0x00000000))
436             {
437                 return DXGI_FORMAT_R8_UNORM; // D3DX10/11 writes this out as DX10 extension
438             }
439
440             // No DXGI format maps to ISBITMASK(0x0f,0x00,0x00,0xf0) aka D3DFMT_A4L4
441         }
442
443         if (16 == ddpf.RGBBitCount)
444         {
445             if (ISBITMASK(0x0000ffff,0x00000000,0x00000000,0x00000000))
446             {
447                 return DXGI_FORMAT_R16_UNORM; // D3DX10/11 writes this out as DX10 extension
448             }
449             if (ISBITMASK(0x000000ff,0x00000000,0x00000000,0x0000ff00))
450             {
451                 return DXGI_FORMAT_R8G8_UNORM; // D3DX10/11 writes this out as DX10 extension
452             }
453         }
454     }
455     else if (ddpf.flags & DDS_ALPHA)
456     {
457         if (8 == ddpf.RGBBitCount)
458         {
459             return DXGI_FORMAT_A8_UNORM;
460         }
461     }
462     else if (ddpf.flags & DDS_FOURCC)
463     {
464         if (MAKEFOURCC( 'D', 'X', 'T', '1' ) == ddpf.fourCC)
465         {
466             return DXGI_FORMAT_BC1_UNORM;
467         }
468         if (MAKEFOURCC( 'D', 'X', 'T', '3' ) == ddpf.fourCC)
469         {
470             return DXGI_FORMAT_BC2_UNORM;
471         }
472         if (MAKEFOURCC( 'D', 'X', 'T', '5' ) == ddpf.fourCC)
473         {
474             return DXGI_FORMAT_BC3_UNORM;
475         }
476
477         // While pre-mulitplied alpha isn't directly supported by the DXGI formats,
478         // they are basically the same as these BC formats so they can be mapped
479         if (MAKEFOURCC( 'D', 'X', 'T', '2' ) == ddpf.fourCC)
480         {
481             return DXGI_FORMAT_BC2_UNORM;
482         }
483         if (MAKEFOURCC( 'D', 'X', 'T', '4' ) == ddpf.fourCC)
484         {
485             return DXGI_FORMAT_BC3_UNORM;
486         }
487
488         if (MAKEFOURCC( 'A', 'T', 'I', '1' ) == ddpf.fourCC)
489         {
490             return DXGI_FORMAT_BC4_UNORM;
491         }
492         if (MAKEFOURCC( 'B', 'C', '4', 'U' ) == ddpf.fourCC)
493         {
494             return DXGI_FORMAT_BC4_UNORM;
495         }
496         if (MAKEFOURCC( 'B', 'C', '4', 'S' ) == ddpf.fourCC)
497         {
498             return DXGI_FORMAT_BC4_SNORM;
499         }
500
501         if (MAKEFOURCC( 'A', 'T', 'I', '2' ) == ddpf.fourCC)
502         {
503             return DXGI_FORMAT_BC5_UNORM;
504         }
505         if (MAKEFOURCC( 'B', 'C', '5', 'U' ) == ddpf.fourCC)
506         {
507             return DXGI_FORMAT_BC5_UNORM;
508         }
509         if (MAKEFOURCC( 'B', 'C', '5', 'S' ) == ddpf.fourCC)
510         {
511             return DXGI_FORMAT_BC5_SNORM;
512         }
513
514         // BC6H and BC7 are written using the "DX10" extended header
515
516         if (MAKEFOURCC( 'R', 'G', 'B', 'G' ) == ddpf.fourCC)
517         {
518             return DXGI_FORMAT_R8G8_B8G8_UNORM;
519         }
520         if (MAKEFOURCC( 'G', 'R', 'G', 'B' ) == ddpf.fourCC)
521         {
522             return DXGI_FORMAT_G8R8_G8B8_UNORM;
523         }
524
525         // Check for D3DFORMAT enums being set here
526         switch( ddpf.fourCC )
527         {
528         case 36: // D3DFMT_A16B16G16R16
529             return DXGI_FORMAT_R16G16B16A16_UNORM;
530
531         case 110: // D3DFMT_Q16W16V16U16
532             return DXGI_FORMAT_R16G16B16A16_SNORM;
533
534         case 111: // D3DFMT_R16F
535             return DXGI_FORMAT_R16_FLOAT;
536
537         case 112: // D3DFMT_G16R16F
538             return DXGI_FORMAT_R16G16_FLOAT;
539
540         case 113: // D3DFMT_A16B16G16R16F
541             return DXGI_FORMAT_R16G16B16A16_FLOAT;
542
543         case 114: // D3DFMT_R32F
544             return DXGI_FORMAT_R32_FLOAT;
545
546         case 115: // D3DFMT_G32R32F
547             return DXGI_FORMAT_R32G32_FLOAT;
548
549         case 116: // D3DFMT_A32B32G32R32F
550             return DXGI_FORMAT_R32G32B32A32_FLOAT;
551         }
552     }
553
554     return DXGI_FORMAT_UNKNOWN;
555 }
556
557
558 //--------------------------------------------------------------------------------------
559 static void FillInitData( _In_ size_t width,
560                           _In_ size_t height,
561                           _In_ size_t depth,
562                           _In_ size_t mipCount,
563                           _In_ size_t arraySize,
564                           _In_ DXGI_FORMAT format,
565                           _In_ size_t maxsize,
566                           _In_ size_t bitSize,
567                           _In_reads_bytes_(bitSize) const byte* bitData,
568                           _Out_ size_t& twidth,
569                           _Out_ size_t& theight,
570                           _Out_ size_t& tdepth,
571                           _Out_ size_t& skipMip,
572                           _Out_writes_(mipCount*arraySize) D3D11_SUBRESOURCE_DATA* initData )
573 {
574     if ( !bitData || !initData )
575         throw ref new Platform::InvalidArgumentException();
576
577     skipMip = 0;
578     twidth = 0;
579     theight = 0;
580     tdepth = 0;
581
582     size_t NumBytes = 0;
583     size_t RowBytes = 0;
584     size_t NumRows = 0;
585     const byte* pSrcBits = bitData;
586     const byte* pEndBits = bitData + bitSize;
587
588     size_t index = 0;
589     for( size_t j = 0; j < arraySize; j++ )
590     {
591         size_t w = width;
592         size_t h = height;
593         size_t d = depth;
594         for( size_t i = 0; i < mipCount; i++ )
595         {
596             GetSurfaceInfo( w,
597                             h,
598                             format,
599                             &NumBytes,
600                             &RowBytes,
601                             &NumRows
602                           );
603
604             if ( (mipCount <= 1) || !maxsize || (w <= maxsize && h <= maxsize && d <= maxsize) )
605             {
606                 if ( !twidth )
607                 {
608                     twidth = w;
609                     theight = h;
610                     tdepth = d;
611                 }
612
613                 initData[index].pSysMem = ( const void* )pSrcBits;
614                 initData[index].SysMemPitch = static_cast<UINT>( RowBytes );
615                 initData[index].SysMemSlicePitch = static_cast<UINT>( NumBytes );
616                 ++index;
617             }
618             else
619                 ++skipMip;
620
621             if (pSrcBits + (NumBytes*d) > pEndBits)
622             {
623                 throw ref new Platform::OutOfBoundsException();
624             }
625   
626             pSrcBits += NumBytes * d;
627
628             w = w >> 1;
629             h = h >> 1;
630             d = d >> 1;
631             if (w == 0)
632             {
633                 w = 1;
634             }
635             if (h == 0)
636             {
637                 h = 1;
638             }
639             if (d == 0)
640             {
641                 d = 1;
642             }
643         }
644     }
645
646     if ( !index )
647         throw ref new Platform::FailureException();
648 }
649
650
651 //--------------------------------------------------------------------------------------
652 static HRESULT CreateD3DResources( _In_ ID3D11Device* d3dDevice,
653                                    _In_ uint32 resDim,
654                                    _In_ size_t width,
655                                    _In_ size_t height,
656                                    _In_ size_t depth,
657                                    _In_ size_t mipCount,
658                                    _In_ size_t arraySize,
659                                    _In_ DXGI_FORMAT format,
660                                    _In_ bool isCubeMap,
661                                    _In_reads_(mipCount*arraySize) D3D11_SUBRESOURCE_DATA* initData,
662                                    _Out_opt_ ID3D11Resource** texture,
663                                    _Out_opt_ ID3D11ShaderResourceView** textureView )
664 {
665     if ( !d3dDevice || !initData )
666         return E_INVALIDARG;
667
668     HRESULT hr = E_FAIL;
669
670     switch ( resDim ) 
671     {
672         case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
673             {
674                 D3D11_TEXTURE1D_DESC desc;
675                 desc.Width = static_cast<UINT>( width ); 
676                 desc.MipLevels = static_cast<UINT>( mipCount );
677                 desc.ArraySize = static_cast<UINT>( arraySize );
678                 desc.Format = format;
679                 desc.Usage = D3D11_USAGE_DEFAULT;
680                 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
681                 desc.CPUAccessFlags = 0;
682                 desc.MiscFlags = 0;
683
684                 ID3D11Texture1D* tex = nullptr;
685                 hr = d3dDevice->CreateTexture1D( &desc,
686                                                  initData,
687                                                  &tex
688                                                );
689                 if (SUCCEEDED( hr ) && tex != 0)
690                 {
691                     if (textureView != 0)
692                     {
693                         D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
694                         memset( &SRVDesc, 0, sizeof( SRVDesc ) );
695                         SRVDesc.Format = format;
696
697                         if (arraySize > 1)
698                         {
699                             SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1DARRAY;
700                             SRVDesc.Texture1DArray.MipLevels = desc.MipLevels;
701                             SRVDesc.Texture1DArray.ArraySize = static_cast<UINT>( arraySize );
702                         }
703                         else
704                         {
705                             SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1D;
706                             SRVDesc.Texture1D.MipLevels = desc.MipLevels;
707                         }
708
709                         hr = d3dDevice->CreateShaderResourceView( tex,
710                                                                   &SRVDesc,
711                                                                   textureView
712                                                                 );
713                     }
714
715                     if (texture != 0)
716                     {
717                         *texture = tex;
718                     }
719                     else
720                     {
721                         tex->Release();
722                     }
723                 }
724             }
725            break;
726
727         case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
728             {
729                 D3D11_TEXTURE2D_DESC desc;
730                 desc.Width = static_cast<UINT>( width );
731                 desc.Height = static_cast<UINT>( height );
732                 desc.MipLevels = static_cast<UINT>( mipCount );
733                 desc.ArraySize = static_cast<UINT>( arraySize );
734                 desc.Format = format;
735                 desc.SampleDesc.Count = 1;
736                 desc.SampleDesc.Quality = 0;
737                 desc.Usage = D3D11_USAGE_DEFAULT;
738                 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
739                 desc.CPUAccessFlags = 0;
740                 desc.MiscFlags = (isCubeMap) ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;
741
742                 ID3D11Texture2D* tex = nullptr;
743                 hr = d3dDevice->CreateTexture2D( &desc,
744                                                  initData,
745                                                  &tex
746                                                );
747                 if (SUCCEEDED( hr ) && tex != 0)
748                 {
749                     if (textureView != 0)
750                     {
751                         D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
752                         memset( &SRVDesc, 0, sizeof( SRVDesc ) );
753                         SRVDesc.Format = format;
754
755                         if (isCubeMap)
756                         {
757                             if (arraySize > 6)
758                             {
759                                 SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBEARRAY;
760                                 SRVDesc.TextureCubeArray.MipLevels = desc.MipLevels;
761
762                                 // Earlier we set arraySize to (NumCubes * 6)
763                                 SRVDesc.TextureCubeArray.NumCubes = static_cast<UINT>( arraySize / 6 );
764                             }
765                             else
766                             {
767                                 SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBE;
768                                 SRVDesc.TextureCube.MipLevels = desc.MipLevels;
769                             }
770                         }
771                         else if (arraySize > 1)
772                         {
773                             SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2DARRAY;
774                             SRVDesc.Texture2DArray.MipLevels = desc.MipLevels;
775                             SRVDesc.Texture2DArray.ArraySize = static_cast<UINT>( arraySize );
776                         }
777                         else
778                         {
779                             SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2D;
780                             SRVDesc.Texture2D.MipLevels = desc.MipLevels;
781                         }
782
783                         hr = d3dDevice->CreateShaderResourceView( tex,
784                                                                   &SRVDesc,
785                                                                   textureView
786                                                                 );
787                     }
788
789                     if (texture != 0)
790                     {
791                         *texture = tex;
792                     }
793                     else
794                     {
795                         tex->Release();
796                     }
797                 }
798             }
799             break;
800
801         case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
802             {
803                 D3D11_TEXTURE3D_DESC desc;
804                 desc.Width = static_cast<UINT>( width );
805                 desc.Height = static_cast<UINT>( height );
806                 desc.Depth = static_cast<UINT>( depth );
807                 desc.MipLevels = static_cast<UINT>( mipCount );
808                 desc.Format = format;
809                 desc.Usage = D3D11_USAGE_DEFAULT;
810                 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
811                 desc.CPUAccessFlags = 0;
812                 desc.MiscFlags = 0;
813
814                 ID3D11Texture3D* tex = nullptr;
815                 hr = d3dDevice->CreateTexture3D( &desc,
816                                                  initData,
817                                                  &tex
818                                                );
819                 if (SUCCEEDED( hr ) && tex != 0)
820                 {
821                     if (textureView != 0)
822                     {
823                         D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
824                         memset( &SRVDesc, 0, sizeof( SRVDesc ) );
825                         SRVDesc.Format = format;
826                         SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE3D;
827                         SRVDesc.Texture3D.MipLevels = desc.MipLevels;
828
829                         hr = d3dDevice->CreateShaderResourceView( tex,
830                                                                   &SRVDesc,
831                                                                   textureView
832                                                                 );
833                     }
834
835                     if (texture != 0)
836                     {
837                         *texture = tex;
838                     }
839                     else
840                     {
841                         tex->Release();
842                     }
843                 }
844             }
845             break; 
846     }
847
848     return hr;
849 }
850
851
852 //--------------------------------------------------------------------------------------
853 static void CreateTextureFromDDS( _In_ ID3D11Device* d3dDevice,
854                                   _In_ const DDS_HEADER* header,
855                                   _In_reads_bytes_(bitSize) const byte* bitData,
856                                   _In_ size_t bitSize,
857                                   _Out_opt_ ID3D11Resource** texture,
858                                   _Out_opt_ ID3D11ShaderResourceView** textureView,
859                                   _In_ size_t maxsize )
860 {
861     HRESULT hr = S_OK;
862
863     size_t width = header->width;
864     size_t height = header->height;
865     size_t depth = header->depth;
866
867     uint32 resDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
868     size_t arraySize = 1;
869     DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
870     bool isCubeMap = false;
871
872     size_t mipCount = header->mipMapCount;
873     if (0 == mipCount)
874     {
875         mipCount = 1;
876     }
877
878     if ((header->ddspf.flags & DDS_FOURCC) &&
879         (MAKEFOURCC( 'D', 'X', '1', '0' ) == header->ddspf.fourCC ))
880     {
881         const DDS_HEADER_DXT10* d3d10ext = reinterpret_cast<const DDS_HEADER_DXT10*>( (const char*)header + sizeof(DDS_HEADER) );
882
883         arraySize = d3d10ext->arraySize;
884         if (arraySize == 0)
885         {
886             throw ref new Platform::FailureException();
887         }
888
889         if (BitsPerPixel( d3d10ext->dxgiFormat ) == 0)
890         {
891             throw ref new Platform::FailureException();
892         }
893            
894         format = d3d10ext->dxgiFormat;
895
896         switch ( d3d10ext->resourceDimension )
897         {
898         case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
899             // D3DX writes 1D textures with a fixed Height of 1
900             if ((header->flags & DDS_HEIGHT) && height != 1)
901             {
902                 throw ref new Platform::FailureException();
903             }
904             height = depth = 1;
905             break;
906
907         case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
908             if (d3d10ext->miscFlag & D3D11_RESOURCE_MISC_TEXTURECUBE)
909             {
910                 arraySize *= 6;
911                 isCubeMap = true;
912             }
913             depth = 1;
914             break;
915
916         case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
917             if (!(header->flags & DDS_HEADER_FLAGS_VOLUME))
918             {
919                 throw ref new Platform::FailureException();
920             }
921
922             if (arraySize > 1)
923             {
924                 throw ref new Platform::FailureException();
925             }
926             break;
927
928         default:
929             return throw ref new Platform::FailureException();
930         }
931
932         resDim = d3d10ext->resourceDimension;
933     }
934     else
935     {
936         format = GetDXGIFormat( header->ddspf );
937
938         if (format == DXGI_FORMAT_UNKNOWN)
939         {
940            return throw ref new Platform::FailureException();
941         }
942
943         if (header->flags & DDS_HEADER_FLAGS_VOLUME)
944         {
945             resDim = D3D11_RESOURCE_DIMENSION_TEXTURE3D;
946         }
947         else 
948         {
949             if (header->caps2 & DDS_CUBEMAP)
950             {
951                 // We require all six faces to be defined
952                 if ((header->caps2 & DDS_CUBEMAP_ALLFACES ) != DDS_CUBEMAP_ALLFACES)
953                 {
954                     return throw ref new Platform::FailureException();
955                 }
956
957                 arraySize = 6;
958                 isCubeMap = true;
959             }
960
961             depth = 1;
962             resDim = D3D11_RESOURCE_DIMENSION_TEXTURE2D;
963
964             // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture
965         }
966
967         assert( BitsPerPixel( format ) != 0 );
968     }
969
970     // Bound sizes (for security purposes we don't trust DDS file metadata larger than the D3D 11.x hardware requirements)
971     if (mipCount > D3D11_REQ_MIP_LEVELS)
972     {
973         return throw ref new Platform::FailureException();
974     }
975
976     switch ( resDim )
977     {
978         case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
979             if ((arraySize > D3D11_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION) ||
980                 (width > D3D11_REQ_TEXTURE1D_U_DIMENSION) )
981             {
982                 return throw ref new Platform::FailureException();
983             }
984             break;
985
986         case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
987             if (isCubeMap)
988             {
989                 // This is the right bound because we set arraySize to (NumCubes*6) above
990                 if ((arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||
991                     (width > D3D11_REQ_TEXTURECUBE_DIMENSION) ||
992                     (height > D3D11_REQ_TEXTURECUBE_DIMENSION))
993                 {
994                     return throw ref new Platform::FailureException();
995                 }
996             }
997             else if ((arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||
998                      (width > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION) ||
999                      (height > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION))
1000             {
1001                 return throw ref new Platform::FailureException();
1002             }
1003             break;
1004
1005         case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
1006             if ((arraySize > 1) ||
1007                 (width > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||
1008                 (height > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||
1009                 (depth > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) )
1010             {
1011                 return throw ref new Platform::FailureException();
1012             }
1013             break;
1014     }
1015
1016     // Create the texture
1017     std::unique_ptr<D3D11_SUBRESOURCE_DATA> initData( new D3D11_SUBRESOURCE_DATA[ mipCount * arraySize ] );
1018
1019     size_t skipMip = 0;
1020     size_t twidth = 0;
1021     size_t theight = 0;
1022     size_t tdepth = 0;
1023     FillInitData( width, height, depth, mipCount, arraySize, format, maxsize, bitSize, bitData,
1024                   twidth, theight, tdepth, skipMip, initData.get() );
1025
1026     hr = CreateD3DResources( d3dDevice, resDim, twidth, theight, tdepth, mipCount - skipMip, arraySize, format, isCubeMap, initData.get(), texture, textureView );
1027
1028     if ( (hr == E_INVALIDARG) && !maxsize && (mipCount > 1) )
1029     {
1030         // Retry with a maxsize determined by feature level
1031         switch( d3dDevice->GetFeatureLevel() )
1032         {
1033         case D3D_FEATURE_LEVEL_9_1:
1034         case D3D_FEATURE_LEVEL_9_2:
1035             if (isCubeMap)
1036             {
1037                 maxsize = 512 /*D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION*/;
1038             }
1039             else
1040             {
1041                 maxsize = (resDim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
1042                           ? 256 /*D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION*/
1043                           : 2048 /*D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION*/;
1044             }
1045             break;
1046
1047         case D3D_FEATURE_LEVEL_9_3:
1048             maxsize = (resDim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
1049                       ? 256 /*D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION*/
1050                       : 4096 /*D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION*/;
1051             break;
1052
1053         default: // D3D_FEATURE_LEVEL_10_0 & D3D_FEATURE_LEVEL_10_1
1054             maxsize = (resDim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
1055                       ? 2048 /*D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION*/
1056                       : 8192 /*D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION*/;
1057             break;
1058         }
1059
1060         FillInitData( width, height, depth, mipCount, arraySize, format, maxsize, bitSize, bitData,
1061                       twidth, theight, tdepth, skipMip, initData.get() );
1062
1063         hr = CreateD3DResources( d3dDevice, resDim, twidth, theight, tdepth, mipCount - skipMip, arraySize, format, isCubeMap, initData.get(), texture, textureView );
1064     }
1065
1066     DX::ThrowIfFailed(hr);
1067 }
1068
1069 //--------------------------------------------------------------------------------------
1070 void CreateDDSTextureFromMemory( _In_ ID3D11Device* d3dDevice,
1071                                  _In_reads_bytes_(ddsDataSize) const byte* ddsData,
1072                                  _In_ size_t ddsDataSize,
1073                                  _Out_opt_ ID3D11Resource** texture,
1074                                  _Out_opt_ ID3D11ShaderResourceView** textureView,
1075                                  _In_ size_t maxsize )
1076 {
1077     if (!d3dDevice || !ddsData || (!texture && !textureView))
1078     {
1079         throw ref new Platform::InvalidArgumentException();
1080     }
1081
1082     // Validate DDS file in memory
1083     if (ddsDataSize < (sizeof(uint32) + sizeof(DDS_HEADER)))
1084     {
1085         throw ref new Platform::FailureException();
1086     }
1087
1088     uint32 dwMagicNumber = *( const uint32* )( ddsData );
1089     if (dwMagicNumber != DDS_MAGIC)
1090     {
1091         throw ref new Platform::FailureException();
1092     }
1093
1094     const DDS_HEADER* header = reinterpret_cast<const DDS_HEADER*>( ddsData + sizeof( uint32 ) );
1095
1096     // Verify header to validate DDS file
1097     if (header->size != sizeof(DDS_HEADER) ||
1098         header->ddspf.size != sizeof(DDS_PIXELFORMAT))
1099     {
1100         throw ref new Platform::FailureException();
1101     }
1102
1103     // Check for DX10 extension
1104     bool bDXT10Header = false;
1105     if ((header->ddspf.flags & DDS_FOURCC) &&
1106         (MAKEFOURCC( 'D', 'X', '1', '0' ) == header->ddspf.fourCC) )
1107     {
1108         // Must be long enough for both headers and magic value
1109         if (ddsDataSize < (sizeof(DDS_HEADER) + sizeof(uint32) + sizeof(DDS_HEADER_DXT10)))
1110         {
1111             throw ref new Platform::FailureException();
1112         }
1113
1114         bDXT10Header = true;
1115     }
1116
1117     ptrdiff_t offset = sizeof( uint32 )
1118                        + sizeof( DDS_HEADER )
1119                        + (bDXT10Header ? sizeof( DDS_HEADER_DXT10 ) : 0);
1120
1121     CreateTextureFromDDS( d3dDevice,
1122                           header,
1123                           ddsData + offset,
1124                           ddsDataSize - offset,
1125                           texture,
1126                           textureView,
1127                           maxsize
1128                         );
1129 }