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 --- dlls/d3dx9_36/surface.c | 106 +++++++++++++++++++++++++++++++--------- 1 file changed, 84 insertions(+), 22 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index a5143cbee4..fdf0ce28da 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 *srcformatdesc, *destformatdesc; + 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,25 +2161,92 @@ HRESULT WINAPI D3DXLoadSurfaceFromSurface(IDirect3DSurface9 *dst_surface, if (!dst_surface || !src_surface) return D3DERR_INVALIDCALL;
+ IDirect3DSurface9_GetDesc(src_surface, &src_desc); + srcformatdesc = 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 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); + destformatdesc = get_format_info(dst_desc.Format); + if (!dst_rect) + { + dst_rect = &dst_rect_temp; + dst_rect_temp.left = 0; + dst_rect_temp.top = 0; + dst_rect_temp.right = dst_desc.Width; + dst_rect_temp.bottom = dst_desc.Height; + } + else if (dst_rect->left == dst_rect->right || dst_rect->top == dst_rect->bottom) + { + WARN("Empty dst_rect specified.\n"); + return 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 & (srcformatdesc->block_width - 1)) + && !(src_rect->top & (srcformatdesc->block_height - 1)) + && !(dst_rect->left & (destformatdesc->block_width - 1)) + && !(dst_rect->top & (destformatdesc->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 = ~0u; + break; + } }
if (d3d_filter != ~0u) @@ -2189,14 +2259,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;
Signed-off-by: Robin Kertels robin.kertels@gmail.com --- dlls/d3dx9_36/tests/surface.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index e9b9e04178..9fedcb04bf 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1032,6 +1032,26 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) hr = D3DXLoadSurfaceFromSurface(surf, NULL, NULL, newsurf, NULL, NULL, D3DX_FILTER_LINEAR, 0); ok(hr == D3D_OK, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x.\n", hr, D3D_OK);
+ /* rects */ + SetRect(&rect, 2, 2, 1, 1); + hr = D3DXLoadSurfaceFromSurface(surf, NULL, NULL, newsurf, NULL, &rect, D3DX_FILTER_NONE, 0); + ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x.\n", hr, D3DERR_INVALIDCALL); + hr = D3DXLoadSurfaceFromSurface(surf, NULL, &rect, newsurf, NULL, NULL, D3DX_FILTER_NONE, 0); + ok(hr == D3DERR_INVALIDCALL, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x.\n", hr, D3DERR_INVALIDCALL); + SetRect(&rect, 1, 1, 1, 1); + hr = D3DXLoadSurfaceFromSurface(surf, NULL, NULL, newsurf, NULL, &rect, D3DX_FILTER_NONE, 0); + ok(hr == E_FAIL, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x.\n", hr, E_FAIL); + hr = D3DXLoadSurfaceFromSurface(surf, NULL, &rect, newsurf, NULL, NULL, D3DX_FILTER_NONE, 0); + ok(hr == E_FAIL, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x.\n", hr, E_FAIL); + SetRect(&rect, 1, 1, 2, 2); + SetRect(&destrect, 1, 1, 2, 2); + hr = D3DXLoadSurfaceFromSurface(surf, NULL, &rect, newsurf, NULL, &destrect, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x.\n", hr, D3D_OK); + hr = D3DXLoadSurfaceFromSurface(surf, NULL, &rect, newsurf, NULL, NULL, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x.\n", hr, D3D_OK); + hr = D3DXLoadSurfaceFromSurface(surf, NULL, NULL, newsurf, NULL, &destrect, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "D3DXLoadSurfaceFromSurface returned %#x, expected %#x.\n", hr, D3D_OK); + IDirect3DSurface9_Release(newsurf);
check_release((IUnknown*)surf, 0);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=74983
Your paranoid android.
=== w8 (32 bit report) ===
d3dx9_36: surface.c:1043: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005. surface.c:1045: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005.
=== w8adm (32 bit report) ===
d3dx9_36: surface.c:1043: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005. surface.c:1045: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005.
=== w1064v1507 (32 bit report) ===
d3dx9_36: surface.c:1043: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005. surface.c:1045: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005.
=== w1064v1809 (32 bit report) ===
d3dx9_36: surface.c:1043: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005. surface.c:1045: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005.
=== w1064v1809_2scr (32 bit report) ===
d3dx9_36: surface.c:1043: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005. surface.c:1045: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005.
=== w1064v1809_ar (32 bit report) ===
d3dx9_36: surface.c:1043: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005. surface.c:1045: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005.
=== w1064v1809_he (32 bit report) ===
d3dx9_36: surface.c:1043: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005. surface.c:1045: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005.
=== w1064v1809_ja (32 bit report) ===
d3dx9_36: surface.c:1043: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005. surface.c:1045: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005.
=== w1064v1809_zh_CN (32 bit report) ===
d3dx9_36: surface.c:1043: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005. surface.c:1045: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005.
=== w864 (64 bit report) ===
d3dx9_36: surface.c:1043: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005. surface.c:1045: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005.
=== w1064v1507 (64 bit report) ===
d3dx9_36: surface.c:1043: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005. surface.c:1045: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005.
=== w1064v1809 (64 bit report) ===
d3dx9_36: surface.c:1043: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005. surface.c:1045: Test failed: D3DXLoadSurfaceFromSurface returned 0, expected 0x80004005.