wgl: DWM integration.

This commit is contained in:
José Fonseca 2009-09-24 13:08:34 +01:00
parent 9ea277ba7a
commit 4e5ed05b02
10 changed files with 381 additions and 68 deletions

View file

@ -376,6 +376,7 @@ EXPORTS
DrvDescribePixelFormat
DrvGetLayerPaletteEntries
DrvGetProcAddress
DrvPresentBuffers
DrvRealizeLayerPalette
DrvReleaseContext
DrvSetCallbackProcs

View file

@ -375,6 +375,7 @@ EXPORTS
DrvDescribePixelFormat = DrvDescribePixelFormat@16
DrvGetLayerPaletteEntries = DrvGetLayerPaletteEntries@20
DrvGetProcAddress = DrvGetProcAddress@4
DrvPresentBuffers = DrvPresentBuffers@8
DrvRealizeLayerPalette = DrvRealizeLayerPalette@12
DrvReleaseContext = DrvReleaseContext@4
DrvSetCallbackProcs = DrvSetCallbackProcs@8

View file

@ -29,6 +29,7 @@
#include "glapi/glthread.h"
#include "util/u_debug.h"
#include "util/u_math.h"
#include "pipe/p_screen.h"
#include "state_tracker/st_public.h"
@ -62,38 +63,28 @@ stw_flush_frontbuffer(struct pipe_screen *screen,
struct pipe_surface *surface,
void *context_private )
{
const struct stw_winsys *stw_winsys = stw_dev->stw_winsys;
HDC hdc = (HDC)context_private;
struct stw_framebuffer *fb;
fb = stw_framebuffer_from_hdc( hdc );
/* fb can be NULL if window was destroyed already */
if (fb) {
if (!fb) {
/* fb can be NULL if window was destroyed already */
return;
}
#if DEBUG
{
struct pipe_surface *surface2;
if(!st_get_framebuffer_surface( fb->stfb, ST_SURFACE_FRONT_LEFT, &surface2 ))
assert(0);
else
assert(surface2 == surface);
}
{
/* ensure that a random surface was not passed to us */
struct pipe_surface *surface2;
if(!st_get_framebuffer_surface( fb->stfb, ST_SURFACE_FRONT_LEFT, &surface2 ))
assert(0);
else
assert(surface2 == surface);
}
#endif
#ifdef DEBUG
if(stw_dev->trace_running) {
screen = trace_screen(screen)->screen;
surface = trace_surface(surface)->surface;
}
#endif
}
stw_winsys->flush_frontbuffer(screen, surface, hdc);
if(fb) {
stw_framebuffer_update(fb);
stw_framebuffer_release(fb);
}
stw_framebuffer_present_locked(hdc, fb, ST_SURFACE_FRONT_LEFT);
}
@ -126,6 +117,9 @@ stw_init(const struct stw_winsys *stw_winsys)
if(!screen)
goto error1;
if(stw_winsys->get_adapter_luid)
stw_winsys->get_adapter_luid(screen, &stw_dev->AdapterLuid);
#ifdef DEBUG
stw_dev->screen = trace_screen_create(screen);
stw_dev->trace_running = stw_dev->screen != screen ? TRUE : FALSE;
@ -229,6 +223,14 @@ DrvSetCallbackProcs(
INT nProcs,
PROC *pProcs )
{
size_t size;
if (stw_dev == NULL)
return;
size = MIN2(nProcs * sizeof *pProcs, sizeof stw_dev->callbacks);
memcpy(&stw_dev->callbacks, pProcs, size);
return;
}

View file

@ -52,10 +52,14 @@ struct stw_device
boolean trace_running;
#endif
LUID AdapterLuid;
struct stw_pixelformat_info pixelformats[STW_MAX_PIXELFORMATS];
unsigned pixelformat_count;
unsigned pixelformat_extended_count;
GLCALLBACKTABLE callbacks;
pipe_mutex ctx_mutex;
struct handle_table *ctx_table;

View file

@ -1,8 +1,8 @@
/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
*
* Copyright 2008-2009 Vmware, Inc.
* All Rights Reserved.
*
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
@ -10,19 +10,19 @@
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*
**************************************************************************/
#include <windows.h>
@ -83,6 +83,9 @@ stw_framebuffer_destroy_locked(
*link = fb->next;
fb->next = NULL;
if(fb->shared_surface)
stw_dev->stw_winsys->shared_surface_close(stw_dev->screen, fb->shared_surface);
st_unreference_framebuffer(fb->stfb);
pipe_mutex_unlock( fb->mutex );
@ -106,13 +109,18 @@ static INLINE void
stw_framebuffer_get_size( struct stw_framebuffer *fb )
{
unsigned width, height;
RECT rect;
RECT client_rect;
RECT window_rect;
POINT client_pos;
assert(fb->hWnd);
GetClientRect( fb->hWnd, &rect );
width = rect.right - rect.left;
height = rect.bottom - rect.top;
/* Get the client area size. */
GetClientRect( fb->hWnd, &client_rect );
assert(client_rect.left == 0);
assert(client_rect.top == 0);
width = client_rect.right - client_rect.left;
height = client_rect.bottom - client_rect.top;
if(width < 1)
width = 1;
@ -124,6 +132,31 @@ stw_framebuffer_get_size( struct stw_framebuffer *fb )
fb->width = width;
fb->height = height;
}
client_pos.x = 0;
client_pos.y = 0;
ClientToScreen(fb->hWnd, &client_pos);
GetWindowRect(fb->hWnd, &window_rect);
fb->client_rect.left = client_pos.x - window_rect.left;
fb->client_rect.top = client_pos.y - window_rect.top;
fb->client_rect.right = fb->client_rect.left + fb->width;
fb->client_rect.bottom = fb->client_rect.top + fb->height;
#if 0
debug_printf("\n");
debug_printf("%s: client_position = (%i, %i)\n",
__FUNCTION__, client_pos.x, client_pos.y);
debug_printf("%s: window_rect = (%i, %i) - (%i, %i)\n",
__FUNCTION__,
window_rect.left, window_rect.top,
window_rect.right, window_rect.bottom);
debug_printf("%s: client_rect = (%i, %i) - (%i, %i)\n",
__FUNCTION__,
fb->client_rect.left, fb->client_rect.top,
fb->client_rect.right, fb->client_rect.bottom);
#endif
}
@ -155,6 +188,7 @@ stw_call_window_proc(
* can be masked out by the application. */
LPWINDOWPOS lpWindowPos = (LPWINDOWPOS)pParams->lParam;
if((lpWindowPos->flags & SWP_SHOWWINDOW) ||
!(lpWindowPos->flags & SWP_NOMOVE) ||
!(lpWindowPos->flags & SWP_NOSIZE)) {
fb = stw_framebuffer_from_hwnd( pParams->hwnd );
if(fb) {
@ -436,12 +470,126 @@ stw_pixelformat_get(
BOOL APIENTRY
DrvSwapBuffers(
HDC hdc )
DrvPresentBuffers(HDC hdc, PGLPRESENTBUFFERSDATA data)
{
struct stw_framebuffer *fb;
struct pipe_screen *screen;
struct pipe_surface *surface;
unsigned surface_index;
BOOL ret = FALSE;
fb = stw_framebuffer_from_hdc( hdc );
if (fb == NULL)
return FALSE;
screen = stw_dev->screen;
surface_index = (unsigned)(uintptr_t)data->pPrivateData;
if(!st_get_framebuffer_surface( fb->stfb, surface_index, &surface ))
goto fail;
#ifdef DEBUG
if(stw_dev->trace_running) {
screen = trace_screen(screen)->screen;
surface = trace_surface(surface)->surface;
}
#endif
if(data->hSharedSurface != fb->hSharedSurface) {
if(fb->shared_surface) {
stw_dev->stw_winsys->shared_surface_close(screen, fb->shared_surface);
fb->shared_surface = NULL;
}
fb->hSharedSurface = data->hSharedSurface;
if(data->hSharedSurface &&
stw_dev->stw_winsys->shared_surface_open) {
fb->shared_surface = stw_dev->stw_winsys->shared_surface_open(screen, fb->hSharedSurface);
}
}
if(fb->shared_surface) {
stw_dev->stw_winsys->compose(screen,
surface,
fb->shared_surface,
&fb->client_rect,
data->PresentHistoryToken);
}
else {
stw_dev->stw_winsys->present( screen, surface, hdc );
}
ret = TRUE;
fail:
stw_framebuffer_update(fb);
stw_framebuffer_release(fb);
return ret;
}
/**
* Queue a composition.
*
* It will drop the lock on success.
*/
BOOL
stw_framebuffer_present_locked(HDC hdc,
struct stw_framebuffer *fb,
unsigned surface_index)
{
if(stw_dev->callbacks.wglCbPresentBuffers &&
stw_dev->stw_winsys->compose) {
GLCBPRESENTBUFFERSDATA data;
memset(&data, 0, sizeof data);
data.magic1 = 2;
data.magic2 = 0;
data.AdapterLuid = stw_dev->AdapterLuid;
data.rect = fb->client_rect;
data.pPrivateData = (void *)(uintptr_t)surface_index;
stw_framebuffer_release(fb);
return stw_dev->callbacks.wglCbPresentBuffers(hdc, &data);
}
else {
struct pipe_screen *screen = stw_dev->screen;
struct pipe_surface *surface;
if(!st_get_framebuffer_surface( fb->stfb, surface_index, &surface )) {
/* FIXME: this shouldn't happen, but does on glean */
stw_framebuffer_release(fb);
return FALSE;
}
#ifdef DEBUG
if(stw_dev->trace_running) {
screen = trace_screen(screen)->screen;
surface = trace_surface(surface)->surface;
}
#endif
stw_dev->stw_winsys->present( screen, surface, hdc );
stw_framebuffer_update(fb);
stw_framebuffer_release(fb);
return TRUE;
}
}
BOOL APIENTRY
DrvSwapBuffers(
HDC hdc )
{
struct stw_framebuffer *fb;
fb = stw_framebuffer_from_hdc( hdc );
if (fb == NULL)
@ -457,27 +605,7 @@ DrvSwapBuffers(
*/
st_notify_swapbuffers( fb->stfb );
screen = stw_dev->screen;
if(!st_get_framebuffer_surface( fb->stfb, ST_SURFACE_BACK_LEFT, &surface )) {
/* FIXME: this shouldn't happen, but does on glean */
stw_framebuffer_release(fb);
return FALSE;
}
#ifdef DEBUG
if(stw_dev->trace_running) {
screen = trace_screen(screen)->screen;
surface = trace_surface(surface)->surface;
}
#endif
stw_dev->stw_winsys->flush_frontbuffer( screen, surface, hdc );
stw_framebuffer_update(fb);
stw_framebuffer_release(fb);
return TRUE;
return stw_framebuffer_present_locked(hdc, fb, ST_SURFACE_BACK_LEFT);
}

View file

@ -73,9 +73,20 @@ struct stw_framebuffer
/* FIXME: Make this work for multiple contexts bound to the same framebuffer */
boolean must_resize;
unsigned width;
unsigned height;
/**
* Client area rectangle, relative to the window upper-left corner.
*
* @sa GLCBPRESENTBUFFERSDATA::rect.
*/
RECT client_rect;
HANDLE hSharedSurface;
struct stw_shared_surface *shared_surface;
/**
* This is protected by stw_device::fb_mutex, not the mutex above.
*
@ -126,6 +137,11 @@ BOOL
stw_framebuffer_allocate(
struct stw_framebuffer *fb );
BOOL
stw_framebuffer_present_locked(HDC hdc,
struct stw_framebuffer *fb,
unsigned surface_index);
void
stw_framebuffer_update(
struct stw_framebuffer *fb);

View file

@ -1,6 +1,6 @@
/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2008-2009 Vmware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@ -18,7 +18,7 @@
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@ -388,6 +388,113 @@ typedef struct _GLCLTPROCTABLE
typedef VOID (APIENTRY * PFN_SETPROCTABLE)(PGLCLTPROCTABLE);
/**
* Presentation data passed to opengl32!wglCbPresentBuffers.
*
* Pure software drivers don't need to worry about this -- if they stick to the
* GDI API then will integrate with the Desktop Window Manager (DWM) without
* problems. Hardware drivers, however, cannot present directly to the primary
* surface while the DWM is active, as DWM gets exclusive access to the primary
* surface.
*
* Proper DWM integration requires:
* - advertise the PFD_SUPPORT_COMPOSITION flag
* - redirect glFlush/glfinish/wglSwapBuffers into a surface shared with the
* DWM process.
*
* @sa http://www.opengl.org/pipeline/article/vol003_7/
* @sa http://blogs.msdn.com/greg_schechter/archive/2006/05/02/588934.aspx
*/
typedef struct _GLCBPRESENTBUFFERSDATA
{
/**
* wglCbPresentBuffers enforces this to be 2.
*/
DWORD magic1;
/**
* wglCbPresentBuffers enforces to be 0 or 1, but it is most commonly
* set to 0.
*/
DWORD magic2;
/**
* Locally unique identifier (LUID) of the graphics adapter.
*
* This should contain the value returned by D3DKMTOpenAdapterFromHdc. It
* is passed to dwmapi!DwmpDxGetWindowSharedSurface in order to obtain
* the shared surface handle for the bound drawable (window).
*
* @sa http://msdn.microsoft.com/en-us/library/ms799177.aspx
*/
LUID AdapterLuid;
/**
* This is passed unmodified to DrvPresentBuffers
*/
LPVOID pPrivateData;
/**
* Client area rectangle to update, relative to the window upper-left corner.
*/
RECT rect;
} GLCBPRESENTBUFFERSDATA, *PGLCBPRESENTBUFFERSDATA;
/**
* Callbacks supplied to DrvSetCallbackProcs by the OpenGL runtime.
*
* Pointers to several callback functions in opengl32.dll.
*/
typedef struct _GLCALLBACKTABLE
{
/** Unused */
PROC wglCbSetCurrentValue;
/** Unused */
PROC wglCbGetCurrentValue;
/** Unused */
PROC wglCbGetDhglrc;
/** Unused */
PROC wglCbGetDdHandle;
/**
* Queue a present composition.
*
* Makes the runtime call DrvPresentBuffers with the composition information.
*/
BOOL (APIENTRY *wglCbPresentBuffers)(HDC hdc, PGLCBPRESENTBUFFERSDATA data);
} GLCALLBACKTABLE;
typedef struct _GLPRESENTBUFFERSDATA
{
/**
* The shared surface handle.
*
* Return by dwmapi!DwmpDxGetWindowSharedSurface.
*
* @sa http://channel9.msdn.com/forums/TechOff/251261-Help-Getting-the-shared-window-texture-out-of-DWM-/
*/
HANDLE hSharedSurface;
LUID AdapterLuid;
/**
* Present history token.
*
* This is returned by dwmapi!DwmpDxGetWindowSharedSurface and
* should be passed to D3DKMTRender in D3DKMT_RENDER::PresentHistoryToken.
*
* @sa http://msdn.microsoft.com/en-us/library/ms799176.aspx
*/
ULONGLONG PresentHistoryToken;
/** Same as GLCBPRESENTBUFFERSDATA::pPrivateData */
LPVOID pPrivateData;
} GLPRESENTBUFFERSDATA, *PGLPRESENTBUFFERSDATA;
BOOL APIENTRY
DrvCopyContext(
DHGLRC dhrcSource,
@ -434,6 +541,9 @@ PROC APIENTRY
DrvGetProcAddress(
LPCSTR lpszProc );
BOOL APIENTRY
DrvPresentBuffers(HDC hdc, PGLPRESENTBUFFERSDATA data);
BOOL APIENTRY
DrvRealizeLayerPalette(
HDC hdc,

View file

@ -154,8 +154,11 @@ stw_pixelformat_add(
pfi->pfd.dwFlags = PFD_SUPPORT_OPENGL;
/* TODO: also support non-native pixel formats */
pfi->pfd.dwFlags |= PFD_DRAW_TO_WINDOW ;
pfi->pfd.dwFlags |= PFD_DRAW_TO_WINDOW;
/* See http://www.opengl.org/pipeline/article/vol003_7/ */
pfi->pfd.dwFlags |= PFD_SUPPORT_COMPOSITION;
if (doublebuffer)
pfi->pfd.dwFlags |= PFD_DOUBLEBUFFER | PFD_SWAP_COPY;

View file

@ -30,6 +30,10 @@
#include <windows.h>
#ifndef PFD_SUPPORT_COMPOSITION
#define PFD_SUPPORT_COMPOSITION 0x00008000
#endif
#include "main/mtypes.h"
#include "pipe/p_compiler.h"

View file

@ -1,6 +1,6 @@
/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2008-2009 Vmware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@ -18,7 +18,7 @@
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@ -36,6 +36,8 @@ struct pipe_screen;
struct pipe_context;
struct pipe_surface;
struct stw_shared_surface;
struct stw_winsys
{
struct pipe_screen *
@ -44,10 +46,52 @@ struct stw_winsys
struct pipe_context *
(*create_context)( struct pipe_screen *screen );
/**
* Present the color buffer to the window associated with the device context.
*/
void
(*flush_frontbuffer)( struct pipe_screen *screen,
struct pipe_surface *surf,
HDC hDC );
(*present)( struct pipe_screen *screen,
struct pipe_surface *surf,
HDC hDC );
/**
* Locally unique identifier (LUID) of the graphics adapter.
*
* @sa GLCBPRESENTBUFFERSDATA::AdapterLuid;
*/
boolean
(*get_adapter_luid)( struct pipe_screen *screen,
LUID *pAdapterLuid );
/**
* Open a shared surface (optional).
*
* @sa GLCBPRESENTBUFFERSDATA::hSharedSurface;
*/
struct stw_shared_surface *
(*shared_surface_open)(struct pipe_screen *screen,
HANDLE hSharedSurface);
/**
* Open a shared surface (optional).
*/
void
(*shared_surface_close)(struct pipe_screen *screen,
struct stw_shared_surface *surface);
/**
* Compose into a shared (optional).
*
* Blit the color buffer into a shared surface.
*
* @sa GLPRESENTBUFFERSDATA::PresentHistoryToken.
*/
void
(*compose)( struct pipe_screen *screen,
struct pipe_surface *src,
struct stw_shared_surface *dest,
LPCRECT pRect,
ULONGLONG PresentHistoryToken );
};
boolean