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,
// yes, because we like things looking good
*preserve_aspect_ratio = TRUE;
- return 0;
+ *present_cookie = 0;
+ return S_OK;
}
virtual void STDMETHODCALLTYPE EndPresent(
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>
{
if(p_backend)
backend = p_backend;
+ else if(!strcmp(platform->name, "X11"))
+ backend.reset(new GalliumDXGIX11IdentityBackend((Display*)display));
else
backend.reset(new GalliumDXGIIdentityBackend());
}
blitter.reset(new dxgi_blitter(pipe));
window = 0;
+
+ hr = resolve_zero_width_height(true);
+ if(!SUCCEEDED(hr))
+ throw hr;
}
void init_for_window()
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)
{
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;
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.
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(
[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.
* *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,
[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();
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;
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.
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);
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 */
WineDXGIBackend_AddRef,
WineDXGIBackend_Release,
WineDXGIBackend_BeginPresent,
- WineDXGIBackend_EndPresent
+ WineDXGIBackend_EndPresent,
+ WineDXGIBackend_TestPresent,
+ WineDXGIBackend_GetPresentSize
};
IGalliumDXGIBackend* new_WineDXGIBackend()