Mesa (master): d3d1x: rework DXGI for occlusion testing and default width/ height

Luca Barbieri lb at kemper.freedesktop.org
Mon Sep 27 20:28:44 UTC 2010


Module: Mesa
Branch: master
Commit: f976cd0c9ead6a5e63146c11823770176c149a12
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=f976cd0c9ead6a5e63146c11823770176c149a12

Author: Luca Barbieri <luca at luca-barbieri.com>
Date:   Mon Sep 27 20:25:17 2010 +0200

d3d1x: rework DXGI for occlusion testing and default width/height

---

 .../state_trackers/d3d1x/dxgi/src/dxgi_native.cpp  |   89 ++++++++++++++++++-
 .../state_trackers/d3d1x/gd3dapi/galliumdxgi.idl   |   26 +++++-
 .../state_trackers/d3d1x/winedlls/dxgi/dxgi_dll.c  |   88 +++++++++++++++----
 3 files changed, 174 insertions(+), 29 deletions(-)

diff --git a/src/gallium/state_trackers/d3d1x/dxgi/src/dxgi_native.cpp b/src/gallium/state_trackers/d3d1x/dxgi/src/dxgi_native.cpp
index a75a953..e1c3461 100644
--- a/src/gallium/state_trackers/d3d1x/dxgi/src/dxgi_native.cpp
+++ b/src/gallium/state_trackers/d3d1x/dxgi/src/dxgi_native.cpp
@@ -65,10 +65,12 @@ struct GalliumDXGIObject : public GalliumPrivateDataComObject<Base>
 
 COM_INTERFACE(IGalliumDXGIBackend, IUnknown)
 
+// TODO: somehow check whether the window is fully obscured or not
 struct GalliumDXGIIdentityBackend : public GalliumComObject<IGalliumDXGIBackend>
 {
-	virtual void * STDMETHODCALLTYPE BeginPresent(
+	virtual HRESULT STDMETHODCALLTYPE BeginPresent(
 		HWND hwnd,
+		void** present_cookie,
 		void** window,
 		RECT *rect,
 		RGNDATA **rgndata,
@@ -84,7 +86,8 @@ struct GalliumDXGIIdentityBackend : public GalliumComObject<IGalliumDXGIBackend>
 
 		// yes, because we like things looking good
 		*preserve_aspect_ratio = TRUE;
-		return 0;
+		*present_cookie = 0;
+		return S_OK;
 	}
 
 	virtual void STDMETHODCALLTYPE EndPresent(
@@ -92,6 +95,45 @@ struct GalliumDXGIIdentityBackend : public GalliumComObject<IGalliumDXGIBackend>
 		void* present_cookie
 	)
 	{}
+
+	virtual HRESULT STDMETHODCALLTYPE TestPresent(HWND hwnd)
+	{
+		return S_OK;
+	}
+
+        virtual HRESULT STDMETHODCALLTYPE GetPresentSize(
+                HWND hwnd,
+                unsigned* width,
+                unsigned* height
+        )
+        {
+                *width = 0;
+                *height = 0;
+                return S_OK;
+        }
+};
+
+// TODO: maybe install an X11 error hook, so we can return errors properly
+struct GalliumDXGIX11IdentityBackend : public GalliumDXGIIdentityBackend
+{
+	Display* dpy;
+
+	GalliumDXGIX11IdentityBackend(Display* dpy)
+	: dpy(dpy)
+	{}
+
+	virtual HRESULT STDMETHODCALLTYPE GetPresentSize(
+		HWND hwnd,
+		unsigned* width,
+		unsigned* height
+	)
+        {
+		XWindowAttributes xwa;
+		XGetWindowAttributes(dpy, (Window)hwnd, &xwa);
+		*width = xwa.width;
+		*height = xwa.height;
+		return S_OK;
+        }
 };
 
 struct GalliumDXGIFactory : public GalliumDXGIObject<IDXGIFactory1, IUnknown>
@@ -107,6 +149,8 @@ struct GalliumDXGIFactory : public GalliumDXGIObject<IDXGIFactory1, IUnknown>
 	 {
 		if(p_backend)
 			backend = p_backend;
+		else if(!strcmp(platform->name, "X11"))
+			backend.reset(new GalliumDXGIX11IdentityBackend((Display*)display));
 		else
 			backend.reset(new GalliumDXGIIdentityBackend());
 	}
@@ -887,6 +931,10 @@ struct GalliumDXGISwapChain : public GalliumDXGIObject<IDXGISwapChain, GalliumDX
 
 		blitter.reset(new dxgi_blitter(pipe));
 		window = 0;
+
+		hr = resolve_zero_width_height(true);
+		if(!SUCCEEDED(hr))
+			throw hr;
 	}
 
 	void init_for_window()
@@ -1006,12 +1054,36 @@ struct GalliumDXGISwapChain : public GalliumDXGIObject<IDXGISwapChain, GalliumDX
 		return true;
 	}
 
+	HRESULT resolve_zero_width_height(bool force = false)
+	{
+		if(!force && desc.BufferDesc.Width && desc.BufferDesc.Height)
+			return S_OK;
+
+		unsigned width, height;
+		HRESULT hr = parent->backend->GetPresentSize(desc.OutputWindow, &width, &height);
+		if(!SUCCEEDED(hr))
+			return hr;
+
+		// On Windows, 8 is used, and a debug message saying so gets printed
+		if(!width)
+			width = 8;
+		if(!height)
+			height = 8;
+
+		if(!desc.BufferDesc.Width)
+			desc.BufferDesc.Width = width;
+		if(!desc.BufferDesc.Height)
+			desc.BufferDesc.Height = height;
+		return S_OK;
+	}
+
 	virtual HRESULT STDMETHODCALLTYPE Present(
 		UINT sync_interval,
 		UINT flags)
 	{
+		HRESULT hr;
 		if(flags & DXGI_PRESENT_TEST)
-			return S_OK;
+			return parent->backend->TestPresent(desc.OutputWindow);
 
 		if(!buffer0)
 		{
@@ -1030,7 +1102,11 @@ struct GalliumDXGISwapChain : public GalliumDXGIObject<IDXGISwapChain, GalliumDX
 		struct pipe_resource* src;
 		struct pipe_surface* dst_surface;
 
-		void* present_cookie = parent->backend->BeginPresent(desc.OutputWindow, &cur_window, &rect, &rgndata, &preserve_aspect_ratio);
+		void* present_cookie;
+		hr = parent->backend->BeginPresent(desc.OutputWindow, &present_cookie, &cur_window, &rect, &rgndata, &preserve_aspect_ratio);
+		if(hr != S_OK)
+			return hr;
+
 		if(!cur_window || rect.left >= rect.right || rect.top >= rect.bottom)
 			goto end_present;
 
@@ -1051,6 +1127,9 @@ struct GalliumDXGISwapChain : public GalliumDXGIObject<IDXGISwapChain, GalliumDX
 		src = gallium_buffer0;
 		dst_surface = 0;
 
+		assert(src);
+		assert(dst);
+
 		/* TODO: sharing the context for blitting won't work correctly if queries are active
 		 * Hopefully no one is crazy enough to keep queries active while presenting, expecting
 		 * sensible results.
@@ -1235,7 +1314,7 @@ end_present:
 		desc.BufferDesc.Width = width;
 		desc.BufferDesc.Height = height;
 		desc.Flags = swap_chain_flags;
-		return S_OK;
+		return resolve_zero_width_height();
 	}
 
 	virtual HRESULT STDMETHODCALLTYPE ResizeTarget(
diff --git a/src/gallium/state_trackers/d3d1x/gd3dapi/galliumdxgi.idl b/src/gallium/state_trackers/d3d1x/gd3dapi/galliumdxgi.idl
index 92fda33..c6233c8 100644
--- a/src/gallium/state_trackers/d3d1x/gd3dapi/galliumdxgi.idl
+++ b/src/gallium/state_trackers/d3d1x/gd3dapi/galliumdxgi.idl
@@ -65,7 +65,7 @@ import "../d3dapi/dxgi.idl";
 [object, local, uuid("c22d2f85-f7dd-40b0-a50b-5d308f973c5e")]
 interface IGalliumDXGIBackend : IUnknown
 {
-	/* Returns a cookie that is passed to EndPresent
+	/* *present_cookie is set to a cookie that is passed to EndPresent
 	 *
 	 * *window and *rect are the window and subrectangle
 	 * to present in.
@@ -81,16 +81,20 @@ interface IGalliumDXGIBackend : IUnknown
 	 * *rgndata is valid until EndPresent is called, at which point EndPresent
 	 * may free the data.
 	 *
-	 * If window is set 0, the window is fully obscured, so don't present
-	 * anything, and tell the app of the obscuration.
+	 * However, the rect field should still be set as normal if possible (especially
+	 * the dimension)..
 	 *
 	 * If preserve_aspect_ratio is set, *rgndata will be ignored. This
 	 * limitation may be lifted in future versions.
 	 *
-	 * EndPresent is still called even if you return 0 in window.
+	 * If the window is fully obscured, return DXGI_STATUS_OCCLUDED.
+	 * Everything else is ignored in that case.
+	 *
+	 * EndPresent is only called when S_OK is returned.
 	 */
-	void* BeginPresent(
+	HRESULT BeginPresent(
 		[in] HWND hwnd,
+		[out] void** present_cookie,
 		[out] void** window,
 		[out] RECT* rect,
 		[out] struct _RGNDATA** rgndata,
@@ -101,6 +105,18 @@ interface IGalliumDXGIBackend : IUnknown
 		[in] HWND hwnd,
 		[out] void* present_cookie
 	);
+
+	/* If the window is fully obscured, return DXGI_STATUS_OCCLUDED, else S_OK */
+	HRESULT TestPresent(
+		[in] HWND hwnd
+	);
+
+	/* Get size of rectangle that would be returned by BeginPresent */
+	HRESULT GetPresentSize(
+		[in] HWND hwnd,
+		[out] unsigned* width,
+		[out] unsigned* height
+	);
 }
 
 void GalliumDXGIUseNothing();
diff --git a/src/gallium/state_trackers/d3d1x/winedlls/dxgi/dxgi_dll.c b/src/gallium/state_trackers/d3d1x/winedlls/dxgi/dxgi_dll.c
index 5a90004..43e2980 100644
--- a/src/gallium/state_trackers/d3d1x/winedlls/dxgi/dxgi_dll.c
+++ b/src/gallium/state_trackers/d3d1x/winedlls/dxgi/dxgi_dll.c
@@ -58,16 +58,17 @@ struct WineDXGIBackend
 		LONG ref;
 };
 
-static void* STDMETHODCALLTYPE WineDXGIBackend_BeginPresent(
+static HRESULT STDMETHODCALLTYPE WineDXGIBackend_BeginPresent(
 	IGalliumDXGIBackend* This,
 	HWND hwnd,
+	void** ppresent_cookie,
 	void** pwindow,
 	RECT* prect,
 	RGNDATA** prgndata,
 	BOOL* ppreserve_aspect_ratio)
 {
 	/* this is the parent HWND which actually has an X11 window associated */
-	HWND x11_hwnd = GetAncestor(hwnd, GA_ROOT);
+	HWND x11_hwnd;
 	HDC hdc;
 	RECT client_rect;
 	POINT x11_hwnd_origin_from_screen;
@@ -77,17 +78,14 @@ static void* STDMETHODCALLTYPE WineDXGIBackend_BeginPresent(
 	unsigned code = X11DRV_GET_DRAWABLE;
 	unsigned rgndata_size;
 	RGNDATA* rgndata;
-
-	hdc = GetDC(x11_hwnd);
-	ExtEscape(hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, sizeof(drawable), (LPTSTR)&drawable);
-
-	GetDCOrgEx(hdc, &x11_hwnd_origin_from_screen);
-	ReleaseDC(x11_hwnd, hdc);
+	RECT rgn_box;
+	int rgn_box_type;
 
 	hdc = GetDC(hwnd);
 	GetDCOrgEx(hdc, &hwnd_origin_from_screen);
 	hrgn = CreateRectRgn(0, 0, 0, 0);
 	GetRandomRgn(hdc, hrgn, SYSRGN);
+	rgn_box_type = GetRgnBox(hrgn, &rgn_box);
 
 	/* the coordinate system differs depending on whether Wine is
 	 * pretending to be Win9x or WinNT, so match that behavior.
@@ -96,6 +94,25 @@ static void* STDMETHODCALLTYPE WineDXGIBackend_BeginPresent(
 		OffsetRgn(hrgn, -hwnd_origin_from_screen.x, -hwnd_origin_from_screen.y);
 	ReleaseDC(hwnd, hdc);
 
+	if(rgn_box_type == NULLREGION)
+	{
+		DeleteObject(hrgn);
+		return DXGI_STATUS_OCCLUDED;
+	}
+
+	rgndata_size = GetRegionData(hrgn, 0, NULL);
+	rgndata = HeapAlloc(GetProcessHeap(), 0, rgndata_size);
+	GetRegionData(hrgn, rgndata_size, rgndata);
+	DeleteObject(hrgn);
+	*prgndata = rgndata;
+
+	x11_hwnd = GetAncestor(hwnd, GA_ROOT);
+	hdc = GetDC(x11_hwnd);
+	ExtEscape(hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, sizeof(drawable), (LPTSTR)&drawable);
+
+	GetDCOrgEx(hdc, &x11_hwnd_origin_from_screen);
+	ReleaseDC(x11_hwnd, hdc);
+
 	*pwindow = (void*)drawable;
 	GetClientRect(hwnd, &client_rect);
 
@@ -105,28 +122,59 @@ static void* STDMETHODCALLTYPE WineDXGIBackend_BeginPresent(
 	prect->right = prect->left + client_rect.right;
 	prect->bottom = prect->top + client_rect.bottom;
 
-	rgndata_size = GetRegionData(hrgn, 0, NULL);
-	rgndata = HeapAlloc(GetProcessHeap(), 0, rgndata_size);
-	GetRegionData(hrgn, rgndata_size, rgndata);
-	*prgndata = rgndata;
-
 	// Windows doesn't preserve the aspect ratio
 	// TODO: maybe let the user turn this on somehow
 	*ppreserve_aspect_ratio = FALSE;
 
-	DeleteObject(hrgn);
+	*ppresent_cookie = rgndata;
 
-	return rgndata;
+	// TODO: check for errors and return them
+	return S_OK;
 }
 
 static void STDMETHODCALLTYPE WineDXGIBackend_EndPresent(
-		IGalliumDXGIBackend* This,
-		HWND hwnd,
-		void *present_cookie)
+	IGalliumDXGIBackend* This,
+	HWND hwnd,
+	void *present_cookie)
 {
 	HeapFree(GetProcessHeap(), 0, present_cookie);
 }
 
+static HRESULT STDMETHODCALLTYPE WineDXGIBackend_TestPresent(
+	IGalliumDXGIBackend* This,
+	HWND hwnd)
+{
+	HDC hdc;
+	HRGN hrgn;
+	RECT rgn_box;
+	int rgn_box_type;
+
+	// TODO: is there a simpler way to check this?
+	hdc = GetDC(hwnd);
+	hrgn = CreateRectRgn(0, 0, 0, 0);
+	GetRandomRgn(hdc, hrgn, SYSRGN);
+	rgn_box_type = GetRgnBox(hrgn, &rgn_box);
+	DeleteObject(hrgn);
+	ReleaseDC(hwnd, hdc);
+
+	return rgn_box_type == NULLREGION ? DXGI_STATUS_OCCLUDED : S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE WineDXGIBackend_GetPresentSize(
+	IGalliumDXGIBackend* This,
+	HWND hwnd,
+	unsigned* width,
+	unsigned* height)
+{
+	RECT client_rect;
+	GetClientRect(hwnd, &client_rect);
+	*width = client_rect.right - client_rect.left;
+	*height = client_rect.bottom - client_rect.top;
+
+	// TODO: check for errors and return them
+	return S_OK;
+}
+
 /* Wine should switch to C++ at least to be able to implement COM interfaces in a sensible way,
  * instead of this ridiculous amount of clumsy duplicated code everywhere
  * C++ exists exactly to avoid having to write the following code */
@@ -165,7 +213,9 @@ static IGalliumDXGIBackendVtbl WineDXGIBackend_vtbl =
 	WineDXGIBackend_AddRef,
 	WineDXGIBackend_Release,
 	WineDXGIBackend_BeginPresent,
-	WineDXGIBackend_EndPresent
+	WineDXGIBackend_EndPresent,
+	WineDXGIBackend_TestPresent,
+	WineDXGIBackend_GetPresentSize
 };
 
 IGalliumDXGIBackend* new_WineDXGIBackend()




More information about the mesa-commit mailing list