[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