From a961ec335d5f38c07181e4956341c9b4cca59fa4 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Sat, 20 Jun 2015 20:06:11 +0200 Subject: [PATCH] st/nine: Handle Window Occlusion Apps can know if the window is occluded by checking for specific error messages. The behaviour is different for Device9 and Device9Ex. This allow games to release the mouse and stop rendering until the focus is restored. In case of multiple swapchain we do care only of the device one. Signed-off-by: Patrick Rudolph Reviewed-by: Axel Davy --- include/D3D9/d3d9types.h | 1 + include/d3dadapter/present.h | 3 ++ src/gallium/state_trackers/nine/device9.c | 19 ++++++-- src/gallium/state_trackers/nine/device9.h | 3 ++ src/gallium/state_trackers/nine/device9ex.c | 48 ++++++++++++++++++-- src/gallium/state_trackers/nine/device9ex.h | 14 ++++++ src/gallium/state_trackers/nine/swapchain9.c | 23 ++++++++++ src/gallium/state_trackers/nine/swapchain9.h | 3 ++ 8 files changed, 108 insertions(+), 6 deletions(-) diff --git a/include/D3D9/d3d9types.h b/include/D3D9/d3d9types.h index 52fbc99dad7..d74ce80bb30 100644 --- a/include/D3D9/d3d9types.h +++ b/include/D3D9/d3d9types.h @@ -227,6 +227,7 @@ typedef struct _RGNDATA { #define D3DERR_DRIVERINVALIDCALL MAKE_D3DHRESULT(2157) #define D3DERR_DEVICEREMOVED MAKE_D3DHRESULT(2160) #define D3DERR_DEVICEHUNG MAKE_D3DHRESULT(2164) +#define S_PRESENT_OCCLUDED MAKE_D3DSTATUS(2168) /******************************************************** * Bitmasks * diff --git a/include/d3dadapter/present.h b/include/d3dadapter/present.h index 08a97297201..162f703e320 100644 --- a/include/d3dadapter/present.h +++ b/include/d3dadapter/present.h @@ -69,6 +69,8 @@ typedef struct ID3DPresentVtbl HRESULT (WINAPI *SetCursor)(ID3DPresent *This, void *pBitmap, POINT *pHotspot, BOOL bShow); HRESULT (WINAPI *SetGammaRamp)(ID3DPresent *This, const D3DGAMMARAMP *pRamp, HWND hWndOverride); HRESULT (WINAPI *GetWindowInfo)(ID3DPresent *This, HWND hWnd, int *width, int *height, int *depth); + /* Available since version 1.1 */ + BOOL (WINAPI *GetWindowOccluded)(ID3DPresent *This); } ID3DPresentVtbl; struct ID3DPresent @@ -96,6 +98,7 @@ struct ID3DPresent #define ID3DPresent_SetCursor(p,a,b,c) (p)->lpVtbl->SetCursor(p,a,b,c) #define ID3DPresent_SetGammaRamp(p,a,b) (p)->lpVtbl->SetGammaRamp(p,a,b) #define ID3DPresent_GetWindowInfo(p,a,b,c,d) (p)->lpVtbl->GetWindowSize(p,a,b,c,d) +#define ID3DPresent_GetWindowOccluded(p) (p)->lpVtbl->GetWindowOccluded(p) typedef struct ID3DPresentGroupVtbl { diff --git a/src/gallium/state_trackers/nine/device9.c b/src/gallium/state_trackers/nine/device9.c index 6cd7099981d..cb6c813b650 100644 --- a/src/gallium/state_trackers/nine/device9.c +++ b/src/gallium/state_trackers/nine/device9.c @@ -81,7 +81,7 @@ static void nine_setup_fpu(void) #endif -static void +void NineDevice9_SetDefaultState( struct NineDevice9 *This, boolean is_reset ) { struct NineSurface9 *refSurf = NULL; @@ -527,7 +527,14 @@ NineDevice9_ResumeRecording( struct NineDevice9 *This ) HRESULT WINAPI NineDevice9_TestCooperativeLevel( struct NineDevice9 *This ) { - return D3D_OK; /* TODO */ + if (NineSwapChain9_GetOccluded(This->swapchains[0])) { + This->device_needs_reset = TRUE; + return D3DERR_DEVICELOST; + } else if (This->device_needs_reset) { + return D3DERR_DEVICENOTRESET; + } + + return D3D_OK; } UINT WINAPI @@ -766,11 +773,16 @@ NineDevice9_Reset( struct NineDevice9 *This, DBG("This=%p pPresentationParameters=%p\n", This, pPresentationParameters); + if (NineSwapChain9_GetOccluded(This->swapchains[0])) { + This->device_needs_reset = TRUE; + return D3DERR_DEVICELOST; + } + for (i = 0; i < This->nswapchains; ++i) { D3DPRESENT_PARAMETERS *params = &pPresentationParameters[i]; hr = NineSwapChain9_Resize(This->swapchains[i], params, NULL); if (hr != D3D_OK) - return hr; + break; } nine_pipe_context_clear(This); @@ -781,6 +793,7 @@ NineDevice9_Reset( struct NineDevice9 *This, This, 0, (IDirect3DSurface9 *)This->swapchains[0]->buffers[0]); /* XXX: better use GetBackBuffer here ? */ + This->device_needs_reset = (hr != D3D_OK); return hr; } diff --git a/src/gallium/state_trackers/nine/device9.h b/src/gallium/state_trackers/nine/device9.h index 6a81ea91d34..f462bcb1c36 100644 --- a/src/gallium/state_trackers/nine/device9.h +++ b/src/gallium/state_trackers/nine/device9.h @@ -137,6 +137,7 @@ struct NineDevice9 /* dummy vbo (containing 0 0 0 0) to bind if vertex shader input * is not bound to anything by the vertex declaration */ struct pipe_resource *dummy_vbo; + BOOL device_needs_reset; int minor_version_num; }; static inline struct NineDevice9 * @@ -176,6 +177,8 @@ void NineDevice9_dtor( struct NineDevice9 *This ); /*** Nine private ***/ +void +NineDevice9_SetDefaultState( struct NineDevice9 *This, boolean is_reset ); struct pipe_screen * NineDevice9_GetScreen( struct NineDevice9 *This ); diff --git a/src/gallium/state_trackers/nine/device9ex.c b/src/gallium/state_trackers/nine/device9ex.c index 5fb30da74f3..11244b1bedf 100644 --- a/src/gallium/state_trackers/nine/device9ex.c +++ b/src/gallium/state_trackers/nine/device9ex.c @@ -20,7 +20,9 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "device9.h" #include "device9ex.h" +#include "nine_pipe.h" #include "swapchain9ex.h" #include "nine_helpers.h" @@ -159,6 +161,14 @@ NineDevice9Ex_CheckDeviceState( struct NineDevice9Ex *This, DBG("This=%p hDestinationWindow=%p\n", This, hDestinationWindow); + user_assert(!This->base.swapchains[0]->params.Windowed, D3D_OK); + + if (This->base.params.hFocusWindow == hDestinationWindow) { + if (NineSwapChain9_GetOccluded(This->base.swapchains[0])) + return S_PRESENT_OCCLUDED; + } else if(!NineSwapChain9_GetOccluded(This->base.swapchains[0])) { + return S_PRESENT_OCCLUDED; + } /* TODO: handle the other return values */ return D3D_OK; } @@ -222,12 +232,37 @@ NineDevice9Ex_ResetEx( struct NineDevice9Ex *This, if (pFullscreenDisplayMode) mode = &(pFullscreenDisplayMode[i]); hr = NineSwapChain9_Resize(This->base.swapchains[i], params, mode); if (FAILED(hr)) - return (hr == D3DERR_OUTOFVIDEOMEMORY) ? hr : D3DERR_DEVICELOST; + break; } NineDevice9_SetRenderTarget( (struct NineDevice9 *)This, 0, (IDirect3DSurface9 *)This->base.swapchains[0]->buffers[0]); + return hr; +} + +HRESULT WINAPI +NineDevice9Ex_Reset( struct NineDevice9Ex *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ) +{ + HRESULT hr = D3D_OK; + unsigned i; + + DBG("This=%p pPresentationParameters=%p\n", This, pPresentationParameters); + + for (i = 0; i < This->base.nswapchains; ++i) { + D3DPRESENT_PARAMETERS *params = &pPresentationParameters[i]; + hr = NineSwapChain9_Resize(This->base.swapchains[i], params, NULL); + if (FAILED(hr)) + break; + } + + nine_pipe_context_clear((struct NineDevice9 *)This); + nine_state_clear(&This->base.state, TRUE); + + NineDevice9_SetDefaultState((struct NineDevice9 *)This, TRUE); + NineDevice9_SetRenderTarget( + (struct NineDevice9 *)This, 0, (IDirect3DSurface9 *)This->base.swapchains[0]->buffers[0]); return hr; } @@ -249,11 +284,18 @@ NineDevice9Ex_GetDisplayModeEx( struct NineDevice9Ex *This, return NineSwapChain9Ex_GetDisplayModeEx(swapchain, pMode, pRotation); } +HRESULT WINAPI +NineDevice9Ex_TestCooperativeLevel( struct NineDevice9Ex *This ) +{ + return D3D_OK; +} + + IDirect3DDevice9ExVtbl NineDevice9Ex_vtable = { (void *)NineUnknown_QueryInterface, (void *)NineUnknown_AddRef, (void *)NineUnknown_Release, - (void *)NineDevice9_TestCooperativeLevel, + (void *)NineDevice9Ex_TestCooperativeLevel, (void *)NineDevice9_GetAvailableTextureMem, (void *)NineDevice9_EvictManagedResources, (void *)NineDevice9_GetDirect3D, @@ -266,7 +308,7 @@ IDirect3DDevice9ExVtbl NineDevice9Ex_vtable = { (void *)NineDevice9_CreateAdditionalSwapChain, (void *)NineDevice9_GetSwapChain, (void *)NineDevice9_GetNumberOfSwapChains, - (void *)NineDevice9_Reset, + (void *)NineDevice9Ex_Reset, (void *)NineDevice9_Present, (void *)NineDevice9_GetBackBuffer, (void *)NineDevice9_GetRasterStatus, diff --git a/src/gallium/state_trackers/nine/device9ex.h b/src/gallium/state_trackers/nine/device9ex.h index c00fad5ffa2..1c7e57e0974 100644 --- a/src/gallium/state_trackers/nine/device9ex.h +++ b/src/gallium/state_trackers/nine/device9ex.h @@ -73,6 +73,13 @@ NineDevice9Ex_PresentEx( struct NineDevice9Ex *This, const RGNDATA *pDirtyRegion, DWORD dwFlags ); +HRESULT WINAPI +NineDevice9Ex_Present( struct NineDevice9Ex *This, + const RECT *pSourceRect, + const RECT *pDestRect, + HWND hDestWindowOverride, + const RGNDATA *pDirtyRegion ); + HRESULT WINAPI NineDevice9Ex_GetGPUThreadPriority( struct NineDevice9Ex *This, INT *pPriority ); @@ -141,10 +148,17 @@ NineDevice9Ex_ResetEx( struct NineDevice9Ex *This, D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode ); +HRESULT WINAPI +NineDevice9Ex_Reset( struct NineDevice9Ex *This, + D3DPRESENT_PARAMETERS *pPresentationParameters ); + HRESULT WINAPI NineDevice9Ex_GetDisplayModeEx( struct NineDevice9Ex *This, UINT iSwapChain, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation ); +HRESULT WINAPI +NineDevice9Ex_TestCooperativeLevel( struct NineDevice9Ex *This ); + #endif /* _NINE_DEVICE9EX_H_ */ diff --git a/src/gallium/state_trackers/nine/swapchain9.c b/src/gallium/state_trackers/nine/swapchain9.c index c8d3ca15890..5d05f1f4697 100644 --- a/src/gallium/state_trackers/nine/swapchain9.c +++ b/src/gallium/state_trackers/nine/swapchain9.c @@ -787,6 +787,19 @@ NineSwapChain9_Present( struct NineSwapChain9 *This, if (hr == D3DERR_WASSTILLDRAWING) return hr; + if (This->base.device->ex) { + if (NineSwapChain9_GetOccluded(This)) { + return S_PRESENT_OCCLUDED; + } + } else { + if (NineSwapChain9_GetOccluded(This)) { + This->base.device->device_needs_reset = TRUE; + } + if (This->base.device->device_needs_reset) { + return D3DERR_DEVICELOST; + } + } + switch (This->params.SwapEffect) { case D3DSWAPEFFECT_FLIP: UNTESTED(4); @@ -992,3 +1005,13 @@ NineSwapChain9_new( struct NineDevice9 *pDevice, implicit, pPresent, pPresentationParameters, pCTX, hFocusWindow, NULL); } + +BOOL +NineSwapChain9_GetOccluded( struct NineSwapChain9 *This ) +{ + if (This->base.device->minor_version_num > 0) { + return ID3DPresent_GetWindowOccluded(This->present); + } + + return FALSE; +} diff --git a/src/gallium/state_trackers/nine/swapchain9.h b/src/gallium/state_trackers/nine/swapchain9.h index 5e48dde5004..4bd74f7b6ec 100644 --- a/src/gallium/state_trackers/nine/swapchain9.h +++ b/src/gallium/state_trackers/nine/swapchain9.h @@ -139,4 +139,7 @@ HRESULT WINAPI NineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This, D3DPRESENT_PARAMETERS *pPresentationParameters ); +BOOL +NineSwapChain9_GetOccluded( struct NineSwapChain9 *This ); + #endif /* _NINE_SWAPCHAIN9_H_ */ -- 2.30.2