From: Robin Kertels robin.kertels@gmail.com
This allows us to use IDirect3DDevice9_StretchRect and avoid GPU synchronization. It massively improves performance in Dead Space 1 which calls LoadSurfaceFromSurface every frame before presenting.
Signed-off-by: Robin Kertels robin.kertels@gmail.com Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- v4: Improve style a tiny bit.
dlls/d3dx9_36/surface.c | 105 +++++++++++++++++++++++++++++++--------- 1 file changed, 82 insertions(+), 23 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index a5143cbee4a8..045d7267c96e 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -2142,11 +2142,14 @@ HRESULT WINAPI D3DXLoadSurfaceFromSurface(IDirect3DSurface9 *dst_surface, const PALETTEENTRY *dst_palette, const RECT *dst_rect, IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect, DWORD filter, D3DCOLOR color_key) { + const struct pixel_format_desc *src_format_desc, *dst_format_desc; + D3DSURFACE_DESC src_desc, dst_desc; + struct volume src_size, dst_size; IDirect3DSurface9 *temp_surface; D3DTEXTUREFILTERTYPE d3d_filter; IDirect3DDevice9 *device; - D3DSURFACE_DESC src_desc; D3DLOCKED_RECT lock; + RECT dst_rect_temp; HRESULT hr; RECT s;
@@ -2158,28 +2161,92 @@ HRESULT WINAPI D3DXLoadSurfaceFromSurface(IDirect3DSurface9 *dst_surface, if (!dst_surface || !src_surface) return D3DERR_INVALIDCALL;
+ IDirect3DSurface9_GetDesc(src_surface, &src_desc); + src_format_desc = get_format_info(src_desc.Format); + if (!src_rect) + { + SetRect(&s, 0, 0, src_desc.Width, src_desc.Height); + src_rect = &s; + } + else if (src_rect->left == src_rect->right || src_rect->top == src_rect->bottom) + { + WARN("Empty src_rect specified.\n"); + return filter == D3DX_FILTER_NONE ? D3D_OK : E_FAIL; + } + else if (src_rect->left > src_rect->right || src_rect->right > src_desc.Width + || src_rect->left < 0 || src_rect->left > src_desc.Width + || src_rect->top > src_rect->bottom || src_rect->bottom > src_desc.Height + || src_rect->top < 0 || src_rect->top > src_desc.Height) + { + WARN("Invalid src_rect specified.\n"); + return D3DERR_INVALIDCALL; + } + + src_size.width = src_rect->right - src_rect->left; + src_size.height = src_rect->bottom - src_rect->top; + src_size.depth = 1; + + IDirect3DSurface9_GetDesc(dst_surface, &dst_desc); + dst_format_desc = get_format_info(dst_desc.Format); + if (!dst_rect) + { + SetRect(&dst_rect_temp, 0, 0, dst_desc.Width, dst_desc.Height); + dst_rect = &dst_rect_temp; + } + else if (dst_rect->left == dst_rect->right || dst_rect->top == dst_rect->bottom) + { + WARN("Empty dst_rect specified.\n"); + return filter == D3DX_FILTER_NONE ? D3D_OK : E_FAIL; + } + else if (dst_rect->left > dst_rect->right || dst_rect->right > dst_desc.Width + || dst_rect->left < 0 || dst_rect->left > dst_desc.Width + || dst_rect->top > dst_rect->bottom || dst_rect->bottom > dst_desc.Height + || dst_rect->top < 0 || dst_rect->top > dst_desc.Height) + { + WARN("Invalid dst_rect specified.\n"); + return D3DERR_INVALIDCALL; + } + + dst_size.width = dst_rect->right - dst_rect->left; + dst_size.height = dst_rect->bottom - dst_rect->top; + dst_size.depth = 1; + if (!dst_palette && !src_palette && !color_key) { - switch (filter) + if (src_desc.Format == dst_desc.Format + && dst_size.width == src_size.width + && dst_size.height == src_size.height + && color_key == 0 + && !(src_rect->left & (src_format_desc->block_width - 1)) + && !(src_rect->top & (src_format_desc->block_height - 1)) + && !(dst_rect->left & (dst_format_desc->block_width - 1)) + && !(dst_rect->top & (dst_format_desc->block_height - 1))) { - case D3DX_FILTER_NONE: - d3d_filter = D3DTEXF_NONE; - break; + d3d_filter = D3DTEXF_NONE; + } + else + { + switch (filter) + { + case D3DX_FILTER_NONE: + d3d_filter = D3DTEXF_NONE; + break;
- case D3DX_FILTER_POINT: - d3d_filter = D3DTEXF_POINT; - break; + case D3DX_FILTER_POINT: + d3d_filter = D3DTEXF_POINT; + break;
- case D3DX_FILTER_LINEAR: - d3d_filter = D3DTEXF_LINEAR; - break; + case D3DX_FILTER_LINEAR: + d3d_filter = D3DTEXF_LINEAR; + break;
- default: - d3d_filter = ~0u; - break; + default: + d3d_filter = D3DTEXF_FORCE_DWORD; + break; + } }
- if (d3d_filter != ~0u) + if (d3d_filter != D3DTEXF_FORCE_DWORD) { IDirect3DSurface9_GetDevice(src_surface, &device); hr = IDirect3DDevice9_StretchRect(device, src_surface, src_rect, dst_surface, dst_rect, d3d_filter); @@ -2189,14 +2256,6 @@ HRESULT WINAPI D3DXLoadSurfaceFromSurface(IDirect3DSurface9 *dst_surface, } }
- IDirect3DSurface9_GetDesc(src_surface, &src_desc); - - if (!src_rect) - { - SetRect(&s, 0, 0, src_desc.Width, src_desc.Height); - src_rect = &s; - } - if (FAILED(lock_surface(src_surface, NULL, &lock, &temp_surface, FALSE))) return D3DXERR_INVALIDDATA;