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 DDPF_ALPHAPIXELS 0x00000001
54 #define DDPF_ALPHA 0x00000002
55 #define DDPF_FOURCC 0x00000004
56 #define DDPF_PALETTEINDEXED8 0x00000020
57 #define DDPF_RGB 0x00000040
58 #define DDPF_LUMINANCE 0x00020000
59 #define DDPF_BUMPDUDV 0x00080000
61 #define DDSCAPS2_CUBEMAP 0x00000200
62 #define DDSCAPS2_VOLUME 0x00200000
64 #define DDS_DIMENSION_TEXTURE1D 2
65 #define DDS_DIMENSION_TEXTURE2D 3
66 #define DDS_DIMENSION_TEXTURE3D 4
68 #define DDS_RESOURCE_MISC_TEXTURECUBE 0x00000004
70 #define DDS_BLOCK_WIDTH 4
71 #define DDS_BLOCK_HEIGHT 4
89 DWORD pitchOrLinearSize
;
93 DDS_PIXELFORMAT ddspf
;
103 DWORD resourceDimension
;
109 typedef struct dds_info
{
117 UINT bytes_per_block
; /* for uncompressed format, this means bytes per pixel*/
119 WICDdsDimension dimension
;
120 WICDdsAlphaMode alpha_mode
;
121 const GUID
*pixel_format
;
124 typedef struct dds_frame_info
{
128 UINT bytes_per_block
; /* for uncompressed format, this means bytes per pixel*/
131 UINT width_in_blocks
;
132 UINT height_in_blocks
;
133 const GUID
*pixel_format
;
134 UINT pixel_format_bpp
;
137 typedef struct DdsDecoder
{
138 IWICBitmapDecoder IWICBitmapDecoder_iface
;
139 IWICDdsDecoder IWICDdsDecoder_iface
;
140 IWICWineDecoder IWICWineDecoder_iface
;
144 CRITICAL_SECTION lock
;
148 typedef struct DdsFrameDecode
{
149 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
150 IWICDdsFrameDecode IWICDdsFrameDecode_iface
;
154 CRITICAL_SECTION lock
;
158 static struct dds_format
{
159 DDS_PIXELFORMAT pixel_format
;
160 DXGI_FORMAT dxgi_format
;
162 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('D', 'X', 'T', '1'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC1_UNORM
},
163 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('D', 'X', 'T', '2'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC2_UNORM
},
164 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('D', 'X', 'T', '3'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC2_UNORM
},
165 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('D', 'X', 'T', '4'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC3_UNORM
},
166 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('D', 'X', 'T', '5'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC3_UNORM
},
167 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('B', 'C', '4', 'U'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC4_UNORM
},
168 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('B', 'C', '4', 'S'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC4_SNORM
},
169 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('B', 'C', '5', 'U'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC5_UNORM
},
170 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('B', 'C', '5', 'S'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC5_SNORM
},
171 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('A', 'T', 'I', '1'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC4_UNORM
},
172 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('A', 'T', 'I', '2'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC5_UNORM
},
173 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('R', 'G', 'B', 'G'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_R8G8_B8G8_UNORM
},
174 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('G', 'R', 'G', 'B'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_G8R8_G8B8_UNORM
},
175 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, MAKEFOURCC('D', 'X', '1', '0'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_UNKNOWN
},
176 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x24, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16G16B16A16_UNORM
},
177 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x6E, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16G16B16A16_SNORM
},
178 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x6F, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16_FLOAT
},
179 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x70, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16G16_FLOAT
},
180 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x71, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16G16B16A16_FLOAT
},
181 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x72, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R32_FLOAT
},
182 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x73, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R32G32_FLOAT
},
183 { { sizeof(DDS_PIXELFORMAT
), DDPF_FOURCC
, 0x74, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R32G32B32A32_FLOAT
},
184 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0xFF,0xFF00,0xFF0000,0xFF000000 }, DXGI_FORMAT_R8G8B8A8_UNORM
},
185 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0xFF0000,0xFF00,0xFF,0xFF000000 }, DXGI_FORMAT_B8G8R8A8_UNORM
},
186 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0xFF0000,0xFF00,0xFF,0 }, DXGI_FORMAT_B8G8R8X8_UNORM
},
187 /* The red and blue masks are swapped for DXGI_FORMAT_R10G10B10A2_UNORM.
188 * For "correct" one, the RGB masks should be 0x3FF00000,0xFFC00,0x3FF.
189 * see: https://walbourn.github.io/dds-update-and-1010102-problems */
190 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0x3FF,0xFFC00,0x3FF00000,0xC0000000 }, DXGI_FORMAT_R10G10B10A2_UNORM
},
191 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0xFFFF,0xFFFF0000,0,0 }, DXGI_FORMAT_R16G16_UNORM
},
192 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 32, 0xFFFFFFFF,0,0,0 }, DXGI_FORMAT_R32_FLOAT
},
193 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 16, 0xF800,0x7E0,0x1F,0 }, DXGI_FORMAT_B5G6R5_UNORM
},
194 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 16, 0x7C00,0x3E0,0x1F,0x8000 }, DXGI_FORMAT_B5G5R5A1_UNORM
},
195 { { sizeof(DDS_PIXELFORMAT
), DDPF_RGB
, 0, 16, 0xF00,0xF0,0xF,0xF000 }, DXGI_FORMAT_B4G4R4A4_UNORM
},
196 { { sizeof(DDS_PIXELFORMAT
), DDPF_ALPHA
, 0, 8, 0,0,0,0xFF }, DXGI_FORMAT_A8_UNORM
},
197 { { sizeof(DDS_PIXELFORMAT
), DDPF_LUMINANCE
, 0, 16, 0xFFFF,0,0,0 }, DXGI_FORMAT_R16_UNORM
},
198 { { sizeof(DDS_PIXELFORMAT
), DDPF_LUMINANCE
, 0, 16, 0xFF,0,0,0xFF00 }, DXGI_FORMAT_R8G8_UNORM
},
199 { { sizeof(DDS_PIXELFORMAT
), DDPF_LUMINANCE
, 0, 8, 0xFF,0,0,0 }, DXGI_FORMAT_R8_UNORM
}
202 static DXGI_FORMAT compressed_formats
[] = {
203 DXGI_FORMAT_BC1_TYPELESS
, DXGI_FORMAT_BC1_UNORM
, DXGI_FORMAT_BC1_UNORM_SRGB
,
204 DXGI_FORMAT_BC2_TYPELESS
, DXGI_FORMAT_BC2_UNORM
, DXGI_FORMAT_BC2_UNORM_SRGB
,
205 DXGI_FORMAT_BC3_TYPELESS
, DXGI_FORMAT_BC3_UNORM
, DXGI_FORMAT_BC3_UNORM_SRGB
,
206 DXGI_FORMAT_BC4_TYPELESS
, DXGI_FORMAT_BC4_UNORM
, DXGI_FORMAT_BC4_SNORM
,
207 DXGI_FORMAT_BC5_TYPELESS
, DXGI_FORMAT_BC5_UNORM
, DXGI_FORMAT_BC5_SNORM
,
208 DXGI_FORMAT_BC6H_TYPELESS
, DXGI_FORMAT_BC6H_UF16
, DXGI_FORMAT_BC6H_SF16
,
209 DXGI_FORMAT_BC7_TYPELESS
, DXGI_FORMAT_BC7_UNORM
, DXGI_FORMAT_BC7_UNORM_SRGB
212 static HRESULT WINAPI
DdsDecoder_Dds_GetFrame(IWICDdsDecoder
*, UINT
, UINT
, UINT
, IWICBitmapFrameDecode
**);
214 static inline BOOL
has_extended_header(DDS_HEADER
*header
)
216 return (header
->ddspf
.flags
& DDPF_FOURCC
) &&
217 (header
->ddspf
.fourCC
== MAKEFOURCC('D', 'X', '1', '0'));
220 static WICDdsDimension
get_dimension(DDS_HEADER
*header
, DDS_HEADER_DXT10
*header_dxt10
)
223 if (header_dxt10
->miscFlag
& DDS_RESOURCE_MISC_TEXTURECUBE
) return WICDdsTextureCube
;
224 switch (header_dxt10
->resourceDimension
)
226 case DDS_DIMENSION_TEXTURE1D
: return WICDdsTexture1D
;
227 case DDS_DIMENSION_TEXTURE2D
: return WICDdsTexture2D
;
228 case DDS_DIMENSION_TEXTURE3D
: return WICDdsTexture3D
;
229 default: return WICDdsTexture2D
;
232 if (header
->caps2
& DDSCAPS2_CUBEMAP
) {
233 return WICDdsTextureCube
;
234 } else if (header
->caps2
& DDSCAPS2_VOLUME
) {
235 return WICDdsTexture3D
;
237 return WICDdsTexture2D
;
242 static DXGI_FORMAT
get_dxgi_format(DDS_PIXELFORMAT
*pixel_format
)
246 for (i
= 0; i
< ARRAY_SIZE(dds_formats
); i
++)
248 if ((pixel_format
->flags
& dds_formats
[i
].pixel_format
.flags
) &&
249 (pixel_format
->fourCC
== dds_formats
[i
].pixel_format
.fourCC
) &&
250 (pixel_format
->rgbBitCount
== dds_formats
[i
].pixel_format
.rgbBitCount
) &&
251 (pixel_format
->rBitMask
== dds_formats
[i
].pixel_format
.rBitMask
) &&
252 (pixel_format
->gBitMask
== dds_formats
[i
].pixel_format
.gBitMask
) &&
253 (pixel_format
->bBitMask
== dds_formats
[i
].pixel_format
.bBitMask
) &&
254 (pixel_format
->aBitMask
== dds_formats
[i
].pixel_format
.aBitMask
))
255 return dds_formats
[i
].dxgi_format
;
258 return DXGI_FORMAT_UNKNOWN
;
261 static WICDdsAlphaMode
get_alpha_mode_from_fourcc(DWORD fourcc
)
265 case MAKEFOURCC('D', 'X', 'T', '1'):
266 case MAKEFOURCC('D', 'X', 'T', '2'):
267 case MAKEFOURCC('D', 'X', 'T', '4'):
268 return WICDdsAlphaModePremultiplied
;
270 return WICDdsAlphaModeUnknown
;
274 static UINT
get_bytes_per_block_from_format(DXGI_FORMAT format
)
276 /* for uncompressed format, return bytes per pixel*/
279 case DXGI_FORMAT_R8_TYPELESS
:
280 case DXGI_FORMAT_R8_UNORM
:
281 case DXGI_FORMAT_R8_UINT
:
282 case DXGI_FORMAT_R8_SNORM
:
283 case DXGI_FORMAT_R8_SINT
:
284 case DXGI_FORMAT_A8_UNORM
:
286 case DXGI_FORMAT_R8G8_TYPELESS
:
287 case DXGI_FORMAT_R8G8_UNORM
:
288 case DXGI_FORMAT_R8G8_UINT
:
289 case DXGI_FORMAT_R8G8_SNORM
:
290 case DXGI_FORMAT_R8G8_SINT
:
291 case DXGI_FORMAT_R16_TYPELESS
:
292 case DXGI_FORMAT_R16_FLOAT
:
293 case DXGI_FORMAT_D16_UNORM
:
294 case DXGI_FORMAT_R16_UNORM
:
295 case DXGI_FORMAT_R16_UINT
:
296 case DXGI_FORMAT_R16_SNORM
:
297 case DXGI_FORMAT_R16_SINT
:
298 case DXGI_FORMAT_B5G6R5_UNORM
:
299 case DXGI_FORMAT_B5G5R5A1_UNORM
:
300 case DXGI_FORMAT_B4G4R4A4_UNORM
:
302 case DXGI_FORMAT_R10G10B10A2_TYPELESS
:
303 case DXGI_FORMAT_R10G10B10A2_UNORM
:
304 case DXGI_FORMAT_R10G10B10A2_UINT
:
305 case DXGI_FORMAT_R11G11B10_FLOAT
:
306 case DXGI_FORMAT_R8G8B8A8_TYPELESS
:
307 case DXGI_FORMAT_R8G8B8A8_UNORM
:
308 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
:
309 case DXGI_FORMAT_R8G8B8A8_UINT
:
310 case DXGI_FORMAT_R8G8B8A8_SNORM
:
311 case DXGI_FORMAT_R8G8B8A8_SINT
:
312 case DXGI_FORMAT_R16G16_TYPELESS
:
313 case DXGI_FORMAT_R16G16_FLOAT
:
314 case DXGI_FORMAT_R16G16_UNORM
:
315 case DXGI_FORMAT_R16G16_UINT
:
316 case DXGI_FORMAT_R16G16_SNORM
:
317 case DXGI_FORMAT_R16G16_SINT
:
318 case DXGI_FORMAT_R32_TYPELESS
:
319 case DXGI_FORMAT_D32_FLOAT
:
320 case DXGI_FORMAT_R32_FLOAT
:
321 case DXGI_FORMAT_R32_UINT
:
322 case DXGI_FORMAT_R32_SINT
:
323 case DXGI_FORMAT_R24G8_TYPELESS
:
324 case DXGI_FORMAT_D24_UNORM_S8_UINT
:
325 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS
:
326 case DXGI_FORMAT_X24_TYPELESS_G8_UINT
:
327 case DXGI_FORMAT_R9G9B9E5_SHAREDEXP
:
328 case DXGI_FORMAT_R8G8_B8G8_UNORM
:
329 case DXGI_FORMAT_G8R8_G8B8_UNORM
:
330 case DXGI_FORMAT_B8G8R8A8_UNORM
:
331 case DXGI_FORMAT_B8G8R8X8_UNORM
:
332 case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM
:
333 case DXGI_FORMAT_B8G8R8A8_TYPELESS
:
334 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
:
335 case DXGI_FORMAT_B8G8R8X8_TYPELESS
:
336 case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB
:
338 case DXGI_FORMAT_BC1_UNORM
:
339 case DXGI_FORMAT_BC1_TYPELESS
:
340 case DXGI_FORMAT_BC1_UNORM_SRGB
:
341 case DXGI_FORMAT_BC4_TYPELESS
:
342 case DXGI_FORMAT_BC4_UNORM
:
343 case DXGI_FORMAT_BC4_SNORM
:
344 case DXGI_FORMAT_R16G16B16A16_TYPELESS
:
345 case DXGI_FORMAT_R16G16B16A16_FLOAT
:
346 case DXGI_FORMAT_R16G16B16A16_UNORM
:
347 case DXGI_FORMAT_R16G16B16A16_UINT
:
348 case DXGI_FORMAT_R16G16B16A16_SNORM
:
349 case DXGI_FORMAT_R16G16B16A16_SINT
:
350 case DXGI_FORMAT_R32G32_TYPELESS
:
351 case DXGI_FORMAT_R32G32_FLOAT
:
352 case DXGI_FORMAT_R32G32_UINT
:
353 case DXGI_FORMAT_R32G32_SINT
:
354 case DXGI_FORMAT_R32G8X24_TYPELESS
:
355 case DXGI_FORMAT_D32_FLOAT_S8X24_UINT
:
356 case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS
:
357 case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT
:
359 case DXGI_FORMAT_R32G32B32_TYPELESS
:
360 case DXGI_FORMAT_R32G32B32_FLOAT
:
361 case DXGI_FORMAT_R32G32B32_UINT
:
362 case DXGI_FORMAT_R32G32B32_SINT
:
364 case DXGI_FORMAT_BC2_UNORM
:
365 case DXGI_FORMAT_BC2_TYPELESS
:
366 case DXGI_FORMAT_BC2_UNORM_SRGB
:
367 case DXGI_FORMAT_BC3_UNORM
:
368 case DXGI_FORMAT_BC3_TYPELESS
:
369 case DXGI_FORMAT_BC3_UNORM_SRGB
:
370 case DXGI_FORMAT_BC5_TYPELESS
:
371 case DXGI_FORMAT_BC5_UNORM
:
372 case DXGI_FORMAT_BC5_SNORM
:
373 case DXGI_FORMAT_BC6H_TYPELESS
:
374 case DXGI_FORMAT_BC6H_UF16
:
375 case DXGI_FORMAT_BC6H_SF16
:
376 case DXGI_FORMAT_BC7_TYPELESS
:
377 case DXGI_FORMAT_BC7_UNORM
:
378 case DXGI_FORMAT_BC7_UNORM_SRGB
:
379 case DXGI_FORMAT_R32G32B32A32_TYPELESS
:
380 case DXGI_FORMAT_R32G32B32A32_FLOAT
:
381 case DXGI_FORMAT_R32G32B32A32_UINT
:
382 case DXGI_FORMAT_R32G32B32A32_SINT
:
385 WARN("DXGI format 0x%x is not supported in DDS decoder\n", format
);
390 static BOOL
is_compressed(DXGI_FORMAT format
)
394 for (i
= 0; i
< ARRAY_SIZE(compressed_formats
); i
++)
396 if (format
== compressed_formats
[i
]) return TRUE
;
401 static void get_dds_info(dds_info
* info
, DDS_HEADER
*header
, DDS_HEADER_DXT10
*header_dxt10
)
406 info
->width
= header
->width
;
407 info
->height
= header
->height
;
409 info
->mip_levels
= 1;
410 info
->array_size
= 1;
411 if (header
->depth
) info
->depth
= header
->depth
;
412 if (header
->mipMapCount
) info
->mip_levels
= header
->mipMapCount
;
414 if (has_extended_header(header
)) {
415 if (header_dxt10
->arraySize
) info
->array_size
= header_dxt10
->arraySize
;
416 info
->format
= header_dxt10
->dxgiFormat
;
417 info
->dimension
= get_dimension(NULL
, header_dxt10
);
418 info
->alpha_mode
= header_dxt10
->miscFlags2
& 0x00000008;
419 info
->data_offset
= sizeof(DWORD
) + sizeof(*header
) + sizeof(*header_dxt10
);
421 info
->format
= get_dxgi_format(&header
->ddspf
);
422 info
->dimension
= get_dimension(header
, NULL
);
423 info
->alpha_mode
= get_alpha_mode_from_fourcc(header
->ddspf
.fourCC
);
424 info
->data_offset
= sizeof(DWORD
) + sizeof(*header
);
426 info
->pixel_format
= (info
->alpha_mode
== WICDdsAlphaModePremultiplied
) ?
427 &GUID_WICPixelFormat32bppPBGRA
: &GUID_WICPixelFormat32bppBGRA
;
429 if (header
->ddspf
.flags
& (DDPF_RGB
| DDPF_ALPHA
| DDPF_LUMINANCE
)) {
430 info
->bytes_per_block
= header
->ddspf
.rgbBitCount
/ 8;
432 info
->bytes_per_block
= get_bytes_per_block_from_format(info
->format
);
435 /* get frame count */
437 if (info
->depth
== 1) {
438 info
->frame_count
= info
->array_size
* info
->mip_levels
;
440 info
->frame_count
= 0;
442 for (i
= 0; i
< info
->mip_levels
; i
++)
444 info
->frame_count
+= depth
;
445 if (depth
> 1) depth
/= 2;
447 info
->frame_count
*= info
->array_size
;
449 if (info
->dimension
== WICDdsTextureCube
) info
->frame_count
*= 6;
452 static UINT
get_pixel_format_bpp(const GUID
*pixel_format
)
456 IWICComponentInfo
*info
= NULL
;
457 IWICPixelFormatInfo
* format_info
= NULL
;
459 hr
= CreateComponentInfo(pixel_format
, &info
);
460 if (hr
!= S_OK
) goto end
;
461 hr
= IWICComponentInfo_QueryInterface(info
, &IID_IWICPixelFormatInfo
, (void **)&format_info
);
462 if (hr
!= S_OK
) goto end
;
464 IWICPixelFormatInfo_GetBitsPerPixel(format_info
, &bpp
);
467 if (format_info
) IWICPixelFormatInfo_Release(format_info
);
468 if (info
) IWICComponentInfo_Release(info
);
473 static inline DdsDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
475 return CONTAINING_RECORD(iface
, DdsDecoder
, IWICBitmapDecoder_iface
);
478 static inline DdsDecoder
*impl_from_IWICDdsDecoder(IWICDdsDecoder
*iface
)
480 return CONTAINING_RECORD(iface
, DdsDecoder
, IWICDdsDecoder_iface
);
483 static inline DdsDecoder
*impl_from_IWICWineDecoder(IWICWineDecoder
*iface
)
485 return CONTAINING_RECORD(iface
, DdsDecoder
, IWICWineDecoder_iface
);
488 static inline DdsFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
490 return CONTAINING_RECORD(iface
, DdsFrameDecode
, IWICBitmapFrameDecode_iface
);
493 static inline DdsFrameDecode
*impl_from_IWICDdsFrameDecode(IWICDdsFrameDecode
*iface
)
495 return CONTAINING_RECORD(iface
, DdsFrameDecode
, IWICDdsFrameDecode_iface
);
498 static HRESULT WINAPI
DdsFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
501 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
502 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
504 if (!ppv
) return E_INVALIDARG
;
506 if (IsEqualIID(&IID_IUnknown
, iid
) ||
507 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
508 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
)) {
509 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
510 } else if (IsEqualGUID(&IID_IWICDdsFrameDecode
, iid
)) {
511 *ppv
= &This
->IWICDdsFrameDecode_iface
;
514 return E_NOINTERFACE
;
517 IUnknown_AddRef((IUnknown
*)*ppv
);
521 static ULONG WINAPI
DdsFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
523 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
524 ULONG ref
= InterlockedIncrement(&This
->ref
);
526 TRACE("(%p) refcount=%u\n", iface
, ref
);
531 static ULONG WINAPI
DdsFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
533 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
534 ULONG ref
= InterlockedDecrement(&This
->ref
);
536 TRACE("(%p) refcount=%u\n", iface
, ref
);
539 HeapFree(GetProcessHeap(), 0, This
->pixel_data
);
540 HeapFree(GetProcessHeap(), 0, This
->block_data
);
541 HeapFree(GetProcessHeap(), 0, This
);
547 static HRESULT WINAPI
DdsFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
548 UINT
*puiWidth
, UINT
*puiHeight
)
550 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
552 if (!puiWidth
|| !puiHeight
) return E_INVALIDARG
;
554 *puiWidth
= This
->info
.width
;
555 *puiHeight
= This
->info
.height
;
557 TRACE("(%p) -> (%d,%d)\n", iface
, *puiWidth
, *puiHeight
);
562 static HRESULT WINAPI
DdsFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
563 WICPixelFormatGUID
*pPixelFormat
)
565 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
567 if (!pPixelFormat
) return E_INVALIDARG
;
569 *pPixelFormat
= *This
->info
.pixel_format
;
571 TRACE("(%p) -> %s\n", iface
, debugstr_guid(pPixelFormat
));
576 static HRESULT WINAPI
DdsFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
577 double *pDpiX
, double *pDpiY
)
579 FIXME("(%p,%p,%p): stub.\n", iface
, pDpiX
, pDpiY
);
584 static HRESULT WINAPI
DdsFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
585 IWICPalette
*pIPalette
)
587 FIXME("(%p,%p): stub.\n", iface
, pIPalette
);
592 static HRESULT WINAPI
DdsFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
593 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
595 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
596 UINT bpp
, frame_stride
, frame_size
;
597 INT x
, y
, width
, height
;
600 TRACE("(%p,%s,%u,%u,%p)\n", iface
, debug_wic_rect(prc
), cbStride
, cbBufferSize
, pbBuffer
);
602 if (!pbBuffer
) return E_INVALIDARG
;
604 bpp
= This
->info
.pixel_format_bpp
;
605 frame_stride
= This
->info
.width
* bpp
/ 8;
606 frame_size
= frame_stride
* This
->info
.height
;
608 if (cbStride
< frame_stride
) return E_INVALIDARG
;
609 if (cbBufferSize
< frame_size
) return WINCODEC_ERR_INSUFFICIENTBUFFER
;
616 height
= prc
->Height
;
617 if (x
< 0 || y
< 0 || width
<= 0 || height
<= 0 ||
618 x
+ width
> This
->info
.width
||
619 y
+ height
> This
->info
.height
) {
622 if (cbStride
< width
* bpp
/ 8) return E_INVALIDARG
;
623 if (cbBufferSize
< cbStride
* height
) return WINCODEC_ERR_INSUFFICIENTBUFFER
;
625 EnterCriticalSection(&This
->lock
);
627 if (!This
->pixel_data
) {
628 This
->pixel_data
= HeapAlloc(GetProcessHeap(), 0, frame_size
);
629 if (!This
->pixel_data
) {
636 LeaveCriticalSection(&This
->lock
);
641 static HRESULT WINAPI
DdsFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
642 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
644 FIXME("(%p,%p): stub.\n", iface
, ppIMetadataQueryReader
);
649 static HRESULT WINAPI
DdsFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
650 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
652 FIXME("(%p,%u,%p,%p): stub.\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
657 static HRESULT WINAPI
DdsFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
658 IWICBitmapSource
**ppIThumbnail
)
660 FIXME("(%p,%p): stub.\n", iface
, ppIThumbnail
);
665 static const IWICBitmapFrameDecodeVtbl DdsFrameDecode_Vtbl
= {
666 DdsFrameDecode_QueryInterface
,
667 DdsFrameDecode_AddRef
,
668 DdsFrameDecode_Release
,
669 DdsFrameDecode_GetSize
,
670 DdsFrameDecode_GetPixelFormat
,
671 DdsFrameDecode_GetResolution
,
672 DdsFrameDecode_CopyPalette
,
673 DdsFrameDecode_CopyPixels
,
674 DdsFrameDecode_GetMetadataQueryReader
,
675 DdsFrameDecode_GetColorContexts
,
676 DdsFrameDecode_GetThumbnail
679 static HRESULT WINAPI
DdsFrameDecode_Dds_QueryInterface(IWICDdsFrameDecode
*iface
,
680 REFIID iid
, void **ppv
)
682 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
683 return DdsFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
686 static ULONG WINAPI
DdsFrameDecode_Dds_AddRef(IWICDdsFrameDecode
*iface
)
688 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
689 return DdsFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
692 static ULONG WINAPI
DdsFrameDecode_Dds_Release(IWICDdsFrameDecode
*iface
)
694 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
695 return DdsFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
698 static HRESULT WINAPI
DdsFrameDecode_Dds_GetSizeInBlocks(IWICDdsFrameDecode
*iface
,
699 UINT
*widthInBlocks
, UINT
*heightInBlocks
)
701 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
703 if (!widthInBlocks
|| !heightInBlocks
) return E_INVALIDARG
;
705 *widthInBlocks
= This
->info
.width_in_blocks
;
706 *heightInBlocks
= This
->info
.height_in_blocks
;
708 TRACE("(%p,%p,%p) -> (%d,%d)\n", iface
, widthInBlocks
, heightInBlocks
, *widthInBlocks
, *heightInBlocks
);
713 static HRESULT WINAPI
DdsFrameDecode_Dds_GetFormatInfo(IWICDdsFrameDecode
*iface
,
714 WICDdsFormatInfo
*formatInfo
)
716 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
718 if (!formatInfo
) return E_INVALIDARG
;
720 formatInfo
->DxgiFormat
= This
->info
.format
;
721 formatInfo
->BytesPerBlock
= This
->info
.bytes_per_block
;
722 formatInfo
->BlockWidth
= This
->info
.block_width
;
723 formatInfo
->BlockHeight
= This
->info
.block_height
;
725 TRACE("(%p,%p) -> (0x%x,%d,%d,%d)\n", iface
, formatInfo
,
726 formatInfo
->DxgiFormat
, formatInfo
->BytesPerBlock
, formatInfo
->BlockWidth
, formatInfo
->BlockHeight
);
731 static HRESULT WINAPI
DdsFrameDecode_Dds_CopyBlocks(IWICDdsFrameDecode
*iface
,
732 const WICRect
*boundsInBlocks
, UINT stride
, UINT bufferSize
,
735 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
736 int x
, y
, width
, height
;
737 UINT bytes_per_block
, frame_stride
, frame_size
, i
;
738 BYTE
*data
, *dst_buffer
;
740 TRACE("(%p,%p,%u,%u,%p)\n", iface
, boundsInBlocks
, stride
, bufferSize
, buffer
);
742 if (!buffer
) return E_INVALIDARG
;
744 bytes_per_block
= This
->info
.bytes_per_block
;
745 frame_stride
= This
->info
.width_in_blocks
* bytes_per_block
;
746 frame_size
= frame_stride
* This
->info
.height_in_blocks
;
747 if (!boundsInBlocks
) {
748 if (stride
< frame_stride
) return E_INVALIDARG
;
749 if (bufferSize
< frame_size
) return E_INVALIDARG
;
750 memcpy(buffer
, This
->block_data
, frame_size
);
754 x
= boundsInBlocks
->X
;
755 y
= boundsInBlocks
->Y
;
756 width
= boundsInBlocks
->Width
;
757 height
= boundsInBlocks
->Height
;
758 if (x
< 0 || y
< 0 || width
<= 0 || height
<= 0 ||
759 x
+ width
> This
->info
.width_in_blocks
||
760 y
+ height
> This
->info
.height_in_blocks
) {
763 if (stride
< width
* bytes_per_block
) return E_INVALIDARG
;
764 if (bufferSize
< stride
* height
) return E_INVALIDARG
;
766 data
= This
->block_data
+ (x
+ y
* This
->info
.width_in_blocks
) * bytes_per_block
;
768 for (i
= 0; i
< height
; i
++)
770 memcpy(dst_buffer
, data
, (size_t)width
* bytes_per_block
);
771 data
+= This
->info
.width_in_blocks
* bytes_per_block
;
772 dst_buffer
+= stride
;
778 static const IWICDdsFrameDecodeVtbl DdsFrameDecode_Dds_Vtbl
= {
779 DdsFrameDecode_Dds_QueryInterface
,
780 DdsFrameDecode_Dds_AddRef
,
781 DdsFrameDecode_Dds_Release
,
782 DdsFrameDecode_Dds_GetSizeInBlocks
,
783 DdsFrameDecode_Dds_GetFormatInfo
,
784 DdsFrameDecode_Dds_CopyBlocks
787 static HRESULT
DdsFrameDecode_CreateInstance(DdsFrameDecode
**frame_decode
)
789 DdsFrameDecode
*result
;
791 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(*result
));
792 if (!result
) return E_OUTOFMEMORY
;
794 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &DdsFrameDecode_Vtbl
;
795 result
->IWICDdsFrameDecode_iface
.lpVtbl
= &DdsFrameDecode_Dds_Vtbl
;
797 InitializeCriticalSection(&result
->lock
);
798 result
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DdsFrameDecode.lock");
800 *frame_decode
= result
;
804 static HRESULT WINAPI
DdsDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
807 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
808 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
810 if (!ppv
) return E_INVALIDARG
;
812 if (IsEqualIID(&IID_IUnknown
, iid
) ||
813 IsEqualIID(&IID_IWICBitmapDecoder
, iid
)) {
814 *ppv
= &This
->IWICBitmapDecoder_iface
;
815 } else if (IsEqualIID(&IID_IWICDdsDecoder
, iid
)) {
816 *ppv
= &This
->IWICDdsDecoder_iface
;
817 } else if (IsEqualIID(&IID_IWICWineDecoder
, iid
)) {
818 *ppv
= &This
->IWICWineDecoder_iface
;
821 return E_NOINTERFACE
;
824 IUnknown_AddRef((IUnknown
*)*ppv
);
828 static ULONG WINAPI
DdsDecoder_AddRef(IWICBitmapDecoder
*iface
)
830 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
831 ULONG ref
= InterlockedIncrement(&This
->ref
);
833 TRACE("(%p) refcount=%u\n", iface
, ref
);
838 static ULONG WINAPI
DdsDecoder_Release(IWICBitmapDecoder
*iface
)
840 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
841 ULONG ref
= InterlockedDecrement(&This
->ref
);
843 TRACE("(%p) refcount=%u\n", iface
, ref
);
847 This
->lock
.DebugInfo
->Spare
[0] = 0;
848 DeleteCriticalSection(&This
->lock
);
849 if (This
->stream
) IStream_Release(This
->stream
);
850 HeapFree(GetProcessHeap(), 0, This
);
856 static HRESULT WINAPI
DdsDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
859 FIXME("(%p,%p,%p): stub.\n", iface
, stream
, capability
);
864 static HRESULT WINAPI
DdsDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
865 WICDecodeOptions cacheOptions
)
867 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
870 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
872 EnterCriticalSection(&This
->lock
);
874 hr
= IWICWineDecoder_Initialize(&This
->IWICWineDecoder_iface
, pIStream
, cacheOptions
);
875 if (FAILED(hr
)) goto end
;
877 if (This
->info
.dimension
== WICDdsTextureCube
||
878 (This
->info
.format
!= DXGI_FORMAT_BC1_UNORM
&&
879 This
->info
.format
!= DXGI_FORMAT_BC2_UNORM
&&
880 This
->info
.format
!= DXGI_FORMAT_BC3_UNORM
)) {
881 IStream_Release(pIStream
);
883 This
->initialized
= FALSE
;
884 hr
= WINCODEC_ERR_BADHEADER
;
888 LeaveCriticalSection(&This
->lock
);
893 static HRESULT WINAPI
DdsDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
894 GUID
*pguidContainerFormat
)
896 TRACE("(%p,%p)\n", iface
, pguidContainerFormat
);
898 memcpy(pguidContainerFormat
, &GUID_ContainerFormatDds
, sizeof(GUID
));
903 static HRESULT WINAPI
DdsDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
904 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
906 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
908 return get_decoder_info(&CLSID_WICDdsDecoder
, ppIDecoderInfo
);
911 static HRESULT WINAPI
DdsDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
912 IWICPalette
*pIPalette
)
914 TRACE("(%p,%p)\n", iface
, pIPalette
);
916 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
919 static HRESULT WINAPI
DdsDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
920 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
922 if (!ppIMetadataQueryReader
) return E_INVALIDARG
;
924 FIXME("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
929 static HRESULT WINAPI
DdsDecoder_GetPreview(IWICBitmapDecoder
*iface
,
930 IWICBitmapSource
**ppIBitmapSource
)
932 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
934 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
937 static HRESULT WINAPI
DdsDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
938 UINT cCount
, IWICColorContext
**ppDdslorContexts
, UINT
*pcActualCount
)
940 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppDdslorContexts
, pcActualCount
);
942 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
945 static HRESULT WINAPI
DdsDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
946 IWICBitmapSource
**ppIThumbnail
)
948 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
950 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
953 static HRESULT WINAPI
DdsDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
956 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
958 if (!pCount
) return E_INVALIDARG
;
959 if (!This
->initialized
) return WINCODEC_ERR_WRONGSTATE
;
961 EnterCriticalSection(&This
->lock
);
963 *pCount
= This
->info
.frame_count
;
965 LeaveCriticalSection(&This
->lock
);
967 TRACE("(%p) -> %d\n", iface
, *pCount
);
972 static HRESULT WINAPI
DdsDecoder_GetFrame(IWICBitmapDecoder
*iface
,
973 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
975 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
976 UINT frame_per_texture
, array_index
, mip_level
, slice_index
, depth
;
978 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
980 if (!ppIBitmapFrame
) return E_INVALIDARG
;
982 EnterCriticalSection(&This
->lock
);
984 if (!This
->initialized
) {
985 LeaveCriticalSection(&This
->lock
);
986 return WINCODEC_ERR_WRONGSTATE
;
989 if (This
->info
.dimension
== WICDdsTextureCube
) {
990 frame_per_texture
= This
->info
.mip_levels
;
992 frame_per_texture
= This
->info
.frame_count
/ This
->info
.array_size
;
994 array_index
= index
/ frame_per_texture
;
995 slice_index
= index
% frame_per_texture
;
996 depth
= This
->info
.depth
;
998 while (slice_index
>= depth
)
1000 slice_index
-= depth
;
1002 if (depth
> 1) depth
/= 2;
1005 LeaveCriticalSection(&This
->lock
);
1007 return DdsDecoder_Dds_GetFrame(&This
->IWICDdsDecoder_iface
, array_index
, mip_level
, slice_index
, ppIBitmapFrame
);
1010 static const IWICBitmapDecoderVtbl DdsDecoder_Vtbl
= {
1011 DdsDecoder_QueryInterface
,
1014 DdsDecoder_QueryCapability
,
1015 DdsDecoder_Initialize
,
1016 DdsDecoder_GetContainerFormat
,
1017 DdsDecoder_GetDecoderInfo
,
1018 DdsDecoder_CopyPalette
,
1019 DdsDecoder_GetMetadataQueryReader
,
1020 DdsDecoder_GetPreview
,
1021 DdsDecoder_GetColorContexts
,
1022 DdsDecoder_GetThumbnail
,
1023 DdsDecoder_GetFrameCount
,
1027 static HRESULT WINAPI
DdsDecoder_Dds_QueryInterface(IWICDdsDecoder
*iface
,
1028 REFIID iid
, void **ppv
)
1030 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
1031 return DdsDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1034 static ULONG WINAPI
DdsDecoder_Dds_AddRef(IWICDdsDecoder
*iface
)
1036 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
1037 return DdsDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
1040 static ULONG WINAPI
DdsDecoder_Dds_Release(IWICDdsDecoder
*iface
)
1042 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
1043 return DdsDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1046 static HRESULT WINAPI
DdsDecoder_Dds_GetParameters(IWICDdsDecoder
*iface
,
1047 WICDdsParameters
*parameters
)
1049 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
1052 if (!parameters
) return E_INVALIDARG
;
1054 EnterCriticalSection(&This
->lock
);
1056 if (!This
->initialized
) {
1057 hr
= WINCODEC_ERR_WRONGSTATE
;
1061 parameters
->Width
= This
->info
.width
;
1062 parameters
->Height
= This
->info
.height
;
1063 parameters
->Depth
= This
->info
.depth
;
1064 parameters
->MipLevels
= This
->info
.mip_levels
;
1065 parameters
->ArraySize
= This
->info
.array_size
;
1066 parameters
->DxgiFormat
= This
->info
.format
;
1067 parameters
->Dimension
= This
->info
.dimension
;
1068 parameters
->AlphaMode
= This
->info
.alpha_mode
;
1070 TRACE("(%p) -> (%dx%d depth=%d mipLevels=%d arraySize=%d dxgiFormat=0x%x dimension=0x%x alphaMode=0x%x)\n",
1071 iface
, parameters
->Width
, parameters
->Height
, parameters
->Depth
, parameters
->MipLevels
,
1072 parameters
->ArraySize
, parameters
->DxgiFormat
, parameters
->Dimension
, parameters
->AlphaMode
);
1077 LeaveCriticalSection(&This
->lock
);
1082 static HRESULT WINAPI
DdsDecoder_Dds_GetFrame(IWICDdsDecoder
*iface
,
1083 UINT arrayIndex
, UINT mipLevel
, UINT sliceIndex
,
1084 IWICBitmapFrameDecode
**bitmapFrame
)
1086 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
1089 UINT width
, height
, depth
, block_width
, block_height
, width_in_blocks
, height_in_blocks
, size
;
1090 UINT frame_width
= 0, frame_height
= 0, frame_width_in_blocks
= 0, frame_height_in_blocks
= 0, frame_size
= 0;
1091 UINT bytes_per_block
, bytesread
, i
;
1092 DdsFrameDecode
*frame_decode
= NULL
;
1094 TRACE("(%p,%u,%u,%u,%p)\n", iface
, arrayIndex
, mipLevel
, sliceIndex
, bitmapFrame
);
1096 if (!bitmapFrame
) return E_INVALIDARG
;
1098 EnterCriticalSection(&This
->lock
);
1100 if (!This
->initialized
) {
1101 hr
= WINCODEC_ERR_WRONGSTATE
;
1105 if ((arrayIndex
>= This
->info
.array_size
&& This
->info
.dimension
!= WICDdsTextureCube
) ||
1106 (arrayIndex
>= This
->info
.array_size
* 6) ||
1107 (mipLevel
>= This
->info
.mip_levels
) ||
1108 (sliceIndex
>= This
->info
.depth
)) {
1113 if (is_compressed(This
->info
.format
)) {
1114 block_width
= DDS_BLOCK_WIDTH
;
1115 block_height
= DDS_BLOCK_HEIGHT
;
1120 bytes_per_block
= This
->info
.bytes_per_block
;
1121 seek
.QuadPart
= This
->info
.data_offset
;
1123 width
= This
->info
.width
;
1124 height
= This
->info
.height
;
1125 depth
= This
->info
.depth
;
1126 for (i
= 0; i
< This
->info
.mip_levels
; i
++)
1128 width_in_blocks
= (width
+ block_width
- 1) / block_width
;
1129 height_in_blocks
= (height
+ block_height
- 1) / block_height
;
1130 size
= width_in_blocks
* height_in_blocks
* bytes_per_block
;
1133 seek
.QuadPart
+= size
* depth
;
1134 } else if (i
== mipLevel
){
1135 seek
.QuadPart
+= size
* sliceIndex
;
1136 frame_width
= width
;
1137 frame_height
= height
;
1138 frame_width_in_blocks
= width_in_blocks
;
1139 frame_height_in_blocks
= height_in_blocks
;
1140 frame_size
= frame_width_in_blocks
* frame_height_in_blocks
* bytes_per_block
;
1141 if (arrayIndex
== 0) break;
1143 seek
.QuadPart
+= arrayIndex
* size
* depth
;
1145 if (width
> 1) width
/= 2;
1146 if (height
> 1) height
/= 2;
1147 if (depth
> 1) depth
/= 2;
1150 hr
= DdsFrameDecode_CreateInstance(&frame_decode
);
1151 if (hr
!= S_OK
) goto end
;
1152 frame_decode
->info
.width
= frame_width
;
1153 frame_decode
->info
.height
= frame_height
;
1154 frame_decode
->info
.format
= This
->info
.format
;
1155 frame_decode
->info
.bytes_per_block
= bytes_per_block
;
1156 frame_decode
->info
.block_width
= block_width
;
1157 frame_decode
->info
.block_height
= block_height
;
1158 frame_decode
->info
.width_in_blocks
= frame_width_in_blocks
;
1159 frame_decode
->info
.height_in_blocks
= frame_height_in_blocks
;
1160 frame_decode
->info
.pixel_format
= This
->info
.pixel_format
;
1161 frame_decode
->info
.pixel_format_bpp
= get_pixel_format_bpp(This
->info
.pixel_format
);
1162 frame_decode
->block_data
= HeapAlloc(GetProcessHeap(), 0, frame_size
);
1163 frame_decode
->pixel_data
= NULL
;
1164 hr
= IStream_Seek(This
->stream
, seek
, SEEK_SET
, NULL
);
1165 if (hr
!= S_OK
) goto end
;
1166 hr
= IStream_Read(This
->stream
, frame_decode
->block_data
, frame_size
, &bytesread
);
1167 if (hr
!= S_OK
|| bytesread
!= frame_size
) {
1168 hr
= WINCODEC_ERR_STREAMREAD
;
1171 *bitmapFrame
= &frame_decode
->IWICBitmapFrameDecode_iface
;
1176 LeaveCriticalSection(&This
->lock
);
1178 if (hr
!= S_OK
&& frame_decode
) DdsFrameDecode_Release(&frame_decode
->IWICBitmapFrameDecode_iface
);
1183 static const IWICDdsDecoderVtbl DdsDecoder_Dds_Vtbl
= {
1184 DdsDecoder_Dds_QueryInterface
,
1185 DdsDecoder_Dds_AddRef
,
1186 DdsDecoder_Dds_Release
,
1187 DdsDecoder_Dds_GetParameters
,
1188 DdsDecoder_Dds_GetFrame
1191 static HRESULT WINAPI
DdsDecoder_Wine_QueryInterface(IWICWineDecoder
*iface
, REFIID iid
, void **ppv
)
1193 DdsDecoder
*This
= impl_from_IWICWineDecoder(iface
);
1194 return DdsDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1197 static ULONG WINAPI
DdsDecoder_Wine_AddRef(IWICWineDecoder
*iface
)
1199 DdsDecoder
*This
= impl_from_IWICWineDecoder(iface
);
1200 return DdsDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
1203 static ULONG WINAPI
DdsDecoder_Wine_Release(IWICWineDecoder
*iface
)
1205 DdsDecoder
*This
= impl_from_IWICWineDecoder(iface
);
1206 return DdsDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1209 static HRESULT WINAPI
DdsDecoder_Wine_Initialize(IWICWineDecoder
*iface
, IStream
*stream
, WICDecodeOptions options
)
1211 DdsDecoder
*This
= impl_from_IWICWineDecoder(iface
);
1212 DDS_HEADER_DXT10 header_dxt10
;
1219 TRACE("(This %p, stream %p, options %#x)\n", iface
, stream
, options
);
1221 EnterCriticalSection(&This
->lock
);
1223 if (This
->initialized
) {
1224 hr
= WINCODEC_ERR_WRONGSTATE
;
1229 hr
= IStream_Seek(stream
, seek
, SEEK_SET
, NULL
);
1230 if (FAILED(hr
)) goto end
;
1232 hr
= IStream_Read(stream
, &magic
, sizeof(magic
), &bytesread
);
1233 if (FAILED(hr
)) goto end
;
1234 if (bytesread
!= sizeof(magic
)) {
1235 hr
= WINCODEC_ERR_STREAMREAD
;
1238 if (magic
!= DDS_MAGIC
) {
1239 hr
= WINCODEC_ERR_UNKNOWNIMAGEFORMAT
;
1243 hr
= IStream_Read(stream
, &header
, sizeof(header
), &bytesread
);
1244 if (FAILED(hr
)) goto end
;
1245 if (bytesread
!= sizeof(header
)) {
1246 hr
= WINCODEC_ERR_STREAMREAD
;
1249 if (header
.size
!= sizeof(header
)) {
1250 hr
= WINCODEC_ERR_BADHEADER
;
1254 if (has_extended_header(&header
)) {
1255 hr
= IStream_Read(stream
, &header_dxt10
, sizeof(header_dxt10
), &bytesread
);
1256 if (FAILED(hr
)) goto end
;
1257 if (bytesread
!= sizeof(header_dxt10
)) {
1258 hr
= WINCODEC_ERR_STREAMREAD
;
1263 get_dds_info(&This
->info
, &header
, &header_dxt10
);
1265 This
->initialized
= TRUE
;
1266 This
->stream
= stream
;
1267 IStream_AddRef(stream
);
1270 LeaveCriticalSection(&This
->lock
);
1275 static const IWICWineDecoderVtbl DdsDecoder_Wine_Vtbl
= {
1276 DdsDecoder_Wine_QueryInterface
,
1277 DdsDecoder_Wine_AddRef
,
1278 DdsDecoder_Wine_Release
,
1279 DdsDecoder_Wine_Initialize
1282 HRESULT
DdsDecoder_CreateInstance(REFIID iid
, void** ppv
)
1287 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1291 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(DdsDecoder
));
1292 if (!This
) return E_OUTOFMEMORY
;
1294 This
->IWICBitmapDecoder_iface
.lpVtbl
= &DdsDecoder_Vtbl
;
1295 This
->IWICDdsDecoder_iface
.lpVtbl
= &DdsDecoder_Dds_Vtbl
;
1296 This
->IWICWineDecoder_iface
.lpVtbl
= &DdsDecoder_Wine_Vtbl
;
1298 This
->initialized
= FALSE
;
1299 This
->stream
= NULL
;
1300 InitializeCriticalSection(&This
->lock
);
1301 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DdsDecoder.lock");
1303 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1304 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);