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