Hi there,
I was playing with a older Japanese side scrolling shooter benchmark and was getting 4.3 frames per second. Some digging revealed that the game made extensive use of Blt on gdi surfaces and it looks like the current implementation of Blt actually locks the entire destination surface to blt to it. This then causes the Unlock to copy the entire screen out. This means that every time any sprite moved the entire screen redrew.
I threw together this patch, which seems far to simple to be at all correct, and suddenly i was getting 28.8 frames per second. I know it is not fully correct because a a portion of the game (drawn by FastBlt it looks like) stopped rendering correctly with this patch.
But I thought it may get someone who knows that area better thinking about it. If we can optimize this then a number of the scrolling shooter games will become playable. I am told that these style games are still very popular here.
And if said people in the know where to busy, maybe they could give me some pointers on if I have the right approach or not.
If anyone is interested I can provide an archive with the benchmark program in it.
-aric
diff --git a/dlls/wined3d/surface_base.c b/dlls/wined3d/surface_base.c index 57809e1..2ec3a52 100644 --- a/dlls/wined3d/surface_base.c +++ b/dlls/wined3d/surface_base.c @@ -852,7 +852,7 @@ IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface,
if (Src == This) { - IWineD3DSurface_LockRect(iface, &dlock, NULL, 0); + IWineD3DSurface_LockRect(iface, &dlock, DestRect, 0); dfmt = This->resource.format; slock = dlock; sfmt = dfmt; @@ -877,20 +877,26 @@ IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, sfmt = Src->resource.format; } sEntry = getFormatDescEntry(sfmt, NULL, NULL); - IWineD3DSurface_LockRect(iface, &dlock,NULL,0); + IWineD3DSurface_LockRect(iface, &dlock, DestRect,0); }
if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
if (sEntry->isFourcc && dEntry->isFourcc) - { - memcpy(dlock.pBits, slock.pBits, This->resource.size); - goto release; + { + if (!DestRect) + { + memcpy(dlock.pBits, slock.pBits, This->resource.size); + goto release; + } }
if (DestRect) { - xdst = *DestRect; + xdst.top = 0; + xdst.bottom = DestRect->bottom - DestRect->top; + xdst.left = 0; + xdst.right = DestRect->right - DestRect->left; } else {
2008/7/25 Aric Stewart aric@codeweavers.com:
IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
IWineD3DSurface_LockRect(iface, &dlock, DestRect, 0); dfmt = This->resource.format; slock = dlock;
I don't think you can simply insert DestRect there, unless it's the same as SrcRect (because of the slock = dlock line a few lines down).
if (DestRect) {
xdst = *DestRect;
xdst.top = 0;
xdst.bottom = DestRect->bottom - DestRect->top;
xdst.left = 0;
}xdst.right = DestRect->right - DestRect->left;
This will break things like checking for out of surface rectangles, clipping and overlapping blits.
Stefan knows this part of the code better than me, but I don't think there's anything wrong with the concept of the patch.
Stefan knows this part of the code better than me, but I don't think there's anything wrong with the concept of the patch.
I agree with Henri on a quick look. I want to add though that you have to watch out not to dereference DestRect without checking it for NULL first