mirror of
https://github.com/reactos/wine.git
synced 2025-01-31 17:23:53 +00:00
gdi32: New DC locking mechanism that doesn't require holding the global GDI lock.
This commit is contained in:
parent
ee2db299de
commit
d88ff791ef
@ -587,7 +587,7 @@ static HGDIOBJ BITMAP_SelectObject( HGDIOBJ handle, void *obj, HDC hdc )
|
||||
if (handle)
|
||||
{
|
||||
dc->hBitmap = handle;
|
||||
dc->flags &= ~DC_DIRTY;
|
||||
dc->dirty = 0;
|
||||
SetRectRgn( dc->hVisRgn, 0, 0, bitmap->bitmap.bmWidth, bitmap->bitmap.bmHeight);
|
||||
DC_InitDC( dc );
|
||||
}
|
||||
|
@ -58,8 +58,6 @@ void CLIPPING_UpdateGCRegion( DC * dc )
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (dc->flags & DC_DIRTY) ERR( "DC is dirty. Please report this.\n" );
|
||||
|
||||
/* update the intersection of meta and clip regions */
|
||||
if (dc->hMetaRgn && dc->hClipRgn)
|
||||
{
|
||||
@ -177,7 +175,7 @@ INT16 WINAPI SelectVisRgn16( HDC16 hdc16, HRGN16 hrgn )
|
||||
|
||||
TRACE("%p %04x\n", hdc, hrgn );
|
||||
|
||||
dc->flags &= ~DC_DIRTY;
|
||||
dc->dirty = 0;
|
||||
|
||||
retval = CombineRgn( dc->hVisRgn, HRGN_32(hrgn), 0, RGN_COPY );
|
||||
CLIPPING_UpdateGCRegion( dc );
|
||||
@ -547,7 +545,6 @@ INT16 WINAPI RestoreVisRgn16( HDC16 hdc16 )
|
||||
dc->saved_visrgn = saved->next;
|
||||
DeleteObject( saved->hrgn );
|
||||
HeapFree( GetProcessHeap(), 0, saved );
|
||||
dc->flags &= ~DC_DIRTY;
|
||||
CLIPPING_UpdateGCRegion( dc );
|
||||
done:
|
||||
DC_ReleaseDCPtr( dc );
|
||||
|
146
dlls/gdi32/dc.c
146
dlls/gdi32/dc.c
@ -20,6 +20,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -50,6 +51,25 @@ static const struct gdi_obj_funcs dc_funcs =
|
||||
DC_DeleteObject /* pDeleteObject */
|
||||
};
|
||||
|
||||
|
||||
static inline DC *get_dc_obj( HDC hdc )
|
||||
{
|
||||
DC *dc = GDI_GetObjPtr( hdc, MAGIC_DONTCARE );
|
||||
if (!dc) return NULL;
|
||||
|
||||
if ((GDIMAGIC(dc->header.wMagic) != DC_MAGIC) &&
|
||||
(GDIMAGIC(dc->header.wMagic) != MEMORY_DC_MAGIC) &&
|
||||
(GDIMAGIC(dc->header.wMagic) != METAFILE_DC_MAGIC) &&
|
||||
(GDIMAGIC(dc->header.wMagic) != ENHMETAFILE_DC_MAGIC))
|
||||
{
|
||||
GDI_ReleaseObj( hdc );
|
||||
SetLastError( ERROR_INVALID_HANDLE );
|
||||
dc = NULL;
|
||||
}
|
||||
return dc;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DC_AllocDC
|
||||
*/
|
||||
@ -63,6 +83,9 @@ DC *DC_AllocDC( const DC_FUNCTIONS *funcs, WORD magic )
|
||||
dc->hSelf = hdc;
|
||||
dc->funcs = funcs;
|
||||
dc->physDev = NULL;
|
||||
dc->thread = GetCurrentThreadId();
|
||||
dc->refcount = 1;
|
||||
dc->dirty = 0;
|
||||
dc->saveLevel = 0;
|
||||
dc->saved_dc = 0;
|
||||
dc->dwHookData = 0;
|
||||
@ -136,16 +159,22 @@ DC *DC_AllocDC( const DC_FUNCTIONS *funcs, WORD magic )
|
||||
*/
|
||||
DC *DC_GetDCPtr( HDC hdc )
|
||||
{
|
||||
GDIOBJHDR *ptr = GDI_GetObjPtr( hdc, MAGIC_DONTCARE );
|
||||
if (!ptr) return NULL;
|
||||
if ((GDIMAGIC(ptr->wMagic) == DC_MAGIC) ||
|
||||
(GDIMAGIC(ptr->wMagic) == MEMORY_DC_MAGIC) ||
|
||||
(GDIMAGIC(ptr->wMagic) == METAFILE_DC_MAGIC) ||
|
||||
(GDIMAGIC(ptr->wMagic) == ENHMETAFILE_DC_MAGIC))
|
||||
return (DC *)ptr;
|
||||
GDI_ReleaseObj( hdc );
|
||||
SetLastError( ERROR_INVALID_HANDLE );
|
||||
return NULL;
|
||||
DC *dc = get_dc_obj( hdc );
|
||||
if (!dc) return NULL;
|
||||
|
||||
if (!InterlockedCompareExchange( &dc->refcount, 1, 0 ))
|
||||
{
|
||||
dc->thread = GetCurrentThreadId();
|
||||
}
|
||||
else if (dc->thread != GetCurrentThreadId())
|
||||
{
|
||||
GDI_ReleaseObj( hdc );
|
||||
SetLastError( ERROR_ACCESS_DENIED );
|
||||
return NULL;
|
||||
}
|
||||
else InterlockedIncrement( &dc->refcount );
|
||||
|
||||
return dc;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
@ -159,10 +188,9 @@ DC *DC_GetDCUpdate( HDC hdc )
|
||||
{
|
||||
DC *dc = DC_GetDCPtr( hdc );
|
||||
if (!dc) return NULL;
|
||||
while (dc->flags & DC_DIRTY)
|
||||
while (InterlockedExchange( &dc->dirty, 0 ))
|
||||
{
|
||||
DCHOOKPROC proc = dc->hookThunk;
|
||||
dc->flags &= ~DC_DIRTY;
|
||||
if (proc)
|
||||
{
|
||||
DWORD_PTR data = dc->dwHookData;
|
||||
@ -181,6 +209,7 @@ DC *DC_GetDCUpdate( HDC hdc )
|
||||
*/
|
||||
void DC_ReleaseDCPtr( DC *dc )
|
||||
{
|
||||
release_dc_ptr( dc );
|
||||
GDI_ReleaseObj( dc->hSelf );
|
||||
}
|
||||
|
||||
@ -190,10 +219,66 @@ void DC_ReleaseDCPtr( DC *dc )
|
||||
*/
|
||||
BOOL DC_FreeDCPtr( DC *dc )
|
||||
{
|
||||
assert( dc->refcount == 1 );
|
||||
return GDI_FreeObject( dc->hSelf, dc );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_dc_ptr
|
||||
*
|
||||
* Retrieve a DC pointer but release the GDI lock.
|
||||
*/
|
||||
DC *get_dc_ptr( HDC hdc )
|
||||
{
|
||||
DC *dc = get_dc_obj( hdc );
|
||||
if (!dc) return NULL;
|
||||
|
||||
if (!InterlockedCompareExchange( &dc->refcount, 1, 0 ))
|
||||
{
|
||||
dc->thread = GetCurrentThreadId();
|
||||
}
|
||||
else if (dc->thread != GetCurrentThreadId())
|
||||
{
|
||||
WARN( "dc %p belongs to thread %04x\n", hdc, dc->thread );
|
||||
GDI_ReleaseObj( hdc );
|
||||
return NULL;
|
||||
}
|
||||
else InterlockedIncrement( &dc->refcount );
|
||||
|
||||
GDI_ReleaseObj( hdc );
|
||||
return dc;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* release_dc_ptr
|
||||
*/
|
||||
void release_dc_ptr( DC *dc )
|
||||
{
|
||||
LONG ref;
|
||||
|
||||
dc->thread = 0;
|
||||
ref = InterlockedDecrement( &dc->refcount );
|
||||
assert( ref >= 0 );
|
||||
if (ref) dc->thread = GetCurrentThreadId(); /* we still own it */
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* update_dc
|
||||
*
|
||||
* Make sure the DC vis region is up to date.
|
||||
* This function may call up to USER so the GDI lock should _not_
|
||||
* be held when calling it.
|
||||
*/
|
||||
void update_dc( DC *dc )
|
||||
{
|
||||
if (InterlockedExchange( &dc->dirty, 0 ) && dc->hookThunk)
|
||||
dc->hookThunk( dc->hSelf, DCHC_INVALIDVISRGN, dc->dwHookData, 0 );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DC_DeleteObject
|
||||
*/
|
||||
@ -355,6 +440,8 @@ HDC WINAPI GetDCState( HDC hdc )
|
||||
newdc->BoundsRect = dc->BoundsRect;
|
||||
|
||||
newdc->hSelf = (HDC)handle;
|
||||
newdc->thread = GetCurrentThreadId();
|
||||
newdc->refcount = 1;
|
||||
newdc->saveLevel = 0;
|
||||
newdc->saved_dc = 0;
|
||||
|
||||
@ -415,7 +502,7 @@ void WINAPI SetDCState( HDC hdc, HDC hdcs )
|
||||
}
|
||||
TRACE("%p %p\n", hdc, hdcs );
|
||||
|
||||
dc->flags = dcs->flags & ~(DC_SAVED | DC_DIRTY);
|
||||
dc->flags = dcs->flags & ~DC_SAVED;
|
||||
dc->layout = dcs->layout;
|
||||
dc->hDevice = dcs->hDevice;
|
||||
dc->ROPmode = dcs->ROPmode;
|
||||
@ -801,6 +888,12 @@ BOOL WINAPI DeleteDC( HDC hdc )
|
||||
GDI_CheckNotLock();
|
||||
|
||||
if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
|
||||
if (dc->refcount != 1)
|
||||
{
|
||||
FIXME( "not deleting busy DC %p refcount %u\n", dc->hSelf, dc->refcount );
|
||||
DC_ReleaseDCPtr( dc );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Call hook procedure to check whether is it OK to delete this DC */
|
||||
if (dc->hookThunk)
|
||||
@ -1419,25 +1512,22 @@ DWORD WINAPI GetDCHook16( HDC16 hdc16, FARPROC16 *phookProc )
|
||||
WORD WINAPI SetHookFlags16(HDC16 hdc16, WORD flags)
|
||||
{
|
||||
HDC hdc = HDC_32( hdc16 );
|
||||
DC *dc = DC_GetDCPtr( hdc );
|
||||
DC *dc = get_dc_obj( hdc ); /* not get_dc_ptr, this needs to work from any thread */
|
||||
LONG ret = 0;
|
||||
|
||||
if( dc )
|
||||
{
|
||||
WORD wRet = dc->flags & DC_DIRTY;
|
||||
if (!dc) return 0;
|
||||
|
||||
/* "Undocumented Windows" info is slightly confusing.
|
||||
*/
|
||||
/* "Undocumented Windows" info is slightly confusing. */
|
||||
|
||||
TRACE("hDC %p, flags %04x\n",hdc,flags);
|
||||
TRACE("hDC %p, flags %04x\n",hdc,flags);
|
||||
|
||||
if( flags & DCHF_INVALIDATEVISRGN )
|
||||
dc->flags |= DC_DIRTY;
|
||||
else if( flags & DCHF_VALIDATEVISRGN || !flags )
|
||||
dc->flags &= ~DC_DIRTY;
|
||||
DC_ReleaseDCPtr( dc );
|
||||
return wRet;
|
||||
}
|
||||
return 0;
|
||||
if (flags & DCHF_INVALIDATEVISRGN)
|
||||
ret = InterlockedExchange( &dc->dirty, 1 );
|
||||
else if (flags & DCHF_VALIDATEVISRGN || !flags)
|
||||
ret = InterlockedExchange( &dc->dirty, 0 );
|
||||
|
||||
GDI_ReleaseObj( dc );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -444,6 +444,12 @@ HENHMETAFILE WINAPI CloseEnhMetaFile(HDC hdc) /* [in] metafile DC */
|
||||
DC_ReleaseDCPtr( dc );
|
||||
return NULL;
|
||||
}
|
||||
if (dc->refcount != 1)
|
||||
{
|
||||
FIXME( "not deleting busy DC %p refcount %u\n", dc->hSelf, dc->refcount );
|
||||
DC_ReleaseDCPtr( dc );
|
||||
return NULL;
|
||||
}
|
||||
physDev = (EMFDRV_PDEVICE *)dc->physDev;
|
||||
|
||||
if(dc->saveLevel)
|
||||
|
@ -269,6 +269,9 @@ typedef struct tagDC
|
||||
HDC hSelf; /* Handle to this DC */
|
||||
const struct tagDC_FUNCS *funcs; /* DC function table */
|
||||
PHYSDEV physDev; /* Physical device (driver-specific) */
|
||||
DWORD thread; /* thread owning the DC */
|
||||
LONG refcount; /* thread refcount */
|
||||
LONG dirty; /* dirty flag */
|
||||
INT saveLevel;
|
||||
HDC saved_dc;
|
||||
DWORD_PTR dwHookData;
|
||||
@ -335,7 +338,6 @@ typedef struct tagDC
|
||||
|
||||
/* DC flags */
|
||||
#define DC_SAVED 0x0002 /* It is a saved DC */
|
||||
#define DC_DIRTY 0x0004 /* hVisRgn has to be updated */
|
||||
#define DC_BOUNDS_ENABLE 0x0008 /* Bounding rectangle tracking is enabled */
|
||||
#define DC_BOUNDS_SET 0x0010 /* Bounding rectangle has been set */
|
||||
|
||||
@ -397,6 +399,9 @@ extern DC * DC_GetDCUpdate( HDC hdc );
|
||||
extern DC * DC_GetDCPtr( HDC hdc );
|
||||
extern void DC_ReleaseDCPtr( DC *dc );
|
||||
extern BOOL DC_FreeDCPtr( DC *dc );
|
||||
extern DC *get_dc_ptr( HDC hdc );
|
||||
extern void release_dc_ptr( DC *dc );
|
||||
extern void update_dc( DC *dc );
|
||||
extern void DC_InitDC( DC * dc );
|
||||
extern void DC_UpdateXforms( DC * dc );
|
||||
|
||||
|
@ -314,6 +314,12 @@ static DC *MFDRV_CloseMetaFile( HDC hdc )
|
||||
DC_ReleaseDCPtr( dc );
|
||||
return NULL;
|
||||
}
|
||||
if (dc->refcount != 1)
|
||||
{
|
||||
FIXME( "not deleting busy DC %p refcount %u\n", dc->hSelf, dc->refcount );
|
||||
DC_ReleaseDCPtr( dc );
|
||||
return NULL;
|
||||
}
|
||||
physDev = (METAFILEDRV_PDEVICE *)dc->physDev;
|
||||
|
||||
/* Construct the end of metafile record - this is documented
|
||||
|
Loading…
x
Reference in New Issue
Block a user