Explorar el Código

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

tags/snb-magic
Luca Barbieri hace 15 años
padre
commit
f976cd0c9e

+ 84
- 5
src/gallium/state_trackers/d3d1x/dxgi/src/dxgi_native.cpp Ver fichero

@@ -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(

+ 21
- 5
src/gallium/state_trackers/d3d1x/gd3dapi/galliumdxgi.idl Ver fichero

@@ -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();

+ 69
- 19
src/gallium/state_trackers/d3d1x/winedlls/dxgi/dxgi_dll.c Ver fichero

@@ -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()

Cargando…
Cancelar
Guardar