2 * Copyright 2014 Michael Müller
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
20 #include "wine/port.h"
21 #include "wined3d_private.h"
22 #include "wine/library.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
26 static void* txc_dxtn_handle
;
27 static void (*pfetch_2d_texel_rgba_dxt1
)(int srcRowStride
, const BYTE
*pixData
, int i
, int j
, DWORD
*texel
);
28 static void (*pfetch_2d_texel_rgba_dxt3
)(int srcRowStride
, const BYTE
*pixData
, int i
, int j
, DWORD
*texel
);
29 static void (*pfetch_2d_texel_rgba_dxt5
)(int srcRowStride
, const BYTE
*pixData
, int i
, int j
, DWORD
*texel
);
30 static void (*ptx_compress_dxtn
)(int comps
, int width
, int height
, const BYTE
*srcPixData
,
31 GLenum destformat
, BYTE
*dest
, int dstRowStride
);
33 static inline BOOL
dxt1_to_x8r8g8b8(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
,
34 DWORD pitch_out
, unsigned int w
, unsigned int h
, BOOL alpha
)
39 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
41 for (y
= 0; y
< h
; ++y
)
43 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
44 for (x
= 0; x
< w
; ++x
)
46 /* pfetch_2d_texel_rgba_dxt1 doesn't correctly handle pitch */
47 pfetch_2d_texel_rgba_dxt1(0, src
+ (y
/ 4) * pitch_in
+ (x
/ 4) * 8,
48 x
& 3, y
& 3, &color
);
51 dst_line
[x
] = (color
& 0xff00ff00) | ((color
& 0xff) << 16) |
52 ((color
& 0xff0000) >> 16);
56 dst_line
[x
] = 0xff000000 | ((color
& 0xff) << 16) |
57 (color
& 0xff00) | ((color
& 0xff0000) >> 16);
65 static inline BOOL
dxt1_to_x4r4g4b4(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
,
66 DWORD pitch_out
, unsigned int w
, unsigned int h
, BOOL alpha
)
71 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
73 for (y
= 0; y
< h
; ++y
)
75 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
76 for (x
= 0; x
< w
; ++x
)
78 /* pfetch_2d_texel_rgba_dxt1 doesn't correctly handle pitch */
79 pfetch_2d_texel_rgba_dxt1(0, src
+ (y
/ 4) * pitch_in
+ (x
/ 4) * 16,
80 x
& 3, y
& 3, &color
);
83 dst_line
[x
] = ((color
& 0xf0000000) >> 16) | ((color
& 0xf00000) >> 20) |
84 ((color
& 0xf000) >> 8) | ((color
& 0xf0) << 4);
88 dst_line
[x
] = 0xf000 | ((color
& 0xf00000) >> 20) |
89 ((color
& 0xf000) >> 8) | ((color
& 0xf0) << 4);
97 static inline BOOL
dxt1_to_x1r5g5b5(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
,
98 DWORD pitch_out
, unsigned int w
, unsigned int h
, BOOL alpha
)
103 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
105 for (y
= 0; y
< h
; ++y
)
107 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
108 for (x
= 0; x
< w
; ++x
)
110 /* pfetch_2d_texel_rgba_dxt1 doesn't correctly handle pitch */
111 pfetch_2d_texel_rgba_dxt1(0, src
+ (y
/ 4) * pitch_in
+ (x
/ 4) * 16,
112 x
& 3, y
& 3, &color
);
115 dst_line
[x
] = ((color
& 0x80000000) >> 16) | ((color
& 0xf80000) >> 19) |
116 ((color
& 0xf800) >> 6) | ((color
& 0xf8) << 7);
120 dst_line
[x
] = 0x8000 | ((color
& 0xf80000) >> 19) |
121 ((color
& 0xf800) >> 6) | ((color
& 0xf8) << 7);
129 static inline BOOL
dxt3_to_x8r8g8b8(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
,
130 DWORD pitch_out
, unsigned int w
, unsigned int h
, BOOL alpha
)
135 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
137 for (y
= 0; y
< h
; ++y
)
139 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
140 for (x
= 0; x
< w
; ++x
)
142 /* pfetch_2d_texel_rgba_dxt3 doesn't correctly handle pitch */
143 pfetch_2d_texel_rgba_dxt3(0, src
+ (y
/ 4) * pitch_in
+ (x
/ 4) * 16,
144 x
& 3, y
& 3, &color
);
147 dst_line
[x
] = (color
& 0xff00ff00) | ((color
& 0xff) << 16) |
148 ((color
& 0xff0000) >> 16);
152 dst_line
[x
] = 0xff000000 | ((color
& 0xff) << 16) |
153 (color
& 0xff00) | ((color
& 0xff0000) >> 16);
161 static inline BOOL
dxt3_to_x4r4g4b4(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
,
162 DWORD pitch_out
, unsigned int w
, unsigned int h
, BOOL alpha
)
167 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
169 for (y
= 0; y
< h
; ++y
)
171 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
172 for (x
= 0; x
< w
; ++x
)
174 /* pfetch_2d_texel_rgba_dxt3 doesn't correctly handle pitch */
175 pfetch_2d_texel_rgba_dxt3(0, src
+ (y
/ 4) * pitch_in
+ (x
/ 4) * 16,
176 x
& 3, y
& 3, &color
);
179 dst_line
[x
] = ((color
& 0xf0000000) >> 16) | ((color
& 0xf00000) >> 20) |
180 ((color
& 0xf000) >> 8) | ((color
& 0xf0) << 4);
184 dst_line
[x
] = 0xf000 | ((color
& 0xf00000) >> 20) |
185 ((color
& 0xf000) >> 8) | ((color
& 0xf0) << 4);
193 static inline BOOL
dxt5_to_x8r8g8b8(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
,
194 DWORD pitch_out
, unsigned int w
, unsigned int h
, BOOL alpha
)
199 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
201 for (y
= 0; y
< h
; ++y
)
203 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
204 for (x
= 0; x
< w
; ++x
)
206 /* pfetch_2d_texel_rgba_dxt5 doesn't correctly handle pitch */
207 pfetch_2d_texel_rgba_dxt5(0, src
+ (y
/ 4) * pitch_in
+ (x
/ 4) * 16,
208 x
& 3, y
& 3, &color
);
211 dst_line
[x
] = (color
& 0xff00ff00) | ((color
& 0xff) << 16) |
212 ((color
& 0xff0000) >> 16);
216 dst_line
[x
] = 0xff000000 | ((color
& 0xff) << 16) |
217 (color
& 0xff00) | ((color
& 0xff0000) >> 16);
225 static inline BOOL
x8r8g8b8_to_dxtn(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
,
226 DWORD pitch_out
, unsigned int w
, unsigned int h
, GLenum destformat
, BOOL alpha
)
231 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
233 tmp
= HeapAlloc(GetProcessHeap(), 0, h
* w
* sizeof(DWORD
));
236 ERR("Failed to allocate memory for conversion\n");
240 for (y
= 0; y
< h
; ++y
)
242 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
243 DWORD
*dst_line
= tmp
+ y
* w
;
244 for (x
= 0; x
< w
; ++x
)
249 dst_line
[x
] = (color
& 0xff00ff00) | ((color
& 0xff) << 16) |
250 ((color
& 0xff0000) >> 16);
254 dst_line
[x
] = 0xff000000 | ((color
& 0xff) << 16) |
255 (color
& 0xff00) | ((color
& 0xff0000) >> 16);
260 ptx_compress_dxtn(4, w
, h
, (BYTE
*)tmp
, destformat
, dst
, pitch_out
);
261 HeapFree(GetProcessHeap(), 0, tmp
);
265 static inline BOOL
x1r5g5b5_to_dxtn(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
,
266 DWORD pitch_out
, unsigned int w
, unsigned int h
, GLenum destformat
, BOOL alpha
)
268 static const unsigned char convert_5to8
[] =
270 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
271 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
272 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
273 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
279 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
281 tmp
= HeapAlloc(GetProcessHeap(), 0, h
* w
* sizeof(DWORD
));
284 ERR("Failed to allocate memory for conversion\n");
288 for (y
= 0; y
< h
; ++y
)
290 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
291 DWORD
*dst_line
= tmp
+ y
* w
;
292 for (x
= 0; x
< w
; ++x
)
297 dst_line
[x
] = ((color
& 0x8000) ? 0xff000000 : 0) |
298 convert_5to8
[(color
& 0x001f)] << 16 |
299 convert_5to8
[(color
& 0x03e0) >> 5] << 8 |
300 convert_5to8
[(color
& 0x7c00) >> 10];
304 dst_line
[x
] = 0xff000000 |
305 convert_5to8
[(color
& 0x001f)] << 16 |
306 convert_5to8
[(color
& 0x03e0) >> 5] << 8 |
307 convert_5to8
[(color
& 0x7c00) >> 10];
312 ptx_compress_dxtn(4, w
, h
, (BYTE
*)tmp
, destformat
, dst
, pitch_out
);
313 HeapFree(GetProcessHeap(), 0, tmp
);
317 BOOL
wined3d_dxt1_decode(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
,
318 enum wined3d_format_id format
, unsigned int w
, unsigned int h
)
320 if (!txc_dxtn_handle
)
325 case WINED3DFMT_B8G8R8A8_UNORM
:
326 return dxt1_to_x8r8g8b8(src
, dst
, pitch_in
, pitch_out
, w
, h
, TRUE
);
327 case WINED3DFMT_B8G8R8X8_UNORM
:
328 return dxt1_to_x8r8g8b8(src
, dst
, pitch_in
, pitch_out
, w
, h
, FALSE
);
329 case WINED3DFMT_B4G4R4A4_UNORM
:
330 return dxt1_to_x4r4g4b4(src
, dst
, pitch_in
, pitch_out
, w
, h
, TRUE
);
331 case WINED3DFMT_B4G4R4X4_UNORM
:
332 return dxt1_to_x4r4g4b4(src
, dst
, pitch_in
, pitch_out
, w
, h
, FALSE
);
333 case WINED3DFMT_B5G5R5A1_UNORM
:
334 return dxt1_to_x1r5g5b5(src
, dst
, pitch_in
, pitch_out
, w
, h
, TRUE
);
335 case WINED3DFMT_B5G5R5X1_UNORM
:
336 return dxt1_to_x1r5g5b5(src
, dst
, pitch_in
, pitch_out
, w
, h
, FALSE
);
341 FIXME("Cannot find a conversion function from format DXT1 to %s.\n", debug_d3dformat(format
));
345 BOOL
wined3d_dxt3_decode(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
,
346 enum wined3d_format_id format
, unsigned int w
, unsigned int h
)
348 if (!txc_dxtn_handle
)
353 case WINED3DFMT_B8G8R8A8_UNORM
:
354 return dxt3_to_x8r8g8b8(src
, dst
, pitch_in
, pitch_out
, w
, h
, TRUE
);
355 case WINED3DFMT_B8G8R8X8_UNORM
:
356 return dxt3_to_x8r8g8b8(src
, dst
, pitch_in
, pitch_out
, w
, h
, FALSE
);
357 case WINED3DFMT_B4G4R4A4_UNORM
:
358 return dxt3_to_x4r4g4b4(src
, dst
, pitch_in
, pitch_out
, w
, h
, TRUE
);
359 case WINED3DFMT_B4G4R4X4_UNORM
:
360 return dxt3_to_x4r4g4b4(src
, dst
, pitch_in
, pitch_out
, w
, h
, FALSE
);
365 FIXME("Cannot find a conversion function from format DXT3 to %s.\n", debug_d3dformat(format
));
369 BOOL
wined3d_dxt5_decode(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
,
370 enum wined3d_format_id format
, unsigned int w
, unsigned int h
)
372 if (!txc_dxtn_handle
)
377 case WINED3DFMT_B8G8R8A8_UNORM
:
378 return dxt5_to_x8r8g8b8(src
, dst
, pitch_in
, pitch_out
, w
, h
, TRUE
);
379 case WINED3DFMT_B8G8R8X8_UNORM
:
380 return dxt5_to_x8r8g8b8(src
, dst
, pitch_in
, pitch_out
, w
, h
, FALSE
);
385 FIXME("Cannot find a conversion function from format DXT5 to %s.\n", debug_d3dformat(format
));
389 BOOL
wined3d_dxt1_encode(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
,
390 enum wined3d_format_id format
, unsigned int w
, unsigned int h
)
392 if (!txc_dxtn_handle
)
397 case WINED3DFMT_B8G8R8A8_UNORM
:
398 return x8r8g8b8_to_dxtn(src
, dst
, pitch_in
, pitch_out
, w
, h
,
399 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
, TRUE
);
400 case WINED3DFMT_B8G8R8X8_UNORM
:
401 return x8r8g8b8_to_dxtn(src
, dst
, pitch_in
, pitch_out
, w
, h
,
402 GL_COMPRESSED_RGB_S3TC_DXT1_EXT
, FALSE
);
403 case WINED3DFMT_B5G5R5A1_UNORM
:
404 return x1r5g5b5_to_dxtn(src
, dst
, pitch_in
, pitch_out
, w
, h
,
405 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
, TRUE
);
406 case WINED3DFMT_B5G5R5X1_UNORM
:
407 return x1r5g5b5_to_dxtn(src
, dst
, pitch_in
, pitch_out
, w
, h
,
408 GL_COMPRESSED_RGB_S3TC_DXT1_EXT
, FALSE
);
413 FIXME("Cannot find a conversion function from format %s to DXT1.\n", debug_d3dformat(format
));
417 BOOL
wined3d_dxt3_encode(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
,
418 enum wined3d_format_id format
, unsigned int w
, unsigned int h
)
420 if (!txc_dxtn_handle
)
425 case WINED3DFMT_B8G8R8A8_UNORM
:
426 return x8r8g8b8_to_dxtn(src
, dst
, pitch_in
, pitch_out
, w
, h
,
427 GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
, TRUE
);
428 case WINED3DFMT_B8G8R8X8_UNORM
:
429 return x8r8g8b8_to_dxtn(src
, dst
, pitch_in
, pitch_out
, w
, h
,
430 GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
, FALSE
);
435 FIXME("Cannot find a conversion function from format %s to DXT3.\n", debug_d3dformat(format
));
439 BOOL
wined3d_dxt5_encode(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
,
440 enum wined3d_format_id format
, unsigned int w
, unsigned int h
)
442 if (!txc_dxtn_handle
)
447 case WINED3DFMT_B8G8R8A8_UNORM
:
448 return x8r8g8b8_to_dxtn(src
, dst
, pitch_in
, pitch_out
, w
, h
,
449 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
, TRUE
);
450 case WINED3DFMT_B8G8R8X8_UNORM
:
451 return x8r8g8b8_to_dxtn(src
, dst
, pitch_in
, pitch_out
, w
, h
,
452 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
, FALSE
);
457 FIXME("Cannot find a conversion function from format %s to DXT5.\n", debug_d3dformat(format
));
461 BOOL
wined3d_dxtn_init(void)
463 static const char *soname
[] =
465 #ifdef SONAME_LIBTXC_DXTN
470 "libtxc_dxtn_s2tc.dylib",
473 "libtxc_dxtn_s2tc.so.0"
477 for (i
= 0; i
< sizeof(soname
)/sizeof(soname
[0]); i
++)
479 txc_dxtn_handle
= wine_dlopen(soname
[i
], RTLD_NOW
, NULL
, 0);
480 if (txc_dxtn_handle
) break;
483 if (!txc_dxtn_handle
)
485 FIXME("Wine cannot find the txc_dxtn library, DXTn software support unavailable.\n");
489 #define LOAD_FUNCPTR(f) \
490 if (!(p##f = wine_dlsym(txc_dxtn_handle, #f, NULL, 0))) \
492 ERR("Can't find symbol %s , DXTn software support unavailable.\n", #f); \
496 LOAD_FUNCPTR(fetch_2d_texel_rgba_dxt1
);
497 LOAD_FUNCPTR(fetch_2d_texel_rgba_dxt3
);
498 LOAD_FUNCPTR(fetch_2d_texel_rgba_dxt5
);
499 LOAD_FUNCPTR(tx_compress_dxtn
);
505 wine_dlclose(txc_dxtn_handle
, NULL
, 0);
506 txc_dxtn_handle
= NULL
;
510 BOOL
wined3d_dxtn_supported(void)
512 return (txc_dxtn_handle
!= NULL
);
515 void wined3d_dxtn_free(void)
518 wine_dlclose(txc_dxtn_handle
, NULL
, 0);