Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
DirectXTexCompressGPU.cpp
Go to the documentation of this file.
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 
16 #include "directxtexp.h"
17 
18 #include "bcdirectcompute.h"
19 
20 namespace DirectX
21 {
22 
23 inline static DWORD _GetSRGBFlags( _In_ DWORD compress )
24 {
25  static_assert( TEX_COMPRESS_SRGB_IN == TEX_FILTER_SRGB_IN, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*" );
26  static_assert( TEX_COMPRESS_SRGB_OUT == TEX_FILTER_SRGB_OUT, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*" );
27  static_assert( TEX_COMPRESS_SRGB == TEX_FILTER_SRGB, "TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*" );
28  return ( compress & TEX_COMPRESS_SRGB );
29 }
30 
31 
32 //-------------------------------------------------------------------------------------
33 // Converts to R8G8B8A8_UNORM or R8G8B8A8_UNORM_SRGB doing any conversion logic needed
34 //-------------------------------------------------------------------------------------
35 static HRESULT _ConvertToRGBA32( _In_ const Image& srcImage, _In_ ScratchImage& image, bool srgb, _In_ DWORD filter )
36 {
37  if ( !srcImage.pixels )
38  return E_POINTER;
39 
40  DXGI_FORMAT format = srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
41 
42  HRESULT hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 );
43  if ( FAILED(hr) )
44  return hr;
45 
46  const Image *img = image.GetImage( 0, 0, 0 );
47  if ( !img )
48  {
49  image.Release();
50  return E_POINTER;
51  }
52 
53  uint8_t* pDest = img->pixels;
54  if ( !pDest )
55  {
56  image.Release();
57  return E_POINTER;
58  }
59 
60  ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( ( sizeof(XMVECTOR) * srcImage.width ), 16 ) ) );
61  if ( !scanline )
62  {
63  image.Release();
64  return E_OUTOFMEMORY;
65  }
66 
67  const uint8_t *pSrc = srcImage.pixels;
68  for( size_t h = 0; h < srcImage.height; ++h )
69  {
70  if ( !_LoadScanline( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) )
71  {
72  image.Release();
73  return E_FAIL;
74  }
75 
76  _ConvertScanline( scanline.get(), srcImage.width, format, srcImage.format, filter );
77 
78  if ( !_StoreScanline( pDest, img->rowPitch, format, scanline.get(), srcImage.width ) )
79  {
80  image.Release();
81  return E_FAIL;
82  }
83 
84  pSrc += srcImage.rowPitch;
85  pDest += img->rowPitch;
86  }
87 
88  return S_OK;
89 }
90 
91 
92 //-------------------------------------------------------------------------------------
93 // Converts to DXGI_FORMAT_R32G32B32A32_FLOAT doing any conversion logic needed
94 //-------------------------------------------------------------------------------------
95 static HRESULT _ConvertToRGBAF32( const Image& srcImage, ScratchImage& image, _In_ DWORD filter )
96 {
97  if ( !srcImage.pixels )
98  return E_POINTER;
99 
100  HRESULT hr = image.Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1 );
101  if ( FAILED(hr) )
102  return hr;
103 
104  const Image *img = image.GetImage( 0, 0, 0 );
105  if ( !img )
106  {
107  image.Release();
108  return E_POINTER;
109  }
110 
111  uint8_t* pDest = img->pixels;
112  if ( !pDest )
113  {
114  image.Release();
115  return E_POINTER;
116  }
117 
118  const uint8_t *pSrc = srcImage.pixels;
119  for( size_t h = 0; h < srcImage.height; ++h )
120  {
121  if ( !_LoadScanline( reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) )
122  {
123  image.Release();
124  return E_FAIL;
125  }
126 
127  _ConvertScanline( reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.format, filter );
128 
129  pSrc += srcImage.rowPitch;
130  pDest += img->rowPitch;
131  }
132 
133  return S_OK;
134 }
135 
136 
137 //-------------------------------------------------------------------------------------
138 // Compress using GPU, converting to the proper input format for the shader if needed
139 //-------------------------------------------------------------------------------------
140 inline static HRESULT _GPUCompress( _In_ GPUCompressBC* gpubc, _In_ const Image& srcImage, _In_ const Image& destImage, _In_ DWORD compress )
141 {
142  if ( !gpubc )
143  return E_POINTER;
144 
145  assert( srcImage.pixels && destImage.pixels );
146 
147  DXGI_FORMAT format = gpubc->GetSourceFormat();
148 
149  if ( srcImage.format == format )
150  {
151  // Input is already in our required source format
152  return gpubc->Compress( srcImage, destImage );
153  }
154  else
155  {
156  // Convert format and then use as the source image
157  ScratchImage image;
158  HRESULT hr;
159 
160  DWORD srgb = _GetSRGBFlags( compress );
161 
162  switch( format )
163  {
164  case DXGI_FORMAT_R8G8B8A8_UNORM:
165  hr = _ConvertToRGBA32( srcImage, image, false, srgb );
166  break;
167 
168  case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
169  hr = _ConvertToRGBA32( srcImage, image, true, srgb );
170  break;
171 
172  case DXGI_FORMAT_R32G32B32A32_FLOAT:
173  hr = _ConvertToRGBAF32( srcImage, image, srgb );
174  break;
175 
176  default:
177  hr = E_UNEXPECTED;
178  break;
179  }
180 
181  if ( FAILED(hr) )
182  return hr;
183 
184  const Image *img = image.GetImage( 0, 0, 0 );
185  if ( !img )
186  return E_POINTER;
187 
188  return gpubc->Compress( *img, destImage );
189  }
190 }
191 
192 
193 //=====================================================================================
194 // Entry-points
195 //=====================================================================================
196 
197 //-------------------------------------------------------------------------------------
198 // Compression
199 //-------------------------------------------------------------------------------------
200 _Use_decl_annotations_
201 HRESULT Compress( ID3D11Device* pDevice, const Image& srcImage, DXGI_FORMAT format, DWORD compress, float alphaWeight, ScratchImage& image )
202 {
203  if ( !pDevice || IsCompressed(srcImage.format) || !IsCompressed(format) )
204  return E_INVALIDARG;
205 
206  if ( IsTypeless(format)
207  || IsTypeless(srcImage.format) || IsPlanar(srcImage.format) || IsPalettized(srcImage.format) )
208  return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
209 
210  // Setup GPU compressor
211  std::unique_ptr<GPUCompressBC> gpubc( new (std::nothrow) GPUCompressBC );
212  if ( !gpubc )
213  return E_OUTOFMEMORY;
214 
215  HRESULT hr = gpubc->Initialize( pDevice );
216  if ( FAILED(hr) )
217  return hr;
218 
219  hr = gpubc->Prepare( srcImage.width, srcImage.height, format, alphaWeight );
220  if ( FAILED(hr) )
221  return hr;
222 
223  // Create workspace for result
224  hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 );
225  if ( FAILED(hr) )
226  return hr;
227 
228  const Image *img = image.GetImage( 0, 0, 0 );
229  if ( !img )
230  {
231  image.Release();
232  return E_POINTER;
233  }
234 
235  hr = _GPUCompress( gpubc.get(), srcImage, *img, compress );
236  if ( FAILED(hr) )
237  image.Release();
238 
239  return hr;
240 }
241 
242 _Use_decl_annotations_
243 HRESULT Compress( ID3D11Device* pDevice, const Image* srcImages, size_t nimages, const TexMetadata& metadata,
244  DXGI_FORMAT format, DWORD compress, float alphaWeight, ScratchImage& cImages )
245 {
246  if ( !pDevice || !srcImages || !nimages )
247  return E_INVALIDARG;
248 
249  if ( IsCompressed(metadata.format) || !IsCompressed(format) )
250  return E_INVALIDARG;
251 
252  if ( IsTypeless(format)
253  || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format) )
254  return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
255 
256  cImages.Release();
257 
258  // Setup GPU compressor
259  std::unique_ptr<GPUCompressBC> gpubc( new (std::nothrow) GPUCompressBC );
260  if ( !gpubc )
261  return E_OUTOFMEMORY;
262 
263  HRESULT hr = gpubc->Initialize( pDevice );
264  if ( FAILED(hr) )
265  return hr;
266 
267  // Create workspace for result
268  TexMetadata mdata2 = metadata;
269  mdata2.format = format;
270  hr = cImages.Initialize( mdata2 );
271  if ( FAILED(hr) )
272  return hr;
273 
274  if ( nimages != cImages.GetImageCount() )
275  {
276  cImages.Release();
277  return E_FAIL;
278  }
279 
280  const Image* dest = cImages.GetImages();
281  if ( !dest )
282  {
283  cImages.Release();
284  return E_POINTER;
285  }
286 
287  // Process images (ordered by size)
288  switch( metadata.dimension )
289  {
292  {
293  size_t w = metadata.width;
294  size_t h = metadata.height;
295 
296  for( size_t level=0; level < metadata.mipLevels; ++level )
297  {
298  hr = gpubc->Prepare( w, h, format, alphaWeight );
299  if ( FAILED(hr) )
300  {
301  cImages.Release();
302  return hr;
303  }
304 
305  for( size_t item = 0; item < metadata.arraySize; ++item )
306  {
307  size_t index = metadata.ComputeIndex( level, item, 0 );
308  if ( index >= nimages )
309  {
310  cImages.Release();
311  return E_FAIL;
312  }
313 
314  assert( dest[ index ].format == format );
315 
316  const Image& src = srcImages[ index ];
317 
318  if ( src.width != dest[ index ].width || src.height != dest[ index ].height )
319  {
320  cImages.Release();
321  return E_FAIL;
322  }
323 
324  hr = _GPUCompress( gpubc.get(), src, dest[ index ], compress );
325  if ( FAILED(hr) )
326  {
327  cImages.Release();
328  return hr;
329  }
330  }
331 
332  if ( h > 1 )
333  h >>= 1;
334 
335  if ( w > 1 )
336  w >>= 1;
337  }
338  }
339  break;
340 
342  {
343  size_t w = metadata.width;
344  size_t h = metadata.height;
345  size_t d = metadata.depth;
346 
347  for( size_t level=0; level < metadata.mipLevels; ++level )
348  {
349  hr = gpubc->Prepare( w, h, format, alphaWeight );
350  if ( FAILED(hr) )
351  {
352  cImages.Release();
353  return hr;
354  }
355 
356  for( size_t slice=0; slice < d; ++slice )
357  {
358  size_t index = metadata.ComputeIndex( level, 0, slice );
359  if ( index >= nimages )
360  {
361  cImages.Release();
362  return E_FAIL;
363  }
364 
365  assert( dest[ index ].format == format );
366 
367  const Image& src = srcImages[ index ];
368 
369  if ( src.width != dest[ index ].width || src.height != dest[ index ].height )
370  {
371  cImages.Release();
372  return E_FAIL;
373  }
374 
375  hr = _GPUCompress( gpubc.get(), src, dest[ index ], compress );
376  if ( FAILED(hr) )
377  {
378  cImages.Release();
379  return hr;
380  }
381  }
382 
383  if ( h > 1 )
384  h >>= 1;
385 
386  if ( w > 1 )
387  w >>= 1;
388 
389  if ( d > 1 )
390  d >>= 1;
391  }
392  }
393  break;
394 
395  default:
396  return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
397  }
398 
399  return S_OK;
400 }
401 
402 }; // namespace
std::unique_ptr< DirectX::XMVECTOR, aligned_deleter > ScopedAlignedArrayXMVECTOR
Definition: scoped.h:27
const Image * GetImage(_In_ size_t mip, _In_ size_t item, _In_ size_t slice) const
uint8_t * pixels
Definition: DirectXTex.h:230
bool IsPlanar(_In_ DXGI_FORMAT fmt)
DXGI_FORMAT format
Definition: DirectXTex.h:125
static HRESULT _ConvertToRGBA32(_In_ const Image &srcImage, _In_ ScratchImage &image, bool srgb, _In_ DWORD filter)
size_t _In_ DXGI_FORMAT size_t _In_ TEXP_LEGACY_FORMAT _In_ DWORD flags assert(pDestination &&outSize > 0)
HRESULT Initialize(_In_ const TexMetadata &mdata, _In_ DWORD flags=CP_FLAGS_NONE)
HRESULT Initialize2D(_In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _In_ size_t arraySize, _In_ size_t mipLevels, _In_ DWORD flags=CP_FLAGS_NONE)
_Use_decl_annotations_ bool _LoadScanline(XMVECTOR *pDestination, size_t count, LPCVOID pSource, size_t size, DXGI_FORMAT format)
static HRESULT _ConvertToRGBAF32(const Image &srcImage, ScratchImage &image, _In_ DWORD filter)
size_t ComputeIndex(_In_ size_t mip, _In_ size_t item, _In_ size_t slice) const
bool IsCompressed(_In_ DXGI_FORMAT fmt)
size_t rowPitch
Definition: DirectXTex.h:228
size_t GetImageCount() const
Definition: DirectXTex.h:264
static DWORD _GetSRGBFlags(_In_ DWORD compress)
_In_ size_t _In_ const TexMetadata & metadata
Definition: DirectXTexP.h:116
_Use_decl_annotations_ void _ConvertScanline(XMVECTOR *pBuffer, size_t count, DXGI_FORMAT outFormat, DXGI_FORMAT inFormat, DWORD flags)
bool IsPalettized(_In_ DXGI_FORMAT fmt)
bool IsTypeless(_In_ DXGI_FORMAT fmt, _In_ bool partialTypeless=true)
TEX_DIMENSION dimension
Definition: DirectXTex.h:126
char * dest
Definition: lz4.h:61
DXGI_FORMAT format
Definition: DirectXTex.h:227
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
Definition: DirectXTexP.h:175
static HRESULT _GPUCompress(_In_ GPUCompressBC *gpubc, _In_ const Image &srcImage, _In_ const Image &destImage, _In_ DWORD compress)
const Image * GetImages() const
Definition: DirectXTex.h:263
HRESULT Compress(_In_ const Image &srcImage, _In_ DXGI_FORMAT format, _In_ DWORD compress, _In_ float alphaRef, _Out_ ScratchImage &cImage)
_Use_decl_annotations_ bool _StoreScanline(LPVOID pDestination, size_t size, DXGI_FORMAT format, const XMVECTOR *pSource, size_t count, float threshold)