]> git.cworth.org Git - apitrace/blob - thirdparty/directxtex/DirectXTex/DirectXTexConvert.cpp
f19c269ff756fa3cce146cbfd9d7f7b57cc04be6
[apitrace] / thirdparty / directxtex / DirectXTex / DirectXTexConvert.cpp
1 //-------------------------------------------------------------------------------------
2 // DirectXTexConvert.cpp
3 //  
4 // DirectX Texture Library - Image conversion 
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 #ifdef USE_XNAMATH
19 #if XNAMATH_VERSION < 205
20 #error This file requires XNAMATH v2.05 or later
21 #endif
22 #else
23 using namespace DirectX::PackedVector;
24 #endif
25
26 namespace DirectX
27 {
28
29 //-------------------------------------------------------------------------------------
30 // Copies an image row with optional clearing of alpha value to 1.0
31 // (can be used in place as well) otherwise copies the image row unmodified.
32 //-------------------------------------------------------------------------------------
33 void _CopyScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, size_t inSize, DXGI_FORMAT format, DWORD flags )
34 {
35     assert( pDestination && outSize > 0 );
36     assert( pSource && inSize > 0 );
37     assert( IsValid(format) && !IsVideo(format) );
38
39     if ( flags & TEXP_SCANLINE_SETALPHA )
40     {
41         switch( format )
42         {
43         //-----------------------------------------------------------------------------
44         case DXGI_FORMAT_R32G32B32A32_TYPELESS:
45         case DXGI_FORMAT_R32G32B32A32_FLOAT:
46         case DXGI_FORMAT_R32G32B32A32_UINT:
47         case DXGI_FORMAT_R32G32B32A32_SINT:
48             {
49                 uint32_t alpha;
50                 if ( format == DXGI_FORMAT_R32G32B32A32_FLOAT )
51                     alpha = 0x3f800000;
52                 else if ( format == DXGI_FORMAT_R32G32B32A32_SINT )
53                     alpha = 0x7fffffff;
54                 else
55                     alpha = 0xffffffff;
56
57                 if ( pDestination == pSource )
58                 {
59                     uint32_t *dPtr = reinterpret_cast<uint32_t*>(pDestination);
60                     for( size_t count = 0; count < outSize; count += 16 )
61                     {
62                         dPtr += 3;
63                         *(dPtr++) = alpha;
64                     }
65                 }
66                 else
67                 {
68                     const uint32_t * __restrict sPtr = reinterpret_cast<const uint32_t*>(pSource);
69                     uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
70                     size_t size = std::min<size_t>( outSize, inSize );
71                     for( size_t count = 0; count < size; count += 16 )
72                     {
73                         *(dPtr++) = *(sPtr++);
74                         *(dPtr++) = *(sPtr++);
75                         *(dPtr++) = *(sPtr++);
76                         *(dPtr++) = alpha;
77                         sPtr++;
78                     }
79                 }
80             }
81             return;
82
83         //-----------------------------------------------------------------------------
84         case DXGI_FORMAT_R16G16B16A16_TYPELESS:
85         case DXGI_FORMAT_R16G16B16A16_FLOAT:
86         case DXGI_FORMAT_R16G16B16A16_UNORM:
87         case DXGI_FORMAT_R16G16B16A16_UINT:
88         case DXGI_FORMAT_R16G16B16A16_SNORM:
89         case DXGI_FORMAT_R16G16B16A16_SINT:
90             {
91                 uint16_t alpha;
92                 if ( format == DXGI_FORMAT_R16G16B16A16_FLOAT )
93                     alpha = 0x3c00;
94                 else if ( format == DXGI_FORMAT_R16G16B16A16_SNORM || format == DXGI_FORMAT_R16G16B16A16_SINT )
95                     alpha = 0x7fff;
96                 else
97                     alpha = 0xffff;
98
99                 if ( pDestination == pSource )
100                 {
101                     uint16_t *dPtr = reinterpret_cast<uint16_t*>(pDestination);
102                     for( size_t count = 0; count < outSize; count += 8 )
103                     {
104                         dPtr += 3;
105                         *(dPtr++) = alpha;
106                     }
107                 }
108                 else
109                 {
110                     const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
111                     uint16_t * __restrict dPtr = reinterpret_cast<uint16_t*>(pDestination);
112                     size_t size = std::min<size_t>( outSize, inSize );
113                     for( size_t count = 0; count < size; count += 8 )
114                     {
115                         *(dPtr++) = *(sPtr++);
116                         *(dPtr++) = *(sPtr++);
117                         *(dPtr++) = *(sPtr++);
118                         *(dPtr++) = alpha;
119                         sPtr++;
120                     }
121                 }
122             }
123             return;
124
125         //-----------------------------------------------------------------------------
126         case DXGI_FORMAT_R10G10B10A2_TYPELESS:
127         case DXGI_FORMAT_R10G10B10A2_UNORM:
128         case DXGI_FORMAT_R10G10B10A2_UINT:
129         case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
130             if ( pDestination == pSource )
131             {
132                 uint32_t *dPtr = reinterpret_cast<uint32_t*>(pDestination);
133                 for( size_t count = 0; count < outSize; count += 4 )
134                 {
135 #pragma warning(suppress: 6001 6101) // PREFast doesn't properly understand the aliasing here.
136                     *dPtr |= 0xC0000000;
137                     ++dPtr;
138                 }
139             }
140             else
141             {
142                 const uint32_t * __restrict sPtr = reinterpret_cast<const uint32_t*>(pSource);
143                 uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
144                 size_t size = std::min<size_t>( outSize, inSize );
145                 for( size_t count = 0; count < size; count += 4 )
146                 {
147                     *(dPtr++) = *(sPtr++) | 0xC0000000;
148                 }
149             }
150             return;
151
152         //-----------------------------------------------------------------------------
153         case DXGI_FORMAT_R8G8B8A8_TYPELESS:
154         case DXGI_FORMAT_R8G8B8A8_UNORM:
155         case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
156         case DXGI_FORMAT_R8G8B8A8_UINT:
157         case DXGI_FORMAT_R8G8B8A8_SNORM:
158         case DXGI_FORMAT_R8G8B8A8_SINT:
159         case DXGI_FORMAT_B8G8R8A8_UNORM:
160         case DXGI_FORMAT_B8G8R8A8_TYPELESS:
161         case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
162             {
163                 const uint32_t alpha = ( format == DXGI_FORMAT_R8G8B8A8_SNORM || format == DXGI_FORMAT_R8G8B8A8_SINT ) ? 0x7f000000 : 0xff000000;
164
165                 if ( pDestination == pSource )
166                 {
167                     uint32_t *dPtr = reinterpret_cast<uint32_t*>(pDestination);
168                     for( size_t count = 0; count < outSize; count += 4 )
169                     {
170                         uint32_t t = *dPtr & 0xFFFFFF;
171                         t |= alpha;
172                         *(dPtr++) = t;
173                     }
174                 }
175                 else
176                 {
177                     const uint32_t * __restrict sPtr = reinterpret_cast<const uint32_t*>(pSource);
178                     uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
179                     size_t size = std::min<size_t>( outSize, inSize );
180                     for( size_t count = 0; count < size; count += 4 )
181                     {
182                         uint32_t t = *(sPtr++) & 0xFFFFFF;
183                         t |= alpha;
184                         *(dPtr++) = t;
185                     }
186                 }
187             }
188             return;
189
190         //-----------------------------------------------------------------------------
191         case DXGI_FORMAT_B5G5R5A1_UNORM:
192             if ( pDestination == pSource )
193             {
194                 uint16_t *dPtr = reinterpret_cast<uint16_t*>(pDestination);
195                 for( size_t count = 0; count < outSize; count += 2 )
196                 {
197                     *(dPtr++) |= 0x8000;
198                 }
199             }
200             else
201             {
202                 const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
203                 uint16_t * __restrict dPtr = reinterpret_cast<uint16_t*>(pDestination);
204                 size_t size = std::min<size_t>( outSize, inSize );
205                 for( size_t count = 0; count < size; count += 2 )
206                 {
207                     *(dPtr++) = *(sPtr++) | 0x8000;
208                 }
209             }
210             return;
211
212         //-----------------------------------------------------------------------------
213         case DXGI_FORMAT_A8_UNORM:
214             memset( pDestination, 0xff, outSize );
215             return;
216
217 #ifdef DXGI_1_2_FORMATS
218         //-----------------------------------------------------------------------------
219         case DXGI_FORMAT_B4G4R4A4_UNORM:
220             if ( pDestination == pSource )
221             {
222                 uint16_t *dPtr = reinterpret_cast<uint16_t*>(pDestination);
223                 for( size_t count = 0; count < outSize; count += 2 )
224                 {
225                     *(dPtr++) |= 0xF000;
226                 }
227             }
228             else
229             {
230                 const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
231                 uint16_t * __restrict dPtr = reinterpret_cast<uint16_t*>(pDestination);
232                 size_t size = std::min<size_t>( outSize, inSize );
233                 for( size_t count = 0; count < size; count += 2 )
234                 {
235                     *(dPtr++) = *(sPtr++) | 0xF000;
236                 }
237             }
238             return;
239 #endif // DXGI_1_2_FORMATS
240         }
241     }
242
243     // Fall-through case is to just use memcpy (assuming this is not an in-place operation)
244     if ( pDestination == pSource )
245         return;
246
247     size_t size = std::min<size_t>( outSize, inSize );
248     memcpy_s( pDestination, outSize, pSource, size );
249 }
250
251
252 //-------------------------------------------------------------------------------------
253 // Swizzles (RGB <-> BGR) an image row with optional clearing of alpha value to 1.0
254 // (can be used in place as well) otherwise copies the image row unmodified.
255 //-------------------------------------------------------------------------------------
256 void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, size_t inSize, DXGI_FORMAT format, DWORD flags )
257 {
258     assert( pDestination && outSize > 0 );
259     assert( pSource && inSize > 0 );
260     assert( IsValid(format) && !IsVideo(format) );
261
262     switch( format )
263     {
264     //---------------------------------------------------------------------------------
265     case DXGI_FORMAT_R10G10B10A2_TYPELESS:
266     case DXGI_FORMAT_R10G10B10A2_UNORM:
267     case DXGI_FORMAT_R10G10B10A2_UINT:
268     case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
269         if ( flags & TEXP_SCANLINE_LEGACY )
270         {
271             // Swap Red (R) and Blue (B) channel (used for D3DFMT_A2R10G10B10 legacy sources)
272             if ( pDestination == pSource )
273             {
274                 uint32_t *dPtr = reinterpret_cast<uint32_t*>(pDestination);
275                 for( size_t count = 0; count < outSize; count += 4 )
276                 {
277 #pragma warning(suppress: 6001 6101) // PREFast doesn't properly understand the aliasing here.
278                     uint32_t t = *dPtr;
279
280                     uint32_t t1 = (t & 0x3ff00000) >> 20;
281                     uint32_t t2 = (t & 0x000003ff) << 20;
282                     uint32_t t3 = (t & 0x000ffc00);
283                     uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xC0000000 : (t & 0xC0000000);
284
285                     *(dPtr++) = t1 | t2 | t3 | ta;
286                 }
287             }
288             else
289             {
290                 const uint32_t * __restrict sPtr = reinterpret_cast<const uint32_t*>(pSource);
291                 uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
292                 size_t size = std::min<size_t>( outSize, inSize );
293                 for( size_t count = 0; count < size; count += 4 )
294                 {
295                     uint32_t t = *(sPtr++);
296
297                     uint32_t t1 = (t & 0x3ff00000) >> 20;
298                     uint32_t t2 = (t & 0x000003ff) << 20;
299                     uint32_t t3 = (t & 0x000ffc00);
300                     uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xC0000000 : (t & 0xC0000000);
301
302                     *(dPtr++) = t1 | t2 | t3 | ta;
303                 }
304             }
305             return;
306         }
307         break;
308
309     //---------------------------------------------------------------------------------
310     case DXGI_FORMAT_R8G8B8A8_TYPELESS:
311     case DXGI_FORMAT_R8G8B8A8_UNORM:
312     case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
313     case DXGI_FORMAT_B8G8R8A8_UNORM:
314     case DXGI_FORMAT_B8G8R8X8_UNORM:
315     case DXGI_FORMAT_B8G8R8A8_TYPELESS:
316     case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
317     case DXGI_FORMAT_B8G8R8X8_TYPELESS:
318     case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
319         // Swap Red (R) and Blue (B) channels (used to convert from DXGI 1.1 BGR formats to DXGI 1.0 RGB)
320         if ( pDestination == pSource )
321         {
322             uint32_t *dPtr = reinterpret_cast<uint32_t*>(pDestination);
323             for( size_t count = 0; count < outSize; count += 4 )
324             {
325                 uint32_t t = *dPtr;
326
327                 uint32_t t1 = (t & 0x00ff0000) >> 16;
328                 uint32_t t2 = (t & 0x000000ff) << 16;
329                 uint32_t t3 = (t & 0x0000ff00);
330                 uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : (t & 0xFF000000);
331
332                 *(dPtr++) = t1 | t2 | t3 | ta;
333             }
334         }
335         else
336         {
337             const uint32_t * __restrict sPtr = reinterpret_cast<const uint32_t*>(pSource);
338             uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
339             size_t size = std::min<size_t>( outSize, inSize );
340             for( size_t count = 0; count < size; count += 4 )
341             {
342                 uint32_t t = *(sPtr++);
343
344                 uint32_t t1 = (t & 0x00ff0000) >> 16;
345                 uint32_t t2 = (t & 0x000000ff) << 16;
346                 uint32_t t3 = (t & 0x0000ff00);
347                 uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : (t & 0xFF000000);
348
349                 *(dPtr++) = t1 | t2 | t3 | ta;
350             }
351         }
352         return;
353     }
354
355     // Fall-through case is to just use memcpy (assuming this is not an in-place operation)
356     if ( pDestination == pSource )
357         return;
358
359     size_t size = std::min<size_t>( outSize, inSize );
360     memcpy_s( pDestination, outSize, pSource, size );
361 }
362
363
364 //-------------------------------------------------------------------------------------
365 // Converts an image row with optional clearing of alpha value to 1.0
366 // Returns true if supported, false if expansion case not supported
367 //-------------------------------------------------------------------------------------
368 bool _ExpandScanline( LPVOID pDestination, size_t outSize, DXGI_FORMAT outFormat,  
369                       LPCVOID pSource, size_t inSize, DXGI_FORMAT inFormat, DWORD flags )
370 {
371     assert( pDestination && outSize > 0 );
372     assert( pSource && inSize > 0 );
373     assert( IsValid(outFormat) && !IsVideo(outFormat) );
374     assert( IsValid(inFormat) && !IsVideo(inFormat) );
375
376     switch( inFormat )
377     {
378     case DXGI_FORMAT_B5G6R5_UNORM:
379         if ( outFormat != DXGI_FORMAT_R8G8B8A8_UNORM )
380             return false;
381
382         // DXGI_FORMAT_B5G6R5_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM
383         {
384             const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
385             uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
386
387             for( size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4 )
388             {
389                 uint16_t t = *(sPtr++);
390
391                 uint32_t t1 = ((t & 0xf800) >> 8) | ((t & 0xe000) >> 13);
392                 uint32_t t2 = ((t & 0x07e0) << 5) | ((t & 0x0600) >> 5);
393                 uint32_t t3 = ((t & 0x001f) << 19) | ((t & 0x001c) << 14);
394
395                 *(dPtr++) = t1 | t2 | t3 | 0xff000000;
396             }
397         }
398         return true;
399         
400     case DXGI_FORMAT_B5G5R5A1_UNORM:
401         if ( outFormat != DXGI_FORMAT_R8G8B8A8_UNORM )
402             return false;
403
404         // DXGI_FORMAT_B5G5R5A1_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM
405         {
406             const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
407             uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
408
409             for( size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4 )
410             {
411                 uint16_t t = *(sPtr++);
412
413                 uint32_t t1 = ((t & 0x7c00) >> 7) | ((t & 0x7000) >> 12);
414                 uint32_t t2 = ((t & 0x03e0) << 6) | ((t & 0x0380) << 1);
415                 uint32_t t3 = ((t & 0x001f) << 19) | ((t & 0x001c) << 14);
416                 uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : ((t & 0x8000) ? 0xff000000 : 0);
417
418                 *(dPtr++) = t1 | t2 | t3 | ta;
419             }
420         }
421         return true;
422
423 #ifdef DXGI_1_2_FORMATS
424     case DXGI_FORMAT_B4G4R4A4_UNORM:
425         if ( outFormat != DXGI_FORMAT_R8G8B8A8_UNORM )
426             return false;
427
428         // DXGI_FORMAT_B4G4R4A4_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM
429         {
430             const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
431             uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
432
433             for( size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4 )
434             {
435                 uint16_t t = *(sPtr++);
436
437                 uint32_t t1 = ((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8);
438                 uint32_t t2 = ((t & 0x00f0) << 8) | ((t & 0x00f0) << 4);
439                 uint32_t t3 = ((t & 0x000f) << 20) | ((t & 0x000f) << 16);
440                 uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : (((t & 0xf000) << 16) | ((t & 0xf000) << 12));
441
442                 *(dPtr++) = t1 | t2 | t3 | ta;
443             }
444         }
445         return true;
446 #endif // DXGI_1_2_FORMATS
447     }
448
449     return false;
450 }
451
452
453 //-------------------------------------------------------------------------------------
454 // Loads an image row into standard RGBA XMVECTOR (aligned) array
455 //-------------------------------------------------------------------------------------
456 #define LOAD_SCANLINE( type, func )\
457         if ( size >= sizeof(type) )\
458         {\
459             const type * __restrict sPtr = reinterpret_cast<const type*>(pSource);\
460             for( size_t icount = 0; icount < size; icount += sizeof(type) )\
461             {\
462                 if ( dPtr >= ePtr ) break;\
463                 *(dPtr++) = func( sPtr++ );\
464             }\
465             return true;\
466         }\
467         return false;
468
469 #define LOAD_SCANLINE3( type, func, defvec )\
470         if ( size >= sizeof(type) )\
471         {\
472             const type * __restrict sPtr = reinterpret_cast<const type*>(pSource);\
473             for( size_t icount = 0; icount < size; icount += sizeof(type) )\
474             {\
475                 XMVECTOR v = func( sPtr++ );\
476                 if ( dPtr >= ePtr ) break;\
477                 *(dPtr++) = XMVectorSelect( defvec, v, g_XMSelect1110 );\
478             }\
479             return true;\
480         }\
481         return false;
482
483 #define LOAD_SCANLINE2( type, func, defvec )\
484         if ( size >= sizeof(type) )\
485         {\
486             const type * __restrict sPtr = reinterpret_cast<const type*>(pSource);\
487             for( size_t icount = 0; icount < size; icount += sizeof(type) )\
488             {\
489                 XMVECTOR v = func( sPtr++ );\
490                 if ( dPtr >= ePtr ) break;\
491                 *(dPtr++) = XMVectorSelect( defvec, v, g_XMSelect1100 );\
492             }\
493             return true;\
494         }\
495         return false;
496
497 bool _LoadScanline( XMVECTOR* pDestination, size_t count,
498                     LPCVOID pSource, size_t size, DXGI_FORMAT format )
499 {
500     assert( pDestination && count > 0 && (((uintptr_t)pDestination & 0xF) == 0) );
501     assert( pSource && size > 0 );
502     assert( IsValid(format) && !IsVideo(format) && !IsTypeless(format) && !IsCompressed(format) );
503
504     XMVECTOR* __restrict dPtr = pDestination;
505     if ( !dPtr )
506         return false;
507
508     const XMVECTOR* ePtr = pDestination + count;
509
510     switch( format )
511     {
512     case DXGI_FORMAT_R32G32B32A32_FLOAT:
513         {
514             size_t msize = (size > (sizeof(XMVECTOR)*count)) ? (sizeof(XMVECTOR)*count) : size;
515             memcpy_s( dPtr, sizeof(XMVECTOR)*count, pSource, msize );
516         }
517         return true;
518
519     case DXGI_FORMAT_R32G32B32A32_UINT:
520         LOAD_SCANLINE( XMUINT4, XMLoadUInt4 )
521
522     case DXGI_FORMAT_R32G32B32A32_SINT:
523         LOAD_SCANLINE( XMINT4, XMLoadSInt4 )
524
525     case DXGI_FORMAT_R32G32B32_FLOAT:
526         LOAD_SCANLINE3( XMFLOAT3, XMLoadFloat3, g_XMIdentityR3 )
527
528     case DXGI_FORMAT_R32G32B32_UINT:
529         LOAD_SCANLINE3( XMUINT3, XMLoadUInt3, g_XMIdentityR3 )
530
531     case DXGI_FORMAT_R32G32B32_SINT:
532         LOAD_SCANLINE3( XMINT3, XMLoadSInt3, g_XMIdentityR3 )
533
534     case DXGI_FORMAT_R16G16B16A16_FLOAT:
535         LOAD_SCANLINE( XMHALF4, XMLoadHalf4 )
536
537     case DXGI_FORMAT_R16G16B16A16_UNORM:
538         LOAD_SCANLINE( XMUSHORTN4, XMLoadUShortN4 ) 
539
540     case DXGI_FORMAT_R16G16B16A16_UINT:
541         LOAD_SCANLINE( XMUSHORT4, XMLoadUShort4 )
542
543     case DXGI_FORMAT_R16G16B16A16_SNORM:
544         LOAD_SCANLINE( XMSHORTN4, XMLoadShortN4 )
545
546     case DXGI_FORMAT_R16G16B16A16_SINT:
547         LOAD_SCANLINE( XMSHORT4, XMLoadShort4 )
548
549     case DXGI_FORMAT_R32G32_FLOAT:
550         LOAD_SCANLINE2( XMFLOAT2, XMLoadFloat2, g_XMIdentityR3 )
551
552     case DXGI_FORMAT_R32G32_UINT:
553         LOAD_SCANLINE2( XMUINT2, XMLoadUInt2, g_XMIdentityR3 )
554
555     case DXGI_FORMAT_R32G32_SINT:
556         LOAD_SCANLINE2( XMINT2, XMLoadSInt2, g_XMIdentityR3 )
557
558     case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
559         if ( size >= (sizeof(float)+sizeof(uint32_t)) )
560         {
561             const float * sPtr = reinterpret_cast<const float*>(pSource);
562             for( size_t icount = 0; icount < size; icount += (sizeof(float)+sizeof(uint32_t)) )
563             {
564                 const uint8_t* ps8 = reinterpret_cast<const uint8_t*>( &sPtr[1] );
565                 if ( dPtr >= ePtr ) break;
566                 *(dPtr++) = XMVectorSet( sPtr[0], static_cast<float>( *ps8 ), 0.f, 1.f );
567                 sPtr += 2;
568             }
569             return true;
570         }
571         return false;
572
573     case DXGI_FORMAT_R10G10B10A2_UNORM:
574     case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
575         LOAD_SCANLINE( XMUDECN4, XMLoadUDecN4 );
576
577     case DXGI_FORMAT_R10G10B10A2_UINT:
578         LOAD_SCANLINE( XMUDEC4, XMLoadUDec4 );
579
580     case DXGI_FORMAT_R11G11B10_FLOAT:
581         LOAD_SCANLINE3( XMFLOAT3PK, XMLoadFloat3PK, g_XMIdentityR3 );
582
583     case DXGI_FORMAT_R8G8B8A8_UNORM:
584     case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
585         LOAD_SCANLINE( XMUBYTEN4, XMLoadUByteN4 )
586
587     case DXGI_FORMAT_R8G8B8A8_UINT:
588         LOAD_SCANLINE( XMUBYTE4, XMLoadUByte4 )
589
590     case DXGI_FORMAT_R8G8B8A8_SNORM:
591         LOAD_SCANLINE( XMBYTEN4, XMLoadByteN4 )
592
593     case DXGI_FORMAT_R8G8B8A8_SINT:
594         LOAD_SCANLINE( XMBYTE4, XMLoadByte4 )
595
596     case DXGI_FORMAT_R16G16_FLOAT:
597         LOAD_SCANLINE2( XMHALF2, XMLoadHalf2, g_XMIdentityR3 )
598
599     case DXGI_FORMAT_R16G16_UNORM:
600         LOAD_SCANLINE2( XMUSHORTN2, XMLoadUShortN2, g_XMIdentityR3 )
601
602     case DXGI_FORMAT_R16G16_UINT:
603         LOAD_SCANLINE2( XMUSHORT2, XMLoadUShort2, g_XMIdentityR3 )
604
605     case DXGI_FORMAT_R16G16_SNORM:
606         LOAD_SCANLINE2( XMSHORTN2, XMLoadShortN2, g_XMIdentityR3 )
607
608     case DXGI_FORMAT_R16G16_SINT:
609         LOAD_SCANLINE2( XMSHORT2, XMLoadShort2, g_XMIdentityR3 )
610
611     case DXGI_FORMAT_D32_FLOAT:
612     case DXGI_FORMAT_R32_FLOAT:
613         if ( size >= sizeof(float) )
614         {
615             const float* __restrict sPtr = reinterpret_cast<const float*>(pSource);
616             for( size_t icount = 0; icount < size; icount += sizeof(float) )
617             {
618                 XMVECTOR v = XMLoadFloat( sPtr++ );
619                 if ( dPtr >= ePtr ) break;
620                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1000 );
621             }
622             return true;
623         }
624         return false;
625
626     case DXGI_FORMAT_R32_UINT:
627         if ( size >= sizeof(uint32_t) )
628         {
629             const uint32_t* __restrict sPtr = reinterpret_cast<const uint32_t*>(pSource);
630             for( size_t icount = 0; icount < size; icount += sizeof(uint32_t) )
631             {
632                 XMVECTOR v = XMLoadInt( sPtr++ );
633                 v = XMConvertVectorUIntToFloat( v, 0 );
634                 if ( dPtr >= ePtr ) break;
635                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1000 );
636             }
637             return true;
638         }
639         return false;
640
641     case DXGI_FORMAT_R32_SINT:
642         if ( size >= sizeof(int32_t) )
643         {
644             const int32_t * __restrict sPtr = reinterpret_cast<const int32_t*>(pSource);
645             for( size_t icount = 0; icount < size; icount += sizeof(int32_t) )
646             {
647                 XMVECTOR v = XMLoadInt( reinterpret_cast<const uint32_t*> (sPtr++) );
648                 v = XMConvertVectorIntToFloat( v, 0 );
649                 if ( dPtr >= ePtr ) break;
650                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1000 );
651             }
652             return true;
653         }
654         return false;
655
656     case DXGI_FORMAT_D24_UNORM_S8_UINT:
657         if ( size >= sizeof(uint32_t) )
658         {
659             const uint32_t * sPtr = reinterpret_cast<const uint32_t*>(pSource);
660             for( size_t icount = 0; icount < size; icount += sizeof(uint32_t) )
661             {
662                 float d = static_cast<float>( *sPtr & 0xFFFFFF ) / 16777215.f;
663                 float s = static_cast<float>( ( *sPtr & 0xFF000000 ) >> 24 );
664                 ++sPtr;
665                 if ( dPtr >= ePtr ) break;
666                 *(dPtr++) = XMVectorSet( d, s, 0.f, 1.f );
667             }
668             return true;
669         }
670         return false;
671
672     case DXGI_FORMAT_R8G8_UNORM:
673         LOAD_SCANLINE2( XMUBYTEN2, XMLoadUByteN2, g_XMIdentityR3 )
674
675     case DXGI_FORMAT_R8G8_UINT:
676         LOAD_SCANLINE2( XMUBYTE2, XMLoadUByte2, g_XMIdentityR3 )
677
678     case DXGI_FORMAT_R8G8_SNORM:
679         LOAD_SCANLINE2( XMBYTEN2, XMLoadByteN2, g_XMIdentityR3 )
680
681     case DXGI_FORMAT_R8G8_SINT:
682         LOAD_SCANLINE2( XMBYTE2, XMLoadByte2, g_XMIdentityR3 )
683
684     case DXGI_FORMAT_R16_FLOAT:
685         if ( size >= sizeof(HALF) )
686         {
687             const HALF * __restrict sPtr = reinterpret_cast<const HALF*>(pSource);
688             for( size_t icount = 0; icount < size; icount += sizeof(HALF) )
689             {
690                 if ( dPtr >= ePtr ) break;
691                 *(dPtr++) = XMVectorSet( XMConvertHalfToFloat(*sPtr++), 0.f, 0.f, 1.f );
692             }
693             return true;
694         }
695         return false;
696
697     case DXGI_FORMAT_D16_UNORM:
698     case DXGI_FORMAT_R16_UNORM:
699         if ( size >= sizeof(uint16_t) )
700         {
701             const uint16_t* __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
702             for( size_t icount = 0; icount < size; icount += sizeof(uint16_t) )
703             {
704                 if ( dPtr >= ePtr ) break;
705                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++) / 65535.f, 0.f, 0.f, 1.f );
706             }
707             return true;
708         }
709         return false;
710
711     case DXGI_FORMAT_R16_UINT:
712         if ( size >= sizeof(uint16_t) )
713         {
714             const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
715             for( size_t icount = 0; icount < size; icount += sizeof(uint16_t) )
716             {
717                 if ( dPtr >= ePtr ) break;
718                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++), 0.f, 0.f, 1.f );
719             }
720             return true;
721         }
722         return false;
723
724     case DXGI_FORMAT_R16_SNORM:
725         if ( size >= sizeof(int16_t) )
726         {
727             const int16_t * __restrict sPtr = reinterpret_cast<const int16_t*>(pSource);
728             for( size_t icount = 0; icount < size; icount += sizeof(int16_t) )
729             {
730                 if ( dPtr >= ePtr ) break;
731                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++) / 32767.f, 0.f, 0.f, 1.f );
732             }
733             return true;
734         }
735         return false;
736
737     case DXGI_FORMAT_R16_SINT:
738         if ( size >= sizeof(int16_t) )
739         {
740             const int16_t * __restrict sPtr = reinterpret_cast<const int16_t*>(pSource);
741             for( size_t icount = 0; icount < size; icount += sizeof(int16_t) )
742             {
743                 if ( dPtr >= ePtr ) break;
744                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++), 0.f, 0.f, 1.f );
745             }
746             return true;
747         }
748         return false;
749
750     case DXGI_FORMAT_R8_UNORM:
751         if ( size >= sizeof(uint8_t) )
752         {
753             const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
754             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
755             {
756                 if ( dPtr >= ePtr ) break;
757                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++) / 255.f, 0.f, 0.f, 1.f );
758             }
759             return true;
760         }
761         return false;
762
763     case DXGI_FORMAT_R8_UINT:
764         if ( size >= sizeof(uint8_t) )
765         {
766             const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
767             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
768             {
769                 if ( dPtr >= ePtr ) break;
770                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++), 0.f, 0.f, 1.f );
771             }
772             return true;
773         }
774         return false;
775
776     case DXGI_FORMAT_R8_SNORM:
777         if ( size >= sizeof(char) )
778         {
779             const char * __restrict sPtr = reinterpret_cast<const char*>(pSource);
780             for( size_t icount = 0; icount < size; icount += sizeof(char) )
781             {
782                 if ( dPtr >= ePtr ) break;
783                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++) / 127.f, 0.f, 0.f, 1.f );
784             }
785             return true;
786         }
787         return false;
788
789     case DXGI_FORMAT_R8_SINT:
790         if ( size >= sizeof(char) )
791         {
792             const char * __restrict sPtr = reinterpret_cast<const char*>(pSource);
793             for( size_t icount = 0; icount < size; icount += sizeof(char) )
794             {
795                 if ( dPtr >= ePtr ) break;
796                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++), 0.f, 0.f, 1.f );
797             }
798             return true;
799         }
800         return false;
801
802     case DXGI_FORMAT_A8_UNORM:
803         if ( size >= sizeof(uint8_t) )
804         {
805             const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
806             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
807             {
808                 if ( dPtr >= ePtr ) break;
809                 *(dPtr++) = XMVectorSet( 0.f, 0.f, 0.f, static_cast<float>(*sPtr++) / 255.f );
810             }
811             return true;
812         }
813         return false;
814
815     case DXGI_FORMAT_R1_UNORM:
816         if ( size >= sizeof(uint8_t) )
817         {
818             const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
819             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
820             {
821                 for( size_t bcount = 0; bcount < 8; ++bcount )
822                 {
823                     if ( dPtr >= ePtr ) break;
824                     *(dPtr++) = XMVectorSet( (((*sPtr >> bcount) & 0x1) ? 1.f : 0.f), 0.f, 0.f, 1.f );
825                 }
826                 
827                 ++sPtr;
828             }
829             return true;
830         }
831         return false;
832
833     case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
834         LOAD_SCANLINE3( XMFLOAT3SE, XMLoadFloat3SE, g_XMIdentityR3 )
835
836     case DXGI_FORMAT_R8G8_B8G8_UNORM:
837         if ( size >= sizeof(XMUBYTEN4) )
838         {
839             const XMUBYTEN4 * __restrict sPtr = reinterpret_cast<const XMUBYTEN4*>(pSource);
840             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
841             {
842                 XMVECTOR v = XMLoadUByteN4( sPtr++ );
843                 XMVECTOR v1 = XMVectorSwizzle<0, 3, 2, 1>( v );
844                 if ( dPtr >= ePtr ) break;
845                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1110 );
846                 if ( dPtr >= ePtr ) break;
847                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v1, g_XMSelect1110 );
848             }
849             return true;
850         }
851         return false;
852
853     case DXGI_FORMAT_G8R8_G8B8_UNORM:
854         if ( size >= sizeof(XMUBYTEN4) )
855         {
856             const XMUBYTEN4 * __restrict sPtr = reinterpret_cast<const XMUBYTEN4*>(pSource);
857             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
858             {
859                 XMVECTOR v = XMLoadUByteN4( sPtr++ );
860                 XMVECTOR v0 = XMVectorSwizzle<1, 0, 3, 2>( v );
861                 XMVECTOR v1 = XMVectorSwizzle<1, 2, 3, 0>( v );
862                 if ( dPtr >= ePtr ) break;
863                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v0, g_XMSelect1110 );
864                 if ( dPtr >= ePtr ) break;
865                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v1, g_XMSelect1110 );
866             }
867             return true;
868         }
869         return false;
870
871     case DXGI_FORMAT_B5G6R5_UNORM:
872         if ( size >= sizeof(XMU565) )
873         {
874             static XMVECTORF32 s_Scale = { 1.f/31.f, 1.f/63.f, 1.f/31.f, 1.f };
875             const XMU565 * __restrict sPtr = reinterpret_cast<const XMU565*>(pSource);
876             for( size_t icount = 0; icount < size; icount += sizeof(XMU565) )
877             {
878                 XMVECTOR v = XMLoadU565( sPtr++ );
879                 v = XMVectorMultiply( v, s_Scale );
880                 v = XMVectorSwizzle<2, 1, 0, 3>( v );
881                 if ( dPtr >= ePtr ) break;
882                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1110 );
883             }
884             return true;
885         }
886         return false;
887
888     case DXGI_FORMAT_B5G5R5A1_UNORM:
889         if ( size >= sizeof(XMU555) )
890         {
891             static XMVECTORF32 s_Scale = { 1.f/31.f, 1.f/31.f, 1.f/31.f, 1.f };
892             const XMU555 * __restrict sPtr = reinterpret_cast<const XMU555*>(pSource);
893             for( size_t icount = 0; icount < size; icount += sizeof(XMU555) )
894             {
895                 XMVECTOR v = XMLoadU555( sPtr++ );
896                 v = XMVectorMultiply( v, s_Scale );
897                 if ( dPtr >= ePtr ) break;
898                 *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>( v );
899             }
900             return true;
901         }
902         return false;
903
904     case DXGI_FORMAT_B8G8R8A8_UNORM:
905     case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
906         if ( size >= sizeof(XMUBYTEN4) )
907         {
908             const XMUBYTEN4 * __restrict sPtr = reinterpret_cast<const XMUBYTEN4*>(pSource);
909             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
910             {
911                 XMVECTOR v = XMLoadUByteN4( sPtr++ );
912                 if ( dPtr >= ePtr ) break;
913                 *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>( v );
914             }
915             return true;
916         }
917         return false;
918
919     case DXGI_FORMAT_B8G8R8X8_UNORM:
920     case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
921         if ( size >= sizeof(XMUBYTEN4) )
922         {
923             const XMUBYTEN4 * __restrict sPtr = reinterpret_cast<const XMUBYTEN4*>(pSource);
924             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
925             {
926                 XMVECTOR v = XMLoadUByteN4( sPtr++ );
927                 v = XMVectorSwizzle<2, 1, 0, 3>( v );
928                 if ( dPtr >= ePtr ) break;
929                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1110 );
930             }
931             return true;
932         }
933         return false;
934
935 #ifdef DXGI_1_2_FORMATS
936     case DXGI_FORMAT_B4G4R4A4_UNORM:
937         if ( size >= sizeof(XMUNIBBLE4) )
938         {
939             static XMVECTORF32 s_Scale = { 1.f/15.f, 1.f/15.f, 1.f/15.f, 1.f/15.f };
940             const XMUNIBBLE4 * __restrict sPtr = reinterpret_cast<const XMUNIBBLE4*>(pSource);
941             for( size_t icount = 0; icount < size; icount += sizeof(XMUNIBBLE4) )
942             {
943                 XMVECTOR v = XMLoadUNibble4( sPtr++ );
944                 v = XMVectorMultiply( v, s_Scale );
945                 if ( dPtr >= ePtr ) break;
946                 *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>( v );
947             }
948             return true;
949         }
950         return false;
951
952     // we don't support the video formats ( see IsVideo function )
953 #endif // DXGI_1_2_FORMATS
954
955     default:
956         return false;
957     }
958 }
959
960
961 //-------------------------------------------------------------------------------------
962 // Stores an image row from standard RGBA XMVECTOR (aligned) array
963 //-------------------------------------------------------------------------------------
964 #define STORE_SCANLINE( type, func )\
965         if ( size >= sizeof(type) )\
966         {\
967             type * __restrict dPtr = reinterpret_cast<type*>(pDestination);\
968             for( size_t icount = 0; icount < size; icount += sizeof(type) )\
969             {\
970                 if ( sPtr >= ePtr ) break;\
971                 func( dPtr++, *sPtr++ );\
972             }\
973         }\
974         return true;
975
976 bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format,
977                      const XMVECTOR* pSource, size_t count )
978 {
979     assert( pDestination && size > 0 );
980     assert( pSource && count > 0 && (((uintptr_t)pSource & 0xF) == 0) );
981     assert( IsValid(format) && !IsVideo(format) && !IsTypeless(format) && !IsCompressed(format) );
982
983     const XMVECTOR* __restrict sPtr = pSource;
984     if ( !sPtr )
985         return false;
986
987     const XMVECTOR* ePtr = pSource + count;
988
989     switch( format )
990     {
991     case DXGI_FORMAT_R32G32B32A32_FLOAT:
992         STORE_SCANLINE( XMFLOAT4, XMStoreFloat4 )
993
994     case DXGI_FORMAT_R32G32B32A32_UINT:
995         STORE_SCANLINE( XMUINT4, XMStoreUInt4 )
996
997     case DXGI_FORMAT_R32G32B32A32_SINT:
998         STORE_SCANLINE( XMINT4, XMStoreSInt4 )
999
1000     case DXGI_FORMAT_R32G32B32_FLOAT:
1001         STORE_SCANLINE( XMFLOAT3, XMStoreFloat3 )
1002
1003     case DXGI_FORMAT_R32G32B32_UINT:
1004         STORE_SCANLINE( XMUINT3, XMStoreUInt3 )
1005
1006     case DXGI_FORMAT_R32G32B32_SINT:
1007         STORE_SCANLINE( XMINT3, XMStoreSInt3 )
1008
1009     case DXGI_FORMAT_R16G16B16A16_FLOAT:
1010         STORE_SCANLINE( XMHALF4, XMStoreHalf4 )
1011
1012     case DXGI_FORMAT_R16G16B16A16_UNORM:
1013         STORE_SCANLINE( XMUSHORTN4, XMStoreUShortN4 ) 
1014
1015     case DXGI_FORMAT_R16G16B16A16_UINT:
1016         STORE_SCANLINE( XMUSHORT4, XMStoreUShort4 )
1017
1018     case DXGI_FORMAT_R16G16B16A16_SNORM:
1019         STORE_SCANLINE( XMSHORTN4, XMStoreShortN4 )
1020
1021     case DXGI_FORMAT_R16G16B16A16_SINT:
1022         STORE_SCANLINE( XMSHORT4, XMStoreShort4 )
1023
1024     case DXGI_FORMAT_R32G32_FLOAT:
1025         STORE_SCANLINE( XMFLOAT2, XMStoreFloat2 )
1026
1027     case DXGI_FORMAT_R32G32_UINT:
1028         STORE_SCANLINE( XMUINT2, XMStoreUInt2 )
1029
1030     case DXGI_FORMAT_R32G32_SINT:
1031         STORE_SCANLINE( XMINT2, XMStoreSInt2 )
1032
1033     case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
1034         if ( size >= (sizeof(float)+sizeof(uint32_t)) )
1035         {
1036             float *dPtr = reinterpret_cast<float*>(pDestination);
1037             for( size_t icount = 0; icount < size; icount += (sizeof(float)+sizeof(uint32_t)) )
1038             {
1039                 if ( sPtr >= ePtr ) break;
1040                 XMFLOAT4 f;
1041                 XMStoreFloat4( &f, *sPtr++ );
1042                 dPtr[0] = f.x;
1043                 uint8_t* ps8 = reinterpret_cast<uint8_t*>( &dPtr[1] );
1044                 ps8[0] = static_cast<uint8_t>( std::min<float>( 255.f, std::max<float>( 0.f, f.y ) ) );
1045                 ps8[1] = ps8[2] = ps8[3] = 0;
1046                 dPtr += 2;
1047             }
1048         }
1049         return true;
1050
1051     case DXGI_FORMAT_R10G10B10A2_UNORM:
1052     case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
1053         STORE_SCANLINE( XMUDECN4, XMStoreUDecN4 );
1054
1055     case DXGI_FORMAT_R10G10B10A2_UINT:
1056         STORE_SCANLINE( XMUDEC4, XMStoreUDec4 );
1057
1058     case DXGI_FORMAT_R11G11B10_FLOAT:
1059         STORE_SCANLINE( XMFLOAT3PK, XMStoreFloat3PK );
1060
1061     case DXGI_FORMAT_R8G8B8A8_UNORM:
1062     case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
1063         STORE_SCANLINE( XMUBYTEN4, XMStoreUByteN4 )
1064
1065     case DXGI_FORMAT_R8G8B8A8_UINT:
1066         STORE_SCANLINE( XMUBYTE4, XMStoreUByte4 )
1067
1068     case DXGI_FORMAT_R8G8B8A8_SNORM:
1069         STORE_SCANLINE( XMBYTEN4, XMStoreByteN4 )
1070
1071     case DXGI_FORMAT_R8G8B8A8_SINT:
1072         STORE_SCANLINE( XMBYTE4, XMStoreByte4 )
1073
1074     case DXGI_FORMAT_R16G16_FLOAT:
1075         STORE_SCANLINE( XMHALF2, XMStoreHalf2 )
1076
1077     case DXGI_FORMAT_R16G16_UNORM:
1078         STORE_SCANLINE( XMUSHORTN2, XMStoreUShortN2 )
1079
1080     case DXGI_FORMAT_R16G16_UINT:
1081         STORE_SCANLINE( XMUSHORT2, XMStoreUShort2 )
1082
1083     case DXGI_FORMAT_R16G16_SNORM:
1084         STORE_SCANLINE( XMSHORTN2, XMStoreShortN2 )
1085
1086     case DXGI_FORMAT_R16G16_SINT:
1087         STORE_SCANLINE( XMSHORT2, XMStoreShort2 )
1088
1089     case DXGI_FORMAT_D32_FLOAT:
1090     case DXGI_FORMAT_R32_FLOAT:
1091         if ( size >= sizeof(float) )
1092         {
1093             float * __restrict dPtr = reinterpret_cast<float*>(pDestination);
1094             for( size_t icount = 0; icount < size; icount += sizeof(float) )
1095             {
1096                 if ( sPtr >= ePtr ) break;
1097                 XMStoreFloat( dPtr++, *(sPtr++) );
1098             }
1099         }
1100         return true;
1101
1102     case DXGI_FORMAT_R32_UINT:
1103         if ( size >= sizeof(uint32_t) )
1104         {
1105             uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
1106             for( size_t icount = 0; icount < size; icount += sizeof(uint32_t) )
1107             {
1108                 if ( sPtr >= ePtr ) break;
1109                 XMVECTOR v = XMConvertVectorFloatToUInt( *(sPtr++), 0 );
1110                 XMStoreInt( dPtr++, v );
1111             }
1112         }
1113         return true;
1114
1115     case DXGI_FORMAT_R32_SINT:
1116         if ( size >= sizeof(uint32_t) )
1117         {
1118             uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
1119             for( size_t icount = 0; icount < size; icount += sizeof(uint32_t) )
1120             {
1121                 if ( sPtr >= ePtr ) break;
1122                 XMVECTOR v = XMConvertVectorFloatToInt( *(sPtr++), 0 );
1123                 XMStoreInt( dPtr++, v );
1124             }
1125         }
1126         return true;
1127
1128     case DXGI_FORMAT_D24_UNORM_S8_UINT:
1129         if ( size >= sizeof(uint32_t) )
1130         {
1131             static const XMVECTORF32 clamp = { 1.f, 255.f, 0.f, 0.f };
1132             XMVECTOR zero = XMVectorZero();
1133             uint32_t *dPtr = reinterpret_cast<uint32_t*>(pDestination);
1134             for( size_t icount = 0; icount < size; icount += sizeof(uint32_t) )
1135             {
1136                 if ( sPtr >= ePtr ) break;
1137                 XMFLOAT4 f;
1138                 XMStoreFloat4( &f, XMVectorClamp( *sPtr++, zero, clamp ) );
1139                 *dPtr++ = (static_cast<uint32_t>( f.x * 16777215.f ) & 0xFFFFFF)
1140                           | ((static_cast<uint32_t>( f.y ) & 0xFF) << 24);
1141             }
1142         }
1143         return true;
1144
1145     case DXGI_FORMAT_R8G8_UNORM:
1146         STORE_SCANLINE( XMUBYTEN2, XMStoreUByteN2 )
1147
1148     case DXGI_FORMAT_R8G8_UINT:
1149         STORE_SCANLINE( XMUBYTE2, XMStoreUByte2 )
1150
1151     case DXGI_FORMAT_R8G8_SNORM:
1152         STORE_SCANLINE( XMBYTEN2, XMStoreByteN2 )
1153
1154     case DXGI_FORMAT_R8G8_SINT:
1155         STORE_SCANLINE( XMBYTE2, XMStoreByte2 )
1156
1157     case DXGI_FORMAT_R16_FLOAT:
1158         if ( size >= sizeof(HALF) )
1159         {
1160             HALF * __restrict dPtr = reinterpret_cast<HALF*>(pDestination);
1161             for( size_t icount = 0; icount < size; icount += sizeof(HALF) )
1162             {
1163                 if ( sPtr >= ePtr ) break;
1164                 float v = XMVectorGetX( *sPtr++ );
1165                 *(dPtr++) = XMConvertFloatToHalf(v);
1166             }
1167         }
1168         return true;
1169
1170     case DXGI_FORMAT_D16_UNORM:
1171     case DXGI_FORMAT_R16_UNORM:
1172         if ( size >= sizeof(int16_t) )
1173         {
1174             int16_t * __restrict dPtr = reinterpret_cast<int16_t*>(pDestination);
1175             for( size_t icount = 0; icount < size; icount += sizeof(int16_t) )
1176             {
1177                 if ( sPtr >= ePtr ) break;
1178                 float v = XMVectorGetX( *sPtr++ );
1179                 v = std::max<float>( std::min<float>( v, 1.f ), 0.f );
1180                 *(dPtr++) = static_cast<uint16_t>( v*65535.f + 0.5f );
1181             }
1182         }
1183         return true;
1184
1185     case DXGI_FORMAT_R16_UINT:
1186         if ( size >= sizeof(uint16_t) )
1187         {
1188             uint16_t * __restrict dPtr = reinterpret_cast<uint16_t*>(pDestination);
1189             for( size_t icount = 0; icount < size; icount += sizeof(uint16_t) )
1190             {
1191                 if ( sPtr >= ePtr ) break;
1192                 float v = XMVectorGetX( *sPtr++ );
1193                 v = std::max<float>( std::min<float>( v, 65535.f ), 0.f );
1194                 *(dPtr++) = static_cast<uint16_t>(v);
1195             }
1196         }
1197         return true;
1198
1199     case DXGI_FORMAT_R16_SNORM:
1200         if ( size >= sizeof(int16_t) )
1201         {
1202             int16_t * __restrict dPtr = reinterpret_cast<int16_t*>(pDestination);
1203             for( size_t icount = 0; icount < size; icount += sizeof(int16_t) )
1204             {
1205                 if ( sPtr >= ePtr ) break;
1206                 float v = XMVectorGetX( *sPtr++ );
1207                 v = std::max<float>( std::min<float>( v, 1.f ), -1.f );
1208                 *(dPtr++) = static_cast<uint16_t>( v * 32767.f );
1209             }
1210         }
1211         return true;
1212
1213     case DXGI_FORMAT_R16_SINT:
1214         if ( size >= sizeof(int16_t) )
1215         {
1216             int16_t * __restrict dPtr = reinterpret_cast<int16_t*>(pDestination);
1217             for( size_t icount = 0; icount < size; icount += sizeof(int16_t) )
1218             {
1219                 if ( sPtr >= ePtr ) break;
1220                 float v = XMVectorGetX( *sPtr++ );
1221                 v = std::max<float>( std::min<float>( v, 32767.f ), -32767.f );
1222                 *(dPtr++) = static_cast<int16_t>(v);
1223             }
1224         }
1225         return true;
1226
1227     case DXGI_FORMAT_R8_UNORM:
1228         if ( size >= sizeof(uint8_t) )
1229         {
1230             uint8_t * __restrict dPtr = reinterpret_cast<uint8_t*>(pDestination);
1231             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
1232             {
1233                 if ( sPtr >= ePtr ) break;
1234                 float v = XMVectorGetX( *sPtr++ );
1235                 v = std::max<float>( std::min<float>( v, 1.f ), 0.f );
1236                 *(dPtr++) = static_cast<uint8_t>( v * 255.f);
1237             }
1238         }
1239         return true;
1240
1241     case DXGI_FORMAT_R8_UINT:
1242         if ( size >= sizeof(uint8_t) )
1243         {
1244             uint8_t * __restrict dPtr = reinterpret_cast<uint8_t*>(pDestination);
1245             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
1246             {
1247                 if ( sPtr >= ePtr ) break;
1248                 float v = XMVectorGetX( *sPtr++ );
1249                 v = std::max<float>( std::min<float>( v, 255.f ), 0.f );
1250                 *(dPtr++) = static_cast<uint8_t>(v);
1251             }
1252         }
1253         return true;
1254
1255     case DXGI_FORMAT_R8_SNORM:
1256         if ( size >= sizeof(char) )
1257         {
1258             char * __restrict dPtr = reinterpret_cast<char*>(pDestination);
1259             for( size_t icount = 0; icount < size; icount += sizeof(char) )
1260             {
1261                 if ( sPtr >= ePtr ) break;
1262                 float v = XMVectorGetX( *sPtr++ );
1263                 v = std::max<float>( std::min<float>( v, 1.f ), -1.f );
1264                 *(dPtr++) = static_cast<char>( v * 127.f );
1265             }
1266         }
1267         return true;
1268
1269     case DXGI_FORMAT_R8_SINT:
1270         if ( size >= sizeof(char) )
1271         {
1272             char * __restrict dPtr = reinterpret_cast<char*>(pDestination);
1273             for( size_t icount = 0; icount < size; icount += sizeof(char) )
1274             {
1275                 if ( sPtr >= ePtr ) break;
1276                 float v = XMVectorGetX( *sPtr++ );
1277                 v = std::max<float>( std::min<float>( v, 127.f ), -127.f );
1278                 *(dPtr++) = static_cast<char>( v );
1279             }
1280         }
1281         return true;
1282
1283     case DXGI_FORMAT_A8_UNORM:
1284         if ( size >= sizeof(uint8_t) )
1285         {
1286             uint8_t * __restrict dPtr = reinterpret_cast<uint8_t*>(pDestination);
1287             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
1288             {
1289                 if ( sPtr >= ePtr ) break;
1290                 float v = XMVectorGetW( *sPtr++ );
1291                 v = std::max<float>( std::min<float>( v, 1.f ), 0.f );
1292                 *(dPtr++) = static_cast<uint8_t>( v * 255.f);
1293             }
1294         }
1295         return true;
1296
1297     case DXGI_FORMAT_R1_UNORM:
1298         if ( size >= sizeof(uint8_t) )
1299         {
1300             uint8_t * __restrict dPtr = reinterpret_cast<uint8_t*>(pDestination);
1301             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
1302             {
1303                 uint8_t pixels = 0;
1304                 for( size_t bcount = 0; bcount < 8; ++bcount )
1305                 {
1306                     if ( sPtr >= ePtr ) break;
1307                     float v = XMVectorGetX( *sPtr++ );
1308                     if ( v > 0.5f )
1309                         pixels |= 1 << bcount;
1310                 }
1311                 *(dPtr++) = pixels;
1312             }
1313         }
1314         return true;
1315
1316     case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
1317         STORE_SCANLINE( XMFLOAT3SE, XMStoreFloat3SE )
1318
1319     case DXGI_FORMAT_R8G8_B8G8_UNORM:
1320         if ( size >= sizeof(XMUBYTEN4) )
1321         {
1322             XMUBYTEN4 * __restrict dPtr = reinterpret_cast<XMUBYTEN4*>(pDestination);
1323             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
1324             {
1325                 if ( sPtr >= ePtr ) break;
1326                 XMVECTOR v0 = *sPtr++;
1327                 XMVECTOR v1 = (sPtr < ePtr) ? XMVectorSplatY( *sPtr++ ) : XMVectorZero();
1328                 XMVECTOR v = XMVectorSelect( v1, v0, g_XMSelect1110 );
1329                 XMStoreUByteN4( dPtr++, v );
1330             }
1331         }
1332         return true;
1333
1334     case DXGI_FORMAT_G8R8_G8B8_UNORM:
1335         if ( size >= sizeof(XMUBYTEN4) )
1336         {
1337             static XMVECTORI32 select1101 = {XM_SELECT_1, XM_SELECT_1, XM_SELECT_0, XM_SELECT_1};
1338
1339             XMUBYTEN4 * __restrict dPtr = reinterpret_cast<XMUBYTEN4*>(pDestination);
1340             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
1341             {
1342                 if ( sPtr >= ePtr ) break;
1343                 XMVECTOR v0 = XMVectorSwizzle<1, 0, 3, 2>( *sPtr++ );
1344                 XMVECTOR v1 = (sPtr < ePtr) ? XMVectorSplatY( *sPtr++ ) : XMVectorZero();
1345                 XMVECTOR v = XMVectorSelect( v1, v0, select1101 );
1346                 XMStoreUByteN4( dPtr++, v );
1347             }
1348         }
1349         return true;
1350
1351     case DXGI_FORMAT_B5G6R5_UNORM:
1352         if ( size >= sizeof(XMU565) )
1353         {
1354             static XMVECTORF32 s_Scale = { 31.f, 63.f, 31.f, 1.f };
1355             XMU565 * __restrict dPtr = reinterpret_cast<XMU565*>(pDestination);
1356             for( size_t icount = 0; icount < size; icount += sizeof(XMU565) )
1357             {
1358                 if ( sPtr >= ePtr ) break;
1359                 XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( *sPtr++ );
1360                 v = XMVectorMultiply( v, s_Scale );
1361                 XMStoreU565( dPtr++, v );
1362             }
1363         }
1364         return true;
1365
1366     case DXGI_FORMAT_B5G5R5A1_UNORM:
1367         if ( size >= sizeof(XMU555) )
1368         {
1369             static XMVECTORF32 s_Scale = { 31.f, 31.f, 31.f, 1.f };
1370             XMU555 * __restrict dPtr = reinterpret_cast<XMU555*>(pDestination);
1371             for( size_t icount = 0; icount < size; icount += sizeof(XMU555) )
1372             {
1373                 if ( sPtr >= ePtr ) break;
1374                 XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( *sPtr++ );
1375                 v = XMVectorMultiply( v, s_Scale );
1376                 XMStoreU555( dPtr++, v );
1377             }
1378         }
1379         return true;
1380
1381     case DXGI_FORMAT_B8G8R8A8_UNORM:
1382     case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
1383         if ( size >= sizeof(XMUBYTEN4) )
1384         {
1385             XMUBYTEN4 * __restrict dPtr = reinterpret_cast<XMUBYTEN4*>(pDestination);
1386             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
1387             {
1388                 if ( sPtr >= ePtr ) break;
1389                 XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( *sPtr++ );
1390                 XMStoreUByteN4( dPtr++, v );
1391             }
1392         }
1393         return true;
1394
1395     case DXGI_FORMAT_B8G8R8X8_UNORM:
1396     case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
1397         if ( size >= sizeof(XMUBYTEN4) )
1398         {
1399             XMUBYTEN4 * __restrict dPtr = reinterpret_cast<XMUBYTEN4*>(pDestination);
1400             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
1401             {
1402                 if ( sPtr >= ePtr ) break;
1403                 XMVECTOR v = XMVectorPermute<2, 1, 0, 7>( *sPtr++, g_XMIdentityR3 );
1404                 XMStoreUByteN4( dPtr++, v );
1405             }
1406         }
1407         return true;
1408
1409 #ifdef DXGI_1_2_FORMATS
1410     case DXGI_FORMAT_B4G4R4A4_UNORM:
1411         if ( size >= sizeof(XMUNIBBLE4) )
1412         {
1413             static XMVECTORF32 s_Scale = { 15.f, 15.f, 15.f, 15.f };
1414             XMUNIBBLE4 * __restrict dPtr = reinterpret_cast<XMUNIBBLE4*>(pDestination);
1415             for( size_t icount = 0; icount < size; icount += sizeof(XMUNIBBLE4) )
1416             {
1417                 if ( sPtr >= ePtr ) break;
1418                 XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( *sPtr++ );
1419                 v = XMVectorMultiply( v, s_Scale );
1420                 XMStoreUNibble4( dPtr++, v );
1421             }
1422         }
1423         return true;
1424
1425     // We don't support the video formats ( see IsVideo function )
1426 #endif // DXGI_1_2_FORMATS
1427
1428     default:
1429         return false;
1430     }
1431 }
1432
1433
1434 //-------------------------------------------------------------------------------------
1435 // Convert DXGI image to/from GUID_WICPixelFormat128bppRGBAFloat (no range conversions)
1436 //-------------------------------------------------------------------------------------
1437 HRESULT _ConvertToR32G32B32A32( const Image& srcImage, ScratchImage& image )
1438 {
1439     if ( !srcImage.pixels )
1440         return E_POINTER;
1441
1442     HRESULT hr = image.Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1 );
1443     if ( FAILED(hr) )
1444         return hr;
1445
1446     const Image *img = image.GetImage( 0, 0, 0 );
1447     if ( !img )
1448     {
1449         image.Release();
1450         return E_POINTER;
1451     }
1452
1453     uint8_t* pDest = img->pixels;
1454     if ( !pDest )
1455     {
1456         image.Release();
1457         return E_POINTER;
1458     }
1459
1460     const uint8_t *pSrc = srcImage.pixels;
1461     for( size_t h = 0; h < srcImage.height; ++h )
1462     {
1463         if ( !_LoadScanline( reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) )
1464         {
1465             image.Release();
1466             return E_FAIL;
1467         }
1468
1469         pSrc += srcImage.rowPitch;
1470         pDest += img->rowPitch;
1471     }
1472
1473     return S_OK;
1474 }
1475
1476 HRESULT _ConvertFromR32G32B32A32( _In_ const Image& srcImage, _In_ const Image& destImage )
1477 {
1478     assert( srcImage.format == DXGI_FORMAT_R32G32B32A32_FLOAT );
1479
1480     if ( !srcImage.pixels || !destImage.pixels )
1481         return E_POINTER;
1482
1483     if ( srcImage.width != destImage.width || srcImage.height != destImage.height )
1484         return E_FAIL;
1485
1486     const uint8_t *pSrc = srcImage.pixels;
1487     uint8_t* pDest = destImage.pixels;
1488
1489     for( size_t h = 0; h < srcImage.height; ++h )
1490     {
1491         if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, reinterpret_cast<const XMVECTOR*>(pSrc), srcImage.width ) )
1492             return E_FAIL;
1493
1494         pSrc += srcImage.rowPitch;
1495         pDest += destImage.rowPitch;
1496     }
1497
1498     return S_OK;
1499 }
1500
1501 HRESULT _ConvertFromR32G32B32A32( const Image& srcImage, DXGI_FORMAT format, ScratchImage& image )
1502 {
1503     if ( !srcImage.pixels )
1504         return E_POINTER;
1505
1506     HRESULT hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 );
1507     if ( FAILED(hr) )
1508         return hr;
1509
1510     const Image *img = image.GetImage( 0, 0, 0 );
1511     if ( !img )
1512     {
1513         image.Release();
1514         return E_POINTER;
1515     }
1516
1517     hr = _ConvertFromR32G32B32A32( srcImage, *img );
1518     if ( FAILED(hr) )
1519     {
1520         image.Release();
1521         return hr;
1522     }
1523
1524     return S_OK;
1525 }
1526
1527 HRESULT _ConvertFromR32G32B32A32( const Image* srcImages, size_t nimages, const TexMetadata& metadata, DXGI_FORMAT format, ScratchImage& result )
1528 {
1529     if ( !srcImages )
1530         return E_POINTER;
1531
1532     result.Release();
1533
1534     assert( metadata.format == DXGI_FORMAT_R32G32B32A32_FLOAT );
1535
1536     TexMetadata mdata2 = metadata;
1537     mdata2.format = format;
1538     HRESULT hr = result.Initialize( mdata2 );
1539     if ( FAILED(hr) )
1540         return hr;
1541
1542     if ( nimages != result.GetImageCount() )
1543     {
1544         result.Release();
1545         return E_FAIL;
1546     }
1547
1548     const Image* dest = result.GetImages();
1549     if ( !dest )
1550     {
1551         result.Release();
1552         return E_POINTER;
1553     }
1554
1555     for( size_t index=0; index < nimages; ++index )
1556     {
1557         const Image& src = srcImages[ index ];
1558         const Image& dst = dest[ index ];
1559
1560         assert( src.format == DXGI_FORMAT_R32G32B32A32_FLOAT );
1561         assert( dst.format == format );
1562
1563         if ( src.width != dst.width || src.height != dst.height )
1564         {
1565             result.Release();
1566             return E_FAIL;
1567         }
1568
1569         const uint8_t* pSrc = src.pixels;
1570         uint8_t* pDest = dst.pixels;
1571         if ( !pSrc || !pDest )
1572         {
1573             result.Release();
1574             return E_POINTER;
1575         }
1576
1577         for( size_t h=0; h < src.height; ++h )
1578         {
1579             if ( !_StoreScanline( pDest, dst.rowPitch, format, reinterpret_cast<const XMVECTOR*>(pSrc), src.width ) )
1580             {
1581                 result.Release();
1582                 return E_FAIL;
1583             }
1584
1585             pSrc += src.rowPitch;
1586             pDest += dst.rowPitch;
1587         }
1588     }
1589
1590     return S_OK;
1591 }
1592
1593
1594 //-------------------------------------------------------------------------------------
1595 // RGB -> sRGB
1596 //-------------------------------------------------------------------------------------
1597 static const uint32_t g_fEncodeGamma22[] =
1598 {
1599     0x00000000, 0x3bd56bd3, 0x3c486344, 0x3c90da15, 0x3cbc2677, 0x3ce67704, 0x3d080183, 0x3d1c7728,
1600     0x3d30a8fb, 0x3d44a03c, 0x3d586400, 0x3d6bf9e7, 0x3d7f6679, 0x3d8956bd, 0x3d92e906, 0x3d9c6b70,
1601     0x3da5df22, 0x3daf451b, 0x3db89e3e, 0x3dc1eb50, 0x3dcb2d04, 0x3dd463f7, 0x3ddd90b9, 0x3de6b3ca,
1602     0x3defcda0, 0x3df8dea6, 0x3e00f3a0, 0x3e0573e3, 0x3e09f046, 0x3e0e68f0, 0x3e12de06, 0x3e174fa6,
1603     0x3e1bbdf2, 0x3e202906, 0x3e2490fd, 0x3e28f5f1, 0x3e2d57fb, 0x3e31b72f, 0x3e3613a4, 0x3e3a6d6e,
1604     0x3e3ec4a0, 0x3e43194d, 0x3e476b84, 0x3e4bbb57, 0x3e5008d7, 0x3e54540f, 0x3e589d0f, 0x3e5ce3e5,
1605     0x3e61289d, 0x3e656b44, 0x3e69abe5, 0x3e6dea8d, 0x3e722745, 0x3e766217, 0x3e7a9b0e, 0x3e7ed235,
1606     0x3e8183c9, 0x3e839d98, 0x3e85b68c, 0x3e87cea8, 0x3e89e5f2, 0x3e8bfc6b, 0x3e8e1219, 0x3e9026ff,
1607     0x3e923b20, 0x3e944e7f, 0x3e966120, 0x3e987307, 0x3e9a8436, 0x3e9c94af, 0x3e9ea476, 0x3ea0b38e,
1608     0x3ea2c1fb, 0x3ea4cfbb, 0x3ea6dcd5, 0x3ea8e94a, 0x3eaaf51c, 0x3ead004e, 0x3eaf0ae2, 0x3eb114d9,
1609     0x3eb31e37, 0x3eb526fe, 0x3eb72f2f, 0x3eb936cd, 0x3ebb3dd8, 0x3ebd4454, 0x3ebf4a43, 0x3ec14fa5,
1610     0x3ec3547e, 0x3ec558cd, 0x3ec75c95, 0x3ec95fd8, 0x3ecb6297, 0x3ecd64d4, 0x3ecf6690, 0x3ed167ce,
1611     0x3ed3688e, 0x3ed568d1, 0x3ed76899, 0x3ed967e9, 0x3edb66bf, 0x3edd651f, 0x3edf630a, 0x3ee16080,
1612     0x3ee35d84, 0x3ee55a16, 0x3ee75636, 0x3ee951e8, 0x3eeb4d2a, 0x3eed4800, 0x3eef4269, 0x3ef13c68,
1613     0x3ef335fc, 0x3ef52f26, 0x3ef727ea, 0x3ef92046, 0x3efb183c, 0x3efd0fcd, 0x3eff06fa, 0x3f007ee2,
1614     0x3f017a16, 0x3f027519, 0x3f036fec, 0x3f046a8f, 0x3f056502, 0x3f065f47, 0x3f07595d, 0x3f085344,
1615     0x3f094cfe, 0x3f0a468b, 0x3f0b3feb, 0x3f0c391e, 0x3f0d3224, 0x3f0e2aff, 0x3f0f23af, 0x3f101c32,
1616     0x3f11148c, 0x3f120cba, 0x3f1304bf, 0x3f13fc9a, 0x3f14f44b, 0x3f15ebd3, 0x3f16e333, 0x3f17da6b,
1617     0x3f18d17a, 0x3f19c860, 0x3f1abf1f, 0x3f1bb5b7, 0x3f1cac28, 0x3f1da272, 0x3f1e9895, 0x3f1f8e92,
1618     0x3f20846a, 0x3f217a1c, 0x3f226fa8, 0x3f23650f, 0x3f245a52, 0x3f254f70, 0x3f264469, 0x3f27393f,
1619     0x3f282df1, 0x3f29227f, 0x3f2a16ea, 0x3f2b0b31, 0x3f2bff56, 0x3f2cf358, 0x3f2de738, 0x3f2edaf6,
1620     0x3f2fce91, 0x3f30c20b, 0x3f31b564, 0x3f32a89b, 0x3f339bb1, 0x3f348ea6, 0x3f35817a, 0x3f36742f,
1621     0x3f3766c3, 0x3f385936, 0x3f394b8a, 0x3f3a3dbe, 0x3f3b2fd3, 0x3f3c21c8, 0x3f3d139e, 0x3f3e0556,
1622     0x3f3ef6ee, 0x3f3fe868, 0x3f40d9c4, 0x3f41cb01, 0x3f42bc20, 0x3f43ad22, 0x3f449e06, 0x3f458ecc,
1623     0x3f467f75, 0x3f477001, 0x3f486071, 0x3f4950c2, 0x3f4a40f8, 0x3f4b3111, 0x3f4c210d, 0x3f4d10ed,
1624     0x3f4e00b2, 0x3f4ef05a, 0x3f4fdfe7, 0x3f50cf58, 0x3f51beae, 0x3f52ade8, 0x3f539d07, 0x3f548c0c,
1625     0x3f557af5, 0x3f5669c4, 0x3f575878, 0x3f584711, 0x3f593590, 0x3f5a23f6, 0x3f5b1241, 0x3f5c0072,
1626     0x3f5cee89, 0x3f5ddc87, 0x3f5eca6b, 0x3f5fb835, 0x3f60a5e7, 0x3f619380, 0x3f6280ff, 0x3f636e65,
1627     0x3f645bb3, 0x3f6548e8, 0x3f663604, 0x3f672309, 0x3f680ff4, 0x3f68fcc8, 0x3f69e983, 0x3f6ad627,
1628     0x3f6bc2b3, 0x3f6caf27, 0x3f6d9b83, 0x3f6e87c8, 0x3f6f73f5, 0x3f70600c, 0x3f714c0b, 0x3f7237f4,
1629     0x3f7323c4, 0x3f740f7f, 0x3f74fb22, 0x3f75e6af, 0x3f76d225, 0x3f77bd85, 0x3f78a8ce, 0x3f799401,
1630     0x3f7a7f1e, 0x3f7b6a25, 0x3f7c5516, 0x3f7d3ff1, 0x3f7e2ab6, 0x3f7f1566, 0x3f800000, 0x3f800000
1631 };
1632
1633 #pragma prefast(suppress : 25000, "FXMVECTOR is 16 bytes")
1634 static inline XMVECTOR _TableEncodeGamma22( FXMVECTOR v )
1635 {
1636     float f[4];
1637     XMStoreFloat4( (XMFLOAT4*)f, v );
1638
1639     for( size_t i=0; i < 4; ++i )
1640     {
1641         float f2 = sqrtf(f[i]) * 254.0f;
1642
1643         uint32_t  i2 = static_cast<uint32_t>(f2);
1644         i2 = std::min<uint32_t>( i2, _countof( g_fEncodeGamma22 )-2 );
1645
1646         float fS = f2 - (float) i2;
1647         float fA = ((float *) g_fEncodeGamma22)[i2];
1648         float fB = ((float *) g_fEncodeGamma22)[i2 + 1];
1649
1650         f[i] = fA + fS * (fB - fA);
1651     }
1652
1653     return XMLoadFloat4( (XMFLOAT4*)f );
1654 }
1655
1656
1657 //-------------------------------------------------------------------------------------
1658 // sRGB -> RGB
1659 //-------------------------------------------------------------------------------------
1660 static const uint32_t g_fDecodeGamma22[] =
1661 {
1662     0x00000000, 0x3b144eb0, 0x3b9ef3b0, 0x3bf84b42, 0x3c2a5c46, 0x3c59c180, 0x3c850eb5, 0x3c9da52a,
1663     0x3cb6967a, 0x3ccfd852, 0x3ce9628b, 0x3d01974b, 0x3d0e9b82, 0x3d1bbba3, 0x3d28f5bc, 0x3d364822,
1664     0x3d43b159, 0x3d51301d, 0x3d5ec344, 0x3d6c69c9, 0x3d7a22c4, 0x3d83f6ad, 0x3d8ae465, 0x3d91da35,
1665     0x3d98d7c7, 0x3d9fdcd2, 0x3da6e914, 0x3dadfc47, 0x3db51635, 0x3dbc36a3, 0x3dc35d62, 0x3dca8a3a,
1666     0x3dd1bd02, 0x3dd8f591, 0x3de033bb, 0x3de7775d, 0x3deec050, 0x3df60e74, 0x3dfd61a6, 0x3e025ce5,
1667     0x3e060b61, 0x3e09bc38, 0x3e0d6f5f, 0x3e1124c8, 0x3e14dc68, 0x3e189630, 0x3e1c521a, 0x3e201016,
1668     0x3e23d01d, 0x3e279225, 0x3e2b5624, 0x3e2f1c10, 0x3e32e3e4, 0x3e36ad94, 0x3e3a7918, 0x3e3e4668,
1669     0x3e42157f, 0x3e45e654, 0x3e49b8e0, 0x3e4d8d1d, 0x3e516304, 0x3e553a8d, 0x3e5913b4, 0x3e5cee70,
1670     0x3e60cabf, 0x3e64a89b, 0x3e6887fb, 0x3e6c68db, 0x3e704b3a, 0x3e742f0e, 0x3e781454, 0x3e7bfb04,
1671     0x3e7fe321, 0x3e81e650, 0x3e83dbc0, 0x3e85d1dc, 0x3e87c8a3, 0x3e89c015, 0x3e8bb830, 0x3e8db0ee,
1672     0x3e8faa51, 0x3e91a454, 0x3e939ef9, 0x3e959a3b, 0x3e97961b, 0x3e999295, 0x3e9b8fa7, 0x3e9d8d52,
1673     0x3e9f8b93, 0x3ea18a6a, 0x3ea389d2, 0x3ea589cb, 0x3ea78a56, 0x3ea98b6e, 0x3eab8d15, 0x3ead8f47,
1674     0x3eaf9204, 0x3eb1954a, 0x3eb39917, 0x3eb59d6c, 0x3eb7a246, 0x3eb9a7a5, 0x3ebbad88, 0x3ebdb3ec,
1675     0x3ebfbad3, 0x3ec1c237, 0x3ec3ca1a, 0x3ec5d27c, 0x3ec7db58, 0x3ec9e4b4, 0x3ecbee85, 0x3ecdf8d3,
1676     0x3ed0039a, 0x3ed20ed8, 0x3ed41a8a, 0x3ed626b5, 0x3ed83351, 0x3eda4065, 0x3edc4de9, 0x3ede5be0,
1677     0x3ee06a4a, 0x3ee27923, 0x3ee4886a, 0x3ee69821, 0x3ee8a845, 0x3eeab8d8, 0x3eecc9d6, 0x3eeedb3f,
1678     0x3ef0ed13, 0x3ef2ff53, 0x3ef511fb, 0x3ef7250a, 0x3ef93883, 0x3efb4c61, 0x3efd60a7, 0x3eff7553,
1679     0x3f00c531, 0x3f01cfeb, 0x3f02dad9, 0x3f03e5f5, 0x3f04f145, 0x3f05fcc4, 0x3f070875, 0x3f081456,
1680     0x3f092067, 0x3f0a2ca8, 0x3f0b3917, 0x3f0c45b7, 0x3f0d5284, 0x3f0e5f7f, 0x3f0f6caa, 0x3f107a03,
1681     0x3f118789, 0x3f12953b, 0x3f13a31d, 0x3f14b12b, 0x3f15bf64, 0x3f16cdca, 0x3f17dc5e, 0x3f18eb1b,
1682     0x3f19fa05, 0x3f1b091b, 0x3f1c185c, 0x3f1d27c7, 0x3f1e375c, 0x3f1f471d, 0x3f205707, 0x3f21671b,
1683     0x3f227759, 0x3f2387c2, 0x3f249852, 0x3f25a90c, 0x3f26b9ef, 0x3f27cafb, 0x3f28dc30, 0x3f29ed8b,
1684     0x3f2aff11, 0x3f2c10bd, 0x3f2d2290, 0x3f2e348b, 0x3f2f46ad, 0x3f3058f7, 0x3f316b66, 0x3f327dfd,
1685     0x3f3390ba, 0x3f34a39d, 0x3f35b6a7, 0x3f36c9d6, 0x3f37dd2b, 0x3f38f0a5, 0x3f3a0443, 0x3f3b1808,
1686     0x3f3c2bf2, 0x3f3d4000, 0x3f3e5434, 0x3f3f688c, 0x3f407d07, 0x3f4191a8, 0x3f42a66c, 0x3f43bb54,
1687     0x3f44d05f, 0x3f45e58e, 0x3f46fadf, 0x3f481054, 0x3f4925ed, 0x3f4a3ba8, 0x3f4b5186, 0x3f4c6789,
1688     0x3f4d7daa, 0x3f4e93f0, 0x3f4faa57, 0x3f50c0e0, 0x3f51d78b, 0x3f52ee58, 0x3f540545, 0x3f551c55,
1689     0x3f563386, 0x3f574ad7, 0x3f58624b, 0x3f5979de, 0x3f5a9191, 0x3f5ba965, 0x3f5cc15b, 0x3f5dd971,
1690     0x3f5ef1a6, 0x3f6009fc, 0x3f612272, 0x3f623b08, 0x3f6353bc, 0x3f646c90, 0x3f658586, 0x3f669e98,
1691     0x3f67b7cb, 0x3f68d11b, 0x3f69ea8d, 0x3f6b041b, 0x3f6c1dc9, 0x3f6d3795, 0x3f6e5180, 0x3f6f6b8b,
1692     0x3f7085b2, 0x3f719ff7, 0x3f72ba5b, 0x3f73d4dc, 0x3f74ef7c, 0x3f760a38, 0x3f772512, 0x3f78400b,
1693     0x3f795b20, 0x3f7a7651, 0x3f7b91a2, 0x3f7cad0e, 0x3f7dc896, 0x3f7ee43c, 0x3f800000, 0x3f800000
1694 };
1695
1696
1697 #pragma prefast(suppress : 25000, "FXMVECTOR is 16 bytes")
1698 static inline XMVECTOR _TableDecodeGamma22( FXMVECTOR v )
1699 {
1700     float f[4];
1701     XMStoreFloat4( (XMFLOAT4*)f, v );
1702
1703     for( size_t i=0; i < 4; ++i )
1704     {
1705         float f2 = f[i] * f[i] * 254.0f;
1706         uint32_t  i2 = static_cast<uint32_t>(f2);
1707         i2 = std::min<uint32_t>( i2, _countof(g_fDecodeGamma22)-2 );
1708
1709         float fS = f2 - (float) i2;
1710         float fA = ((float *) g_fDecodeGamma22)[i2];
1711         float fB = ((float *) g_fDecodeGamma22)[i2 + 1];
1712
1713         f[i] = fA + fS * (fB - fA);
1714     }
1715
1716     return XMLoadFloat4( (XMFLOAT4*)f );
1717 }
1718
1719
1720 //-------------------------------------------------------------------------------------
1721 // Convert scanline based on source/target formats
1722 //-------------------------------------------------------------------------------------
1723 struct ConvertData
1724 {
1725     DXGI_FORMAT format;
1726     size_t datasize;
1727     DWORD flags;
1728 };
1729
1730 static const ConvertData g_ConvertTable[] = {
1731     { DXGI_FORMAT_R32G32B32A32_FLOAT,           32, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1732     { DXGI_FORMAT_R32G32B32A32_UINT,            32, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1733     { DXGI_FORMAT_R32G32B32A32_SINT,            32, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1734     { DXGI_FORMAT_R32G32B32_FLOAT,              32, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B },
1735     { DXGI_FORMAT_R32G32B32_UINT,               32, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B },
1736     { DXGI_FORMAT_R32G32B32_SINT,               32, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B },
1737     { DXGI_FORMAT_R16G16B16A16_FLOAT,           16, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1738     { DXGI_FORMAT_R16G16B16A16_UNORM,           16, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, 
1739     { DXGI_FORMAT_R16G16B16A16_UINT,            16, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, 
1740     { DXGI_FORMAT_R16G16B16A16_SNORM,           16, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, 
1741     { DXGI_FORMAT_R16G16B16A16_SINT,            16, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, 
1742     { DXGI_FORMAT_R32G32_FLOAT,                 32, CONVF_FLOAT | CONVF_R | CONVF_G },
1743     { DXGI_FORMAT_R32G32_UINT,                  32, CONVF_UINT | CONVF_R | CONVF_G  },
1744     { DXGI_FORMAT_R32G32_SINT,                  32, CONVF_SINT | CONVF_R | CONVF_G  },
1745     { DXGI_FORMAT_D32_FLOAT_S8X24_UINT,         32, CONVF_FLOAT | CONVF_DEPTH | CONVF_STENCIL },
1746     { DXGI_FORMAT_R10G10B10A2_UNORM,            10, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1747     { DXGI_FORMAT_R10G10B10A2_UINT,             10, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1748     { DXGI_FORMAT_R11G11B10_FLOAT,              10, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B },
1749     { DXGI_FORMAT_R8G8B8A8_UNORM,               8, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1750     { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,          8, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1751     { DXGI_FORMAT_R8G8B8A8_UINT,                8, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1752     { DXGI_FORMAT_R8G8B8A8_SNORM,               8, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1753     { DXGI_FORMAT_R8G8B8A8_SINT,                8, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1754     { DXGI_FORMAT_R16G16_FLOAT,                 16, CONVF_FLOAT | CONVF_R | CONVF_G },
1755     { DXGI_FORMAT_R16G16_UNORM,                 16, CONVF_UNORM | CONVF_R | CONVF_G },
1756     { DXGI_FORMAT_R16G16_UINT,                  16, CONVF_UINT | CONVF_R | CONVF_G },
1757     { DXGI_FORMAT_R16G16_SNORM,                 16, CONVF_SNORM | CONVF_R | CONVF_G },
1758     { DXGI_FORMAT_R16G16_SINT,                  16, CONVF_SINT | CONVF_R | CONVF_G },
1759     { DXGI_FORMAT_D32_FLOAT,                    32, CONVF_FLOAT | CONVF_DEPTH },
1760     { DXGI_FORMAT_R32_FLOAT,                    32, CONVF_FLOAT | CONVF_R },
1761     { DXGI_FORMAT_R32_UINT,                     32, CONVF_UINT | CONVF_R },
1762     { DXGI_FORMAT_R32_SINT,                     32, CONVF_SINT | CONVF_R },
1763     { DXGI_FORMAT_D24_UNORM_S8_UINT,            32, CONVF_UNORM | CONVF_DEPTH | CONVF_STENCIL },
1764     { DXGI_FORMAT_R8G8_UNORM,                   8, CONVF_UNORM | CONVF_R | CONVF_G },
1765     { DXGI_FORMAT_R8G8_UINT,                    8, CONVF_UINT | CONVF_R | CONVF_G },
1766     { DXGI_FORMAT_R8G8_SNORM,                   8, CONVF_SNORM | CONVF_R | CONVF_G },
1767     { DXGI_FORMAT_R8G8_SINT,                    8, CONVF_SINT | CONVF_R | CONVF_G },
1768     { DXGI_FORMAT_R16_FLOAT,                    16, CONVF_FLOAT | CONVF_R },
1769     { DXGI_FORMAT_D16_UNORM,                    16, CONVF_UNORM | CONVF_DEPTH },
1770     { DXGI_FORMAT_R16_UNORM,                    16, CONVF_UNORM | CONVF_R },
1771     { DXGI_FORMAT_R16_UINT,                     16, CONVF_UINT | CONVF_R },
1772     { DXGI_FORMAT_R16_SNORM,                    16, CONVF_SNORM | CONVF_R },
1773     { DXGI_FORMAT_R16_SINT,                     16, CONVF_SINT | CONVF_R },
1774     { DXGI_FORMAT_R8_UNORM,                     8, CONVF_UNORM | CONVF_R },
1775     { DXGI_FORMAT_R8_UINT,                      8, CONVF_UINT | CONVF_R },
1776     { DXGI_FORMAT_R8_SNORM,                     8, CONVF_SNORM | CONVF_R },
1777     { DXGI_FORMAT_R8_SINT,                      8, CONVF_SINT | CONVF_R },
1778     { DXGI_FORMAT_A8_UNORM,                     8, CONVF_UNORM | CONVF_A },
1779     { DXGI_FORMAT_R1_UNORM,                     1, CONVF_UNORM | CONVF_R },
1780     { DXGI_FORMAT_R9G9B9E5_SHAREDEXP,           9, CONVF_SHAREDEXP | CONVF_R | CONVF_G | CONVF_B },
1781     { DXGI_FORMAT_R8G8_B8G8_UNORM,              8, CONVF_UNORM | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },
1782     { DXGI_FORMAT_G8R8_G8B8_UNORM,              8, CONVF_UNORM | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },
1783     { DXGI_FORMAT_BC1_UNORM,                    8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1784     { DXGI_FORMAT_BC1_UNORM_SRGB,               8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1785     { DXGI_FORMAT_BC2_UNORM,                    8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1786     { DXGI_FORMAT_BC2_UNORM_SRGB,               8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1787     { DXGI_FORMAT_BC3_UNORM,                    8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1788     { DXGI_FORMAT_BC3_UNORM_SRGB,               8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1789     { DXGI_FORMAT_BC4_UNORM,                    8, CONVF_UNORM | CONVF_BC | CONVF_R },
1790     { DXGI_FORMAT_BC4_SNORM,                    8, CONVF_SNORM | CONVF_BC | CONVF_R },
1791     { DXGI_FORMAT_BC5_UNORM,                    8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G },
1792     { DXGI_FORMAT_BC5_SNORM,                    8, CONVF_SNORM | CONVF_BC | CONVF_R | CONVF_G },
1793     { DXGI_FORMAT_B5G6R5_UNORM,                 5, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B },
1794     { DXGI_FORMAT_B5G5R5A1_UNORM,               5, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1795     { DXGI_FORMAT_B8G8R8A8_UNORM,               8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1796     { DXGI_FORMAT_B8G8R8X8_UNORM,               8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B },
1797     { DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM,   10, CONVF_UNORM | CONVF_X2 | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1798     { DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,          8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1799     { DXGI_FORMAT_B8G8R8X8_UNORM_SRGB,          8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B },
1800     { DXGI_FORMAT_BC6H_UF16,                    16, CONVF_FLOAT | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1801     { DXGI_FORMAT_BC6H_SF16,                    16, CONVF_FLOAT | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1802     { DXGI_FORMAT_BC7_UNORM,                    8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1803     { DXGI_FORMAT_BC7_UNORM_SRGB,               8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1804 #ifdef DXGI_1_2_FORMATS
1805     { DXGI_FORMAT_B4G4R4A4_UNORM,               4, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1806 #endif
1807 };
1808
1809 #pragma prefast( suppress : 25004, "Signature must match bsearch_s" );
1810 static int __cdecl _ConvertCompare( void *context, const void* ptr1, const void *ptr2 )
1811 {
1812     UNREFERENCED_PARAMETER(context);
1813     const ConvertData *p1 = reinterpret_cast<const ConvertData*>(ptr1);
1814     const ConvertData *p2 = reinterpret_cast<const ConvertData*>(ptr2);
1815     if ( p1->format == p2->format ) return 0;
1816     else return (p1->format < p2->format ) ? -1 : 1;
1817 }
1818
1819 DWORD _GetConvertFlags( DXGI_FORMAT format )
1820 {
1821 #ifdef _DEBUG
1822     // Ensure conversion table is in ascending order
1823     assert( _countof(g_ConvertTable) > 0 );
1824     DXGI_FORMAT lastvalue = g_ConvertTable[0].format;
1825     for( size_t index=1; index < _countof(g_ConvertTable); ++index )
1826     {
1827         assert( g_ConvertTable[index].format > lastvalue );
1828         lastvalue = g_ConvertTable[index].format;
1829     }
1830 #endif
1831
1832     ConvertData key = { format, 0 };
1833     const ConvertData* in = (const ConvertData*) bsearch_s( &key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData),
1834                                                             _ConvertCompare, 0 );
1835     return (in) ? in->flags : 0;
1836 }
1837
1838 void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, DXGI_FORMAT inFormat, DWORD flags )
1839 {
1840     assert( pBuffer && count > 0 && (((uintptr_t)pBuffer & 0xF) == 0) );
1841     assert( IsValid(outFormat) && !IsVideo(outFormat) && !IsTypeless(outFormat) );
1842     assert( IsValid(inFormat) && !IsVideo(inFormat) && !IsTypeless(inFormat) );
1843
1844     if ( !pBuffer )
1845         return;
1846
1847 #ifdef _DEBUG
1848     // Ensure conversion table is in ascending order
1849     assert( _countof(g_ConvertTable) > 0 );
1850     DXGI_FORMAT lastvalue = g_ConvertTable[0].format;
1851     for( size_t index=1; index < _countof(g_ConvertTable); ++index )
1852     {
1853         assert( g_ConvertTable[index].format > lastvalue );
1854         lastvalue = g_ConvertTable[index].format;
1855     }
1856 #endif
1857
1858     // Determine conversion details about source and dest formats
1859     ConvertData key = { inFormat, 0 };
1860     const ConvertData* in = (const ConvertData*) bsearch_s( &key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData),
1861                                                             _ConvertCompare, 0 );
1862     key.format = outFormat;
1863     const ConvertData* out = (const ConvertData*) bsearch_s( &key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData),
1864                                                             _ConvertCompare, 0 );
1865     if ( !in || !out )
1866     {
1867         assert(false);
1868         return;
1869     }
1870
1871     assert( _GetConvertFlags( inFormat ) == in->flags );
1872     assert( _GetConvertFlags( outFormat ) == out->flags );
1873
1874     // Handle SRGB filtering modes
1875     if ( IsSRGB( inFormat ) )
1876         flags |= TEX_FILTER_SRGB_IN;
1877
1878     if ( IsSRGB( outFormat ) )
1879         flags |= TEX_FILTER_SRGB_OUT;
1880
1881     if ( in->flags & CONVF_SNORM )
1882         flags &= ~TEX_FILTER_SRGB_IN;
1883
1884     if ( out->flags & CONVF_SNORM )
1885         flags &= ~TEX_FILTER_SRGB_OUT;
1886
1887     if ( (flags & (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT) )
1888     {
1889         flags &= ~(TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT);
1890     }
1891
1892     // sRGB input processing (sRGB -> RGB)
1893     if ( flags & TEX_FILTER_SRGB_IN )
1894     {
1895         if ( (in->flags & CONVF_FLOAT) || (in->flags & CONVF_UNORM) )
1896         {
1897             XMVECTOR* ptr = pBuffer;
1898             for( size_t i=0; i < count; ++i )
1899             {
1900                 // rgb = rgb^(2.2); a=a
1901                 XMVECTOR v = *ptr;
1902                 XMVECTOR v1 = _TableDecodeGamma22( v );
1903                 *ptr++ = XMVectorSelect( v, v1, g_XMSelect1110 );
1904             }
1905         }
1906     }
1907
1908     // Handle conversion special cases
1909     DWORD diffFlags = in->flags ^ out->flags;
1910     if ( diffFlags != 0)
1911     {
1912         if ( out->flags & CONVF_UNORM )
1913         {
1914             if ( in->flags & CONVF_SNORM )
1915             {
1916                 // SNORM -> UNORM
1917                 XMVECTOR* ptr = pBuffer;
1918                 for( size_t i=0; i < count; ++i )
1919                 {
1920                     XMVECTOR v = *ptr;
1921                     *ptr++ = XMVectorMultiplyAdd( v, g_XMOneHalf, g_XMOneHalf );
1922                 }
1923             }
1924             else if ( in->flags & CONVF_FLOAT )
1925             {
1926                 // FLOAT -> UNORM
1927                 XMVECTOR* ptr = pBuffer;
1928                 for( size_t i=0; i < count; ++i )
1929                 {
1930                     XMVECTOR v = *ptr;
1931                     *ptr++ = XMVectorSaturate( v );
1932                 }
1933             }
1934         }
1935         else if ( out->flags & CONVF_SNORM )
1936         {
1937             if ( in->flags & CONVF_UNORM )
1938             {
1939                 // UNORM -> SNORM
1940                 static XMVECTORF32 two = { 2.0f, 2.0f, 2.0f, 2.0f };
1941                 XMVECTOR* ptr = pBuffer;
1942                 for( size_t i=0; i < count; ++i )
1943                 {
1944                     XMVECTOR v = *ptr;
1945                     *ptr++ = XMVectorMultiplyAdd( v, two, g_XMNegativeOne );
1946                 }
1947             }
1948             else if ( in->flags & CONVF_FLOAT )
1949             {
1950                 // FLOAT -> SNORM
1951                 XMVECTOR* ptr = pBuffer;
1952                 for( size_t i=0; i < count; ++i )
1953                 {
1954                     XMVECTOR v = *ptr;
1955                     *ptr++ = XMVectorClamp( v, g_XMNegativeOne, g_XMOne );
1956                 }
1957             }
1958         }
1959
1960         // !CONVF_A -> CONVF_A is handled because LoadScanline ensures alpha defaults to 1.0 for no-alpha formats
1961
1962         // CONVF_PACKED cases are handled because LoadScanline/StoreScanline handles packing/unpacking
1963
1964         if ( ((out->flags & CONVF_RGBA_MASK) == CONVF_A) && !(in->flags & CONVF_A) )
1965         {
1966             // !CONVF_A -> A format
1967             XMVECTOR* ptr = pBuffer;
1968             for( size_t i=0; i < count; ++i )
1969             {
1970                 XMVECTOR v = *ptr;
1971                 *ptr++ = XMVectorSplatX( v );
1972             }
1973         }
1974         else if ( ((in->flags & CONVF_RGBA_MASK) == CONVF_A) && !(out->flags & CONVF_A) )
1975         {
1976             // A format -> !CONVF_A
1977             XMVECTOR* ptr = pBuffer;
1978             for( size_t i=0; i < count; ++i )
1979             {
1980                 XMVECTOR v = *ptr;
1981                 *ptr++ = XMVectorSplatW( v );
1982             }
1983         }
1984         else if ( ((in->flags & CONVF_RGB_MASK) == CONVF_R) && ((out->flags & CONVF_RGB_MASK) == (CONVF_R|CONVF_G|CONVF_B)) )
1985         {
1986             // R format -> RGB format
1987             XMVECTOR* ptr = pBuffer;
1988             for( size_t i=0; i < count; ++i )
1989             {
1990                 XMVECTOR v = *ptr;
1991                 XMVECTOR v1 = XMVectorSplatX( v );
1992                 *ptr++ = XMVectorSelect( v, v1, g_XMSelect1110 );
1993             }
1994         }
1995     }
1996
1997     // sRGB output processing (RGB -> sRGB)
1998     if ( flags & TEX_FILTER_SRGB_OUT )
1999     {
2000         if ( (out->flags & CONVF_FLOAT) || (out->flags & CONVF_UNORM) )
2001         {
2002             XMVECTOR* ptr = pBuffer;
2003             for( size_t i=0; i < count; ++i )
2004             {
2005                 // rgb = rgb^(1/2.2); a=a
2006                 XMVECTOR v = *ptr;
2007                 XMVECTOR v1 = _TableEncodeGamma22( v );
2008                 *ptr++ = XMVectorSelect( v, v1, g_XMSelect1110 );
2009             }
2010         }
2011     }
2012 }
2013
2014
2015 //-------------------------------------------------------------------------------------
2016 // Convert the source image using WIC
2017 //-------------------------------------------------------------------------------------
2018 static HRESULT _ConvertUsingWIC( _In_ const Image& srcImage, _In_ const WICPixelFormatGUID& pfGUID,
2019                                  _In_ const WICPixelFormatGUID& targetGUID,
2020                                  _In_ DWORD filter, _In_ float threshold,  _In_ const Image& destImage )
2021 {
2022     assert( srcImage.width == destImage.width );
2023     assert( srcImage.height == destImage.height );
2024
2025     IWICImagingFactory* pWIC = _GetWIC();
2026     if ( !pWIC )
2027         return E_NOINTERFACE;
2028
2029     ScopedObject<IWICFormatConverter> FC;
2030     HRESULT hr = pWIC->CreateFormatConverter( &FC );
2031     if ( FAILED(hr) )
2032         return hr;
2033
2034     // Need to implement usage of TEX_FILTER_SRGB_IN/TEX_FILTER_SRGB_OUT
2035
2036     BOOL canConvert = FALSE;
2037     hr = FC->CanConvert( pfGUID, targetGUID, &canConvert );
2038     if ( FAILED(hr) || !canConvert )
2039     {
2040         // This case is not an issue for the subset of WIC formats that map directly to DXGI
2041         return E_UNEXPECTED;
2042     }
2043
2044     ScopedObject<IWICBitmap> source;
2045     hr = pWIC->CreateBitmapFromMemory( static_cast<UINT>( srcImage.width ), static_cast<UINT>( srcImage.height ), pfGUID,
2046                                        static_cast<UINT>( srcImage.rowPitch ), static_cast<UINT>( srcImage.slicePitch ),
2047                                        srcImage.pixels, &source );
2048     if ( FAILED(hr) )
2049         return hr;
2050
2051     hr = FC->Initialize( source.Get(), targetGUID, _GetWICDither( filter ), 0, threshold, WICBitmapPaletteTypeCustom );
2052     if ( FAILED(hr) )
2053         return hr;
2054
2055     hr = FC->CopyPixels( 0, static_cast<UINT>( destImage.rowPitch ), static_cast<UINT>( destImage.slicePitch ), destImage.pixels );  
2056     if ( FAILED(hr) )
2057         return hr;
2058
2059     return S_OK;
2060 }
2061
2062
2063 //-------------------------------------------------------------------------------------
2064 // Convert the source using WIC and then convert to DXGI format from there
2065 //-------------------------------------------------------------------------------------
2066 static HRESULT _ConvertFromWIC( _In_ const Image& srcImage, _In_ const WICPixelFormatGUID& pfGUID,
2067                                 _In_ DWORD filter, _In_ float threshold,  _In_ const Image& destImage )
2068 {
2069     assert( srcImage.width == destImage.width );
2070     assert( srcImage.height == destImage.height );
2071
2072     IWICImagingFactory* pWIC = _GetWIC();
2073     if ( !pWIC )
2074         return E_NOINTERFACE;
2075
2076     ScopedObject<IWICFormatConverter> FC;
2077     HRESULT hr = pWIC->CreateFormatConverter( &FC );
2078     if ( FAILED(hr) )
2079         return hr;
2080
2081     BOOL canConvert = FALSE;
2082     hr = FC->CanConvert( pfGUID, GUID_WICPixelFormat128bppRGBAFloat, &canConvert );
2083     if ( FAILED(hr) || !canConvert )
2084     {
2085         // This case is not an issue for the subset of WIC formats that map directly to DXGI
2086         return E_UNEXPECTED;
2087     }
2088
2089     ScratchImage temp;
2090     hr = temp.Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1 );
2091     if ( FAILED(hr) )
2092         return hr;
2093
2094     const Image *timg = temp.GetImage( 0, 0, 0 );
2095     if ( !timg )
2096         return E_POINTER;
2097
2098     ScopedObject<IWICBitmap> source;
2099     hr = pWIC->CreateBitmapFromMemory( static_cast<UINT>( srcImage.width ), static_cast<UINT>( srcImage.height ), pfGUID,
2100                                        static_cast<UINT>( srcImage.rowPitch ), static_cast<UINT>( srcImage.slicePitch ),
2101                                        srcImage.pixels, &source );
2102     if ( FAILED(hr) )
2103         return hr;
2104
2105     hr = FC->Initialize( source.Get(), GUID_WICPixelFormat128bppRGBAFloat, _GetWICDither( filter ), 0, threshold, WICBitmapPaletteTypeCustom );
2106     if ( FAILED(hr) )
2107         return hr;
2108
2109     hr = FC->CopyPixels( 0, static_cast<UINT>( timg->rowPitch ), static_cast<UINT>( timg->slicePitch ), timg->pixels );  
2110     if ( FAILED(hr) )
2111         return hr;
2112
2113     // Perform conversion on temp image which is now in R32G32B32A32_FLOAT format to final image
2114     uint8_t *pSrc = timg->pixels;
2115     uint8_t *pDest = destImage.pixels;
2116     if ( !pSrc || !pDest )
2117         return E_POINTER;
2118
2119     for( size_t h = 0; h < srcImage.height; ++h )
2120     {
2121         _ConvertScanline( reinterpret_cast<XMVECTOR*>(pSrc), srcImage.width, destImage.format, DXGI_FORMAT_R32G32B32A32_FLOAT, filter );
2122
2123         if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, reinterpret_cast<const XMVECTOR*>(pSrc), srcImage.width ) )
2124             return E_FAIL;
2125
2126         pSrc += timg->rowPitch;
2127         pDest += destImage.rowPitch;
2128     }
2129
2130     return S_OK;
2131 }
2132
2133
2134 //-------------------------------------------------------------------------------------
2135 // Convert the source from DXGI format then use WIC to convert to final format
2136 //-------------------------------------------------------------------------------------
2137 static HRESULT _ConvertToWIC( _In_ const Image& srcImage, 
2138                               _In_ const WICPixelFormatGUID& targetGUID, _In_ DWORD filter, _In_ float threshold,  _In_ const Image& destImage )
2139 {
2140     assert( srcImage.width == destImage.width );
2141     assert( srcImage.height == destImage.height );
2142
2143     IWICImagingFactory* pWIC = _GetWIC();
2144     if ( !pWIC )
2145         return E_NOINTERFACE;
2146
2147     ScopedObject<IWICFormatConverter> FC;
2148     HRESULT hr = pWIC->CreateFormatConverter( &FC );
2149     if ( FAILED(hr) )
2150         return hr;
2151
2152     BOOL canConvert = FALSE;
2153     hr = FC->CanConvert( GUID_WICPixelFormat128bppRGBAFloat, targetGUID, &canConvert );
2154     if ( FAILED(hr) || !canConvert )
2155     {
2156         // This case is not an issue for the subset of WIC formats that map directly to DXGI
2157         return E_UNEXPECTED;
2158     }
2159
2160     ScratchImage temp;
2161     hr = temp.Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1 );
2162     if ( FAILED(hr) )
2163         return hr;
2164
2165     const Image *timg = temp.GetImage( 0, 0, 0 );
2166     if ( !timg )
2167         return E_POINTER;
2168
2169     const uint8_t *pSrc = srcImage.pixels;
2170     if ( !pSrc )
2171         return E_POINTER;
2172
2173     uint8_t *pDest = timg->pixels;
2174     if ( !pDest )
2175         return E_POINTER;
2176
2177     for( size_t h = 0; h < srcImage.height; ++h )
2178     {
2179         if ( !_LoadScanline( reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) )
2180             return E_FAIL;
2181
2182         _ConvertScanline( reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.format, filter );
2183
2184         pSrc += srcImage.rowPitch;
2185         pDest += timg->rowPitch;
2186     }
2187
2188     // Perform conversion on temp image which is now in R32G32B32A32_FLOAT format
2189     ScopedObject<IWICBitmap> source;
2190     hr = pWIC->CreateBitmapFromMemory( static_cast<UINT>( timg->width ), static_cast<UINT>( timg->height ), GUID_WICPixelFormat128bppRGBAFloat,
2191                                        static_cast<UINT>( timg->rowPitch ), static_cast<UINT>( timg->slicePitch ),
2192                                        timg->pixels, &source );
2193     if ( FAILED(hr) )
2194         return hr;
2195
2196     hr = FC->Initialize( source.Get(), targetGUID, _GetWICDither( filter ), 0, threshold, WICBitmapPaletteTypeCustom );
2197     if ( FAILED(hr) )
2198         return hr;
2199
2200     hr = FC->CopyPixels( 0, static_cast<UINT>( destImage.rowPitch ), static_cast<UINT>( destImage.slicePitch ), destImage.pixels );  
2201     if ( FAILED(hr) )
2202         return hr;
2203
2204     return S_OK;
2205 }
2206
2207
2208 //-------------------------------------------------------------------------------------
2209 // Convert the source image (not using WIC)
2210 //-------------------------------------------------------------------------------------
2211 static HRESULT _Convert( _In_ const Image& srcImage, _In_ DWORD filter, _In_ const Image& destImage )
2212 {
2213     assert( srcImage.width == destImage.width );
2214     assert( srcImage.height == destImage.height );
2215
2216     ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( (sizeof(XMVECTOR)*srcImage.width), 16 ) ) );
2217     if ( !scanline )
2218         return E_OUTOFMEMORY;
2219
2220     const uint8_t *pSrc = srcImage.pixels;
2221     uint8_t *pDest = destImage.pixels;
2222     if ( !pSrc || !pDest )
2223         return E_POINTER;
2224
2225     for( size_t h = 0; h < srcImage.height; ++h )
2226     {
2227         if ( !_LoadScanline( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) )
2228             return E_FAIL;
2229
2230         _ConvertScanline( scanline.get(), srcImage.width, destImage.format, srcImage.format, filter );
2231
2232         if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width ) )
2233             return E_FAIL;
2234
2235         pSrc += srcImage.rowPitch;
2236         pDest += destImage.rowPitch;
2237     }
2238
2239     return S_OK;
2240 }
2241
2242
2243 //=====================================================================================
2244 // Entry-points
2245 //=====================================================================================
2246
2247 //-------------------------------------------------------------------------------------
2248 // Convert image
2249 //-------------------------------------------------------------------------------------
2250 HRESULT Convert( const Image& srcImage, DXGI_FORMAT format, DWORD filter, float threshold, ScratchImage& image )
2251 {
2252     if ( (srcImage.format == format) || !IsValid( format ) )
2253         return E_INVALIDARG;
2254
2255     if ( !srcImage.pixels )
2256         return E_POINTER;
2257
2258     if ( IsCompressed(srcImage.format) || IsCompressed(format)
2259          || IsVideo(srcImage.format) || IsVideo(format) 
2260          || IsTypeless(srcImage.format) || IsTypeless(format) )
2261         return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
2262
2263 #ifdef _AMD64_
2264     if ( (srcImage.width > 0xFFFFFFFF) || (srcImage.height > 0xFFFFFFFF) )
2265         return E_INVALIDARG;
2266 #endif
2267
2268     HRESULT hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 );
2269     if ( FAILED(hr) )
2270         return hr;
2271    
2272     const Image *rimage = image.GetImage( 0, 0, 0 );
2273     if ( !rimage )
2274     {
2275         image.Release();
2276         return E_POINTER;
2277     }
2278
2279     WICPixelFormatGUID pfGUID;
2280     if ( _DXGIToWIC( srcImage.format, pfGUID ) )
2281     {
2282         WICPixelFormatGUID targetGUID;
2283         if ( _DXGIToWIC( format, targetGUID ) )
2284         {
2285             // Case 1: Both source and target formats are WIC supported
2286             hr = _ConvertUsingWIC( srcImage, pfGUID, targetGUID, filter, threshold, *rimage );
2287         }
2288         else
2289         {
2290             // Case 2: Source format is supported by WIC, but not the target format
2291             hr = _ConvertFromWIC( srcImage, pfGUID, filter, threshold, *rimage );
2292         }
2293     }
2294     else
2295     {
2296         WICPixelFormatGUID targetGUID;
2297         if ( _DXGIToWIC( format, targetGUID ) )
2298         {
2299             // Case 3: Source format is not supported by WIC, but does support the target format
2300             hr = _ConvertToWIC( srcImage, targetGUID, filter, threshold, *rimage );
2301         }
2302         else
2303         {
2304             // Case 4: Both source and target format are not supported by WIC
2305             hr = _Convert( srcImage, filter, *rimage );
2306         }
2307     }
2308
2309     if ( FAILED(hr) )
2310     {
2311         image.Release();
2312         return hr;
2313     }
2314
2315     return S_OK;
2316 }
2317
2318
2319 //-------------------------------------------------------------------------------------
2320 // Convert image (complex)
2321 //-------------------------------------------------------------------------------------
2322 HRESULT Convert( const Image* srcImages, size_t nimages, const TexMetadata& metadata,
2323                  DXGI_FORMAT format, DWORD filter, float threshold, ScratchImage& result )
2324 {
2325     if ( !srcImages || !nimages || (metadata.format == format) || !IsValid(format) )
2326         return E_INVALIDARG;
2327
2328     if ( IsCompressed(metadata.format) || IsCompressed(format)
2329          || IsVideo(metadata.format) || IsVideo(format) 
2330          || IsTypeless(metadata.format) || IsTypeless(format) )
2331         return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
2332
2333 #ifdef _AMD64_
2334     if ( (metadata.width > 0xFFFFFFFF) || (metadata.height > 0xFFFFFFFF) )
2335         return E_INVALIDARG;
2336 #endif
2337
2338     TexMetadata mdata2 = metadata;
2339     mdata2.format = format;
2340     HRESULT hr = result.Initialize( mdata2 );
2341     if ( FAILED(hr) )
2342         return hr;
2343
2344     if ( nimages != result.GetImageCount() )
2345     {
2346         result.Release();
2347         return E_FAIL;
2348     }
2349
2350     const Image* dest = result.GetImages();
2351     if ( !dest )
2352     {
2353         result.Release();
2354         return E_POINTER;
2355     }
2356
2357     WICPixelFormatGUID pfGUID, targetGUID;
2358     bool wicpf = _DXGIToWIC( metadata.format, pfGUID );
2359     bool wictargetpf = _DXGIToWIC( format, targetGUID );
2360
2361     for( size_t index=0; index < nimages; ++index )
2362     {
2363         const Image& src = srcImages[ index ];
2364         if ( src.format != metadata.format )
2365         {
2366             result.Release();
2367             return E_FAIL;
2368         }
2369
2370 #ifdef _AMD64_
2371         if ( (src.width > 0xFFFFFFFF) || (src.height > 0xFFFFFFFF) )
2372             return E_FAIL;
2373 #endif
2374
2375         const Image& dst = dest[ index ];
2376         assert( dst.format == format );
2377
2378         if ( src.width != dst.width || src.height != dst.height )
2379         {
2380             result.Release();
2381             return E_FAIL;
2382         }
2383
2384         if ( wicpf )
2385         {
2386             if ( wictargetpf )
2387             {
2388                 // Case 1: Both source and target formats are WIC supported
2389                 hr = _ConvertUsingWIC( src, pfGUID, targetGUID, filter, threshold, dst );
2390             }
2391             else
2392             {
2393                 // Case 2: Source format is supported by WIC, but not the target format
2394                 hr = _ConvertFromWIC( src, pfGUID, filter, threshold, dst );
2395             }
2396         }
2397         else
2398         {
2399             if ( wictargetpf )
2400             {
2401                 // Case 3: Source format is not supported by WIC, but does support the target format
2402                 hr = _ConvertToWIC( src, targetGUID, filter, threshold, dst );
2403             }
2404             else
2405             {
2406                 // Case 4: Both source and target format are not supported by WIC
2407                 hr = _Convert( src, filter, dst );
2408             }
2409         }
2410
2411         if ( FAILED(hr) )
2412         {
2413             result.Release();
2414             return hr;
2415         }
2416     }
2417
2418     return S_OK;
2419 }
2420
2421 }; // namespace