1 //-------------------------------------------------------------------------------------
2 // DirectXTexPMAlpha.cpp
3 //
4 // DirectX Texture Library - Premultiplied alpha operations
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 namespace DirectX
19 {
20 
_PremultiplyAlpha(_In_ const Image & srcImage,_In_ const Image & destImage)21 static HRESULT _PremultiplyAlpha( _In_ const Image& srcImage, _In_ const Image& destImage )
22 {
23     assert( srcImage.width == destImage.width );
24     assert( srcImage.height == destImage.height );
25 
26     ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( (sizeof(XMVECTOR)*srcImage.width), 16 ) ) );
27     if ( !scanline )
28         return E_OUTOFMEMORY;
29 
30     const uint8_t *pSrc = srcImage.pixels;
31     uint8_t *pDest = destImage.pixels;
32     if ( !pSrc || !pDest )
33         return E_POINTER;
34 
35     for( size_t h = 0; h < srcImage.height; ++h )
36     {
37         if ( !_LoadScanline( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) )
38             return E_FAIL;
39 
40         XMVECTOR* ptr = scanline.get();
41         for( size_t w = 0; w < srcImage.width; ++w )
42         {
43             XMVECTOR v = *ptr;
44             XMVECTOR alpha = XMVectorSplatW( *ptr );
45             alpha = XMVectorMultiply( v, alpha );
46             *(ptr++) = XMVectorSelect( v, alpha, g_XMSelect1110 );
47         }
48 
49         if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width ) )
50             return E_FAIL;
51 
52         pSrc += srcImage.rowPitch;
53         pDest += destImage.rowPitch;
54     }
55 
56     return S_OK;
57 }
58 
_PremultiplyAlphaLinear(_In_ const Image & srcImage,_In_ DWORD flags,_In_ const Image & destImage)59 static HRESULT _PremultiplyAlphaLinear( _In_ const Image& srcImage, _In_ DWORD flags, _In_ const Image& destImage )
60 {
61     assert( srcImage.width == destImage.width );
62     assert( srcImage.height == destImage.height );
63 
64     static_assert( TEX_PMALPHA_SRGB_IN == TEX_FILTER_SRGB_IN, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*" );
65     static_assert( TEX_PMALPHA_SRGB_OUT == TEX_FILTER_SRGB_OUT, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*" );
66     static_assert( TEX_PMALPHA_SRGB == TEX_FILTER_SRGB, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*" );
67     flags &= TEX_PMALPHA_SRGB;
68 
69     ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( (sizeof(XMVECTOR)*srcImage.width), 16 ) ) );
70     if ( !scanline )
71         return E_OUTOFMEMORY;
72 
73     const uint8_t *pSrc = srcImage.pixels;
74     uint8_t *pDest = destImage.pixels;
75     if ( !pSrc || !pDest )
76         return E_POINTER;
77 
78     for( size_t h = 0; h < srcImage.height; ++h )
79     {
80         if ( !_LoadScanlineLinear( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format, flags ) )
81             return E_FAIL;
82 
83         XMVECTOR* ptr = scanline.get();
84         for( size_t w = 0; w < srcImage.width; ++w )
85         {
86             XMVECTOR v = *ptr;
87             XMVECTOR alpha = XMVectorSplatW( *ptr );
88             alpha = XMVectorMultiply( v, alpha );
89             *(ptr++) = XMVectorSelect( v, alpha, g_XMSelect1110 );
90         }
91 
92         if ( !_StoreScanlineLinear( pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width, flags ) )
93             return E_FAIL;
94 
95         pSrc += srcImage.rowPitch;
96         pDest += destImage.rowPitch;
97     }
98 
99     return S_OK;
100 }
101 
102 
103 //=====================================================================================
104 // Entry-points
105 //=====================================================================================
106 
107 //-------------------------------------------------------------------------------------
108 // Converts to a premultiplied alpha version of the texture
109 //-------------------------------------------------------------------------------------
110 _Use_decl_annotations_
PremultiplyAlpha(const Image & srcImage,DWORD flags,ScratchImage & image)111 HRESULT PremultiplyAlpha( const Image& srcImage, DWORD flags, ScratchImage& image )
112 {
113     if ( !srcImage.pixels )
114         return E_POINTER;
115 
116     if ( IsCompressed(srcImage.format)
117          || IsPlanar(srcImage.format)
118          || IsPalettized(srcImage.format)
119          || IsTypeless(srcImage.format)
120          || !HasAlpha(srcImage.format) )
121         return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
122 
123 #ifdef _M_X64
124     if ( (srcImage.width > 0xFFFFFFFF) || (srcImage.height > 0xFFFFFFFF) )
125         return E_INVALIDARG;
126 #endif
127 
128     HRESULT hr = image.Initialize2D( srcImage.format, srcImage.width, srcImage.height, 1, 1 );
129     if ( FAILED(hr) )
130         return hr;
131 
132     const Image *rimage = image.GetImage( 0, 0, 0 );
133     if ( !rimage )
134     {
135         image.Release();
136         return E_POINTER;
137     }
138 
139     hr = ( flags & TEX_PMALPHA_IGNORE_SRGB ) ? _PremultiplyAlpha( srcImage, *rimage ) : _PremultiplyAlphaLinear( srcImage, flags, *rimage );
140     if ( FAILED(hr) )
141     {
142         image.Release();
143         return hr;
144     }
145 
146     return S_OK;
147 }
148 
149 
150 //-------------------------------------------------------------------------------------
151 // Converts to a premultiplied alpha version of the texture (complex)
152 //-------------------------------------------------------------------------------------
153 _Use_decl_annotations_
PremultiplyAlpha(const Image * srcImages,size_t nimages,const TexMetadata & metadata,DWORD flags,ScratchImage & result)154 HRESULT PremultiplyAlpha( const Image* srcImages, size_t nimages, const TexMetadata& metadata, DWORD flags, ScratchImage& result )
155 {
156     if ( !srcImages || !nimages )
157         return E_INVALIDARG;
158 
159     if ( IsCompressed(metadata.format)
160          || IsPlanar(metadata.format)
161          || IsPalettized(metadata.format)
162          || IsTypeless(metadata.format)
163          || !HasAlpha(metadata.format) )
164         return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
165 
166 #ifdef _M_X64
167     if ( (metadata.width > 0xFFFFFFFF) || (metadata.height > 0xFFFFFFFF) )
168         return E_INVALIDARG;
169 #endif
170 
171     if ( metadata.IsPMAlpha() )
172     {
173         // Already premultiplied
174         return E_FAIL;
175     }
176 
177     TexMetadata mdata2 = metadata;
178     mdata2.SetAlphaMode(TEX_ALPHA_MODE_PREMULTIPLIED);
179     HRESULT hr = result.Initialize( mdata2 );
180     if ( FAILED(hr) )
181         return hr;
182 
183     if ( nimages != result.GetImageCount() )
184     {
185         result.Release();
186         return E_FAIL;
187     }
188 
189     const Image* dest = result.GetImages();
190     if ( !dest )
191     {
192         result.Release();
193         return E_POINTER;
194     }
195 
196     for( size_t index=0; index < nimages; ++index )
197     {
198         const Image& src = srcImages[ index ];
199         if ( src.format != metadata.format )
200         {
201             result.Release();
202             return E_FAIL;
203         }
204 
205 #ifdef _M_X64
206         if ( (src.width > 0xFFFFFFFF) || (src.height > 0xFFFFFFFF) )
207             return E_FAIL;
208 #endif
209         const Image& dst = dest[ index ];
210         assert( dst.format == metadata.format );
211 
212         if ( src.width != dst.width || src.height != dst.height )
213         {
214             result.Release();
215             return E_FAIL;
216         }
217 
218         hr = ( flags & TEX_PMALPHA_IGNORE_SRGB ) ? _PremultiplyAlpha( src, dst ) : _PremultiplyAlphaLinear( src, flags, dst );
219         if ( FAILED(hr) )
220         {
221             result.Release();
222             return hr;
223         }
224     }
225 
226     return S_OK;
227 }
228 
229 }; // namespace
230