wined3d: Always store the palette index in the alpha component.

This commit is contained in:
Stefan Dösinger 2014-05-13 16:21:49 +02:00 committed by Alexandre Julliard
parent eb4d5c7a25
commit c1cca63e5d
3 changed files with 37 additions and 187 deletions

View File

@ -1104,7 +1104,6 @@ static BOOL surface_convert_color_to_float(const struct wined3d_surface *surface
DWORD color, struct wined3d_color *float_color)
{
const struct wined3d_format *format = surface->resource.format;
const struct wined3d_device *device = surface->resource.device;
switch (format->id)
{
@ -1121,7 +1120,7 @@ static BOOL surface_convert_color_to_float(const struct wined3d_surface *surface
float_color->g = 0.0f;
float_color->b = 0.0f;
}
float_color->a = swapchain_is_p8(device->swapchains[0]) ? color / 255.0f : 1.0f;
float_color->a = color / 255.0f;
break;
case WINED3DFMT_B5G6R5_UNORM:
@ -1458,8 +1457,7 @@ static void surface_download_data(struct wined3d_surface *surface, const struct
int src_pitch = 0;
int dst_pitch = 0;
/* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
if (format->id == WINED3DFMT_P8_UINT && swapchain_is_p8(surface->resource.device->swapchains[0]))
if (format->id == WINED3DFMT_P8_UINT)
{
gl_format = GL_ALPHA;
gl_type = GL_UNSIGNED_BYTE;
@ -3220,10 +3218,8 @@ static void read_from_framebuffer(struct wined3d_surface *surface, DWORD dst_loc
GLint type;
BYTE *row, *top, *bottom;
int i;
BOOL bpp;
BOOL srcIsUpsideDown;
struct wined3d_bo_address data;
UINT pitch = wined3d_surface_get_pitch(surface);
surface_get_memory(surface, &data, dst_location);
@ -3256,53 +3252,19 @@ static void read_from_framebuffer(struct wined3d_surface *surface, DWORD dst_loc
switch (surface->resource.format->id)
{
case WINED3DFMT_P8_UINT:
{
if (swapchain_is_p8(context->swapchain))
{
/* In case of P8 render targets the index is stored in the alpha component */
fmt = GL_ALPHA;
type = GL_UNSIGNED_BYTE;
mem = data.addr;
bpp = surface->resource.format->byte_count;
}
else
{
/* GL can't return palettized data, so read ARGB pixels into a
* separate block of memory and convert them into palettized format
* in software. Slow, but if the app means to use palettized render
* targets and locks it...
*
* Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
* Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
* for the color channels when palettizing the colors.
*/
fmt = GL_RGB;
type = GL_UNSIGNED_BYTE;
pitch *= 3;
mem = HeapAlloc(GetProcessHeap(), 0, surface->resource.size * 3);
if (!mem)
{
ERR("Out of memory\n");
return;
}
bpp = surface->resource.format->byte_count * 3;
}
}
break;
fmt = GL_ALPHA;
type = GL_UNSIGNED_BYTE;
break;
default:
mem = data.addr;
fmt = surface->resource.format->glFormat;
type = surface->resource.format->glType;
bpp = surface->resource.format->byte_count;
}
if (data.buffer_object)
{
GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, data.buffer_object));
checkGLcall("glBindBufferARB");
if (mem)
ERR("mem not null for pbo -- unexpected\n");
}
/* Setup pixel store pack state -- to glReadPixels into the correct place */
@ -3311,106 +3273,54 @@ static void read_from_framebuffer(struct wined3d_surface *surface, DWORD dst_loc
gl_info->gl_ops.gl.p_glReadPixels(0, 0,
surface->resource.width, surface->resource.height,
fmt, type, mem);
fmt, type, data.addr);
checkGLcall("glReadPixels");
/* Reset previous pixel store pack state */
gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
checkGLcall("glPixelStorei");
if (data.buffer_object && !srcIsUpsideDown)
{
/* Check if we need to flip the image. If we need to flip use glMapBufferARB
* to get a pointer to it and perform the flipping in software. This is a lot
* faster than calling glReadPixels for each line. In case we want more speed
* we should rerender it flipped in a FBO and read the data back from the FBO. */
mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB));
checkGLcall("glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB)");
}
/* TODO: Merge this with the palettization loop below for P8 targets */
if (!srcIsUpsideDown)
{
UINT len;
/* glReadPixels returns the image upside down, and there is no way to prevent this.
Flip the lines in software */
len = surface->resource.width * bpp;
* Flip the lines in software. */
UINT pitch = wined3d_surface_get_pitch(surface);
row = HeapAlloc(GetProcessHeap(), 0, len);
if (!row)
if (!(row = HeapAlloc(GetProcessHeap(), 0, pitch)))
goto error;
if (data.buffer_object)
{
ERR("Out of memory\n");
if (surface->resource.format->id == WINED3DFMT_P8_UINT)
HeapFree(GetProcessHeap(), 0, mem);
return;
mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB));
checkGLcall("glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB)");
}
else
mem = data.addr;
top = mem;
bottom = mem + pitch * (surface->resource.height - 1);
for (i = 0; i < surface->resource.height / 2; i++)
{
memcpy(row, top, len);
memcpy(top, bottom, len);
memcpy(bottom, row, len);
memcpy(row, top, pitch);
memcpy(top, bottom, pitch);
memcpy(bottom, row, pitch);
top += pitch;
bottom -= pitch;
}
HeapFree(GetProcessHeap(), 0, row);
if (data.buffer_object)
GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB));
}
error:
if (data.buffer_object)
{
if (!srcIsUpsideDown)
GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB));
GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
checkGLcall("glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0)");
}
context_release(context);
/* For P8 textures we need to perform an inverse palette lookup. This is
* done by searching for a palette index which matches the RGB value.
* Note this isn't guaranteed to work when there are multiple entries for
* the same color but we have no choice. In case of P8 render targets,
* the index is stored in the alpha component so no conversion is needed. */
if (surface->resource.format->id == WINED3DFMT_P8_UINT && !swapchain_is_p8(context->swapchain))
{
const RGBQUAD *colors = NULL;
DWORD width = pitch / 3;
int x, y, c;
if (!surface->palette)
{
ERR("Palette is missing, cannot perform inverse palette lookup\n");
HeapFree(GetProcessHeap(), 0, mem);
return;
}
colors = surface->palette->colors;
for (y = 0; y < surface->resource.height; y++)
{
for (x = 0; x < surface->resource.width; x++)
{
/* start lines pixels */
const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
const BYTE *green = blue + 1;
const BYTE *red = green + 1;
for (c = 0; c < 256; c++)
{
if (*red == colors[c].rgbRed
&& *green == colors[c].rgbGreen
&& *blue == colors[c].rgbBlue)
{
*((BYTE *)data.addr + y * width + x) = c;
break;
}
}
}
}
HeapFree(GetProcessHeap(), 0, mem);
}
}
/* Read the framebuffer contents into a texture. Note that this function
@ -3518,52 +3428,31 @@ static BOOL color_in_range(const struct wined3d_color_key *color_key, DWORD colo
void d3dfmt_p8_init_palette(const struct wined3d_surface *surface, BYTE table[256][4], BOOL colorkey)
{
const struct wined3d_device *device = surface->resource.device;
const struct wined3d_palette *pal = surface->palette;
BOOL index_in_alpha = FALSE;
unsigned int i;
/* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
* Reading back the RGB output each lockrect (each frame as they lock the whole screen)
* is slow. Further RGB->P8 conversion is not possible because palettes can have
* duplicate entries. Store the color key in the unused alpha component to speed the
* download up and to make conversion unneeded. */
index_in_alpha = swapchain_is_p8(device->swapchains[0]);
if (!pal)
{
FIXME("No palette set.\n");
if (index_in_alpha)
{
/* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
* there's no palette at this time. */
/* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
* there's no palette at this time. */
for (i = 0; i < 256; i++) table[i][3] = i;
}
}
else
{
TRACE("Using surface palette %p\n", pal);
/* Get the surface's palette */
for (i = 0; i < 256; ++i)
{
table[i][0] = pal->colors[i].rgbRed;
table[i][1] = pal->colors[i].rgbGreen;
table[i][2] = pal->colors[i].rgbBlue;
/* When index_in_alpha is set the palette index is stored in the
* alpha component. In case of a readback we can then read
* GL_ALPHA. Color keying is handled in surface_blt_special() using a
* GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
* color key itself is passed to glAlphaFunc in other cases the
* alpha component of pixels that should be masked away is set to 0. */
if (index_in_alpha)
table[i][3] = i;
else if (colorkey && color_in_range(&surface->container->src_blt_color_key, i))
table[i][3] = 0x00;
else if (pal->flags & WINED3D_PALETTE_ALPHA)
table[i][3] = pal->colors[i].rgbReserved;
else
table[i][3] = 0xff;
/* The palette index is stored in the alpha component. In case of a
* readback we can then read GL_ALPHA. Color keying is handled in
* surface_blt_to_drawable() using a GL_ALPHA_TEST using GL_NOT_EQUAL.
* In case of a P8 surface the color key itself is passed to
* glAlphaFunc in other cases the alpha component of pixels that
* should be masked away is set to 0. */
table[i][3] = i;
}
}
}
@ -4253,11 +4142,10 @@ static void surface_blt_to_drawable(const struct wined3d_device *device,
gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
checkGLcall("glEnable(GL_ALPHA_TEST)");
/* When the primary render target uses P8, the alpha component
* contains the palette index. Which means that the colorkey is one of
* the palette entries. In other cases pixels that should be masked
* away have alpha set to 0. */
if (swapchain_is_p8(context->swapchain))
/* For P8 surfaces, the alpha component contains the palette index.
* Which means that the colorkey is one of the palette entries. In
* other cases pixels that should be masked away have alpha set to 0. */
if (src_surface->resource.format->id == WINED3DFMT_P8_UINT)
gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
(float)src_surface->container->src_blt_color_key.color_space_low_value / 256.0f);
else

View File

@ -3064,6 +3064,7 @@ DWORD wined3d_format_convert_from_float(const struct wined3d_surface *surface, c
{WINED3DFMT_R8G8B8X8_UNORM, 255.0f, 255.0f, 255.0f, 255.0f, 0, 8, 16, 24},
{WINED3DFMT_B10G10R10A2_UNORM, 1023.0f, 1023.0f, 1023.0f, 3.0f, 20, 10, 0, 30},
{WINED3DFMT_R10G10B10A2_UNORM, 1023.0f, 1023.0f, 1023.0f, 3.0f, 0, 10, 20, 30},
{WINED3DFMT_P8_UINT, 0.0f, 0.0f, 0.0f, 255.0f, 0, 0, 0, 0},
};
const struct wined3d_format *format = surface->resource.format;
unsigned int i;
@ -3087,40 +3088,6 @@ DWORD wined3d_format_convert_from_float(const struct wined3d_surface *surface, c
return ret;
}
if (format->id == WINED3DFMT_P8_UINT)
{
const RGBQUAD *e;
BYTE r, g, b, a;
if (!surface->palette)
{
WARN("Surface doesn't have a palette, returning 0.\n");
return 0;
}
r = (BYTE)((color->r * 255.0f) + 0.5f);
g = (BYTE)((color->g * 255.0f) + 0.5f);
b = (BYTE)((color->b * 255.0f) + 0.5f);
a = (BYTE)((color->a * 255.0f) + 0.5f);
e = &surface->palette->colors[a];
if (e->rgbRed == r && e->rgbGreen == g && e->rgbBlue == b)
return a;
WARN("Alpha didn't match index, searching full palette.\n");
for (i = 0; i < 256; ++i)
{
e = &surface->palette->colors[i];
if (e->rgbRed == r && e->rgbGreen == g && e->rgbBlue == b)
return i;
}
FIXME("Unable to convert color to palette index.\n");
return 0;
}
FIXME("Conversion for format %s not implemented.\n", debug_d3dformat(format->id));
return 0;

View File

@ -2636,11 +2636,6 @@ struct wined3d_swapchain
HWND backup_wnd;
};
static inline BOOL swapchain_is_p8(const struct wined3d_swapchain *swapchain)
{
return swapchain->desc.backbuffer_format == WINED3DFMT_P8_UINT;
}
void x11_copy_to_screen(const struct wined3d_swapchain *swapchain, const RECT *rect) DECLSPEC_HIDDEN;
struct wined3d_context *swapchain_get_context(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;