[PATCH 2/5] wined3d: Merge the IWineD3DSurface::BltFast() implementations.

Henri Verbeet hverbeet at codeweavers.com
Fri Apr 29 06:03:39 CDT 2011


---
 dlls/wined3d/surface.c         |  869 +++++++++++++++++++++-------------------
 dlls/wined3d/wined3d_private.h |    2 +
 2 files changed, 450 insertions(+), 421 deletions(-)

diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index d5fe048..cbc5dfe 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -35,6 +35,12 @@
 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
 WINE_DECLARE_DEBUG_CHANNEL(d3d);
 
+static HRESULT surface_cpu_bltfast(IWineD3DSurfaceImpl *dst_surface, DWORD dst_x, DWORD dst_y,
+        IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, DWORD trans);
+static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect,
+        IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *fx,
+        WINED3DTEXTUREFILTERTYPE filter);
+
 static void surface_cleanup(IWineD3DSurfaceImpl *This)
 {
     TRACE("(%p) : Cleaning up.\n", This);
@@ -1062,6 +1068,61 @@ static HRESULT surface_flip(IWineD3DSurfaceImpl *surface, IWineD3DSurfaceImpl *o
     return WINED3D_OK;
 }
 
+/* Do not call while under the GL lock. */
+static HRESULT surface_bltfast(IWineD3DSurfaceImpl *dst_surface, DWORD dst_x, DWORD dst_y,
+        IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in, DWORD trans)
+{
+    IWineD3DDeviceImpl *device = dst_surface->resource.device;
+
+    TRACE("dst_surface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
+            dst_surface, dst_x, dst_y, src_surface, wine_dbgstr_rect(src_rect_in), trans);
+
+    if ((dst_surface->flags & SFLAG_LOCKED) || (src_surface->flags & SFLAG_LOCKED))
+    {
+        WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
+        return WINEDDERR_SURFACEBUSY;
+    }
+
+    if (device->inScene && (dst_surface == device->depth_stencil || src_surface == device->depth_stencil))
+    {
+        WARN("Attempt to access the depth / stencil surface while in a scene.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+
+    /* Special cases for RenderTargets */
+    if ((dst_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
+            || (src_surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
+    {
+
+        RECT src_rect, dst_rect;
+        DWORD flags = 0;
+
+        surface_get_rect(src_surface, src_rect_in, &src_rect);
+
+        dst_rect.left = dst_x;
+        dst_rect.top = dst_y;
+        dst_rect.right = dst_x + src_rect.right - src_rect.left;
+        dst_rect.bottom = dst_y + src_rect.bottom - src_rect.top;
+
+        /* Convert BltFast flags into Blt ones because BltOverride is called
+         * from Blt as well. */
+        if (trans & WINEDDBLTFAST_SRCCOLORKEY)
+            flags |= WINEDDBLT_KEYSRC;
+        if (trans & WINEDDBLTFAST_DESTCOLORKEY)
+            flags |= WINEDDBLT_KEYDEST;
+        if (trans & WINEDDBLTFAST_WAIT)
+            flags |= WINEDDBLT_WAIT;
+        if (trans & WINEDDBLTFAST_DONOTWAIT)
+            flags |= WINEDDBLT_DONOTWAIT;
+
+        if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface,
+                &dst_rect, src_surface, &src_rect, flags, NULL, WINED3DTEXF_POINT)))
+            return WINED3D_OK;
+    }
+
+    return surface_cpu_bltfast(dst_surface, dst_x, dst_y, src_surface, src_rect_in, trans);
+}
+
 static HRESULT surface_set_mem(IWineD3DSurfaceImpl *surface, void *mem)
 {
     TRACE("surface %p, mem %p.\n", surface, mem);
@@ -1233,6 +1294,7 @@ static const struct wined3d_surface_ops surface_ops =
     surface_unmap,
     surface_getdc,
     surface_flip,
+    surface_bltfast,
     surface_set_mem,
 };
 
@@ -1416,6 +1478,15 @@ static HRESULT gdi_surface_flip(IWineD3DSurfaceImpl *surface, IWineD3DSurfaceImp
     return WINED3D_OK;
 }
 
+static HRESULT gdi_surface_bltfast(IWineD3DSurfaceImpl *dst_surface, DWORD dst_x, DWORD dst_y,
+        IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, DWORD trans)
+{
+    TRACE("dst_surface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
+            dst_surface, dst_x, dst_y, src_surface, wine_dbgstr_rect(src_rect), trans);
+
+    return surface_cpu_bltfast(dst_surface, dst_x, dst_y, src_surface, src_rect, trans);
+}
+
 static HRESULT gdi_surface_set_mem(IWineD3DSurfaceImpl *surface, void *mem)
 {
     TRACE("surface %p, mem %p.\n", surface, mem);
@@ -1474,6 +1545,7 @@ static const struct wined3d_surface_ops gdi_surface_ops =
     gdi_surface_unmap,
     gdi_surface_getdc,
     gdi_surface_flip,
+    gdi_surface_bltfast,
     gdi_surface_set_mem,
 };
 
@@ -3715,410 +3787,149 @@ release:
     return ret;
 }
 
+/* Do not call while under the GL lock. */
 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface,
-        DWORD dstx, DWORD dsty, IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
+        DWORD dst_x, DWORD dst_y, IWineD3DSurface *src_surface, const RECT *src_rect, DWORD trans)
 {
     IWineD3DSurfaceImpl *dst_surface = (IWineD3DSurfaceImpl *)iface;
-    IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
-    const struct wined3d_format *src_format, *dst_format;
-    RECT lock_src, lock_dst, lock_union;
-    WINED3DLOCKED_RECT dlock, slock;
-    HRESULT ret = WINED3D_OK;
-    int bpp, w, h, x, y;
-    const BYTE *sbuf;
-    BYTE *dbuf;
-    RECT rsrc2;
 
-    TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
-            iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
+    TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, trans %#x.\n",
+            iface, dst_x, dst_y, src_surface, wine_dbgstr_rect(src_rect), trans);
 
-    if ((dst_surface->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
-    {
-        WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
-        return WINEDDERR_SURFACEBUSY;
-    }
+    return dst_surface->surface_ops->surface_bltfast(dst_surface, dst_x, dst_y,
+            (IWineD3DSurfaceImpl *)src_surface, src_rect, trans);
+}
 
-    if (!rsrc)
-    {
-        WARN("rsrc is NULL!\n");
-        rsrc2.left = 0;
-        rsrc2.top = 0;
-        rsrc2.right = src->resource.width;
-        rsrc2.bottom = src->resource.height;
-        rsrc = &rsrc2;
-    }
+static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Unmap(IWineD3DSurface *iface)
+{
+    IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
 
-    /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate. */
-    if ((rsrc->bottom > src->resource.height) || (rsrc->bottom < 0)
-            || (rsrc->top > src->resource.height) || (rsrc->top < 0)
-            || (rsrc->left > src->resource.width) || (rsrc->left < 0)
-            || (rsrc->right > src->resource.width) || (rsrc->right < 0)
-            || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
+    TRACE("iface %p.\n", iface);
+
+    if (!(surface->flags & SFLAG_LOCKED))
     {
-        WARN("Application gave us bad source rectangle for BltFast.\n");
-        return WINEDDERR_INVALIDRECT;
+        WARN("Trying to unmap unmapped surface.\n");
+        return WINEDDERR_NOTLOCKED;
     }
+    surface->flags &= ~SFLAG_LOCKED;
 
-    h = rsrc->bottom - rsrc->top;
-    if (h > dst_surface->resource.height-dsty)
-        h = dst_surface->resource.height-dsty;
-    if (h > src->resource.height-rsrc->top)
-        h = src->resource.height-rsrc->top;
-    if (h <= 0)
-        return WINEDDERR_INVALIDRECT;
-
-    w = rsrc->right - rsrc->left;
-    if (w > dst_surface->resource.width-dstx)
-        w = dst_surface->resource.width-dstx;
-    if (w > src->resource.width-rsrc->left)
-        w = src->resource.width-rsrc->left;
-    if (w <= 0)
-        return WINEDDERR_INVALIDRECT;
+    surface->surface_ops->surface_unmap(surface);
 
-    /* Now compute the locking rectangle... */
-    lock_src.left = rsrc->left;
-    lock_src.top = rsrc->top;
-    lock_src.right = lock_src.left + w;
-    lock_src.bottom = lock_src.top + h;
+    return WINED3D_OK;
+}
 
-    lock_dst.left = dstx;
-    lock_dst.top = dsty;
-    lock_dst.right = dstx + w;
-    lock_dst.bottom = dsty + h;
+static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
+        WINED3DLOCKED_RECT *locked_rect, const RECT *rect, DWORD flags)
+{
+    IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
 
-    bpp = dst_surface->resource.format->byte_count;
+    TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
+            iface, locked_rect, wine_dbgstr_rect(rect), flags);
 
-    /* We need to lock the surfaces, or we won't get refreshes when done. */
-    if (src == dst_surface)
+    if (surface->flags & SFLAG_LOCKED)
     {
-        int pitch;
+        WARN("Surface is already mapped.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+    surface->flags |= SFLAG_LOCKED;
 
-        UnionRect(&lock_union, &lock_src, &lock_dst);
+    if (!(surface->flags & SFLAG_LOCKABLE))
+        WARN("Trying to lock unlockable surface.\n");
 
-        /* Lock the union of the two rectangles */
-        ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
-        if (FAILED(ret))
-            goto error;
+    surface->surface_ops->surface_map(surface, rect, flags);
 
-        pitch = dlock.Pitch;
-        slock.Pitch = dlock.Pitch;
+    locked_rect->Pitch = IWineD3DSurface_GetPitch(iface);
 
-        /* Since slock was originally copied from this surface's description, we can just reuse it. */
-        sbuf = dst_surface->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
-        dbuf = dst_surface->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
-        src_format = src->resource.format;
-        dst_format = src_format;
-    }
-    else
+    if (!rect)
     {
-        ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
-        if (FAILED(ret))
-            goto error;
-        ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
-        if (FAILED(ret))
-            goto error;
-
-        sbuf = slock.pBits;
-        dbuf = dlock.pBits;
-        TRACE("Dst is at %p, Src is at %p.\n", dbuf, sbuf);
-
-        src_format = src->resource.format;
-        dst_format = dst_surface->resource.format;
+        locked_rect->pBits = surface->resource.allocatedMemory;
+        surface->lockedRect.left = 0;
+        surface->lockedRect.top = 0;
+        surface->lockedRect.right = surface->resource.width;
+        surface->lockedRect.bottom = surface->resource.height;
     }
-
-    /* Handle compressed surfaces first... */
-    if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
+    else
     {
-        UINT row_block_count;
+        const struct wined3d_format *format = surface->resource.format;
 
-        TRACE("compressed -> compressed copy\n");
-        if (trans)
-            FIXME("trans arg not supported when a compressed surface is involved\n");
-        if (dstx || dsty)
-            FIXME("offset for destination surface is not supported\n");
-        if (src->resource.format->id != dst_surface->resource.format->id)
+        if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
         {
-            FIXME("compressed -> compressed copy only supported for the same type of surface\n");
-            ret = WINED3DERR_WRONGTEXTUREFORMAT;
-            goto error;
+            /* Compressed textures are block based, so calculate the offset of
+             * the block that contains the top-left pixel of the locked rectangle. */
+            locked_rect->pBits = surface->resource.allocatedMemory
+                    + ((rect->top / format->block_height) * locked_rect->Pitch)
+                    + ((rect->left / format->block_width) * format->block_byte_count);
         }
-
-        row_block_count = (w + dst_format->block_width - 1) / dst_format->block_width;
-        for (y = 0; y < h; y += dst_format->block_height)
+        else
         {
-            memcpy(dbuf, sbuf, row_block_count * dst_format->block_byte_count);
-            dbuf += dlock.Pitch;
-            sbuf += slock.Pitch;
+            locked_rect->pBits = surface->resource.allocatedMemory
+                    + (locked_rect->Pitch * rect->top)
+                    + (rect->left * format->byte_count);
         }
-
-        goto error;
+        surface->lockedRect.left = rect->left;
+        surface->lockedRect.top = rect->top;
+        surface->lockedRect.right = rect->right;
+        surface->lockedRect.bottom = rect->bottom;
     }
-    if ((src_format->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dst_format->flags & WINED3DFMT_FLAG_COMPRESSED))
+
+    TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
+    TRACE("Returning memory %p, pitch %u.\n", locked_rect->pBits, locked_rect->Pitch);
+
+    return WINED3D_OK;
+}
+
+static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *dc)
+{
+    IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
+    HRESULT hr;
+
+    TRACE("iface %p, dc %p.\n", iface, dc);
+
+    if (surface->flags & SFLAG_USERPTR)
     {
-        /* TODO: Use the libtxc_dxtn.so shared library to do software
-         * decompression. */
-        ERR("Software decompression not supported.\n");
-        goto error;
+        ERR("Not supported on surfaces with application-provided memory.\n");
+        return WINEDDERR_NODC;
     }
 
-    if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
-    {
-        DWORD keylow, keyhigh;
-        DWORD mask = src->resource.format->red_mask
-                | src->resource.format->green_mask
-                | src->resource.format->blue_mask;
+    /* Give more detailed info for ddraw. */
+    if (surface->flags & SFLAG_DCINUSE)
+        return WINEDDERR_DCALREADYCREATED;
 
-        /* For some 8-bit formats like L8 and P8 color masks don't make sense */
-        if (!mask && bpp == 1)
-            mask = 0xff;
+    /* Can't GetDC if the surface is locked. */
+    if (surface->flags & SFLAG_LOCKED)
+        return WINED3DERR_INVALIDCALL;
 
-        TRACE("Color keyed copy.\n");
-        if (trans & WINEDDBLTFAST_SRCCOLORKEY)
+    hr = surface->surface_ops->surface_getdc(surface);
+    if (FAILED(hr))
+        return hr;
+
+    if (surface->resource.format->id == WINED3DFMT_P8_UINT
+            || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
+    {
+        /* GetDC on palettized formats is unsupported in D3D9, and the method
+         * is missing in D3D8, so this should only be used for DX <=7
+         * surfaces (with non-device palettes). */
+        const PALETTEENTRY *pal = NULL;
+
+        if (surface->palette)
         {
-            keylow = src->SrcBltCKey.dwColorSpaceLowValue;
-            keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
+            pal = surface->palette->palents;
         }
         else
         {
-            /* I'm not sure if this is correct. */
-            FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
-            keylow = dst_surface->DestBltCKey.dwColorSpaceLowValue;
-            keyhigh = dst_surface->DestBltCKey.dwColorSpaceHighValue;
-        }
+            struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
+            IWineD3DSurfaceImpl *dds_primary = swapchain->front_buffer;
 
-#define COPYBOX_COLORKEY(type) \
-do { \
-    const type *s = (const type *)sbuf; \
-    type *d = (type *)dbuf; \
-    type tmp; \
-    for (y = 0; y < h; y++) \
-    { \
-        for (x = 0; x < w; x++) \
-        { \
-            tmp = s[x]; \
-            if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
-        } \
-        s = (const type *)((const BYTE *)s + slock.Pitch); \
-        d = (type *)((BYTE *)d + dlock.Pitch); \
-    } \
-} while(0)
+            if (dds_primary && dds_primary->palette)
+                pal = dds_primary->palette->palents;
+        }
 
-        switch (bpp)
+        if (pal)
         {
-            case 1:
-                COPYBOX_COLORKEY(BYTE);
-                break;
-            case 2:
-                COPYBOX_COLORKEY(WORD);
-                break;
-            case 4:
-                COPYBOX_COLORKEY(DWORD);
-                break;
-            case 3:
-            {
-                const BYTE *s;
-                DWORD tmp;
-                BYTE *d;
-                s = sbuf;
-                d = dbuf;
-                for (y = 0; y < h; ++y)
-                {
-                    for (x = 0; x < w * 3; x += 3)
-                    {
-                        tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
-                        if (tmp < keylow || tmp > keyhigh)
-                        {
-                            d[x + 0] = s[x + 0];
-                            d[x + 1] = s[x + 1];
-                            d[x + 2] = s[x + 2];
-                        }
-                    }
-                    s += slock.Pitch;
-                    d += dlock.Pitch;
-                }
-                break;
-            }
-            default:
-                FIXME("Source color key blitting not supported for bpp %u.\n", bpp * 8);
-                ret = WINED3DERR_NOTAVAILABLE;
-                goto error;
-        }
-#undef COPYBOX_COLORKEY
-        TRACE("Copy done.\n");
-    }
-    else
-    {
-        int width = w * bpp;
-        INT sbufpitch, dbufpitch;
-
-        TRACE("No color key copy.\n");
-        /* Handle overlapping surfaces. */
-        if (sbuf < dbuf)
-        {
-            sbuf += (h - 1) * slock.Pitch;
-            dbuf += (h - 1) * dlock.Pitch;
-            sbufpitch = -slock.Pitch;
-            dbufpitch = -dlock.Pitch;
-        }
-        else
-        {
-            sbufpitch = slock.Pitch;
-            dbufpitch = dlock.Pitch;
-        }
-        for (y = 0; y < h; ++y)
-        {
-            /* This is pretty easy, a line for line memcpy. */
-            memmove(dbuf, sbuf, width);
-            sbuf += sbufpitch;
-            dbuf += dbufpitch;
-        }
-        TRACE("Copy done.\n");
-    }
-
-error:
-    if (src == dst_surface)
-    {
-        IWineD3DSurface_Unmap(iface);
-    }
-    else
-    {
-        IWineD3DSurface_Unmap(iface);
-        IWineD3DSurface_Unmap(src_surface);
-    }
-
-    return ret;
-}
-
-static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Unmap(IWineD3DSurface *iface)
-{
-    IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
-
-    TRACE("iface %p.\n", iface);
-
-    if (!(surface->flags & SFLAG_LOCKED))
-    {
-        WARN("Trying to unmap unmapped surface.\n");
-        return WINEDDERR_NOTLOCKED;
-    }
-    surface->flags &= ~SFLAG_LOCKED;
-
-    surface->surface_ops->surface_unmap(surface);
-
-    return WINED3D_OK;
-}
-
-static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
-        WINED3DLOCKED_RECT *locked_rect, const RECT *rect, DWORD flags)
-{
-    IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
-
-    TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
-            iface, locked_rect, wine_dbgstr_rect(rect), flags);
-
-    if (surface->flags & SFLAG_LOCKED)
-    {
-        WARN("Surface is already mapped.\n");
-        return WINED3DERR_INVALIDCALL;
-    }
-    surface->flags |= SFLAG_LOCKED;
-
-    if (!(surface->flags & SFLAG_LOCKABLE))
-        WARN("Trying to lock unlockable surface.\n");
-
-    surface->surface_ops->surface_map(surface, rect, flags);
-
-    locked_rect->Pitch = IWineD3DSurface_GetPitch(iface);
-
-    if (!rect)
-    {
-        locked_rect->pBits = surface->resource.allocatedMemory;
-        surface->lockedRect.left = 0;
-        surface->lockedRect.top = 0;
-        surface->lockedRect.right = surface->resource.width;
-        surface->lockedRect.bottom = surface->resource.height;
-    }
-    else
-    {
-        const struct wined3d_format *format = surface->resource.format;
-
-        if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
-        {
-            /* Compressed textures are block based, so calculate the offset of
-             * the block that contains the top-left pixel of the locked rectangle. */
-            locked_rect->pBits = surface->resource.allocatedMemory
-                    + ((rect->top / format->block_height) * locked_rect->Pitch)
-                    + ((rect->left / format->block_width) * format->block_byte_count);
-        }
-        else
-        {
-            locked_rect->pBits = surface->resource.allocatedMemory
-                    + (locked_rect->Pitch * rect->top)
-                    + (rect->left * format->byte_count);
-        }
-        surface->lockedRect.left = rect->left;
-        surface->lockedRect.top = rect->top;
-        surface->lockedRect.right = rect->right;
-        surface->lockedRect.bottom = rect->bottom;
-    }
-
-    TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
-    TRACE("Returning memory %p, pitch %u.\n", locked_rect->pBits, locked_rect->Pitch);
-
-    return WINED3D_OK;
-}
-
-static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *dc)
-{
-    IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
-    HRESULT hr;
-
-    TRACE("iface %p, dc %p.\n", iface, dc);
-
-    if (surface->flags & SFLAG_USERPTR)
-    {
-        ERR("Not supported on surfaces with application-provided memory.\n");
-        return WINEDDERR_NODC;
-    }
-
-    /* Give more detailed info for ddraw. */
-    if (surface->flags & SFLAG_DCINUSE)
-        return WINEDDERR_DCALREADYCREATED;
-
-    /* Can't GetDC if the surface is locked. */
-    if (surface->flags & SFLAG_LOCKED)
-        return WINED3DERR_INVALIDCALL;
-
-    hr = surface->surface_ops->surface_getdc(surface);
-    if (FAILED(hr))
-        return hr;
-
-    if (surface->resource.format->id == WINED3DFMT_P8_UINT
-            || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
-    {
-        /* GetDC on palettized formats is unsupported in D3D9, and the method
-         * is missing in D3D8, so this should only be used for DX <=7
-         * surfaces (with non-device palettes). */
-        const PALETTEENTRY *pal = NULL;
-
-        if (surface->palette)
-        {
-            pal = surface->palette->palents;
-        }
-        else
-        {
-            struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
-            IWineD3DSurfaceImpl *dds_primary = swapchain->front_buffer;
-
-            if (dds_primary && dds_primary->palette)
-                pal = dds_primary->palette->palents;
-        }
-
-        if (pal)
-        {
-            RGBQUAD col[256];
-            unsigned int i;
-
-            for (i = 0; i < 256; ++i)
+            RGBQUAD col[256];
+            unsigned int i;
+
+            for (i = 0; i < 256; ++i)
             {
                 col[i].rgbRed = pal[i].peRed;
                 col[i].rgbGreen = pal[i].peGreen;
@@ -5894,7 +5705,6 @@ HRESULT surface_color_fill(IWineD3DSurfaceImpl *s, const RECT *rect, const WINED
     return blitter->color_fill(device, s, rect, color);
 }
 
-/* Not called from the VTable */
 /* Do not call while under the GL lock. */
 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *dst_surface, const RECT *DestRect,
         IWineD3DSurfaceImpl *src_surface, const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx,
@@ -6385,61 +6195,6 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT
     return IWineD3DBaseSurfaceImpl_Blt(iface, DestRect, src_surface, SrcRect, flags, DDBltFx, Filter);
 }
 
-static HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
-        IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
-{
-    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
-    IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
-    IWineD3DDeviceImpl *device = This->resource.device;
-
-    TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
-            iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
-
-    if ((This->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
-    {
-        WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
-        return WINEDDERR_SURFACEBUSY;
-    }
-
-    if (device->inScene && (This == device->depth_stencil || src == device->depth_stencil))
-    {
-        TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
-        return WINED3DERR_INVALIDCALL;
-    }
-
-    /* Special cases for RenderTargets */
-    if ((This->resource.usage & WINED3DUSAGE_RENDERTARGET)
-            || (src->resource.usage & WINED3DUSAGE_RENDERTARGET))
-    {
-
-        RECT SrcRect, DstRect;
-        DWORD flags = 0;
-
-        surface_get_rect(src, rsrc, &SrcRect);
-
-        DstRect.left = dstx;
-        DstRect.top=dsty;
-        DstRect.right = dstx + SrcRect.right - SrcRect.left;
-        DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
-
-        /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
-        if (trans & WINEDDBLTFAST_SRCCOLORKEY)
-            flags |= WINEDDBLT_KEYSRC;
-        if (trans & WINEDDBLTFAST_DESTCOLORKEY)
-            flags |= WINEDDBLT_KEYDEST;
-        if (trans & WINEDDBLTFAST_WAIT)
-            flags |= WINEDDBLT_WAIT;
-        if (trans & WINEDDBLTFAST_DONOTWAIT)
-            flags |= WINEDDBLT_DONOTWAIT;
-
-        if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(This,
-                &DstRect, src, &SrcRect, flags, NULL, WINED3DTEXF_POINT)))
-            return WINED3D_OK;
-    }
-
-    return IWineD3DBaseSurfaceImpl_BltFast(iface, dstx, dsty, src_surface, rsrc, trans);
-}
-
 /* GL locking is done by the caller */
 static void surface_depth_blt(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
         GLuint texture, GLsizei w, GLsizei h, GLenum target)
@@ -7101,7 +6856,7 @@ const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
     IWineD3DBaseSurfaceImpl_GetFlipStatus,
     IWineD3DBaseSurfaceImpl_IsLost,
     IWineD3DBaseSurfaceImpl_Restore,
-    IWineD3DSurfaceImpl_BltFast,
+    IWineD3DBaseSurfaceImpl_BltFast,
     IWineD3DBaseSurfaceImpl_GetPalette,
     IWineD3DBaseSurfaceImpl_SetPalette,
     IWineD3DBaseSurfaceImpl_SetColorKey,
@@ -7292,6 +7047,278 @@ static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined
     return FALSE;
 }
 
+static HRESULT surface_cpu_bltfast(IWineD3DSurfaceImpl *dst_surface, DWORD dst_x, DWORD dst_y,
+        IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, DWORD trans)
+{
+    const struct wined3d_format *src_format, *dst_format;
+    RECT lock_src, lock_dst, lock_union;
+    WINED3DLOCKED_RECT dlock, slock;
+    HRESULT hr = WINED3D_OK;
+    int bpp, w, h, x, y;
+    const BYTE *sbuf;
+    BYTE *dbuf;
+    RECT rsrc2;
+
+    TRACE("dst_surface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
+            dst_surface, dst_x, dst_y, src_surface, wine_dbgstr_rect(src_rect), trans);
+
+    if ((dst_surface->flags & SFLAG_LOCKED) || (src_surface->flags & SFLAG_LOCKED))
+    {
+        WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
+        return WINEDDERR_SURFACEBUSY;
+    }
+
+    if (!src_rect)
+    {
+        WARN("src_rect is NULL!\n");
+        rsrc2.left = 0;
+        rsrc2.top = 0;
+        rsrc2.right = src_surface->resource.width;
+        rsrc2.bottom = src_surface->resource.height;
+        src_rect = &rsrc2;
+    }
+
+    /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate. */
+    if ((src_rect->bottom > src_surface->resource.height) || (src_rect->bottom < 0)
+            || (src_rect->top > src_surface->resource.height) || (src_rect->top < 0)
+            || (src_rect->left > src_surface->resource.width) || (src_rect->left < 0)
+            || (src_rect->right > src_surface->resource.width) || (src_rect->right < 0)
+            || (src_rect->right < src_rect->left) || (src_rect->bottom < src_rect->top))
+    {
+        WARN("Application gave us bad source rectangle for BltFast.\n");
+        return WINEDDERR_INVALIDRECT;
+    }
+
+    h = src_rect->bottom - src_rect->top;
+    if (h > dst_surface->resource.height - dst_y)
+        h = dst_surface->resource.height - dst_y;
+    if (h > src_surface->resource.height - src_rect->top)
+        h = src_surface->resource.height - src_rect->top;
+    if (h <= 0)
+        return WINEDDERR_INVALIDRECT;
+
+    w = src_rect->right - src_rect->left;
+    if (w > dst_surface->resource.width - dst_x)
+        w = dst_surface->resource.width - dst_x;
+    if (w > src_surface->resource.width - src_rect->left)
+        w = src_surface->resource.width - src_rect->left;
+    if (w <= 0)
+        return WINEDDERR_INVALIDRECT;
+
+    /* Now compute the locking rectangle... */
+    lock_src.left = src_rect->left;
+    lock_src.top = src_rect->top;
+    lock_src.right = lock_src.left + w;
+    lock_src.bottom = lock_src.top + h;
+
+    lock_dst.left = dst_x;
+    lock_dst.top = dst_y;
+    lock_dst.right = dst_x + w;
+    lock_dst.bottom = dst_y + h;
+
+    bpp = dst_surface->resource.format->byte_count;
+
+    /* We need to lock the surfaces, or we won't get refreshes when done. */
+    if (src_surface == dst_surface)
+    {
+        int pitch;
+
+        UnionRect(&lock_union, &lock_src, &lock_dst);
+
+        /* Lock the union of the two rectangles */
+        hr = IWineD3DSurface_Map((IWineD3DSurface *)dst_surface, &dlock, &lock_union, 0);
+        if (FAILED(hr))
+            goto error;
+
+        pitch = dlock.Pitch;
+        slock.Pitch = dlock.Pitch;
+
+        /* Since slock was originally copied from this surface's description, we can just reuse it. */
+        sbuf = dst_surface->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
+        dbuf = dst_surface->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
+        src_format = src_surface->resource.format;
+        dst_format = src_format;
+    }
+    else
+    {
+        hr = IWineD3DSurface_Map((IWineD3DSurface *)src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
+        if (FAILED(hr))
+            goto error;
+        hr = IWineD3DSurface_Map((IWineD3DSurface *)dst_surface, &dlock, &lock_dst, 0);
+        if (FAILED(hr))
+            goto error;
+
+        sbuf = slock.pBits;
+        dbuf = dlock.pBits;
+        TRACE("Dst is at %p, Src is at %p.\n", dbuf, sbuf);
+
+        src_format = src_surface->resource.format;
+        dst_format = dst_surface->resource.format;
+    }
+
+    /* Handle compressed surfaces first... */
+    if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
+    {
+        UINT row_block_count;
+
+        TRACE("compressed -> compressed copy\n");
+        if (trans)
+            FIXME("trans arg not supported when a compressed surface is involved\n");
+        if (dst_x || dst_y)
+            FIXME("offset for destination surface is not supported\n");
+        if (src_surface->resource.format->id != dst_surface->resource.format->id)
+        {
+            FIXME("compressed -> compressed copy only supported for the same type of surface\n");
+            hr = WINED3DERR_WRONGTEXTUREFORMAT;
+            goto error;
+        }
+
+        row_block_count = (w + dst_format->block_width - 1) / dst_format->block_width;
+        for (y = 0; y < h; y += dst_format->block_height)
+        {
+            memcpy(dbuf, sbuf, row_block_count * dst_format->block_byte_count);
+            dbuf += dlock.Pitch;
+            sbuf += slock.Pitch;
+        }
+
+        goto error;
+    }
+    if ((src_format->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dst_format->flags & WINED3DFMT_FLAG_COMPRESSED))
+    {
+        /* TODO: Use the libtxc_dxtn.so shared library to do software
+         * decompression. */
+        ERR("Software decompression not supported.\n");
+        goto error;
+    }
+
+    if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
+    {
+        DWORD keylow, keyhigh;
+        DWORD mask = src_surface->resource.format->red_mask
+                | src_surface->resource.format->green_mask
+                | src_surface->resource.format->blue_mask;
+
+        /* For some 8-bit formats like L8 and P8 color masks don't make sense */
+        if (!mask && bpp == 1)
+            mask = 0xff;
+
+        TRACE("Color keyed copy.\n");
+        if (trans & WINEDDBLTFAST_SRCCOLORKEY)
+        {
+            keylow = src_surface->SrcBltCKey.dwColorSpaceLowValue;
+            keyhigh = src_surface->SrcBltCKey.dwColorSpaceHighValue;
+        }
+        else
+        {
+            /* I'm not sure if this is correct. */
+            FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
+            keylow = dst_surface->DestBltCKey.dwColorSpaceLowValue;
+            keyhigh = dst_surface->DestBltCKey.dwColorSpaceHighValue;
+        }
+
+#define COPYBOX_COLORKEY(type) \
+do { \
+    const type *s = (const type *)sbuf; \
+    type *d = (type *)dbuf; \
+    type tmp; \
+    for (y = 0; y < h; y++) \
+    { \
+        for (x = 0; x < w; x++) \
+        { \
+            tmp = s[x]; \
+            if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
+        } \
+        s = (const type *)((const BYTE *)s + slock.Pitch); \
+        d = (type *)((BYTE *)d + dlock.Pitch); \
+    } \
+} while(0)
+
+        switch (bpp)
+        {
+            case 1:
+                COPYBOX_COLORKEY(BYTE);
+                break;
+            case 2:
+                COPYBOX_COLORKEY(WORD);
+                break;
+            case 4:
+                COPYBOX_COLORKEY(DWORD);
+                break;
+            case 3:
+            {
+                const BYTE *s;
+                DWORD tmp;
+                BYTE *d;
+                s = sbuf;
+                d = dbuf;
+                for (y = 0; y < h; ++y)
+                {
+                    for (x = 0; x < w * 3; x += 3)
+                    {
+                        tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
+                        if (tmp < keylow || tmp > keyhigh)
+                        {
+                            d[x + 0] = s[x + 0];
+                            d[x + 1] = s[x + 1];
+                            d[x + 2] = s[x + 2];
+                        }
+                    }
+                    s += slock.Pitch;
+                    d += dlock.Pitch;
+                }
+                break;
+            }
+            default:
+                FIXME("Source color key blitting not supported for bpp %u.\n", bpp * 8);
+                hr = WINED3DERR_NOTAVAILABLE;
+                goto error;
+        }
+#undef COPYBOX_COLORKEY
+        TRACE("Copy done.\n");
+    }
+    else
+    {
+        int width = w * bpp;
+        INT sbufpitch, dbufpitch;
+
+        TRACE("No color key copy.\n");
+        /* Handle overlapping surfaces. */
+        if (sbuf < dbuf)
+        {
+            sbuf += (h - 1) * slock.Pitch;
+            dbuf += (h - 1) * dlock.Pitch;
+            sbufpitch = -slock.Pitch;
+            dbufpitch = -dlock.Pitch;
+        }
+        else
+        {
+            sbufpitch = slock.Pitch;
+            dbufpitch = dlock.Pitch;
+        }
+        for (y = 0; y < h; ++y)
+        {
+            /* This is pretty easy, a line for line memcpy. */
+            memmove(dbuf, sbuf, width);
+            sbuf += sbufpitch;
+            dbuf += dbufpitch;
+        }
+        TRACE("Copy done.\n");
+    }
+
+error:
+    if (src_surface == dst_surface)
+    {
+        IWineD3DSurface_Unmap((IWineD3DSurface *)dst_surface);
+    }
+    else
+    {
+        IWineD3DSurface_Unmap((IWineD3DSurface *)dst_surface);
+        IWineD3DSurface_Unmap((IWineD3DSurface *)src_surface);
+    }
+
+    return hr;
+}
+
 /* Do not call while under the GL lock. */
 static HRESULT cpu_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface,
         const RECT *dst_rect, const WINED3DCOLORVALUE *color)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 5fb2a67..1a702b5 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2027,6 +2027,8 @@ struct wined3d_surface_ops
     void (*surface_unmap)(struct IWineD3DSurfaceImpl *surface);
     HRESULT (*surface_getdc)(struct IWineD3DSurfaceImpl *surface);
     HRESULT (*surface_flip)(struct IWineD3DSurfaceImpl *surface, struct IWineD3DSurfaceImpl *override);
+    HRESULT (*surface_bltfast)(struct IWineD3DSurfaceImpl *dst_surface, DWORD dst_x, DWORD dst_y,
+            IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, DWORD trans);
     HRESULT (*surface_set_mem)(struct IWineD3DSurfaceImpl *surface, void *mem);
 };
 
-- 
1.7.3.4




More information about the wine-patches mailing list