]> git.cworth.org Git - apitrace/blob - thirdparty/directxtex/DirectXTex/DirectXTexD3D11.cpp
thirdparty/directxtex: Import DirectXTex library.
[apitrace] / thirdparty / directxtex / DirectXTex / DirectXTexD3D11.cpp
1 //-------------------------------------------------------------------------------------
2 // DirectXTexD3D11.cpp
3 //  
4 // DirectX Texture Library - Direct3D 11 helpers
5 //
6 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
7 // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
8 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
9 // PARTICULAR PURPOSE.
10 //
11 // Copyright (c) Microsoft Corporation. All rights reserved.
12 //
13 // http://go.microsoft.com/fwlink/?LinkId=248926
14 //-------------------------------------------------------------------------------------
15
16 #include "directxtexp.h"
17
18 #include <d3d10.h>
19
20 namespace DirectX
21 {
22
23 static HRESULT _Capture( _In_ ID3D11DeviceContext* pContext, _In_ ID3D11Resource* pSource, _In_ const TexMetadata& metadata,
24                          _In_ const ScratchImage& result )
25 {
26     if ( !pContext || !pSource || !result.GetPixels() )
27         return E_POINTER;
28
29     if ( metadata.dimension == TEX_DIMENSION_TEXTURE3D )
30     {
31         //--- Volume texture ----------------------------------------------------------
32         assert( metadata.arraySize == 1 );
33
34         size_t height = metadata.height;
35         size_t depth = metadata.depth;
36
37         for( size_t level = 0; level < metadata.mipLevels; ++level )
38         {
39             UINT dindex = D3D11CalcSubresource( static_cast<UINT>( level ), 0, static_cast<UINT>( metadata.mipLevels ) );
40
41             D3D11_MAPPED_SUBRESOURCE mapped;
42             HRESULT hr = pContext->Map( pSource, dindex, D3D11_MAP_READ, 0, &mapped );
43             if ( FAILED(hr) )
44                 return hr;
45
46             const uint8_t* pslice = reinterpret_cast<const uint8_t*>( mapped.pData );
47             if ( !pslice )
48             {
49                 pContext->Unmap( pSource, dindex );
50                 return E_POINTER;
51             }
52
53             size_t lines = ComputeScanlines( metadata.format, height );
54
55             for( size_t slice = 0; slice < depth; ++slice )
56             {
57                 const Image* img = result.GetImage( level, 0, slice );
58                 if ( !img )
59                 {
60                     pContext->Unmap( pSource, dindex );
61                     return E_FAIL;
62                 }
63
64                 if ( !img->pixels )
65                 {
66                     pContext->Unmap( pSource, dindex );
67                     return E_POINTER;
68                 }
69
70                 const uint8_t* sptr = pslice;
71                 uint8_t* dptr = img->pixels;
72                 for( size_t h = 0; h < lines; ++h )
73                 {
74                     size_t msize = std::min<size_t>( img->rowPitch, mapped.RowPitch );
75                     memcpy_s( dptr, img->rowPitch, sptr, msize );
76                     sptr += mapped.RowPitch;
77                     dptr += img->rowPitch;
78                 }
79
80                 pslice += mapped.DepthPitch;
81             }
82
83             pContext->Unmap( pSource, dindex );
84
85             if ( height > 1 )
86                 height >>= 1;
87             if ( depth > 1 )
88                 depth >>= 1;
89         }
90     }
91     else
92     {
93         //--- 1D or 2D texture --------------------------------------------------------
94         assert( metadata.depth == 1 );
95
96         for( size_t item = 0; item < metadata.arraySize; ++item )
97         {
98             size_t height = metadata.height;
99
100             for( size_t level = 0; level < metadata.mipLevels; ++level )
101             {
102                 UINT dindex = D3D11CalcSubresource( static_cast<UINT>( level ), static_cast<UINT>( item ), static_cast<UINT>( metadata.mipLevels ) );
103
104                 D3D11_MAPPED_SUBRESOURCE mapped;
105                 HRESULT hr = pContext->Map( pSource, dindex, D3D11_MAP_READ, 0, &mapped );
106                 if ( FAILED(hr) )
107                     return hr;
108
109                 const Image* img = result.GetImage( level, item, 0 );
110                 if ( !img )
111                 {
112                     pContext->Unmap( pSource, dindex );
113                     return E_FAIL;
114                 }
115
116                 if ( !img->pixels )
117                 {
118                     pContext->Unmap( pSource, dindex );
119                     return E_POINTER;
120                 }
121
122                 size_t lines = ComputeScanlines( metadata.format, height );
123
124                 const uint8_t* sptr = reinterpret_cast<const uint8_t*>( mapped.pData );
125                 uint8_t* dptr = img->pixels;
126                 for( size_t h = 0; h < lines; ++h )
127                 {
128                     size_t msize = std::min<size_t>( img->rowPitch, mapped.RowPitch );
129                     memcpy_s( dptr, img->rowPitch, sptr, msize );
130                     sptr += mapped.RowPitch;
131                     dptr += img->rowPitch;
132                 }
133
134                 pContext->Unmap( pSource, dindex );
135
136                 if ( height > 1 )
137                     height >>= 1;
138             }
139         }
140     }
141
142     return S_OK;
143 }
144
145
146 //=====================================================================================
147 // Entry-points
148 //=====================================================================================
149
150 //-------------------------------------------------------------------------------------
151 // Determine if given texture metadata is supported on the given device
152 //-------------------------------------------------------------------------------------
153 bool IsSupportedTexture( ID3D11Device* pDevice, const TexMetadata& metadata )
154 {
155     if ( !pDevice )
156         return false;
157
158     D3D_FEATURE_LEVEL fl = pDevice->GetFeatureLevel();
159
160     // Validate format
161     DXGI_FORMAT fmt = metadata.format;
162
163     if ( !IsValid( fmt ) )
164         return false;
165
166     if ( IsVideo(fmt) )
167         return false;
168
169     switch( fmt )
170     {
171     case DXGI_FORMAT_BC4_TYPELESS:
172     case DXGI_FORMAT_BC4_UNORM:
173     case DXGI_FORMAT_BC4_SNORM:
174     case DXGI_FORMAT_BC5_TYPELESS:
175     case DXGI_FORMAT_BC5_UNORM:
176     case DXGI_FORMAT_BC5_SNORM:
177         if ( fl < D3D_FEATURE_LEVEL_10_0 )
178             return false;
179         break;
180
181     case DXGI_FORMAT_BC6H_TYPELESS:
182     case DXGI_FORMAT_BC6H_UF16:
183     case DXGI_FORMAT_BC6H_SF16:
184     case DXGI_FORMAT_BC7_TYPELESS:
185     case DXGI_FORMAT_BC7_UNORM:
186     case DXGI_FORMAT_BC7_UNORM_SRGB:
187         if ( fl < D3D_FEATURE_LEVEL_11_0 )
188             return false;
189         break;
190     }
191
192     // Validate miplevel count
193     if ( metadata.mipLevels > D3D11_REQ_MIP_LEVELS )
194         return false;
195        
196     // Validate array size, dimension, and width/height
197     size_t arraySize = metadata.arraySize;
198     size_t iWidth = metadata.width;
199     size_t iHeight = metadata.height;
200     size_t iDepth = metadata.depth;
201
202     // Most cases are known apriori based on feature level, but we use this for robustness to handle the few optional cases
203     UINT formatSupport = 0;
204     pDevice->CheckFormatSupport( fmt, &formatSupport );
205
206     switch ( metadata.dimension )
207     {
208     case TEX_DIMENSION_TEXTURE1D:
209         if ( !(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE1D) )
210             return false;
211
212         if ( (arraySize > D3D11_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION)
213              || (iWidth > D3D11_REQ_TEXTURE1D_U_DIMENSION) )
214             return false;
215
216         if ( fl < D3D_FEATURE_LEVEL_11_0 )
217         {
218             if ( (arraySize > D3D10_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION)
219                  || (iWidth > D3D10_REQ_TEXTURE1D_U_DIMENSION) )
220                 return false;
221
222             if ( fl < D3D_FEATURE_LEVEL_10_0 )
223             {
224                 if ( (arraySize > 1) || (iWidth > 4096 /*D3D_FL9_3_REQ_TEXTURE1D_U_DIMENSION*/) )
225                     return false;
226
227                 if ( (fl < D3D_FEATURE_LEVEL_9_3) && (iWidth > 2048 /*D3D_FL9_1_REQ_TEXTURE1D_U_DIMENSION*/ ) )
228                     return false;
229             }
230         }
231         break;
232
233     case TEX_DIMENSION_TEXTURE2D:
234         if ( metadata.miscFlags & TEX_MISC_TEXTURECUBE )
235         {
236             if ( !(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURECUBE) )
237                 return false;
238
239             if ( (arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION)
240                  || (iWidth > D3D11_REQ_TEXTURECUBE_DIMENSION) 
241                  || (iHeight > D3D11_REQ_TEXTURECUBE_DIMENSION))
242                 return false;
243
244             if ( fl < D3D_FEATURE_LEVEL_11_0 )
245             {
246                 if ( (arraySize > D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION)
247                      || (iWidth > D3D10_REQ_TEXTURECUBE_DIMENSION) 
248                      || (iHeight > D3D10_REQ_TEXTURECUBE_DIMENSION))
249                     return false;
250
251                 if ( (fl < D3D_FEATURE_LEVEL_10_1) && (arraySize != 6) )
252                     return false;
253
254                 if ( fl < D3D_FEATURE_LEVEL_10_0 )
255                 {
256                     if ( (iWidth > 4096 /*D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION*/ )
257                          || (iHeight > 4096 /*D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION*/ ) )
258                         return false;
259
260                     if ( (fl < D3D_FEATURE_LEVEL_9_3)
261                          && ( (iWidth > 512 /*D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION*/)
262                               || (iHeight > 512 /*D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION*/) ) )
263                         return false;
264                 }
265             }
266         }
267         else // Not a cube map
268         {
269             if ( !(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) )
270                 return false;
271
272             if ( (arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION)
273                  || (iWidth > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION) 
274                  || (iHeight > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION))
275                 return false;
276
277             if ( fl < D3D_FEATURE_LEVEL_11_0 )
278             {
279                 if ( (arraySize > D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION)
280                      || (iWidth > D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION) 
281                      || (iHeight > D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION))
282                     return false;
283
284                 if ( fl < D3D_FEATURE_LEVEL_10_0 )
285                 {
286                     if ( (arraySize > 1)
287                          || (iWidth > 4096 /*D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION*/)
288                          || (iHeight > 4096 /*D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION*/) )
289                         return false;
290
291                     if ( (fl < D3D_FEATURE_LEVEL_9_3)
292                          && ( (iWidth > 2048 /*D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION*/)
293                               || (iHeight > 2048 /*D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION*/) ) )
294                         return false;
295                 }
296             }
297         }
298         break;
299
300     case TEX_DIMENSION_TEXTURE3D:
301         if ( !(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE3D) )
302             return false;
303
304         if ( (arraySize > 1)
305              || (iWidth > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) 
306              || (iHeight > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION)
307              || (iDepth > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) )
308             return false;
309
310         if ( fl < D3D_FEATURE_LEVEL_11_0 )
311         {
312             if ( (iWidth > D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) 
313                  || (iHeight > D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION)
314                  || (iDepth > D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) )
315                 return false;
316
317             if ( fl < D3D_FEATURE_LEVEL_10_0 )
318             {
319                 if ( (iWidth > 256 /*D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION*/)
320                      || (iHeight > 256 /*D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION*/)
321                      || (iDepth > 256 /*D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION*/) )
322                     return false;
323             }
324         }
325         break;
326
327     default:
328         // Not a supported dimension
329         return false;
330     }
331
332     return true;
333 }
334
335
336 //-------------------------------------------------------------------------------------
337 // Create a texture resource
338 //-------------------------------------------------------------------------------------
339 HRESULT CreateTexture( ID3D11Device* pDevice, const Image* srcImages, size_t nimages, const TexMetadata& metadata,
340                        ID3D11Resource** ppResource )
341 {
342     if ( !pDevice || !srcImages || !nimages || !ppResource )
343         return E_INVALIDARG;
344
345     if ( !metadata.mipLevels || !metadata.arraySize )
346         return E_INVALIDARG;
347
348 #ifdef _AMD64_
349     if ( (metadata.width > 0xFFFFFFFF) || (metadata.height > 0xFFFFFFFF)
350          || (metadata.mipLevels > 0xFFFFFFFF) || (metadata.arraySize > 0xFFFFFFFF) )
351         return E_INVALIDARG;
352 #endif
353
354     std::unique_ptr<D3D11_SUBRESOURCE_DATA[]> initData( new D3D11_SUBRESOURCE_DATA[ metadata.mipLevels * metadata.arraySize ] );
355     if ( !initData )
356         return E_OUTOFMEMORY;
357
358     // Fill out subresource array
359     if ( metadata.dimension == TEX_DIMENSION_TEXTURE3D )
360     {
361         //--- Volume case -------------------------------------------------------------
362         if ( !metadata.depth )
363             return E_INVALIDARG;
364
365 #ifdef _AMD64_
366         if ( metadata.depth > 0xFFFFFFFF )
367             return E_INVALIDARG;
368 #endif
369
370         if ( metadata.arraySize > 1 )
371             // Direct3D 11 doesn't support arrays of 3D textures
372             return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
373
374         size_t depth = metadata.depth;
375
376         size_t idx = 0;
377         for( size_t level = 0; level < metadata.mipLevels; ++level )
378         {
379             size_t index = metadata.ComputeIndex( level, 0, 0 );
380             if ( index >= nimages )
381                 return E_FAIL;
382
383             const Image& img = srcImages[ index ];
384
385             if ( img.format != metadata.format )
386                 return E_FAIL;
387
388             if ( !img.pixels )
389                 return E_POINTER;
390
391             // Verify pixels in image 1 .. (depth-1) are exactly image->slicePitch apart
392             // For 3D textures, this relies on all slices of the same miplevel being continous in memory
393             // (this is how ScratchImage lays them out), which is why we just give the 0th slice to Direct3D 11
394             const uint8_t* pSlice = img.pixels + img.slicePitch;
395             for( size_t slice = 1; slice < depth; ++slice )
396             {
397                 size_t tindex = metadata.ComputeIndex( level, 0, slice );
398                 if ( tindex >= nimages )
399                     return E_FAIL;
400
401                 const Image& timg = srcImages[ tindex ];
402
403                 if ( !timg.pixels )
404                     return E_POINTER;
405
406                 if ( timg.pixels != pSlice
407                      || timg.format != metadata.format
408                      || timg.rowPitch != img.rowPitch
409                      || timg.slicePitch != img.slicePitch )
410                     return E_FAIL;
411
412                 pSlice = timg.pixels + img.slicePitch;
413             }
414
415             assert( idx < (metadata.mipLevels * metadata.arraySize) );
416
417             initData[idx].pSysMem = img.pixels;
418             initData[idx].SysMemPitch = static_cast<DWORD>( img.rowPitch );
419             initData[idx].SysMemSlicePitch = static_cast<DWORD>( img.slicePitch );
420             ++idx;
421
422             if ( depth > 1 )
423                 depth >>= 1;
424         }
425     }
426     else
427     {
428         //--- 1D or 2D texture case ---------------------------------------------------
429         size_t idx = 0;
430         for( size_t item = 0; item < metadata.arraySize; ++item )
431         {
432             for( size_t level = 0; level < metadata.mipLevels; ++level )
433             {
434                 size_t index = metadata.ComputeIndex( level, item, 0 );
435                 if ( index >= nimages )
436                     return E_FAIL;
437
438                 const Image& img = srcImages[ index ];
439
440                 if ( img.format != metadata.format )
441                     return E_FAIL;
442
443                 if ( !img.pixels )
444                     return E_POINTER;
445
446                 assert( idx < (metadata.mipLevels * metadata.arraySize) );
447
448                 initData[idx].pSysMem = img.pixels;
449                 initData[idx].SysMemPitch = static_cast<DWORD>( img.rowPitch );
450                 initData[idx].SysMemSlicePitch = static_cast<DWORD>( img.slicePitch );
451                 ++idx;
452             }
453         }
454     }
455
456     // Create texture using static initialization data
457     HRESULT hr = E_FAIL;
458
459     switch ( metadata.dimension )
460     {
461     case TEX_DIMENSION_TEXTURE1D:
462         {
463             D3D11_TEXTURE1D_DESC desc;
464             desc.Width = static_cast<UINT>( metadata.width );
465             desc.MipLevels = static_cast<UINT>( metadata.mipLevels );
466             desc.ArraySize = static_cast<UINT>( metadata.arraySize );
467             desc.Format = metadata.format;
468             desc.Usage = D3D11_USAGE_DEFAULT;
469             desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
470             desc.CPUAccessFlags = 0;
471             desc.MiscFlags = 0;
472
473             hr = pDevice->CreateTexture1D( &desc, initData.get(), reinterpret_cast<ID3D11Texture1D**>(ppResource) );
474         }
475         break;
476
477     case TEX_DIMENSION_TEXTURE2D:
478         {
479             D3D11_TEXTURE2D_DESC desc;
480             desc.Width = static_cast<UINT>( metadata.width );
481             desc.Height = static_cast<UINT>( metadata.height ); 
482             desc.MipLevels = static_cast<UINT>( metadata.mipLevels );
483             desc.ArraySize = static_cast<UINT>( metadata.arraySize );
484             desc.Format = metadata.format;
485             desc.SampleDesc.Count = 1;
486             desc.SampleDesc.Quality = 0;
487             desc.Usage = D3D11_USAGE_DEFAULT;
488             desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
489             desc.CPUAccessFlags = 0;
490             desc.MiscFlags = (metadata.miscFlags & TEX_MISC_TEXTURECUBE) ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;
491
492             hr = pDevice->CreateTexture2D( &desc, initData.get(), reinterpret_cast<ID3D11Texture2D**>(ppResource) );
493         }
494         break;
495
496     case TEX_DIMENSION_TEXTURE3D:
497         {
498             D3D11_TEXTURE3D_DESC desc;
499             desc.Width = static_cast<UINT>( metadata.width );
500             desc.Height = static_cast<UINT>( metadata.height );
501             desc.Depth = static_cast<UINT>( metadata.depth );
502             desc.MipLevels = static_cast<UINT>( metadata.mipLevels );
503             desc.Format = metadata.format;
504             desc.Usage = D3D11_USAGE_DEFAULT;
505             desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
506             desc.CPUAccessFlags = 0;
507             desc.MiscFlags = 0;
508
509             hr = pDevice->CreateTexture3D( &desc, initData.get(), reinterpret_cast<ID3D11Texture3D**>(ppResource) );
510         }
511         break;
512     }
513
514     return hr;
515 }
516
517
518 //-------------------------------------------------------------------------------------
519 // Create a shader resource view and associated texture
520 //-------------------------------------------------------------------------------------
521 HRESULT CreateShaderResourceView( ID3D11Device* pDevice, const Image* srcImages, size_t nimages, const TexMetadata& metadata,
522                                   ID3D11ShaderResourceView** ppSRV )
523 {
524     if ( !ppSRV )
525         return E_INVALIDARG;
526
527     ScopedObject<ID3D11Resource> resource;
528     HRESULT hr = CreateTexture( pDevice, srcImages, nimages, metadata, &resource );
529     if ( FAILED(hr) )
530         return hr;
531
532     assert( !resource.IsNull() );
533
534     D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
535     memset( &SRVDesc, 0, sizeof(SRVDesc) );
536     SRVDesc.Format = metadata.format;
537
538     switch ( metadata.dimension )
539     {
540     case TEX_DIMENSION_TEXTURE1D:
541         if ( metadata.arraySize > 1 )
542         {
543             SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
544             SRVDesc.Texture1DArray.MipLevels = static_cast<UINT>( metadata.mipLevels );
545             SRVDesc.Texture1DArray.ArraySize = static_cast<UINT>( metadata.arraySize );
546         }
547         else
548         {
549             SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
550             SRVDesc.Texture1D.MipLevels = static_cast<UINT>( metadata.mipLevels );
551         }
552         break;
553
554     case TEX_DIMENSION_TEXTURE2D:
555         if ( metadata.miscFlags & TEX_MISC_TEXTURECUBE )
556         {
557             if (metadata.arraySize > 6)
558             {
559                 assert( (metadata.arraySize % 6) == 0 );
560                 SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
561                 SRVDesc.TextureCubeArray.MipLevels = static_cast<UINT>( metadata.mipLevels );
562                 SRVDesc.TextureCubeArray.NumCubes = static_cast<UINT>( metadata.arraySize / 6 );
563             }
564             else
565             {
566                 SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
567                 SRVDesc.TextureCube.MipLevels = static_cast<UINT>( metadata.mipLevels );
568             }
569         }
570         else if ( metadata.arraySize > 1 )
571         {
572             SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
573             SRVDesc.Texture2DArray.MipLevels = static_cast<UINT>( metadata.mipLevels );
574             SRVDesc.Texture2DArray.ArraySize = static_cast<UINT>( metadata.arraySize );
575         }
576         else
577         {
578             SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
579             SRVDesc.Texture2D.MipLevels = static_cast<UINT>( metadata.mipLevels );
580         }
581         break;
582
583     case TEX_DIMENSION_TEXTURE3D:
584         assert( metadata.arraySize == 1 );
585         SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
586         SRVDesc.Texture3D.MipLevels = static_cast<UINT>( metadata.mipLevels );
587         break;
588
589     default:
590         return E_FAIL;
591     }
592
593     hr = pDevice->CreateShaderResourceView( resource.Get(), &SRVDesc, ppSRV );
594     if ( FAILED(hr) )
595         return hr;
596
597     assert( *ppSRV );
598
599     return S_OK;
600 }
601
602
603 //-------------------------------------------------------------------------------------
604 // Save a texture resource to a DDS file in memory/on disk
605 //-------------------------------------------------------------------------------------
606 HRESULT CaptureTexture( ID3D11Device* pDevice, ID3D11DeviceContext* pContext, ID3D11Resource* pSource, ScratchImage& result )
607 {
608     if ( !pDevice || !pContext || !pSource )
609         return E_INVALIDARG;
610
611     D3D11_RESOURCE_DIMENSION resType = D3D11_RESOURCE_DIMENSION_UNKNOWN;
612     pSource->GetType( &resType );
613
614     HRESULT hr;
615
616     switch( resType )
617     {
618     case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
619         {
620             ScopedObject<ID3D11Texture1D> pTexture;
621             hr = pSource->QueryInterface( __uuidof(ID3D11Texture1D), (void**) &pTexture );
622             if ( FAILED(hr) )
623                 break;
624
625             assert( pTexture.Get() );
626
627             D3D11_TEXTURE1D_DESC desc;
628             pTexture->GetDesc( &desc );
629
630             desc.BindFlags = 0;
631             desc.MiscFlags = 0;
632             desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
633             desc.Usage = D3D11_USAGE_STAGING;
634
635             ScopedObject<ID3D11Texture1D> pStaging;
636             hr = pDevice->CreateTexture1D( &desc, 0, &pStaging );
637             if ( FAILED(hr) )
638                 break;
639
640             assert( pStaging.Get() );
641
642             pContext->CopyResource( pStaging.Get(), pSource );
643
644             TexMetadata mdata;
645             mdata.width = desc.Width;
646             mdata.height = mdata.depth = 1;
647             mdata.arraySize = desc.ArraySize;
648             mdata.mipLevels = desc.MipLevels;
649             mdata.miscFlags = 0;
650             mdata.format = desc.Format;
651             mdata.dimension = TEX_DIMENSION_TEXTURE1D;
652
653             hr = result.Initialize( mdata );
654             if ( FAILED(hr) )
655                 break;
656
657             hr = _Capture( pContext, pStaging.Get(), mdata, result );
658         }
659         break;
660
661     case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
662         {
663             ScopedObject<ID3D11Texture2D> pTexture;
664             hr = pSource->QueryInterface( __uuidof(ID3D11Texture2D), (void**) &pTexture );
665             if ( FAILED(hr) )
666                 break;
667
668             assert( pTexture.Get() );
669
670             D3D11_TEXTURE2D_DESC desc;
671             pTexture->GetDesc( &desc );
672
673             ScopedObject<ID3D11Texture2D> pStaging;
674             if ( desc.SampleDesc.Count > 1 )
675             {
676                 desc.SampleDesc.Count = 1;
677                 desc.SampleDesc.Quality = 0;
678
679                 ScopedObject<ID3D11Texture2D> pTemp;
680                 hr = pDevice->CreateTexture2D( &desc, 0, &pTemp );
681                 if ( FAILED(hr) )
682                     break;
683
684                 assert( pTemp.Get() );
685
686                 DXGI_FORMAT fmt = desc.Format;
687                 if ( IsTypeless(fmt) )
688                 {
689                     // Assume a UNORM if it exists otherwise use FLOAT
690                     fmt = MakeTypelessUNORM( fmt );
691                     fmt = MakeTypelessFLOAT( fmt );
692                 }
693
694                 UINT support = 0;
695                 hr = pDevice->CheckFormatSupport( fmt, &support );
696                 if ( FAILED(hr) )
697                     break;
698
699                 if ( !(support & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE) )
700                 {
701                     hr = E_FAIL;
702                     break;
703                 }
704
705                 for( UINT item = 0; item < desc.ArraySize; ++item )
706                 {
707                     for( UINT level = 0; level < desc.MipLevels; ++level )
708                     {
709                         UINT index = D3D11CalcSubresource( level, item, desc.MipLevels );
710
711                         pContext->ResolveSubresource( pTemp.Get(), index, pSource, index, fmt );
712                     }
713                 }
714
715                 desc.BindFlags = 0;
716                 desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE;
717                 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
718                 desc.Usage = D3D11_USAGE_STAGING;
719
720                 hr = pDevice->CreateTexture2D( &desc, 0, &pStaging );
721                 if ( FAILED(hr) )
722                     break;
723
724                 assert( pStaging.Get() );
725
726                 pContext->CopyResource( pStaging.Get(), pTemp.Get() );
727             }
728             else
729             {
730                 desc.BindFlags = 0;
731                 desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE;
732                 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
733                 desc.Usage = D3D11_USAGE_STAGING;
734
735                 hr = pDevice->CreateTexture2D( &desc, 0, &pStaging );
736                 if ( FAILED(hr) )
737                     break;
738
739                 assert( pStaging.Get() );
740
741                 pContext->CopyResource( pStaging.Get(), pSource );
742             }
743
744             TexMetadata mdata;
745             mdata.width = desc.Width;
746             mdata.height = desc.Height;
747             mdata.depth = 1;
748             mdata.arraySize = desc.ArraySize;
749             mdata.mipLevels = desc.MipLevels;
750             mdata.miscFlags = (desc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) ? TEX_MISC_TEXTURECUBE : 0;
751             mdata.format = desc.Format;
752             mdata.dimension = TEX_DIMENSION_TEXTURE2D;
753
754             hr = result.Initialize( mdata );
755             if ( FAILED(hr) )
756                 break;
757
758             hr = _Capture( pContext, pStaging.Get(), mdata, result );
759         }
760         break;
761
762     case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
763         {
764             ScopedObject<ID3D11Texture3D> pTexture;
765             hr = pSource->QueryInterface( __uuidof(ID3D11Texture3D), (void**) &pTexture );
766             if ( FAILED(hr) )
767                 break;
768
769             assert( pTexture.Get() );
770
771             D3D11_TEXTURE3D_DESC desc;
772             pTexture->GetDesc( &desc );
773
774             desc.BindFlags = 0;
775             desc.MiscFlags = 0;
776             desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
777             desc.Usage = D3D11_USAGE_STAGING;
778
779             ScopedObject<ID3D11Texture3D> pStaging;
780             hr = pDevice->CreateTexture3D( &desc, 0, &pStaging );
781             if ( FAILED(hr) )
782                 break;
783
784             assert( pStaging.Get() );
785
786             pContext->CopyResource( pStaging.Get(), pSource );
787
788             TexMetadata mdata;
789             mdata.width = desc.Width;
790             mdata.height = desc.Height;
791             mdata.depth = desc.Depth;
792             mdata.arraySize = 1;
793             mdata.mipLevels = desc.MipLevels;
794             mdata.miscFlags = 0;
795             mdata.format = desc.Format;
796             mdata.dimension = TEX_DIMENSION_TEXTURE3D;
797
798             hr = result.Initialize( mdata );
799             if ( FAILED(hr) )
800                 break;
801
802             hr = _Capture( pContext, pStaging.Get(), mdata, result );
803         }
804         break;
805
806     default:
807         hr = E_FAIL;
808         break;
809     }
810
811     if ( FAILED(hr) )
812     {
813         result.Release();
814         return hr;
815     }
816
817     return S_OK;
818 }
819
820 }; // namespace