[PATCH 3/5] wined3d: Always store the palette index in the alpha component.

Stefan Dösinger stefan at codeweavers.com
Mon May 12 08:12:43 CDT 2014


Without P8 textures the alpha component is always available for this.
---
 dlls/wined3d/surface.c         | 185 +++++++++--------------------------------
 dlls/wined3d/utils.c           |  33 +-------
 dlls/wined3d/wined3d_private.h |   5 --
 3 files changed, 38 insertions(+), 185 deletions(-)

diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index b671a0d..1fa0f94 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -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,55 @@ 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.
+         * TODO: Consider flipping the image in an FBO. */
+        UINT pitch = wined3d_surface_get_pitch(surface);
+
+        row = HeapAlloc(GetProcessHeap(), 0, pitch);
+            goto error;
 
-        row = HeapAlloc(GetProcessHeap(), 0, len);
-        if (!row)
+        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 +3429,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 +4143,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
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index ad15c05..da7fdcc 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -3088,38 +3088,7 @@ DWORD wined3d_format_convert_from_float(const struct wined3d_surface *surface, c
     }
 
     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;
-    }
+        return (BYTE)((color->a * 255.0f) + 0.5f);
 
     FIXME("Conversion for format %s not implemented.\n", debug_d3dformat(format->id));
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 943600d..f7b5c57 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -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;
-- 
1.8.5.5




More information about the wine-patches mailing list