diff options
author | Luca Barbieri <[email protected]> | 2010-09-27 20:25:17 +0200 |
---|---|---|
committer | Luca Barbieri <[email protected]> | 2010-09-27 22:20:53 +0200 |
commit | f976cd0c9ead6a5e63146c11823770176c149a12 (patch) | |
tree | 81b5a263de1a6e237e57bd51ecc4ed9fea304706 | |
parent | e01e2e1883b57fdc84807496fdab4fed22f23900 (diff) |
d3d1x: rework DXGI for occlusion testing and default width/height
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 a75a953abfb..e1c34611d14 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 92fda3385b9..c6233c85b99 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 5a900046df2..43e2980afdb 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() |