From e7624e23a3a374896863f54fe30dafd0bff8a91a Mon Sep 17 00:00:00 2001 From: Luca Barbieri Date: Wed, 22 Sep 2010 13:51:53 +0200 Subject: [PATCH] d3d1x: redesign the HWND resolver interface This one should be powerful enough to hook up Wine. --- .../d3d1x/dxgi/src/dxgi_native.cpp | 295 ++++++++++++------ .../state_trackers/d3d1x/gd3d11/d3d11_misc.h | 7 +- .../d3d1x/gd3dapi/galliumdxgi.idl | 49 ++- .../d3d1x/progs/d3d10app/d3d10x11main.cpp | 2 +- .../d3d1x/progs/d3d11app/d3d11x11main.cpp | 2 +- 5 files changed, 250 insertions(+), 105 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 24a812ff4ce..3cbe056e7b6 100644 --- a/src/gallium/state_trackers/d3d1x/dxgi/src/dxgi_native.cpp +++ b/src/gallium/state_trackers/d3d1x/dxgi/src/dxgi_native.cpp @@ -63,22 +63,53 @@ struct GalliumDXGIObject : public GalliumPrivateDataComObject } }; -static void* STDMETHODCALLTYPE identity_resolver(void* cookie, HWND hwnd) +COM_INTERFACE(IGalliumDXGIBackend, IUnknown) + +struct GalliumDXGIIdentityBackend : public GalliumComObject { - return (void*)hwnd; -} + virtual void * STDMETHODCALLTYPE BeginPresent( + HWND hwnd, + void** window, + RECT *rect, + RGNDATA **rgndata, + BOOL* preserve_aspect_ratio + ) + { + *window = (void*)hwnd; + rect->left = 0; + rect->top = 0; + rect->right = INT_MAX; + rect->bottom = INT_MAX; + *rgndata = 0; + + // yes, because we like things looking good + *preserve_aspect_ratio = TRUE; + return 0; + } + + virtual void STDMETHODCALLTYPE EndPresent( + HWND hwnd, + void* present_cookie + ) + {} +}; struct GalliumDXGIFactory : public GalliumDXGIObject { HWND associated_window; const struct native_platform* platform; void* display; - PFNHWNDRESOLVER resolver; + ComPtr backend; void* resolver_cookie; - GalliumDXGIFactory(const struct native_platform* platform, void* display, PFNHWNDRESOLVER resolver, void* resolver_cookie) - : GalliumDXGIObject((IUnknown*)NULL), platform(platform), display(display), resolver(resolver ? resolver : (PFNHWNDRESOLVER)identity_resolver), resolver_cookie(resolver_cookie) - {} + GalliumDXGIFactory(const struct native_platform* platform, void* display, IGalliumDXGIBackend* p_backend) + : GalliumDXGIObject((IUnknown*)NULL), platform(platform), display(display) + { + if(p_backend) + backend = p_backend; + else + backend.reset(new GalliumDXGIIdentityBackend()); + } virtual HRESULT STDMETHODCALLTYPE EnumAdapters( UINT Adapter, @@ -678,6 +709,7 @@ struct dxgi_blitter rasterizer = pipe->create_rasterizer_state(pipe, &rs_state); struct pipe_blend_state blendd; + memset(&blendd, 0, sizeof(blendd)); blendd.rt[0].colormask = PIPE_MASK_RGBA; blend = pipe->create_blend_state(pipe, &blendd); @@ -793,9 +825,12 @@ struct GalliumDXGISwapChain : public GalliumDXGIObject adapter; ComPtr target; + DXGI_SWAP_CHAIN_DESC desc; + struct native_surface* surface; const struct native_config* config; + void* window; struct pipe_resource* resources[NUM_NATIVE_ATTACHMENTS]; int width; int height; @@ -808,8 +843,6 @@ struct GalliumDXGISwapChain : public GalliumDXGIObject(factory), desc(p_desc) + : GalliumDXGIObject(factory), desc(p_desc), surface(0) { HRESULT hr; @@ -835,13 +868,40 @@ struct GalliumDXGISwapChain : public GalliumDXGIObjectresolver(factory->resolver_cookie, desc.OutputWindow); + memset(resources, 0, sizeof(resources)); + + if(desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL && desc.BufferCount != 1) + { + std::cerr << "Gallium DXGI: if DXGI_SWAP_EFFECT_SEQUENTIAL is specified, only BufferCount == 1 is implemented, but " << desc.BufferCount << " was specified: ignoring this" << std::endl; + // change the returned desc, so that the application might perhaps notice what we did and react well + desc.BufferCount = 1; + } + + pipe = gallium_device->GetGalliumContext(); + owns_pipe = false; + if(!pipe) + { + pipe = adapter->display->screen->context_create(adapter->display->screen, 0); + owns_pipe = true; + } + + blitter.reset(new dxgi_blitter(pipe)); + window = 0; + } + + void init_for_window() + { + if(surface) + { + surface->destroy(surface); + surface = 0; + } unsigned config_num; - if(!strcmp(factory->platform->name, "X11")) + if(!strcmp(parent->platform->name, "X11")) { XWindowAttributes xwa; - XGetWindowAttributes((Display*)factory->display, (Window)win, &xwa); + XGetWindowAttributes((Display*)parent->display, (Window)window, &xwa); config_num = adapter->configs_by_native_visual_id[xwa.visual->visualid]; } else @@ -859,7 +919,7 @@ struct GalliumDXGISwapChain : public GalliumDXGIObjectconfigs[config_num]; - surface = adapter->display->create_window_surface(adapter->display, (EGLNativeWindowType)win, config); + surface = adapter->display->create_window_surface(adapter->display, (EGLNativeWindowType)window, config); surface->user_data = this; width = 0; @@ -869,23 +929,6 @@ struct GalliumDXGISwapChain : public GalliumDXGIObjectGetGalliumContext(); - owns_pipe = false; - if(!pipe) - { - pipe = adapter->display->screen->context_create(adapter->display->screen, 0); - owns_pipe = true; - } - - blitter.reset(new dxgi_blitter(pipe)); - formats_compatible = util_is_format_compatible( util_format_description(dxgi_to_pipe_format[desc.BufferDesc.Format]), util_format_description(config->color_format)); @@ -951,7 +994,7 @@ struct GalliumDXGISwapChain : public GalliumDXGIObjectvalidate(surface, 1 << NATIVE_ATTACHMENT_BACK_LEFT, &new_seq_num, resources, &width, &height)) + if(!surface->validate(surface, (1 << NATIVE_ATTACHMENT_BACK_LEFT) | (1 << NATIVE_ATTACHMENT_FRONT_LEFT), &new_seq_num, resources, &width, &height)) return false; if(!ever_validated || seq_num != new_seq_num) @@ -976,16 +1019,36 @@ struct GalliumDXGISwapChain : public GalliumDXGIObjectbackend->BeginPresent(desc.OutputWindow, &cur_window, &rect, &rgndata, &preserve_aspect_ratio); + if(!cur_window || rect.left >= rect.right || rect.top >= rect.bottom) + goto end_present; + + if(cur_window != window) + { + window = cur_window; + init_for_window(); + } + if(needs_validation) { if(!validate()) return DXGI_ERROR_DEVICE_REMOVED; } - bool db = !!(config->buffer_mask & NATIVE_ATTACHMENT_BACK_LEFT); - struct pipe_resource* dst = resources[db ? NATIVE_ATTACHMENT_BACK_LEFT : NATIVE_ATTACHMENT_FRONT_LEFT]; - struct pipe_resource* src = gallium_buffer0; - struct pipe_surface* dst_surface = 0; + db = !!(config->buffer_mask & NATIVE_ATTACHMENT_BACK_LEFT); + dst = resources[db ? NATIVE_ATTACHMENT_BACK_LEFT : NATIVE_ATTACHMENT_FRONT_LEFT]; + src = gallium_buffer0; + dst_surface = 0; /* 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 @@ -993,58 +1056,85 @@ struct GalliumDXGISwapChain : public GalliumDXGIObject dst->width0) + rect.right = dst->width0; + if((unsigned)rect.bottom > dst->height0) + rect.bottom = dst->height0; + if(rect.left > rect.right) + rect.left = rect.right; + if(rect.top > rect.bottom) + rect.top = rect.bottom; - if(!formats_compatible || src->width0 != dst->width0 || dst->width0 != src->width0) - dst_surface = pipe->screen->get_tex_surface(pipe->screen, dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET); + if(rect.left >= rect.right && rect.top >= rect.bottom) + goto end_present; - int delta = src->width0 * dst->height0 - dst->width0 * src->height0; - if(delta > 0) - { - blit_w = dst->width0; - blit_h = dst->width0 * src->height0 / src->width0; - } - else if(delta < 0) - { - blit_w = dst->height0 * src->width0 / src->height0; - blit_h = dst->height0; - } - else + dst_w = rect.right - rect.left; + dst_h = rect.bottom - rect.top; + + // TODO: add support for rgndata +// if(preserve_aspect_ratio || !rgndata) + if(1) { - blit_w = dst->width0; - blit_h = dst->height0; - } + unsigned blit_x, blit_y, blit_w, blit_h; + float black[4] = {0, 0, 0, 0}; + + if(!formats_compatible || src->width0 != dst_w || src->height0 != dst_h) + dst_surface = pipe->screen->get_tex_surface(pipe->screen, dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET); + + if(preserve_aspect_ratio) + { + int delta = src->width0 * dst_h - dst_w * src->height0; + if(delta > 0) + { + blit_w = dst_w; + blit_h = dst_w * src->height0 / src->width0; + } + else if(delta < 0) + { + blit_w = dst_h * src->width0 / src->height0; + blit_h = dst_h; + } + else + { + blit_w = dst_w; + blit_h = dst_h; + } - blit_x = (dst->width0 - blit_w) >> 1; - blit_y = (dst->height0 - blit_h) >> 1; + blit_x = (dst_w - blit_w) >> 1; + blit_y = (dst_h - blit_h) >> 1; + } + else + { + blit_x = 0; + blit_y = 0; + blit_w = dst_w; + blit_h = dst_h; + } - if(blit_x) - pipe->clear_render_target(pipe, dst_surface, black, 0, 0, blit_x, dst->height0); - if(blit_y) - pipe->clear_render_target(pipe, dst_surface, black, 0, 0, dst->width0, blit_y); + if(blit_x) + pipe->clear_render_target(pipe, dst_surface, black, rect.left, rect.top, blit_x, dst_h); + if(blit_y) + pipe->clear_render_target(pipe, dst_surface, black, rect.left, rect.top, dst_w, blit_y); - if(formats_compatible && blit_w == src->width0 && blit_h == src->height0) - { - pipe_subresource sr; - sr.face = 0; - sr.level = 0; - pipe->resource_copy_region(pipe, dst, sr, 0, 0, 0, src, sr, 0, 0, 0, blit_w, blit_h); - } - else - { - blitter->blit(dst_surface, gallium_buffer0_view, blit_x, blit_y, blit_w, blit_h); - if(!owns_pipe) - gallium_device->RestoreGalliumState(); - } + if(formats_compatible && blit_w == src->width0 && blit_h == src->height0) + { + pipe_subresource sr; + sr.face = 0; + sr.level = 0; + pipe->resource_copy_region(pipe, dst, sr, rect.left, rect.top, 0, src, sr, 0, 0, 0, blit_w, blit_h); + } + else + { + blitter->blit(dst_surface, gallium_buffer0_view, rect.left + blit_x, rect.top + blit_y, blit_w, blit_h); + if(!owns_pipe) + gallium_device->RestoreGalliumState(); + } - if(blit_w != dst->width0) - pipe->clear_render_target(pipe, dst_surface, black, blit_x + blit_w, 0, dst->width0 - blit_x - blit_w, dst->height0); - if(blit_h != dst->height0) - pipe->clear_render_target(pipe, dst_surface, black, 0, blit_y + blit_h, dst->width0, dst->height0 - blit_y - blit_h); + if(blit_w != dst_w) + pipe->clear_render_target(pipe, dst_surface, black, rect.left + blit_x + blit_w, rect.top, dst_w - blit_x - blit_w, dst_h); + if(blit_h != dst_h) + pipe->clear_render_target(pipe, dst_surface, black, rect.left, rect.top + blit_y + blit_h, dst_w, dst_h - blit_y - blit_h); + } if(dst_surface) pipe->screen->tex_surface_destroy(dst_surface); @@ -1060,6 +1150,9 @@ struct GalliumDXGISwapChain : public GalliumDXGIObjectbackend->EndPresent(desc.OutputWindow, present_cookie); + ++present_count; return S_OK; } @@ -1225,8 +1318,7 @@ struct dxgi_binding { const struct native_platform* platform; void* display; - PFNHWNDRESOLVER resolver; - void* resolver_cookie; + IGalliumDXGIBackend* backend; }; static dxgi_binding dxgi_default_binding; @@ -1236,50 +1328,57 @@ void STDMETHODCALLTYPE GalliumDXGIUseNothing() { dxgi_thread_binding.platform = 0; dxgi_thread_binding.display = 0; - dxgi_thread_binding.resolver = 0; - dxgi_thread_binding.resolver_cookie = 0; + if(dxgi_thread_binding.backend) + dxgi_thread_binding.backend->Release(); + dxgi_thread_binding.backend = 0; } #ifdef GALLIUM_DXGI_USE_X11 -void STDMETHODCALLTYPE GalliumDXGIUseX11Display(Display* dpy, PFNHWNDRESOLVER resolver, void* resolver_cookie) +void STDMETHODCALLTYPE GalliumDXGIUseX11Display(Display* dpy, IGalliumDXGIBackend* backend) { + GalliumDXGIUseNothing(); dxgi_thread_binding.platform = native_get_x11_platform(); dxgi_thread_binding.display = dpy; - dxgi_thread_binding.resolver = resolver; - dxgi_thread_binding.resolver_cookie = resolver_cookie; + + if(backend) + { + dxgi_thread_binding.backend = backend; + backend->AddRef(); + } } #endif +/* #ifdef GALLIUM_DXGI_USE_DRM void STDMETHODCALLTYPE GalliumDXGIUseDRMCard(int fd) { + GalliumDXGIUseNothing(); dxgi_thread_binding.platform = native_get_drm_platform(); dxgi_thread_binding.display = (void*)fd; - dxgi_thread_binding.resolver = 0; - dxgi_thread_binding.resolver_cookie = 0; + dxgi_thread_binding.backend = 0; } #endif #ifdef GALLIUM_DXGI_USE_FBDEV void STDMETHODCALLTYPE GalliumDXGIUseFBDev(int fd) { + GalliumDXGIUseNothing(); dxgi_thread_binding.platform = native_get_fbdev_platform(); dxgi_thread_binding.display = (void*)fd; - dxgi_thread_binding.resolver = 0; - dxgi_thread_binding.resolver_cookie = 0; + dxgi_thread_binding.backend = 0; } #endif #ifdef GALLIUM_DXGI_USE_GDI void STDMETHODCALLTYPE GalliumDXGIUseHDC(HDC hdc, PFNHWNDRESOLVER resolver, void* resolver_cookie) { + GalliumDXGIUseNothing(); dxgi_thread_binding.platform = native_get_gdi_platform(); dxgi_thread_binding.display = (void*)hdc; - dxgi_thread_binding.resolver = resolver; - dxgi_thread_binding.resolver_cookie = resolver_cookie; + dxgi_thread_binding.backend = 0; } #endif - +*/ void STDMETHODCALLTYPE GalliumDXGIMakeDefault() { dxgi_default_binding = dxgi_thread_binding; @@ -1296,11 +1395,11 @@ void STDMETHODCALLTYPE GalliumDXGIMakeDefault() GalliumDXGIFactory* factory; *ppFactory = 0; if(dxgi_thread_binding.platform) - factory = new GalliumDXGIFactory(dxgi_thread_binding.platform, dxgi_thread_binding.display, dxgi_thread_binding.resolver, dxgi_thread_binding.resolver_cookie); + factory = new GalliumDXGIFactory(dxgi_thread_binding.platform, dxgi_thread_binding.display, dxgi_thread_binding.backend); else if(dxgi_default_binding.platform) - factory = new GalliumDXGIFactory(dxgi_default_binding.platform, dxgi_default_binding.display, dxgi_default_binding.resolver, dxgi_default_binding.resolver_cookie); + factory = new GalliumDXGIFactory(dxgi_default_binding.platform, dxgi_default_binding.display, dxgi_default_binding.backend); else - factory = new GalliumDXGIFactory(native_get_x11_platform(), NULL, NULL, NULL); + factory = new GalliumDXGIFactory(native_get_x11_platform(), NULL, NULL); HRESULT hres = factory->QueryInterface(riid, ppFactory); factory->Release(); return hres; diff --git a/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_misc.h b/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_misc.h index 39e41f19e5f..0d515e3f472 100644 --- a/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_misc.h +++ b/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_misc.h @@ -1,5 +1,10 @@ #if API < 11 -HRESULT D3D10CreateBlob( +extern "C" HRESULT STDMETHODCALLTYPE D3D10CreateBlob( + __in SIZE_T NumBytes, + __out LPD3D10BLOB *ppBuffer +); + +HRESULT STDMETHODCALLTYPE D3D10CreateBlob( __in SIZE_T NumBytes, __out LPD3D10BLOB *ppBuffer ) diff --git a/src/gallium/state_trackers/d3d1x/gd3dapi/galliumdxgi.idl b/src/gallium/state_trackers/d3d1x/gd3dapi/galliumdxgi.idl index 9fbe5d01a7f..e6f51472096 100644 --- a/src/gallium/state_trackers/d3d1x/gd3dapi/galliumdxgi.idl +++ b/src/gallium/state_trackers/d3d1x/gd3dapi/galliumdxgi.idl @@ -62,16 +62,57 @@ import "../d3dapi/dxgi.idl"; * - GDI: HWND */ -typedef struct _XDisplay Display; -typedef void* (*PFNHWNDRESOLVER)(void*, HWND); +[object, local, uuid("c22d2f85-f7dd-40b0-a50b-5d308f973c5e")] +interface IGalliumDXGIBackend : IUnknown +{ + /* Returns a cookie that is passed to EndPresent + * + * *window and *rect are the window and subrectangle + * to present in. + * + * For X11, *window is a Window. + * For other systems, it will be the equivalent way to reference a window. + * + * The rectangle is clipped against the window size, so you can + * specify (0, 0, INT_MAX, INT_MAX) to use the whole window. + * + * rgndata is set to either NULL, or the region, in coordinates relative + * to the subrectangle, to clip presentation to. + * *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. + * + * 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. + */ + void* BeginPresent( + [in] HWND hwnd, + [out] void** window, + [out] RECT* rect, + [out] struct _RGNDATA** rgndata, + [out] BOOL* preserve_aspect_ratio + ); + + void EndPresent( + [in] HWND hwnd, + [out] void* present_cookie + ); +} void GalliumDXGIUseNothing(); /* only a subset of these may be available, depending on platform and compilation options */ -void GalliumDXGIUseX11Display(Display* dpy, PFNHWNDRESOLVER resolver, void* resolver_cookie); +void GalliumDXGIUseX11Display(struct _XDisplay* dpy, IGalliumDXGIBackend* backend); + +/* these don't really work for now void GalliumDXGIUseDRMCard(int fd); void GalliumDXGIUseFBDev(int fd); -void GalliumDXGIUseHDC(HDC hdc, PFNHWNDRESOLVER resolver, void* resolver_cookie); +void GalliumDXGIUseHDC(HDC hdc, IGalliumDXGIGDIBackend* backend); +*/ void GalliumDXGIMakeDefault(); diff --git a/src/gallium/state_trackers/d3d1x/progs/d3d10app/d3d10x11main.cpp b/src/gallium/state_trackers/d3d1x/progs/d3d10app/d3d10x11main.cpp index 4ce3dcf1c56..ddba68518af 100755 --- a/src/gallium/state_trackers/d3d1x/progs/d3d10app/d3d10x11main.cpp +++ b/src/gallium/state_trackers/d3d1x/progs/d3d10app/d3d10x11main.cpp @@ -67,7 +67,7 @@ int main(int argc, char** argv) Window win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap| CWEventMask, &swa); XMapWindow(dpy, win); - GalliumDXGIUseX11Display(dpy, 0, 0); + GalliumDXGIUseX11Display(dpy, 0); DXGI_SWAP_CHAIN_DESC swap_chain_desc; memset(&swap_chain_desc, 0, sizeof(swap_chain_desc)); diff --git a/src/gallium/state_trackers/d3d1x/progs/d3d11app/d3d11x11main.cpp b/src/gallium/state_trackers/d3d1x/progs/d3d11app/d3d11x11main.cpp index 9dcb32537e7..7e1edeb6355 100755 --- a/src/gallium/state_trackers/d3d1x/progs/d3d11app/d3d11x11main.cpp +++ b/src/gallium/state_trackers/d3d1x/progs/d3d11app/d3d11x11main.cpp @@ -41,7 +41,7 @@ int main(int argc, char** argv) Window win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap| CWEventMask, &swa); XMapWindow(dpy, win); - GalliumDXGIUseX11Display(dpy, 0, 0); + GalliumDXGIUseX11Display(dpy, 0); DXGI_SWAP_CHAIN_DESC swap_chain_desc; memset(&swap_chain_desc, 0, sizeof(swap_chain_desc)); -- 2.30.2