d3dx9: Handle pixel formats larger than 32 bits in surface loading / filtering functions.

This commit is contained in:
Matteo Bruni 2014-02-14 17:36:38 +01:00 committed by Alexandre Julliard
parent 73e4f6200e
commit 950c40b117
3 changed files with 100 additions and 97 deletions

View File

@ -98,6 +98,7 @@ HRESULT load_volume_texture_from_dds(IDirect3DVolumeTexture9 *volume_texture, co
const PALETTEENTRY *palette, DWORD filter, DWORD color_key, const D3DXIMAGE_INFO *src_info) DECLSPEC_HIDDEN; const PALETTEENTRY *palette, DWORD filter, DWORD color_key, const D3DXIMAGE_INFO *src_info) DECLSPEC_HIDDEN;
unsigned short float_32_to_16(const float in) DECLSPEC_HIDDEN; unsigned short float_32_to_16(const float in) DECLSPEC_HIDDEN;
float float_16_to_32(const unsigned short in) DECLSPEC_HIDDEN;
/* debug helpers */ /* debug helpers */
const char *debug_d3dxparameter_class(D3DXPARAMETER_CLASS c) DECLSPEC_HIDDEN; const char *debug_d3dxparameter_class(D3DXPARAMETER_CLASS c) DECLSPEC_HIDDEN;

View File

@ -2226,7 +2226,7 @@ D3DXFLOAT16 *WINAPI D3DXFloat32To16Array(D3DXFLOAT16 *pout, const FLOAT *pin, UI
/* Native d3dx9's D3DXFloat16to32Array lacks support for NaN and Inf. Specifically, e = 16 is treated as a /* Native d3dx9's D3DXFloat16to32Array lacks support for NaN and Inf. Specifically, e = 16 is treated as a
* regular number - e.g., 0x7fff is converted to 131008.0 and 0xffff to -131008.0. */ * regular number - e.g., 0x7fff is converted to 131008.0 and 0xffff to -131008.0. */
static inline float float_16_to_32(const unsigned short in) float float_16_to_32(const unsigned short in)
{ {
const unsigned short s = (in & 0x8000); const unsigned short s = (in & 0x8000);
const unsigned short e = (in & 0x7C00) >> 10; const unsigned short e = (in & 0x7C00) >> 10;

View File

@ -1339,33 +1339,6 @@ static void init_argb_conversion_info(const struct pixel_format_desc *srcformat,
} }
} }
static DWORD dword_from_bytes(const BYTE *src, UINT bytes_per_pixel)
{
DWORD ret = 0;
static BOOL fixme_once;
if(bytes_per_pixel > sizeof(DWORD)) {
if(!fixme_once++) FIXME("Unsupported image: %u bytes per pixel\n", bytes_per_pixel);
bytes_per_pixel = sizeof(DWORD);
}
memcpy(&ret, src, bytes_per_pixel);
return ret;
}
static void dword_to_bytes(BYTE *dst, DWORD dword, UINT bytes_per_pixel)
{
static BOOL fixme_once;
if(bytes_per_pixel > sizeof(DWORD)) {
if(!fixme_once++) FIXME("Unsupported image: %u bytes per pixel\n", bytes_per_pixel);
ZeroMemory(dst, bytes_per_pixel);
bytes_per_pixel = sizeof(DWORD);
}
memcpy(dst, &dword, bytes_per_pixel);
}
/************************************************************ /************************************************************
* get_relevant_argb_components * get_relevant_argb_components
* *
@ -1403,55 +1376,78 @@ static DWORD make_argb_color(const struct argb_conversion_info *info, const DWOR
return val; return val;
} }
static void format_to_vec4(const struct pixel_format_desc *format, const DWORD *src, struct vec4 *dst) /* It doesn't work for components bigger than 32 bits (or somewhat smaller but unaligned). */
static void format_to_vec4(const struct pixel_format_desc *format, const BYTE *src, struct vec4 *dst)
{ {
DWORD mask; DWORD mask, tmp;
unsigned int c;
if (format->bits[1]) for (c = 0; c < 4; ++c)
{ {
mask = (1 << format->bits[1]) - 1; static const unsigned int component_offsets[4] = {3, 0, 1, 2};
dst->x = (float)((*src >> format->shift[1]) & mask) / mask; float *dst_component = (float *)dst + component_offsets[c];
}
else
dst->x = 1.0f;
if (format->bits[2]) if (format->bits[c])
{ {
mask = (1 << format->bits[2]) - 1; mask = ~0u >> (32 - format->bits[c]);
dst->y = (float)((*src >> format->shift[2]) & mask) / mask;
}
else
dst->y = 1.0f;
if (format->bits[3]) memcpy(&tmp, src + format->shift[c] / 8,
{ min(sizeof(DWORD), (format->shift[c] % 8 + format->bits[c] + 7) / 8));
mask = (1 << format->bits[3]) - 1;
dst->z = (float)((*src >> format->shift[3]) & mask) / mask;
}
else
dst->z = 1.0f;
if (format->bits[0]) if (format->type == FORMAT_ARGBF16)
{ *dst_component = float_16_to_32(tmp);
mask = (1 << format->bits[0]) - 1; else if (format->type == FORMAT_ARGBF)
dst->w = (float)((*src >> format->shift[0]) & mask) / mask; *dst_component = *(float *)&tmp;
else
*dst_component = (float)((tmp >> format->shift[c] % 8) & mask) / mask;
}
else
*dst_component = 1.0f;
} }
else
dst->w = 1.0f;
} }
static void format_from_vec4(const struct pixel_format_desc *format, const struct vec4 *src, DWORD *dst) /* It doesn't work for components bigger than 32 bits. */
static void format_from_vec4(const struct pixel_format_desc *format, const struct vec4 *src, BYTE *dst)
{ {
*dst = 0; DWORD v, mask32;
unsigned int c, i;
if (format->bits[1]) memset(dst, 0, format->bytes_per_pixel);
*dst |= (DWORD)(src->x * ((1 << format->bits[1]) - 1) + 0.5f) << format->shift[1];
if (format->bits[2]) for (c = 0; c < 4; ++c)
*dst |= (DWORD)(src->y * ((1 << format->bits[2]) - 1) + 0.5f) << format->shift[2]; {
if (format->bits[3]) static const unsigned int component_offsets[4] = {3, 0, 1, 2};
*dst |= (DWORD)(src->z * ((1 << format->bits[3]) - 1) + 0.5f) << format->shift[3]; const float src_component = *((const float *)src + component_offsets[c]);
if (format->bits[0])
*dst |= (DWORD)(src->w * ((1 << format->bits[0]) - 1) + 0.5f) << format->shift[0]; if (!format->bits[c])
continue;
mask32 = ~0u >> (32 - format->bits[c]);
if (format->type == FORMAT_ARGBF16)
v = float_32_to_16(src_component);
else if (format->type == FORMAT_ARGBF)
v = *(DWORD *)&src_component;
else
v = (DWORD)(src_component * ((1 << format->bits[c]) - 1) + 0.5f);
for (i = format->shift[c] / 8 * 8; i < format->shift[c] + format->bits[c]; i += 8)
{
BYTE mask, byte;
if (format->shift[c] > i)
{
mask = mask32 << (format->shift[c] - i);
byte = (v << (format->shift[c] - i)) & mask;
}
else
{
mask = mask32 >> (i - format->shift[c]);
byte = (v >> (i - format->shift[c])) & mask;
}
dst[i / 8] |= byte;
}
}
} }
/************************************************************ /************************************************************
@ -1500,7 +1496,7 @@ void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pit
{ {
struct argb_conversion_info conv_info, ck_conv_info; struct argb_conversion_info conv_info, ck_conv_info;
const struct pixel_format_desc *ck_format = NULL; const struct pixel_format_desc *ck_format = NULL;
DWORD channels[4], pixel; DWORD channels[4];
UINT min_width, min_height, min_depth; UINT min_width, min_height, min_depth;
UINT x, y, z; UINT x, y, z;
@ -1525,30 +1521,32 @@ void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pit
for (y = 0; y < min_height; y++) { for (y = 0; y < min_height; y++) {
const BYTE *src_ptr = src_slice_ptr + y * src_row_pitch; const BYTE *src_ptr = src_slice_ptr + y * src_row_pitch;
BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch; BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch;
DWORD val;
for (x = 0; x < min_width; x++) { for (x = 0; x < min_width; x++) {
/* extract source color components */ if (!src_format->to_rgba && !dst_format->from_rgba
pixel = dword_from_bytes(src_ptr, src_format->bytes_per_pixel); && src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4)
if (!src_format->to_rgba && !dst_format->from_rgba)
{ {
get_relevant_argb_components(&conv_info, pixel, channels); DWORD val;
get_relevant_argb_components(&conv_info, *(DWORD *)src_ptr, channels);
val = make_argb_color(&conv_info, channels); val = make_argb_color(&conv_info, channels);
if (color_key) if (color_key)
{ {
get_relevant_argb_components(&ck_conv_info, pixel, channels); DWORD ck_pixel;
pixel = make_argb_color(&ck_conv_info, channels);
if (pixel == color_key) get_relevant_argb_components(&ck_conv_info, *(DWORD *)src_ptr, channels);
ck_pixel = make_argb_color(&ck_conv_info, channels);
if (ck_pixel == color_key)
val &= ~conv_info.destmask[0]; val &= ~conv_info.destmask[0];
} }
memcpy(dst_ptr, &val, dst_format->bytes_per_pixel);
} }
else else
{ {
struct vec4 color, tmp; struct vec4 color, tmp;
format_to_vec4(src_format, &pixel, &color); format_to_vec4(src_format, src_ptr, &color);
if (src_format->to_rgba) if (src_format->to_rgba)
src_format->to_rgba(&color, &tmp, palette); src_format->to_rgba(&color, &tmp, palette);
else else
@ -1556,8 +1554,10 @@ void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pit
if (ck_format) if (ck_format)
{ {
format_from_vec4(ck_format, &tmp, &pixel); DWORD ck_pixel;
if (pixel == color_key)
format_from_vec4(ck_format, &tmp, (BYTE *)&ck_pixel);
if (ck_pixel == color_key)
tmp.w = 0.0f; tmp.w = 0.0f;
} }
@ -1566,11 +1566,10 @@ void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pit
else else
color = tmp; color = tmp;
format_from_vec4(dst_format, &color, &val); format_from_vec4(dst_format, &color, dst_ptr);
} }
dword_to_bytes(dst_ptr, val, dst_format->bytes_per_pixel); src_ptr += src_format->bytes_per_pixel;
src_ptr += src_format->bytes_per_pixel;
dst_ptr += dst_format->bytes_per_pixel; dst_ptr += dst_format->bytes_per_pixel;
} }
@ -1600,7 +1599,7 @@ void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slic
{ {
struct argb_conversion_info conv_info, ck_conv_info; struct argb_conversion_info conv_info, ck_conv_info;
const struct pixel_format_desc *ck_format = NULL; const struct pixel_format_desc *ck_format = NULL;
DWORD channels[4], pixel; DWORD channels[4];
UINT x, y, z; UINT x, y, z;
ZeroMemory(channels, sizeof(channels)); ZeroMemory(channels, sizeof(channels));
@ -1626,29 +1625,31 @@ void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slic
for (x = 0; x < dst_size->width; x++) for (x = 0; x < dst_size->width; x++)
{ {
const BYTE *src_ptr = src_row_ptr + (x * src_size->width / dst_size->width) * src_format->bytes_per_pixel; const BYTE *src_ptr = src_row_ptr + (x * src_size->width / dst_size->width) * src_format->bytes_per_pixel;
DWORD val;
/* extract source color components */ if (!src_format->to_rgba && !dst_format->from_rgba
pixel = dword_from_bytes(src_ptr, src_format->bytes_per_pixel); && src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4)
if (!src_format->to_rgba && !dst_format->from_rgba)
{ {
get_relevant_argb_components(&conv_info, pixel, channels); DWORD val;
get_relevant_argb_components(&conv_info, *(DWORD *)src_ptr, channels);
val = make_argb_color(&conv_info, channels); val = make_argb_color(&conv_info, channels);
if (color_key) if (color_key)
{ {
get_relevant_argb_components(&ck_conv_info, pixel, channels); DWORD ck_pixel;
pixel = make_argb_color(&ck_conv_info, channels);
if (pixel == color_key) get_relevant_argb_components(&ck_conv_info, *(DWORD *)src_ptr, channels);
ck_pixel = make_argb_color(&ck_conv_info, channels);
if (ck_pixel == color_key)
val &= ~conv_info.destmask[0]; val &= ~conv_info.destmask[0];
} }
memcpy(dst_ptr, &val, dst_format->bytes_per_pixel);
} }
else else
{ {
struct vec4 color, tmp; struct vec4 color, tmp;
format_to_vec4(src_format, &pixel, &color); format_to_vec4(src_format, src_ptr, &color);
if (src_format->to_rgba) if (src_format->to_rgba)
src_format->to_rgba(&color, &tmp, palette); src_format->to_rgba(&color, &tmp, palette);
else else
@ -1656,8 +1657,10 @@ void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slic
if (ck_format) if (ck_format)
{ {
format_from_vec4(ck_format, &tmp, &pixel); DWORD ck_pixel;
if (pixel == color_key)
format_from_vec4(ck_format, &tmp, (BYTE *)&ck_pixel);
if (ck_pixel == color_key)
tmp.w = 0.0f; tmp.w = 0.0f;
} }
@ -1666,10 +1669,9 @@ void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slic
else else
color = tmp; color = tmp;
format_from_vec4(dst_format, &color, &val); format_from_vec4(dst_format, &color, dst_ptr);
} }
dword_to_bytes(dst_ptr, val, dst_format->bytes_per_pixel);
dst_ptr += dst_format->bytes_per_pixel; dst_ptr += dst_format->bytes_per_pixel;
} }
} }