2 * Copyright 2020 Ziqing Hui
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * For uncompressed formats, a block is equivalent to a pixel.
25 * A cube map is equivalent to a 2D texture array which has 6 textures.
26 * A cube map array is equivalent to a 2D texture array which has cubeCount*6 textures.
30 #include "wine/port.h"
40 #include "wincodecs_private.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
46 #define DDS_MAGIC 0x20534444
48 #define MAKEFOURCC(ch0, ch1, ch2, ch3) \
49 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
50 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
53 #define GET_RGB565_R(color) ((BYTE)(((color) >> 11) & 0x1F))
54 #define GET_RGB565_G(color) ((BYTE)(((color) >> 5) & 0x3F))
55 #define GET_RGB565_B(color) ((BYTE)(((color) >> 0) & 0x1F))
56 #define MAKE_RGB565(r, g, b) ((WORD)(((BYTE)(r) << 11) | ((BYTE)(g) << 5) | (BYTE)(b)))
57 #define MAKE_ARGB(a, r, g, b) (((DWORD)(a) << 24) | ((DWORD)(r) << 16) | ((DWORD)(g) << 8) | (DWORD)(b))
59 #define DDPF_ALPHAPIXELS 0x00000001
60 #define DDPF_ALPHA 0x00000002
61 #define DDPF_FOURCC 0x00000004
62 #define DDPF_PALETTEINDEXED8 0x00000020
63 #define DDPF_RGB 0x00000040
64 #define DDPF_LUMINANCE 0x00020000
65 #define DDPF_BUMPDUDV 0x00080000
67 #define DDSCAPS2_CUBEMAP 0x00000200
68 #define DDSCAPS2_VOLUME 0x00200000
70 #define DDS_DIMENSION_TEXTURE1D 2
71 #define DDS_DIMENSION_TEXTURE2D 3
72 #define DDS_DIMENSION_TEXTURE3D 4
74 #define DDS_RESOURCE_MISC_TEXTURECUBE 0x00000004
76 #define DDS_BLOCK_WIDTH 4
77 #define DDS_BLOCK_HEIGHT 4
95 DWORD pitchOrLinearSize
;
99 DDS_PIXELFORMAT ddspf
;
109 DWORD resourceDimension
;
115 typedef struct dds_info
{
123 UINT bytes_per_block
; /* for uncompressed format, this means bytes per pixel*/
125 WICDdsDimension dimension
;
126 WICDdsAlphaMode alpha_mode
;
127 const GUID
*pixel_format
;
128 UINT pixel_format_bpp
;
131 typedef struct dds_frame_info
{
135 UINT bytes_per_block
; /* for uncompressed format, this means bytes per pixel*/
138 UINT width_in_blocks
;
139 UINT height_in_blocks
;
140 const GUID
*pixel_format
;
141 UINT pixel_format_bpp
;
144 typedef struct DdsDecoder
{
145 IWICBitmapDecoder IWICBitmapDecoder_iface
;
146 IWICDdsDecoder IWICDdsDecoder_iface
;
147 IWICWineDecoder IWICWineDecoder_iface
;
151 CRITICAL_SECTION lock
;
155 typedef struct DdsFrameDecode
{
156 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
157 IWICDdsFrameDecode IWICDdsFrameDecode_iface
;
161 CRITICAL_SECTION lock
;
165 static struct dds_format
{
166 DDS_PIXELFORMAT pixel_format
;
167 const GUID
*wic_format
;
169 DXGI_FORMAT dxgi_format
;
170 } dds_format_table
[] = {
171 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('D', 'X', 'T', '1'), 0, 0, 0, 0, 0 },
172 &GUID_WICPixelFormat32bppPBGRA
, 32, DXGI_FORMAT_BC1_UNORM
},
173 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('D', 'X', 'T', '2'), 0, 0, 0, 0, 0 },
174 &GUID_WICPixelFormat32bppPBGRA
, 32, DXGI_FORMAT_BC2_UNORM
},
175 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('D', 'X', 'T', '3'), 0, 0, 0, 0, 0 },
176 &GUID_WICPixelFormat32bppBGRA
, 32, DXGI_FORMAT_BC2_UNORM
},
177 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('D', 'X', 'T', '4'), 0, 0, 0, 0, 0 },
178 &GUID_WICPixelFormat32bppPBGRA
, 32, DXGI_FORMAT_BC3_UNORM
},
179 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('D', 'X', 'T', '5'), 0, 0, 0, 0, 0 },
180 &GUID_WICPixelFormat32bppBGRA
, 32, DXGI_FORMAT_BC3_UNORM
},
181 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('B', 'C', '4', 'U'), 0, 0, 0, 0, 0 },
182 &GUID_WICPixelFormat32bppBGRA
, 32, DXGI_FORMAT_BC4_UNORM
},
183 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('B', 'C', '4', 'S'), 0, 0, 0, 0, 0 },
184 &GUID_WICPixelFormat32bppBGRA
, 32, DXGI_FORMAT_BC4_SNORM
},
185 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('B', 'C', '5', 'U'), 0, 0, 0, 0, 0 },
186 &GUID_WICPixelFormat32bppBGRA
, 32, DXGI_FORMAT_BC5_UNORM
},
187 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('B', 'C', '5', 'S'), 0, 0, 0, 0, 0 },
188 &GUID_WICPixelFormat32bppBGRA
, 32, DXGI_FORMAT_BC5_SNORM
},
189 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('A', 'T', 'I', '1'), 0, 0, 0, 0, 0 },
190 &GUID_WICPixelFormat32bppBGRA
, 32, DXGI_FORMAT_BC4_UNORM
},
191 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('A', 'T', 'I', '2'), 0, 0, 0, 0, 0 },
192 &GUID_WICPixelFormat32bppBGRA
, 32, DXGI_FORMAT_BC5_UNORM
},
193 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('R', 'G', 'B', 'G'), 0, 0, 0, 0, 0 },
194 &GUID_WICPixelFormat32bpp4Channels
, 32, DXGI_FORMAT_R8G8_B8G8_UNORM
},
195 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('G', 'R', 'G', 'B'), 0, 0, 0, 0, 0 },
196 &GUID_WICPixelFormat32bpp4Channels
, 32, DXGI_FORMAT_G8R8_G8B8_UNORM
},
197 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('D', 'X', '1', '0'), 0, 0, 0, 0, 0 },
198 &GUID_WICPixelFormatUndefined
, 0, DXGI_FORMAT_UNKNOWN
},
199 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x24, 0, 0, 0, 0, 0 },
200 &GUID_WICPixelFormat64bppRGBA
, 64, DXGI_FORMAT_R16G16B16A16_UNORM
},
201 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x6E, 0, 0, 0, 0, 0 },
202 &GUID_WICPixelFormat64bppRGBA
, 64, DXGI_FORMAT_R16G16B16A16_SNORM
},
203 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x6F, 0, 0, 0, 0, 0 },
204 &GUID_WICPixelFormat16bppGrayHalf
, 16, DXGI_FORMAT_R16_FLOAT
},
205 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x70, 0, 0, 0, 0, 0 },
206 &GUID_WICPixelFormatUndefined
, 0, DXGI_FORMAT_R16G16_FLOAT
},
207 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x71, 0, 0, 0, 0, 0 },
208 &GUID_WICPixelFormat64bppRGBAHalf
, 64, DXGI_FORMAT_R16G16B16A16_FLOAT
},
209 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x72, 0, 0, 0, 0, 0 },
210 &GUID_WICPixelFormat32bppGrayFloat
, 32, DXGI_FORMAT_R32_FLOAT
},
211 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x73, 0, 0, 0, 0, 0 },
212 &GUID_WICPixelFormatUndefined
, 32, DXGI_FORMAT_R32G32_FLOAT
},
213 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x74, 0, 0, 0, 0, 0 },
214 &GUID_WICPixelFormat128bppRGBAFloat
, 128, DXGI_FORMAT_R32G32B32A32_FLOAT
},
215 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0xFF,0xFF00,0xFF0000,0xFF000000 },
216 &GUID_WICPixelFormat32bppRGBA
, 32, DXGI_FORMAT_R8G8B8A8_UNORM
},
217 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0xFF,0xFF00,0xFF0000,0 },
218 &GUID_WICPixelFormat32bppRGB
, 32, DXGI_FORMAT_UNKNOWN
},
219 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0xFF0000,0xFF00,0xFF,0xFF000000 },
220 &GUID_WICPixelFormat32bppBGRA
, 32, DXGI_FORMAT_B8G8R8A8_UNORM
},
221 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0xFF0000,0xFF00,0xFF,0 },
222 &GUID_WICPixelFormat32bppBGR
, 32, DXGI_FORMAT_B8G8R8X8_UNORM
},
223 /* The red and blue masks are swapped for DXGI_FORMAT_R10G10B10A2_UNORM.
224 * For "correct" one, the RGB masks should be 0x3FF,0xFFC00,0x3FF00000.
225 * see: https://walbourn.github.io/dds-update-and-1010102-problems */
226 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0x3FF00000,0xFFC00,0x3FF,0xC0000000 },
227 &GUID_WICPixelFormat32bppR10G10B10A2
, 32, DXGI_FORMAT_R10G10B10A2_UNORM
},
228 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0x3FF,0xFFC00,0x3FF00000,0xC0000000 },
229 &GUID_WICPixelFormat32bppRGBA1010102
, 32, DXGI_FORMAT_UNKNOWN
},
230 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0xFFFF,0xFFFF0000,0,0 },
231 &GUID_WICPixelFormatUndefined
, 0, DXGI_FORMAT_R16G16_UNORM
},
232 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0xFFFFFFFF,0,0,0 },
233 &GUID_WICPixelFormat32bppGrayFloat
, 32, DXGI_FORMAT_R32_FLOAT
},
234 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 24, 0xFF0000,0x00FF00,0x0000FF,0 },
235 &GUID_WICPixelFormat24bppBGR
, 24, DXGI_FORMAT_UNKNOWN
},
236 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 24, 0x0000FF,0x00FF00,0xFF0000,0 },
237 &GUID_WICPixelFormat24bppRGB
, 24, DXGI_FORMAT_UNKNOWN
},
238 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 16, 0xF800,0x7E0,0x1F,0 },
239 &GUID_WICPixelFormat16bppBGR565
, 16, DXGI_FORMAT_B5G6R5_UNORM
},
240 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 16, 0x7C00,0x3E0,0x1F,0 },
241 &GUID_WICPixelFormat16bppBGR555
, 16, DXGI_FORMAT_UNKNOWN
},
242 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 16, 0x7C00,0x3E0,0x1F,0x8000 },
243 &GUID_WICPixelFormat16bppBGRA5551
, 16, DXGI_FORMAT_B5G5R5A1_UNORM
},
244 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 16, 0xF00,0xF0,0xF,0xF000 },
245 &GUID_WICPixelFormatUndefined
, 0, DXGI_FORMAT_B4G4R4A4_UNORM
},
246 { { sizeof(DDS_PIXELFORMAT
), DDPF_ALPHA
, 0, 8, 0,0,0,0xFF },
247 &GUID_WICPixelFormat8bppAlpha
, 8, DXGI_FORMAT_A8_UNORM
},
248 { { sizeof(DDS_PIXELFORMAT
), DDPF_LUMINANCE
, 0, 16, 0xFFFF,0,0,0 },
249 &GUID_WICPixelFormat16bppGray
, 16, DXGI_FORMAT_R16_UNORM
},
250 { { sizeof(DDS_PIXELFORMAT
), DDPF_LUMINANCE
, 0, 16, 0xFF,0,0,0xFF00 },
251 &GUID_WICPixelFormatUndefined
, 0, DXGI_FORMAT_R8G8_UNORM
},
252 { { sizeof(DDS_PIXELFORMAT
), DDPF_LUMINANCE
, 0, 8, 0xFF,0,0,0 },
253 &GUID_WICPixelFormat8bppGray
, 8, DXGI_FORMAT_R8_UNORM
},
254 { { 0 }, &GUID_WICPixelFormat8bppAlpha
, 8, DXGI_FORMAT_A8_UNORM
},
255 { { 0 }, &GUID_WICPixelFormat8bppGray
, 8, DXGI_FORMAT_R8_UNORM
},
256 { { 0 }, &GUID_WICPixelFormat16bppGray
, 16, DXGI_FORMAT_R16_UNORM
},
257 { { 0 }, &GUID_WICPixelFormat16bppGrayHalf
, 16, DXGI_FORMAT_R16_FLOAT
},
258 { { 0 }, &GUID_WICPixelFormat16bppBGR565
, 16, DXGI_FORMAT_B5G6R5_UNORM
},
259 { { 0 }, &GUID_WICPixelFormat16bppBGRA5551
, 16, DXGI_FORMAT_B5G5R5A1_UNORM
},
260 { { 0 }, &GUID_WICPixelFormat32bppGrayFloat
, 32, DXGI_FORMAT_R32_FLOAT
},
261 { { 0 }, &GUID_WICPixelFormat32bppRGBA
, 32, DXGI_FORMAT_R8G8B8A8_UNORM
},
262 { { 0 }, &GUID_WICPixelFormat32bppBGRA
, 32, DXGI_FORMAT_B8G8R8A8_UNORM
},
263 { { 0 }, &GUID_WICPixelFormat32bppBGR
, 32, DXGI_FORMAT_B8G8R8X8_UNORM
},
264 { { 0 }, &GUID_WICPixelFormat32bppR10G10B10A2
, 32, DXGI_FORMAT_R10G10B10A2_UNORM
},
265 { { 0 }, &GUID_WICPixelFormat32bppRGBE
, 32, DXGI_FORMAT_R9G9B9E5_SHAREDEXP
},
266 { { 0 }, &GUID_WICPixelFormat32bppRGBA1010102XR
, 32, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM
},
267 { { 0 }, &GUID_WICPixelFormat64bppRGBA
, 64, DXGI_FORMAT_R16G16B16A16_UNORM
},
268 { { 0 }, &GUID_WICPixelFormat64bppRGBAHalf
, 64, DXGI_FORMAT_R16G16B16A16_FLOAT
},
269 { { 0 }, &GUID_WICPixelFormat96bppRGBFloat
, 96, DXGI_FORMAT_R32G32B32_FLOAT
},
270 { { 0 }, &GUID_WICPixelFormat128bppRGBAFloat
, 128, DXGI_FORMAT_R32G32B32A32_FLOAT
},
271 { { 0 }, &GUID_WICPixelFormatUndefined
, 0, DXGI_FORMAT_UNKNOWN
}
274 static DXGI_FORMAT compressed_formats
[] = {
275 DXGI_FORMAT_BC1_TYPELESS
, DXGI_FORMAT_BC1_UNORM
, DXGI_FORMAT_BC1_UNORM_SRGB
,
276 DXGI_FORMAT_BC2_TYPELESS
, DXGI_FORMAT_BC2_UNORM
, DXGI_FORMAT_BC2_UNORM_SRGB
,
277 DXGI_FORMAT_BC3_TYPELESS
, DXGI_FORMAT_BC3_UNORM
, DXGI_FORMAT_BC3_UNORM_SRGB
,
278 DXGI_FORMAT_BC4_TYPELESS
, DXGI_FORMAT_BC4_UNORM
, DXGI_FORMAT_BC4_SNORM
,
279 DXGI_FORMAT_BC5_TYPELESS
, DXGI_FORMAT_BC5_UNORM
, DXGI_FORMAT_BC5_SNORM
,
280 DXGI_FORMAT_BC6H_TYPELESS
, DXGI_FORMAT_BC6H_UF16
, DXGI_FORMAT_BC6H_SF16
,
281 DXGI_FORMAT_BC7_TYPELESS
, DXGI_FORMAT_BC7_UNORM
, DXGI_FORMAT_BC7_UNORM_SRGB
284 static HRESULT WINAPI
DdsDecoder_Dds_GetFrame(IWICDdsDecoder
*, UINT
, UINT
, UINT
, IWICBitmapFrameDecode
**);
286 static DWORD
rgb565_to_argb(WORD color
, BYTE alpha
)
288 return MAKE_ARGB(alpha
, (GET_RGB565_R(color
) * 0xFF + 0x0F) / 0x1F,
289 (GET_RGB565_G(color
) * 0xFF + 0x1F) / 0x3F,
290 (GET_RGB565_B(color
) * 0xFF + 0x0F) / 0x1F);
293 static inline BOOL
has_extended_header(DDS_HEADER
*header
)
295 return (header
->ddspf
.flags
& DDPF_FOURCC
) &&
296 (header
->ddspf
.fourCC
== MAKEFOURCC('D', 'X', '1', '0'));
299 static WICDdsDimension
get_dimension(DDS_HEADER
*header
, DDS_HEADER_DXT10
*header_dxt10
)
302 if (header_dxt10
->miscFlag
& DDS_RESOURCE_MISC_TEXTURECUBE
) return WICDdsTextureCube
;
303 switch (header_dxt10
->resourceDimension
)
305 case DDS_DIMENSION_TEXTURE1D
: return WICDdsTexture1D
;
306 case DDS_DIMENSION_TEXTURE2D
: return WICDdsTexture2D
;
307 case DDS_DIMENSION_TEXTURE3D
: return WICDdsTexture3D
;
308 default: return WICDdsTexture2D
;
311 if (header
->caps2
& DDSCAPS2_CUBEMAP
) {
312 return WICDdsTextureCube
;
313 } else if (header
->caps2
& DDSCAPS2_VOLUME
) {
314 return WICDdsTexture3D
;
316 return WICDdsTexture2D
;
321 static struct dds_format
*get_dds_format(DDS_PIXELFORMAT
*pixel_format
)
325 for (i
= 0; i
< ARRAY_SIZE(dds_format_table
); i
++)
327 if ((pixel_format
->flags
& dds_format_table
[i
].pixel_format
.flags
) &&
328 (pixel_format
->fourCC
== dds_format_table
[i
].pixel_format
.fourCC
) &&
329 (pixel_format
->rgbBitCount
== dds_format_table
[i
].pixel_format
.rgbBitCount
) &&
330 (pixel_format
->rBitMask
== dds_format_table
[i
].pixel_format
.rBitMask
) &&
331 (pixel_format
->gBitMask
== dds_format_table
[i
].pixel_format
.gBitMask
) &&
332 (pixel_format
->bBitMask
== dds_format_table
[i
].pixel_format
.bBitMask
) &&
333 (pixel_format
->aBitMask
== dds_format_table
[i
].pixel_format
.aBitMask
))
334 return dds_format_table
+ i
;
337 return dds_format_table
+ ARRAY_SIZE(dds_format_table
) - 1;
340 static WICDdsAlphaMode
get_alpha_mode_from_fourcc(DWORD fourcc
)
344 case MAKEFOURCC('D', 'X', 'T', '1'):
345 case MAKEFOURCC('D', 'X', 'T', '2'):
346 case MAKEFOURCC('D', 'X', 'T', '4'):
347 return WICDdsAlphaModePremultiplied
;
349 return WICDdsAlphaModeUnknown
;
353 static UINT
get_bytes_per_block_from_format(DXGI_FORMAT format
)
355 /* for uncompressed format, return bytes per pixel*/
358 case DXGI_FORMAT_R8_TYPELESS
:
359 case DXGI_FORMAT_R8_UNORM
:
360 case DXGI_FORMAT_R8_UINT
:
361 case DXGI_FORMAT_R8_SNORM
:
362 case DXGI_FORMAT_R8_SINT
:
363 case DXGI_FORMAT_A8_UNORM
:
365 case DXGI_FORMAT_R8G8_TYPELESS
:
366 case DXGI_FORMAT_R8G8_UNORM
:
367 case DXGI_FORMAT_R8G8_UINT
:
368 case DXGI_FORMAT_R8G8_SNORM
:
369 case DXGI_FORMAT_R8G8_SINT
:
370 case DXGI_FORMAT_R16_TYPELESS
:
371 case DXGI_FORMAT_R16_FLOAT
:
372 case DXGI_FORMAT_D16_UNORM
:
373 case DXGI_FORMAT_R16_UNORM
:
374 case DXGI_FORMAT_R16_UINT
:
375 case DXGI_FORMAT_R16_SNORM
:
376 case DXGI_FORMAT_R16_SINT
:
377 case DXGI_FORMAT_B5G6R5_UNORM
:
378 case DXGI_FORMAT_B5G5R5A1_UNORM
:
379 case DXGI_FORMAT_B4G4R4A4_UNORM
:
381 case DXGI_FORMAT_R10G10B10A2_TYPELESS
:
382 case DXGI_FORMAT_R10G10B10A2_UNORM
:
383 case DXGI_FORMAT_R10G10B10A2_UINT
:
384 case DXGI_FORMAT_R11G11B10_FLOAT
:
385 case DXGI_FORMAT_R8G8B8A8_TYPELESS
:
386 case DXGI_FORMAT_R8G8B8A8_UNORM
:
387 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
:
388 case DXGI_FORMAT_R8G8B8A8_UINT
:
389 case DXGI_FORMAT_R8G8B8A8_SNORM
:
390 case DXGI_FORMAT_R8G8B8A8_SINT
:
391 case DXGI_FORMAT_R16G16_TYPELESS
:
392 case DXGI_FORMAT_R16G16_FLOAT
:
393 case DXGI_FORMAT_R16G16_UNORM
:
394 case DXGI_FORMAT_R16G16_UINT
:
395 case DXGI_FORMAT_R16G16_SNORM
:
396 case DXGI_FORMAT_R16G16_SINT
:
397 case DXGI_FORMAT_R32_TYPELESS
:
398 case DXGI_FORMAT_D32_FLOAT
:
399 case DXGI_FORMAT_R32_FLOAT
:
400 case DXGI_FORMAT_R32_UINT
:
401 case DXGI_FORMAT_R32_SINT
:
402 case DXGI_FORMAT_R24G8_TYPELESS
:
403 case DXGI_FORMAT_D24_UNORM_S8_UINT
:
404 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS
:
405 case DXGI_FORMAT_X24_TYPELESS_G8_UINT
:
406 case DXGI_FORMAT_R9G9B9E5_SHAREDEXP
:
407 case DXGI_FORMAT_R8G8_B8G8_UNORM
:
408 case DXGI_FORMAT_G8R8_G8B8_UNORM
:
409 case DXGI_FORMAT_B8G8R8A8_UNORM
:
410 case DXGI_FORMAT_B8G8R8X8_UNORM
:
411 case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM
:
412 case DXGI_FORMAT_B8G8R8A8_TYPELESS
:
413 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
:
414 case DXGI_FORMAT_B8G8R8X8_TYPELESS
:
415 case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB
:
417 case DXGI_FORMAT_BC1_UNORM
:
418 case DXGI_FORMAT_BC1_TYPELESS
:
419 case DXGI_FORMAT_BC1_UNORM_SRGB
:
420 case DXGI_FORMAT_BC4_TYPELESS
:
421 case DXGI_FORMAT_BC4_UNORM
:
422 case DXGI_FORMAT_BC4_SNORM
:
423 case DXGI_FORMAT_R16G16B16A16_TYPELESS
:
424 case DXGI_FORMAT_R16G16B16A16_FLOAT
:
425 case DXGI_FORMAT_R16G16B16A16_UNORM
:
426 case DXGI_FORMAT_R16G16B16A16_UINT
:
427 case DXGI_FORMAT_R16G16B16A16_SNORM
:
428 case DXGI_FORMAT_R16G16B16A16_SINT
:
429 case DXGI_FORMAT_R32G32_TYPELESS
:
430 case DXGI_FORMAT_R32G32_FLOAT
:
431 case DXGI_FORMAT_R32G32_UINT
:
432 case DXGI_FORMAT_R32G32_SINT
:
433 case DXGI_FORMAT_R32G8X24_TYPELESS
:
434 case DXGI_FORMAT_D32_FLOAT_S8X24_UINT
:
435 case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS
:
436 case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT
:
438 case DXGI_FORMAT_R32G32B32_TYPELESS
:
439 case DXGI_FORMAT_R32G32B32_FLOAT
:
440 case DXGI_FORMAT_R32G32B32_UINT
:
441 case DXGI_FORMAT_R32G32B32_SINT
:
443 case DXGI_FORMAT_BC2_UNORM
:
444 case DXGI_FORMAT_BC2_TYPELESS
:
445 case DXGI_FORMAT_BC2_UNORM_SRGB
:
446 case DXGI_FORMAT_BC3_UNORM
:
447 case DXGI_FORMAT_BC3_TYPELESS
:
448 case DXGI_FORMAT_BC3_UNORM_SRGB
:
449 case DXGI_FORMAT_BC5_TYPELESS
:
450 case DXGI_FORMAT_BC5_UNORM
:
451 case DXGI_FORMAT_BC5_SNORM
:
452 case DXGI_FORMAT_BC6H_TYPELESS
:
453 case DXGI_FORMAT_BC6H_UF16
:
454 case DXGI_FORMAT_BC6H_SF16
:
455 case DXGI_FORMAT_BC7_TYPELESS
:
456 case DXGI_FORMAT_BC7_UNORM
:
457 case DXGI_FORMAT_BC7_UNORM_SRGB
:
458 case DXGI_FORMAT_R32G32B32A32_TYPELESS
:
459 case DXGI_FORMAT_R32G32B32A32_FLOAT
:
460 case DXGI_FORMAT_R32G32B32A32_UINT
:
461 case DXGI_FORMAT_R32G32B32A32_SINT
:
464 WARN("DXGI format 0x%x is not supported in DDS decoder\n", format
);
469 static const GUID
*dxgi_format_to_wic_format(DXGI_FORMAT dxgi_format
)
472 for (i
= 0; i
< ARRAY_SIZE(dds_format_table
); i
++)
474 if (dds_format_table
[i
].pixel_format
.size
== 0 &&
475 dds_format_table
[i
].dxgi_format
== dxgi_format
)
476 return dds_format_table
[i
].wic_format
;
478 return &GUID_WICPixelFormatUndefined
;
481 static BOOL
is_compressed(DXGI_FORMAT format
)
485 for (i
= 0; i
< ARRAY_SIZE(compressed_formats
); i
++)
487 if (format
== compressed_formats
[i
]) return TRUE
;
492 static void get_dds_info(dds_info
* info
, DDS_HEADER
*header
, DDS_HEADER_DXT10
*header_dxt10
)
496 struct dds_format
*format_info
;
498 info
->width
= header
->width
;
499 info
->height
= header
->height
;
501 info
->mip_levels
= 1;
502 info
->array_size
= 1;
503 if (header
->depth
) info
->depth
= header
->depth
;
504 if (header
->mipMapCount
) info
->mip_levels
= header
->mipMapCount
;
506 if (has_extended_header(header
)) {
507 if (header_dxt10
->arraySize
) info
->array_size
= header_dxt10
->arraySize
;
508 info
->format
= header_dxt10
->dxgiFormat
;
509 info
->dimension
= get_dimension(NULL
, header_dxt10
);
510 info
->alpha_mode
= header_dxt10
->miscFlags2
& 0x00000008;
511 info
->data_offset
= sizeof(DWORD
) + sizeof(*header
) + sizeof(*header_dxt10
);
512 if (is_compressed(info
->format
)) {
513 info
->pixel_format
= (info
->alpha_mode
== WICDdsAlphaModePremultiplied
) ?
514 &GUID_WICPixelFormat32bppPBGRA
: &GUID_WICPixelFormat32bppBGRA
;
515 info
->pixel_format_bpp
= 32;
517 info
->pixel_format
= dxgi_format_to_wic_format(info
->format
);
518 info
->pixel_format_bpp
= get_bytes_per_block_from_format(info
->format
) * 8;
521 format_info
= get_dds_format(&header
->ddspf
);
522 info
->format
= format_info
->dxgi_format
;
523 info
->dimension
= get_dimension(header
, NULL
);
524 info
->alpha_mode
= get_alpha_mode_from_fourcc(header
->ddspf
.fourCC
);
525 info
->data_offset
= sizeof(DWORD
) + sizeof(*header
);
526 info
->pixel_format
= format_info
->wic_format
;
527 info
->pixel_format_bpp
= format_info
->wic_format_bpp
;
530 if (header
->ddspf
.flags
& (DDPF_RGB
| DDPF_ALPHA
| DDPF_LUMINANCE
)) {
531 info
->bytes_per_block
= header
->ddspf
.rgbBitCount
/ 8;
533 info
->bytes_per_block
= get_bytes_per_block_from_format(info
->format
);
536 /* get frame count */
538 if (info
->depth
== 1) {
539 info
->frame_count
= info
->array_size
* info
->mip_levels
;
541 info
->frame_count
= 0;
543 for (i
= 0; i
< info
->mip_levels
; i
++)
545 info
->frame_count
+= depth
;
546 if (depth
> 1) depth
/= 2;
548 info
->frame_count
*= info
->array_size
;
550 if (info
->dimension
== WICDdsTextureCube
) info
->frame_count
*= 6;
553 static void decode_block(const BYTE
*block_data
, UINT block_count
, DXGI_FORMAT format
,
554 UINT width
, UINT height
, DWORD
*buffer
)
556 const BYTE
*block
, *color_indices
, *alpha_indices
, *alpha_table
;
557 int i
, j
, x
, y
, block_x
, block_y
, color_index
, alpha_index
;
558 int block_size
, color_offset
, color_indices_offset
;
559 WORD color
[4], color_value
= 0;
560 BYTE alpha
[8], alpha_value
= 0;
562 if (format
== DXGI_FORMAT_BC1_UNORM
) {
565 color_indices_offset
= 4;
569 color_indices_offset
= 12;
574 for (i
= 0; i
< block_count
; i
++)
576 block
= block_data
+ i
* block_size
;
578 color
[0] = *((WORD
*)(block
+ color_offset
));
579 color
[1] = *((WORD
*)(block
+ color_offset
+ 2));
580 color
[2] = MAKE_RGB565(((GET_RGB565_R(color
[0]) * 2 + GET_RGB565_R(color
[1]) + 1) / 3),
581 ((GET_RGB565_G(color
[0]) * 2 + GET_RGB565_G(color
[1]) + 1) / 3),
582 ((GET_RGB565_B(color
[0]) * 2 + GET_RGB565_B(color
[1]) + 1) / 3));
583 color
[3] = MAKE_RGB565(((GET_RGB565_R(color
[0]) + GET_RGB565_R(color
[1]) * 2 + 1) / 3),
584 ((GET_RGB565_G(color
[0]) + GET_RGB565_G(color
[1]) * 2 + 1) / 3),
585 ((GET_RGB565_B(color
[0]) + GET_RGB565_B(color
[1]) * 2 + 1) / 3));
589 case DXGI_FORMAT_BC1_UNORM
:
590 if (color
[0] <= color
[1]) {
591 color
[2] = MAKE_RGB565(((GET_RGB565_R(color
[0]) + GET_RGB565_R(color
[1]) + 1) / 2),
592 ((GET_RGB565_G(color
[0]) + GET_RGB565_G(color
[1]) + 1) / 2),
593 ((GET_RGB565_B(color
[0]) + GET_RGB565_B(color
[1]) + 1) / 2));
597 case DXGI_FORMAT_BC2_UNORM
:
600 case DXGI_FORMAT_BC3_UNORM
:
602 alpha
[1] = *(block
+ 1);
603 if (alpha
[0] > alpha
[1]) {
604 for (j
= 2; j
< 8; j
++)
606 alpha
[j
] = (BYTE
)((alpha
[0] * (8 - j
) + alpha
[1] * (j
- 1) + 3) / 7);
609 for (j
= 2; j
< 6; j
++)
611 alpha
[j
] = (BYTE
)((alpha
[0] * (6 - j
) + alpha
[1] * (j
- 1) + 2) / 5);
616 alpha_indices
= block
+ 2;
622 color_indices
= block
+ color_indices_offset
;
623 for (j
= 0; j
< 16; j
++)
627 if (x
>= width
|| y
>= height
) continue;
629 color_index
= (color_indices
[j
/ 4] >> ((j
% 4) * 2)) & 0x3;
630 color_value
= color
[color_index
];
634 case DXGI_FORMAT_BC1_UNORM
:
635 if ((color
[0] <= color
[1]) && !color_value
) {
642 case DXGI_FORMAT_BC2_UNORM
:
643 alpha_value
= (alpha_table
[j
/ 2] >> (j
% 2) * 4) & 0xF;
644 alpha_value
= (BYTE
)((alpha_value
* 0xFF + 0x7)/ 0xF);
646 case DXGI_FORMAT_BC3_UNORM
:
647 alpha_index
= (*((DWORD
*)(alpha_indices
+ (j
/ 8) * 3)) >> ((j
% 8) * 3)) & 0x7;
648 alpha_value
= alpha
[alpha_index
];
653 buffer
[x
+ y
* width
] = rgb565_to_argb(color_value
, alpha_value
);
656 block_x
+= DDS_BLOCK_WIDTH
;
657 if (block_x
>= width
) {
659 block_y
+= DDS_BLOCK_HEIGHT
;
664 static inline DdsDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
666 return CONTAINING_RECORD(iface
, DdsDecoder
, IWICBitmapDecoder_iface
);
669 static inline DdsDecoder
*impl_from_IWICDdsDecoder(IWICDdsDecoder
*iface
)
671 return CONTAINING_RECORD(iface
, DdsDecoder
, IWICDdsDecoder_iface
);
674 static inline DdsDecoder
*impl_from_IWICWineDecoder(IWICWineDecoder
*iface
)
676 return CONTAINING_RECORD(iface
, DdsDecoder
, IWICWineDecoder_iface
);
679 static inline DdsFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
681 return CONTAINING_RECORD(iface
, DdsFrameDecode
, IWICBitmapFrameDecode_iface
);
684 static inline DdsFrameDecode
*impl_from_IWICDdsFrameDecode(IWICDdsFrameDecode
*iface
)
686 return CONTAINING_RECORD(iface
, DdsFrameDecode
, IWICDdsFrameDecode_iface
);
689 static HRESULT WINAPI
DdsFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
692 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
693 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
695 if (!ppv
) return E_INVALIDARG
;
697 if (IsEqualIID(&IID_IUnknown
, iid
) ||
698 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
699 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
)) {
700 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
701 } else if (IsEqualGUID(&IID_IWICDdsFrameDecode
, iid
)) {
702 *ppv
= &This
->IWICDdsFrameDecode_iface
;
705 return E_NOINTERFACE
;
708 IUnknown_AddRef((IUnknown
*)*ppv
);
712 static ULONG WINAPI
DdsFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
714 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
715 ULONG ref
= InterlockedIncrement(&This
->ref
);
717 TRACE("(%p) refcount=%u\n", iface
, ref
);
722 static ULONG WINAPI
DdsFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
724 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
725 ULONG ref
= InterlockedDecrement(&This
->ref
);
727 TRACE("(%p) refcount=%u\n", iface
, ref
);
730 if (This
->pixel_data
!= This
->block_data
) HeapFree(GetProcessHeap(), 0, This
->pixel_data
);
731 HeapFree(GetProcessHeap(), 0, This
->block_data
);
732 HeapFree(GetProcessHeap(), 0, This
);
738 static HRESULT WINAPI
DdsFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
739 UINT
*puiWidth
, UINT
*puiHeight
)
741 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
743 if (!puiWidth
|| !puiHeight
) return E_INVALIDARG
;
745 *puiWidth
= This
->info
.width
;
746 *puiHeight
= This
->info
.height
;
748 TRACE("(%p) -> (%d,%d)\n", iface
, *puiWidth
, *puiHeight
);
753 static HRESULT WINAPI
DdsFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
754 WICPixelFormatGUID
*pPixelFormat
)
756 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
758 if (!pPixelFormat
) return E_INVALIDARG
;
760 *pPixelFormat
= *This
->info
.pixel_format
;
762 TRACE("(%p) -> %s\n", iface
, debugstr_guid(pPixelFormat
));
767 static HRESULT WINAPI
DdsFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
768 double *pDpiX
, double *pDpiY
)
770 FIXME("(%p,%p,%p): stub.\n", iface
, pDpiX
, pDpiY
);
775 static HRESULT WINAPI
DdsFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
776 IWICPalette
*pIPalette
)
778 FIXME("(%p,%p): stub.\n", iface
, pIPalette
);
783 static HRESULT WINAPI
DdsFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
784 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
786 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
787 UINT bpp
, frame_stride
, frame_size
;
788 INT x
, y
, width
, height
;
791 TRACE("(%p,%s,%u,%u,%p)\n", iface
, debug_wic_rect(prc
), cbStride
, cbBufferSize
, pbBuffer
);
793 if (!pbBuffer
) return E_INVALIDARG
;
795 bpp
= This
->info
.pixel_format_bpp
;
796 if (!bpp
) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
798 frame_stride
= This
->info
.width
* bpp
/ 8;
799 frame_size
= frame_stride
* This
->info
.height
;
801 if (cbStride
< frame_stride
) return E_INVALIDARG
;
802 if (cbBufferSize
< frame_size
) return WINCODEC_ERR_INSUFFICIENTBUFFER
;
807 height
= prc
->Height
;
808 if (x
< 0 || y
< 0 || width
<= 0 || height
<= 0 ||
809 x
+ width
> This
->info
.width
||
810 y
+ height
> This
->info
.height
) {
813 if (cbStride
< width
* bpp
/ 8) return E_INVALIDARG
;
814 if (cbBufferSize
< cbStride
* height
) return WINCODEC_ERR_INSUFFICIENTBUFFER
;
817 EnterCriticalSection(&This
->lock
);
819 if (!This
->pixel_data
) {
820 if (is_compressed(This
->info
.format
)) {
821 This
->pixel_data
= HeapAlloc(GetProcessHeap(), 0, frame_size
);
822 if (!This
->pixel_data
) {
826 decode_block(This
->block_data
, This
->info
.width_in_blocks
* This
->info
.height_in_blocks
, This
->info
.format
,
827 This
->info
.width
, This
->info
.height
, (DWORD
*)This
->pixel_data
);
829 This
->pixel_data
= This
->block_data
;
833 hr
= copy_pixels(bpp
, This
->pixel_data
, This
->info
.width
, This
->info
.height
, frame_stride
,
834 prc
, cbStride
, cbBufferSize
, pbBuffer
);
837 LeaveCriticalSection(&This
->lock
);
842 static HRESULT WINAPI
DdsFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
843 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
845 FIXME("(%p,%p): stub.\n", iface
, ppIMetadataQueryReader
);
850 static HRESULT WINAPI
DdsFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
851 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
853 FIXME("(%p,%u,%p,%p): stub.\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
858 static HRESULT WINAPI
DdsFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
859 IWICBitmapSource
**ppIThumbnail
)
861 FIXME("(%p,%p): stub.\n", iface
, ppIThumbnail
);
866 static const IWICBitmapFrameDecodeVtbl DdsFrameDecode_Vtbl
= {
867 DdsFrameDecode_QueryInterface
,
868 DdsFrameDecode_AddRef
,
869 DdsFrameDecode_Release
,
870 DdsFrameDecode_GetSize
,
871 DdsFrameDecode_GetPixelFormat
,
872 DdsFrameDecode_GetResolution
,
873 DdsFrameDecode_CopyPalette
,
874 DdsFrameDecode_CopyPixels
,
875 DdsFrameDecode_GetMetadataQueryReader
,
876 DdsFrameDecode_GetColorContexts
,
877 DdsFrameDecode_GetThumbnail
880 static HRESULT WINAPI
DdsFrameDecode_Dds_QueryInterface(IWICDdsFrameDecode
*iface
,
881 REFIID iid
, void **ppv
)
883 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
884 return DdsFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
887 static ULONG WINAPI
DdsFrameDecode_Dds_AddRef(IWICDdsFrameDecode
*iface
)
889 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
890 return DdsFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
893 static ULONG WINAPI
DdsFrameDecode_Dds_Release(IWICDdsFrameDecode
*iface
)
895 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
896 return DdsFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
899 static HRESULT WINAPI
DdsFrameDecode_Dds_GetSizeInBlocks(IWICDdsFrameDecode
*iface
,
900 UINT
*widthInBlocks
, UINT
*heightInBlocks
)
902 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
904 if (!widthInBlocks
|| !heightInBlocks
) return E_INVALIDARG
;
906 *widthInBlocks
= This
->info
.width_in_blocks
;
907 *heightInBlocks
= This
->info
.height_in_blocks
;
909 TRACE("(%p,%p,%p) -> (%d,%d)\n", iface
, widthInBlocks
, heightInBlocks
, *widthInBlocks
, *heightInBlocks
);
914 static HRESULT WINAPI
DdsFrameDecode_Dds_GetFormatInfo(IWICDdsFrameDecode
*iface
,
915 WICDdsFormatInfo
*formatInfo
)
917 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
919 if (!formatInfo
) return E_INVALIDARG
;
921 formatInfo
->DxgiFormat
= This
->info
.format
;
922 formatInfo
->BytesPerBlock
= This
->info
.bytes_per_block
;
923 formatInfo
->BlockWidth
= This
->info
.block_width
;
924 formatInfo
->BlockHeight
= This
->info
.block_height
;
926 TRACE("(%p,%p) -> (0x%x,%d,%d,%d)\n", iface
, formatInfo
,
927 formatInfo
->DxgiFormat
, formatInfo
->BytesPerBlock
, formatInfo
->BlockWidth
, formatInfo
->BlockHeight
);
932 static HRESULT WINAPI
DdsFrameDecode_Dds_CopyBlocks(IWICDdsFrameDecode
*iface
,
933 const WICRect
*boundsInBlocks
, UINT stride
, UINT bufferSize
,
936 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
937 int x
, y
, width
, height
;
938 UINT bytes_per_block
, frame_stride
, frame_size
;
940 TRACE("(%p,%p,%u,%u,%p)\n", iface
, boundsInBlocks
, stride
, bufferSize
, buffer
);
942 if (!buffer
) return E_INVALIDARG
;
944 bytes_per_block
= This
->info
.bytes_per_block
;
945 frame_stride
= This
->info
.width_in_blocks
* bytes_per_block
;
946 frame_size
= frame_stride
* This
->info
.height_in_blocks
;
948 if (!boundsInBlocks
) {
949 if (stride
< frame_stride
) return E_INVALIDARG
;
950 if (bufferSize
< frame_size
) return E_INVALIDARG
;
952 x
= boundsInBlocks
->X
;
953 y
= boundsInBlocks
->Y
;
954 width
= boundsInBlocks
->Width
;
955 height
= boundsInBlocks
->Height
;
956 if (x
< 0 || y
< 0 || width
<= 0 || height
<= 0 ||
957 x
+ width
> This
->info
.width_in_blocks
||
958 y
+ height
> This
->info
.height_in_blocks
) {
961 if (stride
< width
* bytes_per_block
) return E_INVALIDARG
;
962 if (bufferSize
< stride
* height
) return E_INVALIDARG
;
965 return copy_pixels(This
->info
.bytes_per_block
* 8, This
->block_data
, This
->info
.width_in_blocks
,
966 This
->info
.height_in_blocks
, frame_stride
, boundsInBlocks
, stride
, bufferSize
, buffer
);
969 static const IWICDdsFrameDecodeVtbl DdsFrameDecode_Dds_Vtbl
= {
970 DdsFrameDecode_Dds_QueryInterface
,
971 DdsFrameDecode_Dds_AddRef
,
972 DdsFrameDecode_Dds_Release
,
973 DdsFrameDecode_Dds_GetSizeInBlocks
,
974 DdsFrameDecode_Dds_GetFormatInfo
,
975 DdsFrameDecode_Dds_CopyBlocks
978 static HRESULT
DdsFrameDecode_CreateInstance(DdsFrameDecode
**frame_decode
)
980 DdsFrameDecode
*result
;
982 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(*result
));
983 if (!result
) return E_OUTOFMEMORY
;
985 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &DdsFrameDecode_Vtbl
;
986 result
->IWICDdsFrameDecode_iface
.lpVtbl
= &DdsFrameDecode_Dds_Vtbl
;
988 InitializeCriticalSection(&result
->lock
);
989 result
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DdsFrameDecode.lock");
991 *frame_decode
= result
;
995 static HRESULT WINAPI
DdsDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
998 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
999 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1001 if (!ppv
) return E_INVALIDARG
;
1003 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1004 IsEqualIID(&IID_IWICBitmapDecoder
, iid
)) {
1005 *ppv
= &This
->IWICBitmapDecoder_iface
;
1006 } else if (IsEqualIID(&IID_IWICDdsDecoder
, iid
)) {
1007 *ppv
= &This
->IWICDdsDecoder_iface
;
1008 } else if (IsEqualIID(&IID_IWICWineDecoder
, iid
)) {
1009 *ppv
= &This
->IWICWineDecoder_iface
;
1012 return E_NOINTERFACE
;
1015 IUnknown_AddRef((IUnknown
*)*ppv
);
1019 static ULONG WINAPI
DdsDecoder_AddRef(IWICBitmapDecoder
*iface
)
1021 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1022 ULONG ref
= InterlockedIncrement(&This
->ref
);
1024 TRACE("(%p) refcount=%u\n", iface
, ref
);
1029 static ULONG WINAPI
DdsDecoder_Release(IWICBitmapDecoder
*iface
)
1031 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1032 ULONG ref
= InterlockedDecrement(&This
->ref
);
1034 TRACE("(%p) refcount=%u\n", iface
, ref
);
1038 This
->lock
.DebugInfo
->Spare
[0] = 0;
1039 DeleteCriticalSection(&This
->lock
);
1040 if (This
->stream
) IStream_Release(This
->stream
);
1041 HeapFree(GetProcessHeap(), 0, This
);
1047 static HRESULT WINAPI
DdsDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
1050 FIXME("(%p,%p,%p): stub.\n", iface
, stream
, capability
);
1055 static HRESULT WINAPI
DdsDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1056 WICDecodeOptions cacheOptions
)
1058 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1061 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
1063 EnterCriticalSection(&This
->lock
);
1065 hr
= IWICWineDecoder_Initialize(&This
->IWICWineDecoder_iface
, pIStream
, cacheOptions
);
1066 if (FAILED(hr
)) goto end
;
1068 if (This
->info
.dimension
== WICDdsTextureCube
||
1069 (This
->info
.format
!= DXGI_FORMAT_BC1_UNORM
&&
1070 This
->info
.format
!= DXGI_FORMAT_BC2_UNORM
&&
1071 This
->info
.format
!= DXGI_FORMAT_BC3_UNORM
)) {
1072 IStream_Release(pIStream
);
1073 This
->stream
= NULL
;
1074 This
->initialized
= FALSE
;
1075 hr
= WINCODEC_ERR_BADHEADER
;
1079 LeaveCriticalSection(&This
->lock
);
1084 static HRESULT WINAPI
DdsDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
1085 GUID
*pguidContainerFormat
)
1087 TRACE("(%p,%p)\n", iface
, pguidContainerFormat
);
1089 memcpy(pguidContainerFormat
, &GUID_ContainerFormatDds
, sizeof(GUID
));
1094 static HRESULT WINAPI
DdsDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
1095 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
1097 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
1099 return get_decoder_info(&CLSID_WICDdsDecoder
, ppIDecoderInfo
);
1102 static HRESULT WINAPI
DdsDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
1103 IWICPalette
*pIPalette
)
1105 TRACE("(%p,%p)\n", iface
, pIPalette
);
1107 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
1110 static HRESULT WINAPI
DdsDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1111 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1113 if (!ppIMetadataQueryReader
) return E_INVALIDARG
;
1115 FIXME("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1120 static HRESULT WINAPI
DdsDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1121 IWICBitmapSource
**ppIBitmapSource
)
1123 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1125 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1128 static HRESULT WINAPI
DdsDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1129 UINT cCount
, IWICColorContext
**ppDdslorContexts
, UINT
*pcActualCount
)
1131 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppDdslorContexts
, pcActualCount
);
1133 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1136 static HRESULT WINAPI
DdsDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1137 IWICBitmapSource
**ppIThumbnail
)
1139 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1141 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1144 static HRESULT WINAPI
DdsDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1147 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1149 if (!pCount
) return E_INVALIDARG
;
1150 if (!This
->initialized
) return WINCODEC_ERR_WRONGSTATE
;
1152 EnterCriticalSection(&This
->lock
);
1154 *pCount
= This
->info
.frame_count
;
1156 LeaveCriticalSection(&This
->lock
);
1158 TRACE("(%p) -> %d\n", iface
, *pCount
);
1163 static HRESULT WINAPI
DdsDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1164 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1166 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1167 UINT frame_per_texture
, array_index
, mip_level
, slice_index
, depth
;
1169 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
1171 if (!ppIBitmapFrame
) return E_INVALIDARG
;
1173 EnterCriticalSection(&This
->lock
);
1175 if (!This
->initialized
) {
1176 LeaveCriticalSection(&This
->lock
);
1177 return WINCODEC_ERR_WRONGSTATE
;
1180 if (This
->info
.dimension
== WICDdsTextureCube
) {
1181 frame_per_texture
= This
->info
.mip_levels
;
1183 frame_per_texture
= This
->info
.frame_count
/ This
->info
.array_size
;
1185 array_index
= index
/ frame_per_texture
;
1186 slice_index
= index
% frame_per_texture
;
1187 depth
= This
->info
.depth
;
1189 while (slice_index
>= depth
)
1191 slice_index
-= depth
;
1193 if (depth
> 1) depth
/= 2;
1196 LeaveCriticalSection(&This
->lock
);
1198 return DdsDecoder_Dds_GetFrame(&This
->IWICDdsDecoder_iface
, array_index
, mip_level
, slice_index
, ppIBitmapFrame
);
1201 static const IWICBitmapDecoderVtbl DdsDecoder_Vtbl
= {
1202 DdsDecoder_QueryInterface
,
1205 DdsDecoder_QueryCapability
,
1206 DdsDecoder_Initialize
,
1207 DdsDecoder_GetContainerFormat
,
1208 DdsDecoder_GetDecoderInfo
,
1209 DdsDecoder_CopyPalette
,
1210 DdsDecoder_GetMetadataQueryReader
,
1211 DdsDecoder_GetPreview
,
1212 DdsDecoder_GetColorContexts
,
1213 DdsDecoder_GetThumbnail
,
1214 DdsDecoder_GetFrameCount
,
1218 static HRESULT WINAPI
DdsDecoder_Dds_QueryInterface(IWICDdsDecoder
*iface
,
1219 REFIID iid
, void **ppv
)
1221 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
1222 return DdsDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1225 static ULONG WINAPI
DdsDecoder_Dds_AddRef(IWICDdsDecoder
*iface
)
1227 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
1228 return DdsDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
1231 static ULONG WINAPI
DdsDecoder_Dds_Release(IWICDdsDecoder
*iface
)
1233 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
1234 return DdsDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1237 static HRESULT WINAPI
DdsDecoder_Dds_GetParameters(IWICDdsDecoder
*iface
,
1238 WICDdsParameters
*parameters
)
1240 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
1243 if (!parameters
) return E_INVALIDARG
;
1245 EnterCriticalSection(&This
->lock
);
1247 if (!This
->initialized
) {
1248 hr
= WINCODEC_ERR_WRONGSTATE
;
1252 parameters
->Width
= This
->info
.width
;
1253 parameters
->Height
= This
->info
.height
;
1254 parameters
->Depth
= This
->info
.depth
;
1255 parameters
->MipLevels
= This
->info
.mip_levels
;
1256 parameters
->ArraySize
= This
->info
.array_size
;
1257 parameters
->DxgiFormat
= This
->info
.format
;
1258 parameters
->Dimension
= This
->info
.dimension
;
1259 parameters
->AlphaMode
= This
->info
.alpha_mode
;
1261 TRACE("(%p) -> (%dx%d depth=%d mipLevels=%d arraySize=%d dxgiFormat=0x%x dimension=0x%x alphaMode=0x%x)\n",
1262 iface
, parameters
->Width
, parameters
->Height
, parameters
->Depth
, parameters
->MipLevels
,
1263 parameters
->ArraySize
, parameters
->DxgiFormat
, parameters
->Dimension
, parameters
->AlphaMode
);
1268 LeaveCriticalSection(&This
->lock
);
1273 static HRESULT WINAPI
DdsDecoder_Dds_GetFrame(IWICDdsDecoder
*iface
,
1274 UINT arrayIndex
, UINT mipLevel
, UINT sliceIndex
,
1275 IWICBitmapFrameDecode
**bitmapFrame
)
1277 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
1280 UINT width
, height
, depth
, block_width
, block_height
, width_in_blocks
, height_in_blocks
, size
;
1281 UINT frame_width
= 0, frame_height
= 0, frame_width_in_blocks
= 0, frame_height_in_blocks
= 0, frame_size
= 0;
1282 UINT bytes_per_block
, bytesread
, i
;
1283 DdsFrameDecode
*frame_decode
= NULL
;
1285 TRACE("(%p,%u,%u,%u,%p)\n", iface
, arrayIndex
, mipLevel
, sliceIndex
, bitmapFrame
);
1287 if (!bitmapFrame
) return E_INVALIDARG
;
1289 EnterCriticalSection(&This
->lock
);
1291 if (!This
->initialized
) {
1292 hr
= WINCODEC_ERR_WRONGSTATE
;
1296 if ((arrayIndex
>= This
->info
.array_size
&& This
->info
.dimension
!= WICDdsTextureCube
) ||
1297 (arrayIndex
>= This
->info
.array_size
* 6) ||
1298 (mipLevel
>= This
->info
.mip_levels
) ||
1299 (sliceIndex
>= This
->info
.depth
)) {
1304 if (is_compressed(This
->info
.format
)) {
1305 block_width
= DDS_BLOCK_WIDTH
;
1306 block_height
= DDS_BLOCK_HEIGHT
;
1311 bytes_per_block
= This
->info
.bytes_per_block
;
1312 seek
.QuadPart
= This
->info
.data_offset
;
1314 width
= This
->info
.width
;
1315 height
= This
->info
.height
;
1316 depth
= This
->info
.depth
;
1317 for (i
= 0; i
< This
->info
.mip_levels
; i
++)
1319 width_in_blocks
= (width
+ block_width
- 1) / block_width
;
1320 height_in_blocks
= (height
+ block_height
- 1) / block_height
;
1321 size
= width_in_blocks
* height_in_blocks
* bytes_per_block
;
1324 seek
.QuadPart
+= size
* depth
;
1325 } else if (i
== mipLevel
){
1326 seek
.QuadPart
+= size
* sliceIndex
;
1327 frame_width
= width
;
1328 frame_height
= height
;
1329 frame_width_in_blocks
= width_in_blocks
;
1330 frame_height_in_blocks
= height_in_blocks
;
1331 frame_size
= frame_width_in_blocks
* frame_height_in_blocks
* bytes_per_block
;
1332 if (arrayIndex
== 0) break;
1334 seek
.QuadPart
+= arrayIndex
* size
* depth
;
1336 if (width
> 1) width
/= 2;
1337 if (height
> 1) height
/= 2;
1338 if (depth
> 1) depth
/= 2;
1341 hr
= DdsFrameDecode_CreateInstance(&frame_decode
);
1342 if (hr
!= S_OK
) goto end
;
1343 frame_decode
->info
.width
= frame_width
;
1344 frame_decode
->info
.height
= frame_height
;
1345 frame_decode
->info
.format
= This
->info
.format
;
1346 frame_decode
->info
.bytes_per_block
= bytes_per_block
;
1347 frame_decode
->info
.block_width
= block_width
;
1348 frame_decode
->info
.block_height
= block_height
;
1349 frame_decode
->info
.width_in_blocks
= frame_width_in_blocks
;
1350 frame_decode
->info
.height_in_blocks
= frame_height_in_blocks
;
1351 frame_decode
->info
.pixel_format
= This
->info
.pixel_format
;
1352 frame_decode
->info
.pixel_format_bpp
= This
->info
.pixel_format_bpp
;
1353 frame_decode
->block_data
= HeapAlloc(GetProcessHeap(), 0, frame_size
);
1354 frame_decode
->pixel_data
= NULL
;
1355 hr
= IStream_Seek(This
->stream
, seek
, SEEK_SET
, NULL
);
1356 if (hr
!= S_OK
) goto end
;
1357 hr
= IStream_Read(This
->stream
, frame_decode
->block_data
, frame_size
, &bytesread
);
1358 if (hr
!= S_OK
|| bytesread
!= frame_size
) {
1359 hr
= WINCODEC_ERR_STREAMREAD
;
1362 *bitmapFrame
= &frame_decode
->IWICBitmapFrameDecode_iface
;
1367 LeaveCriticalSection(&This
->lock
);
1369 if (hr
!= S_OK
&& frame_decode
) DdsFrameDecode_Release(&frame_decode
->IWICBitmapFrameDecode_iface
);
1374 static const IWICDdsDecoderVtbl DdsDecoder_Dds_Vtbl
= {
1375 DdsDecoder_Dds_QueryInterface
,
1376 DdsDecoder_Dds_AddRef
,
1377 DdsDecoder_Dds_Release
,
1378 DdsDecoder_Dds_GetParameters
,
1379 DdsDecoder_Dds_GetFrame
1382 static HRESULT WINAPI
DdsDecoder_Wine_QueryInterface(IWICWineDecoder
*iface
, REFIID iid
, void **ppv
)
1384 DdsDecoder
*This
= impl_from_IWICWineDecoder(iface
);
1385 return DdsDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1388 static ULONG WINAPI
DdsDecoder_Wine_AddRef(IWICWineDecoder
*iface
)
1390 DdsDecoder
*This
= impl_from_IWICWineDecoder(iface
);
1391 return DdsDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
1394 static ULONG WINAPI
DdsDecoder_Wine_Release(IWICWineDecoder
*iface
)
1396 DdsDecoder
*This
= impl_from_IWICWineDecoder(iface
);
1397 return DdsDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1400 static HRESULT WINAPI
DdsDecoder_Wine_Initialize(IWICWineDecoder
*iface
, IStream
*stream
, WICDecodeOptions options
)
1402 DdsDecoder
*This
= impl_from_IWICWineDecoder(iface
);
1403 DDS_HEADER_DXT10 header_dxt10
;
1410 TRACE("(This %p, stream %p, options %#x)\n", iface
, stream
, options
);
1412 EnterCriticalSection(&This
->lock
);
1414 if (This
->initialized
) {
1415 hr
= WINCODEC_ERR_WRONGSTATE
;
1420 hr
= IStream_Seek(stream
, seek
, SEEK_SET
, NULL
);
1421 if (FAILED(hr
)) goto end
;
1423 hr
= IStream_Read(stream
, &magic
, sizeof(magic
), &bytesread
);
1424 if (FAILED(hr
)) goto end
;
1425 if (bytesread
!= sizeof(magic
)) {
1426 hr
= WINCODEC_ERR_STREAMREAD
;
1429 if (magic
!= DDS_MAGIC
) {
1430 hr
= WINCODEC_ERR_UNKNOWNIMAGEFORMAT
;
1434 hr
= IStream_Read(stream
, &header
, sizeof(header
), &bytesread
);
1435 if (FAILED(hr
)) goto end
;
1436 if (bytesread
!= sizeof(header
)) {
1437 hr
= WINCODEC_ERR_STREAMREAD
;
1440 if (header
.size
!= sizeof(header
)) {
1441 hr
= WINCODEC_ERR_BADHEADER
;
1445 if (has_extended_header(&header
)) {
1446 hr
= IStream_Read(stream
, &header_dxt10
, sizeof(header_dxt10
), &bytesread
);
1447 if (FAILED(hr
)) goto end
;
1448 if (bytesread
!= sizeof(header_dxt10
)) {
1449 hr
= WINCODEC_ERR_STREAMREAD
;
1454 get_dds_info(&This
->info
, &header
, &header_dxt10
);
1456 This
->initialized
= TRUE
;
1457 This
->stream
= stream
;
1458 IStream_AddRef(stream
);
1461 LeaveCriticalSection(&This
->lock
);
1466 static const IWICWineDecoderVtbl DdsDecoder_Wine_Vtbl
= {
1467 DdsDecoder_Wine_QueryInterface
,
1468 DdsDecoder_Wine_AddRef
,
1469 DdsDecoder_Wine_Release
,
1470 DdsDecoder_Wine_Initialize
1473 HRESULT
DdsDecoder_CreateInstance(REFIID iid
, void** ppv
)
1478 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1482 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(DdsDecoder
));
1483 if (!This
) return E_OUTOFMEMORY
;
1485 This
->IWICBitmapDecoder_iface
.lpVtbl
= &DdsDecoder_Vtbl
;
1486 This
->IWICDdsDecoder_iface
.lpVtbl
= &DdsDecoder_Dds_Vtbl
;
1487 This
->IWICWineDecoder_iface
.lpVtbl
= &DdsDecoder_Wine_Vtbl
;
1489 This
->initialized
= FALSE
;
1490 This
->stream
= NULL
;
1491 InitializeCriticalSection(&This
->lock
);
1492 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DdsDecoder.lock");
1494 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1495 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);