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