DirectXTexCompressGPU.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. //-------------------------------------------------------------------------------------
  2. // DirectXTexCompressGPU.cpp
  3. //
  4. // DirectX Texture Library - DirectCompute-based texture compression
  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. #include "directxtexp.h"
  16. #include "bcdirectcompute.h"
  17. namespace DirectX
  18. {
  19. inline static DWORD _GetSRGBFlags( _In_ DWORD compress )
  20. {
  21. static_assert( TEX_COMPRESS_SRGB_IN == TEX_FILTER_SRGB_IN, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*" );
  22. static_assert( TEX_COMPRESS_SRGB_OUT == TEX_FILTER_SRGB_OUT, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*" );
  23. static_assert( TEX_COMPRESS_SRGB == TEX_FILTER_SRGB, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*" );
  24. return ( compress & TEX_COMPRESS_SRGB );
  25. }
  26. //-------------------------------------------------------------------------------------
  27. // Converts to R8G8B8A8_UNORM or R8G8B8A8_UNORM_SRGB doing any conversion logic needed
  28. //-------------------------------------------------------------------------------------
  29. static HRESULT _ConvertToRGBA32( _In_ const Image& srcImage, _In_ ScratchImage& image, bool srgb, _In_ DWORD filter )
  30. {
  31. if ( !srcImage.pixels )
  32. return E_POINTER;
  33. DXGI_FORMAT format = srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
  34. HRESULT hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 );
  35. if ( FAILED(hr) )
  36. return hr;
  37. const Image *img = image.GetImage( 0, 0, 0 );
  38. if ( !img )
  39. {
  40. image.Release();
  41. return E_POINTER;
  42. }
  43. uint8_t* pDest = img->pixels;
  44. if ( !pDest )
  45. {
  46. image.Release();
  47. return E_POINTER;
  48. }
  49. ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( ( sizeof(XMVECTOR) * srcImage.width ), 16 ) ) );
  50. if ( !scanline )
  51. {
  52. image.Release();
  53. return E_OUTOFMEMORY;
  54. }
  55. const uint8_t *pSrc = srcImage.pixels;
  56. for( size_t h = 0; h < srcImage.height; ++h )
  57. {
  58. if ( !_LoadScanline( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) )
  59. {
  60. image.Release();
  61. return E_FAIL;
  62. }
  63. _ConvertScanline( scanline.get(), srcImage.width, format, srcImage.format, filter );
  64. if ( !_StoreScanline( pDest, img->rowPitch, format, scanline.get(), srcImage.width ) )
  65. {
  66. image.Release();
  67. return E_FAIL;
  68. }
  69. pSrc += srcImage.rowPitch;
  70. pDest += img->rowPitch;
  71. }
  72. return S_OK;
  73. }
  74. //-------------------------------------------------------------------------------------
  75. // Converts to DXGI_FORMAT_R32G32B32A32_FLOAT doing any conversion logic needed
  76. //-------------------------------------------------------------------------------------
  77. static HRESULT _ConvertToRGBAF32( const Image& srcImage, ScratchImage& image, _In_ DWORD filter )
  78. {
  79. if ( !srcImage.pixels )
  80. return E_POINTER;
  81. HRESULT hr = image.Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1 );
  82. if ( FAILED(hr) )
  83. return hr;
  84. const Image *img = image.GetImage( 0, 0, 0 );
  85. if ( !img )
  86. {
  87. image.Release();
  88. return E_POINTER;
  89. }
  90. uint8_t* pDest = img->pixels;
  91. if ( !pDest )
  92. {
  93. image.Release();
  94. return E_POINTER;
  95. }
  96. const uint8_t *pSrc = srcImage.pixels;
  97. for( size_t h = 0; h < srcImage.height; ++h )
  98. {
  99. if ( !_LoadScanline( reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) )
  100. {
  101. image.Release();
  102. return E_FAIL;
  103. }
  104. _ConvertScanline( reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.format, filter );
  105. pSrc += srcImage.rowPitch;
  106. pDest += img->rowPitch;
  107. }
  108. return S_OK;
  109. }
  110. //-------------------------------------------------------------------------------------
  111. // Compress using GPU, converting to the proper input format for the shader if needed
  112. //-------------------------------------------------------------------------------------
  113. inline static HRESULT _GPUCompress( _In_ GPUCompressBC* gpubc, _In_ const Image& srcImage, _In_ const Image& destImage, _In_ DWORD compress )
  114. {
  115. if ( !gpubc )
  116. return E_POINTER;
  117. assert( srcImage.pixels && destImage.pixels );
  118. DXGI_FORMAT format = gpubc->GetSourceFormat();
  119. if ( srcImage.format == format )
  120. {
  121. // Input is already in our required source format
  122. return gpubc->Compress( srcImage, destImage );
  123. }
  124. else
  125. {
  126. // Convert format and then use as the source image
  127. ScratchImage image;
  128. HRESULT hr;
  129. DWORD srgb = _GetSRGBFlags( compress );
  130. switch( format )
  131. {
  132. case DXGI_FORMAT_R8G8B8A8_UNORM:
  133. hr = _ConvertToRGBA32( srcImage, image, false, srgb );
  134. break;
  135. case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
  136. hr = _ConvertToRGBA32( srcImage, image, true, srgb );
  137. break;
  138. case DXGI_FORMAT_R32G32B32A32_FLOAT:
  139. hr = _ConvertToRGBAF32( srcImage, image, srgb );
  140. break;
  141. default:
  142. hr = E_UNEXPECTED;
  143. break;
  144. }
  145. if ( FAILED(hr) )
  146. return hr;
  147. const Image *img = image.GetImage( 0, 0, 0 );
  148. if ( !img )
  149. return E_POINTER;
  150. return gpubc->Compress( *img, destImage );
  151. }
  152. }
  153. //=====================================================================================
  154. // Entry-points
  155. //=====================================================================================
  156. //-------------------------------------------------------------------------------------
  157. // Compression
  158. //-------------------------------------------------------------------------------------
  159. _Use_decl_annotations_
  160. HRESULT Compress( ID3D11Device* pDevice, const Image& srcImage, DXGI_FORMAT format, DWORD compress, float alphaWeight, ScratchImage& image )
  161. {
  162. if ( !pDevice || IsCompressed(srcImage.format) || !IsCompressed(format) )
  163. return E_INVALIDARG;
  164. if ( IsTypeless(format)
  165. || IsTypeless(srcImage.format) || IsPlanar(srcImage.format) || IsPalettized(srcImage.format) )
  166. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  167. // Setup GPU compressor
  168. std::unique_ptr<GPUCompressBC> gpubc( new (std::nothrow) GPUCompressBC );
  169. if ( !gpubc )
  170. return E_OUTOFMEMORY;
  171. HRESULT hr = gpubc->Initialize( pDevice );
  172. if ( FAILED(hr) )
  173. return hr;
  174. hr = gpubc->Prepare( srcImage.width, srcImage.height, format, alphaWeight );
  175. if ( FAILED(hr) )
  176. return hr;
  177. // Create workspace for result
  178. hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 );
  179. if ( FAILED(hr) )
  180. return hr;
  181. const Image *img = image.GetImage( 0, 0, 0 );
  182. if ( !img )
  183. {
  184. image.Release();
  185. return E_POINTER;
  186. }
  187. hr = _GPUCompress( gpubc.get(), srcImage, *img, compress );
  188. if ( FAILED(hr) )
  189. image.Release();
  190. return hr;
  191. }
  192. _Use_decl_annotations_
  193. HRESULT Compress( ID3D11Device* pDevice, const Image* srcImages, size_t nimages, const TexMetadata& metadata,
  194. DXGI_FORMAT format, DWORD compress, float alphaWeight, ScratchImage& cImages )
  195. {
  196. if ( !pDevice || !srcImages || !nimages )
  197. return E_INVALIDARG;
  198. if ( IsCompressed(metadata.format) || !IsCompressed(format) )
  199. return E_INVALIDARG;
  200. if ( IsTypeless(format)
  201. || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format) )
  202. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  203. cImages.Release();
  204. // Setup GPU compressor
  205. std::unique_ptr<GPUCompressBC> gpubc( new (std::nothrow) GPUCompressBC );
  206. if ( !gpubc )
  207. return E_OUTOFMEMORY;
  208. HRESULT hr = gpubc->Initialize( pDevice );
  209. if ( FAILED(hr) )
  210. return hr;
  211. // Create workspace for result
  212. TexMetadata mdata2 = metadata;
  213. mdata2.format = format;
  214. hr = cImages.Initialize( mdata2 );
  215. if ( FAILED(hr) )
  216. return hr;
  217. if ( nimages != cImages.GetImageCount() )
  218. {
  219. cImages.Release();
  220. return E_FAIL;
  221. }
  222. const Image* dest = cImages.GetImages();
  223. if ( !dest )
  224. {
  225. cImages.Release();
  226. return E_POINTER;
  227. }
  228. // Process images (ordered by size)
  229. switch( metadata.dimension )
  230. {
  231. case TEX_DIMENSION_TEXTURE1D:
  232. case TEX_DIMENSION_TEXTURE2D:
  233. {
  234. size_t w = metadata.width;
  235. size_t h = metadata.height;
  236. for( size_t level=0; level < metadata.mipLevels; ++level )
  237. {
  238. hr = gpubc->Prepare( w, h, format, alphaWeight );
  239. if ( FAILED(hr) )
  240. {
  241. cImages.Release();
  242. return hr;
  243. }
  244. for( size_t item = 0; item < metadata.arraySize; ++item )
  245. {
  246. size_t index = metadata.ComputeIndex( level, item, 0 );
  247. if ( index >= nimages )
  248. {
  249. cImages.Release();
  250. return E_FAIL;
  251. }
  252. assert( dest[ index ].format == format );
  253. const Image& src = srcImages[ index ];
  254. if ( src.width != dest[ index ].width || src.height != dest[ index ].height )
  255. {
  256. cImages.Release();
  257. return E_FAIL;
  258. }
  259. hr = _GPUCompress( gpubc.get(), src, dest[ index ], compress );
  260. if ( FAILED(hr) )
  261. {
  262. cImages.Release();
  263. return hr;
  264. }
  265. }
  266. if ( h > 1 )
  267. h >>= 1;
  268. if ( w > 1 )
  269. w >>= 1;
  270. }
  271. }
  272. break;
  273. case TEX_DIMENSION_TEXTURE3D:
  274. {
  275. size_t w = metadata.width;
  276. size_t h = metadata.height;
  277. size_t d = metadata.depth;
  278. for( size_t level=0; level < metadata.mipLevels; ++level )
  279. {
  280. hr = gpubc->Prepare( w, h, format, alphaWeight );
  281. if ( FAILED(hr) )
  282. {
  283. cImages.Release();
  284. return hr;
  285. }
  286. for( size_t slice=0; slice < d; ++slice )
  287. {
  288. size_t index = metadata.ComputeIndex( level, 0, slice );
  289. if ( index >= nimages )
  290. {
  291. cImages.Release();
  292. return E_FAIL;
  293. }
  294. assert( dest[ index ].format == format );
  295. const Image& src = srcImages[ index ];
  296. if ( src.width != dest[ index ].width || src.height != dest[ index ].height )
  297. {
  298. cImages.Release();
  299. return E_FAIL;
  300. }
  301. hr = _GPUCompress( gpubc.get(), src, dest[ index ], compress );
  302. if ( FAILED(hr) )
  303. {
  304. cImages.Release();
  305. return hr;
  306. }
  307. }
  308. if ( h > 1 )
  309. h >>= 1;
  310. if ( w > 1 )
  311. w >>= 1;
  312. if ( d > 1 )
  313. d >>= 1;
  314. }
  315. }
  316. break;
  317. default:
  318. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  319. }
  320. return S_OK;
  321. }
  322. }; // namespace