[Mesa-dev] [PATCH 35/45] st/nine: Handle Window Occlusion

Axel Davy axel.davy at ens.fr
Fri Jan 29 08:08:59 PST 2016


From: Patrick Rudolph <siro at das-labor.org>

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 <siro at das-labor.org>
Reviewed-by: Axel Davy <axel.davy at ens.fr>
---
 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 52fbc99..d74ce80 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 08a9729..162f703 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 48c4a2e..33775ac 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 6a81ea9..f462bcb 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 5fb30da..11244b1 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 c00fad5..1c7e57e 100644
--- a/src/gallium/state_trackers/nine/device9ex.h
+++ b/src/gallium/state_trackers/nine/device9ex.h
@@ -74,6 +74,13 @@ NineDevice9Ex_PresentEx( struct NineDevice9Ex *This,
                          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 );
 
@@ -142,9 +149,16 @@ NineDevice9Ex_ResetEx( struct NineDevice9Ex *This,
                        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 c8d3ca1..5d05f1f 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 5e48dde..4bd74f7 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.7.0



More information about the mesa-dev mailing list