]> git.cworth.org Git - apitrace/blob - thirdparty/directxtex/DirectXTex/DirectXTexMisc.cpp
thirdparty/directxtex: Import DirectXTex library.
[apitrace] / thirdparty / directxtex / DirectXTex / DirectXTexMisc.cpp
1 //-------------------------------------------------------------------------------------
2 // DirectXTexMisc.cpp
3 //  
4 // DirectX Texture Library - Misc image 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
21 //-------------------------------------------------------------------------------------
22 static HRESULT _ComputeMSE( _In_ const Image& image1, _In_ const Image& image2,
23                             _Out_ float& mse, _Out_opt_cap_c_(4) float* mseV )
24 {
25     if ( !image1.pixels || !image2.pixels )
26         return E_POINTER;
27
28     assert( image1.width == image2.width && image1.height == image2.height );
29     assert( !IsCompressed( image1.format ) && !IsCompressed( image2.format )  );
30
31     const size_t width = image1.width;
32
33     ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( (sizeof(XMVECTOR)*width)*2, 16 ) ) );
34     if ( !scanline )
35         return E_OUTOFMEMORY;
36
37     const uint8_t *pSrc1 = image1.pixels;
38     const size_t rowPitch1 = image1.rowPitch;
39
40     const uint8_t *pSrc2 = image2.pixels;
41     const size_t rowPitch2 = image2.rowPitch;
42
43     XMVECTOR acc = XMVectorZero();
44
45     for( size_t h = 0; h < image1.height; ++h )
46     {
47         XMVECTOR* ptr1 = scanline.get();
48         if ( !_LoadScanline( ptr1, width, pSrc1, rowPitch1, image1.format ) )
49             return E_FAIL;
50
51         XMVECTOR* ptr2 = scanline.get() + width;
52         if ( !_LoadScanline( ptr2, width, pSrc2, rowPitch2, image2.format ) )
53             return E_FAIL;
54
55         for( size_t i = 0; i < width; ++i, ++ptr1, ++ptr2 )
56         {
57             // sum[ (I1 - I2)^2 ]
58             XMVECTOR v = XMVectorSubtract( *ptr1, *ptr2 );
59             acc = XMVectorMultiplyAdd( v, v, acc );
60         }
61
62         pSrc1 += rowPitch1;
63         pSrc2 += rowPitch2;
64     }
65
66     // MSE = sum[ (I1 - I2)^2 ] / w*h
67     XMVECTOR d = XMVectorReplicate( float(image1.width * image1.height) );
68     XMVECTOR v = XMVectorDivide( acc, d );
69     if ( mseV )
70     {
71         XMStoreFloat4( reinterpret_cast<XMFLOAT4*>( mseV ), v );
72         mse = mseV[0] + mseV[1] + mseV[2] + mseV[3];
73     }
74     else
75     {
76         XMFLOAT4 _mseV;
77         XMStoreFloat4( &_mseV, v );
78         mse = _mseV.x + _mseV.y + _mseV.z + _mseV.w;
79     }
80
81     return S_OK; 
82 }
83
84
85 //=====================================================================================
86 // Entry points
87 //=====================================================================================
88         
89 //-------------------------------------------------------------------------------------
90 // Copies a rectangle from one image into another
91 //-------------------------------------------------------------------------------------
92 HRESULT CopyRectangle( const Image& srcImage, const Rect& srcRect, const Image& dstImage, DWORD filter, size_t xOffset, size_t yOffset )
93 {
94     if ( !srcImage.pixels || !dstImage.pixels )
95         return E_POINTER;
96
97     if ( IsCompressed( srcImage.format ) || IsCompressed( dstImage.format ) )
98         return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
99
100     // Validate rectangle/offset
101     if ( !srcRect.w || !srcRect.h || ( (srcRect.x + srcRect.w) > srcImage.width ) || ( (srcRect.y + srcRect.h) > srcImage.height ) )
102     {
103         return E_INVALIDARG;
104     }
105
106     if ( ( (xOffset + srcRect.w) > dstImage.width ) || ( (yOffset + srcRect.h) > dstImage.height ) )
107     {
108         return E_INVALIDARG;
109     }
110
111     // Compute source bytes-per-pixel
112     size_t sbpp = BitsPerPixel( srcImage.format );
113     if ( !sbpp )
114         return E_FAIL;
115
116     if ( sbpp < 8 )
117     {
118         // We don't support monochrome (DXGI_FORMAT_R1_UNORM)
119         return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
120     }
121
122     const uint8_t* pEndSrc = srcImage.pixels + srcImage.rowPitch*srcImage.height;
123     const uint8_t* pEndDest = dstImage.pixels + dstImage.rowPitch*dstImage.height;
124
125     // Round to bytes
126     sbpp = ( sbpp + 7 ) / 8;
127
128     const uint8_t* pSrc = srcImage.pixels + (srcRect.y * srcImage.rowPitch) + (srcRect.x * sbpp);
129
130     if ( srcImage.format == dstImage.format )
131     {
132         // Direct copy case (avoid intermediate conversions)
133         uint8_t* pDest = dstImage.pixels + (yOffset * dstImage.rowPitch) + (xOffset * sbpp);
134         const size_t copyW = srcRect.w * sbpp;
135         for( size_t h=0; h < srcRect.h; ++h )
136         {
137             if ( ( (pSrc+copyW) > pEndSrc ) || (pDest > pEndDest) )
138                 return E_FAIL;
139
140             memcpy_s( pDest, pEndDest - pDest, pSrc, copyW );
141
142             pSrc += srcImage.rowPitch;
143             pDest += dstImage.rowPitch;
144         }
145
146         return S_OK;
147     }
148
149     // Compute destination bytes-per-pixel (not the same format as source)
150     size_t dbpp = BitsPerPixel( dstImage.format );
151     if ( !dbpp )
152         return E_FAIL;
153
154     if ( dbpp < 8 )
155     {
156         // We don't support monochrome (DXGI_FORMAT_R1_UNORM)
157         return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
158     }
159
160     // Round to bytes
161     dbpp = ( dbpp + 7 ) / 8;
162
163     uint8_t* pDest = dstImage.pixels + (yOffset * dstImage.rowPitch) + (xOffset * dbpp);
164
165     ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( (sizeof(XMVECTOR)*srcRect.w), 16 ) ) );
166     if ( !scanline )
167         return E_OUTOFMEMORY;
168
169     const size_t copyS = srcRect.w * sbpp;
170     const size_t copyD = srcRect.w * dbpp;
171
172     for( size_t h=0; h < srcRect.h; ++h )
173     {
174         if ( ( (pSrc+copyS) > pEndSrc) || ((pDest+copyD) > pEndDest) )
175             return E_FAIL;
176
177         if ( !_LoadScanline( scanline.get(), srcRect.w, pSrc, copyS, srcImage.format ) )
178             return E_FAIL;
179
180         _ConvertScanline( scanline.get(), srcRect.w, dstImage.format, srcImage.format, filter );
181
182         if ( !_StoreScanline( pDest, copyD, dstImage.format, scanline.get(), srcRect.w ) )
183             return E_FAIL;
184
185         pSrc += srcImage.rowPitch;
186         pDest += dstImage.rowPitch;
187     }
188
189     return S_OK;
190 }
191
192     
193 //-------------------------------------------------------------------------------------
194 // Computes the Mean-Squared-Error (MSE) between two images
195 //-------------------------------------------------------------------------------------
196 HRESULT ComputeMSE( const Image& image1, const Image& image2, float& mse, float* mseV  )
197 {
198     if ( !image1.pixels || !image2.pixels )
199         return E_POINTER;
200
201     if ( image1.width != image2.width || image1.height != image2.height )
202         return E_INVALIDARG;
203
204     if ( IsCompressed(image1.format) )
205     {
206         if ( IsCompressed(image2.format) )
207         {
208             // Case 1: both images are compressed, expand to RGBA32F
209             ScratchImage temp1;
210             HRESULT hr = Decompress( image1, DXGI_FORMAT_R32G32B32A32_FLOAT, temp1 );
211             if ( FAILED(hr) )
212                 return hr;
213
214             ScratchImage temp2;
215             hr = Decompress(  image2, DXGI_FORMAT_R32G32B32A32_FLOAT, temp2 );
216             if ( FAILED(hr) )
217                 return hr;
218
219             const Image* img1 = temp1.GetImage(0,0,0);
220             const Image* img2 = temp2.GetImage(0,0,0);
221             if ( !img1 || !img2 )
222                 return E_POINTER;
223
224             return _ComputeMSE( *img1, *img2, mse, mseV );
225         }
226         else
227         {
228             // Case 2: image1 is compressed, expand to RGBA32F
229             ScratchImage temp;
230             HRESULT hr = Decompress( image1, DXGI_FORMAT_R32G32B32A32_FLOAT, temp );
231             if ( FAILED(hr) )
232                 return hr;
233
234             const Image* img = temp.GetImage(0,0,0);
235             if ( !img )
236                 return E_POINTER;
237
238             return _ComputeMSE( *img, image2, mse, mseV );
239         }
240     }
241     else
242     {
243         if ( IsCompressed(image2.format) )
244         {
245             // Case 3: image2 is compressed, expand to RGBA32F
246             ScratchImage temp;
247             HRESULT hr = Decompress( image2, DXGI_FORMAT_R32G32B32A32_FLOAT, temp );
248             if ( FAILED(hr) )
249                 return hr;
250
251             const Image* img = temp.GetImage(0,0,0);
252             if ( !img )
253                 return E_POINTER;
254
255             return _ComputeMSE( image1, *img, mse, mseV );
256         }
257         else
258         {
259             // Case 4: neither image is compressed
260             return _ComputeMSE( image1, image2, mse, mseV );
261         }
262     }
263 }
264
265 }; // namespace