reactos/dll/opengl/opengl32/wgl.c

1249 lines
32 KiB
C
Raw Normal View History

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: lib/opengl32/wgl.c
* PURPOSE: OpenGL32 lib, rosglXXX functions
* PROGRAMMER: Anich Gregor (blight)
* UPDATE HISTORY:
* Feb 2, 2004: Created
*/
#define OPENGL32_GL_FUNC_PROTOTYPES
#include "opengl32.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#if !defined(UNIMPLEMENTED)
# define UNIMPLEMENTED DBGPRINT( "UNIMPLEMENTED" )
#endif
typedef struct _OPENGL_INFO
{
DWORD Version; /*!< Driver interface version */
DWORD DriverVersion; /*!< Driver version */
WCHAR DriverName[256]; /*!< Driver name */
} OPENGL_INFO, *POPENGL_INFO;
/*! \brief Append OpenGL Rendering Context (GLRC) to list
*
* \param glrc [IN] Pointer to GLRC to append to list
*/
static
void
ROSGL_AppendContext( GLRC *glrc )
{
/* synchronize */
if (WaitForSingleObject( OPENGL32_processdata.glrc_mutex, INFINITE ) ==
WAIT_FAILED)
{
DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
return; /* FIXME: do we have to expect such an error and handle it? */
}
if (OPENGL32_processdata.glrc_list == NULL)
OPENGL32_processdata.glrc_list = glrc;
else
{
GLRC *p = OPENGL32_processdata.glrc_list;
while (p->next != NULL)
p = p->next;
p->next = glrc;
}
/* release mutex */
if (!ReleaseMutex( OPENGL32_processdata.glrc_mutex ))
DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
}
/*! \brief Remove OpenGL Rendering Context (GLRC) from list
*
* \param glrc [IN] Pointer to GLRC to remove from list
*/
static
void
ROSGL_RemoveContext( GLRC *glrc )
{
/* synchronize */
if (WaitForSingleObject( OPENGL32_processdata.glrc_mutex, INFINITE ) ==
WAIT_FAILED)
{
DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
return; /* FIXME: do we have to expect such an error and handle it? */
}
if (glrc == OPENGL32_processdata.glrc_list)
OPENGL32_processdata.glrc_list = glrc->next;
else
{
GLRC *p = OPENGL32_processdata.glrc_list;
while (p != NULL)
{
if (p->next == glrc)
{
p->next = glrc->next;
break;
}
p = p->next;
}
if (p == NULL)
DBGPRINT( "Error: GLRC 0x%08x not found in list!", glrc );
}
/* release mutex */
if (!ReleaseMutex( OPENGL32_processdata.glrc_mutex ))
DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
}
/*! \brief Create a new GL Context (GLRC) and append it to the list
*
* \return Pointer to new GLRC on success
* \retval NULL Returned on failure (i.e. Out of memory)
*/
static
GLRC *
ROSGL_NewContext(void)
{
GLRC *glrc;
/* allocate GLRC */
glrc = (GLRC*)HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, sizeof (GLRC) );
/* append to list */
ROSGL_AppendContext( glrc );
return glrc;
}
/*! \brief Delete all GLDCDATA with this IDC
*
* \param icd [IN] Pointer to a ICD
*/
static
VOID
ROSGL_DeleteDCDataForICD( GLDRIVERDATA *icd )
{
GLDCDATA *p, **pptr;
return;
/* synchronize */
if (WaitForSingleObject( OPENGL32_processdata.dcdata_mutex, INFINITE ) ==
WAIT_FAILED)
{
DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
return;
}
p = OPENGL32_processdata.dcdata_list;
pptr = &OPENGL32_processdata.dcdata_list;
while (p != NULL)
{
if (p->icd == icd)
{
*pptr = p->next;
OPENGL32_UnloadICD( p->icd );
if (!HeapFree( GetProcessHeap(), 0, p ))
DBGPRINT( "Warning: HeapFree() on GLDCDATA failed (%d)",
GetLastError() );
p = *pptr;
}
else
{
pptr = &p->next;
p = p->next;
}
}
/* release mutex */
if (!ReleaseMutex( OPENGL32_processdata.dcdata_mutex ))
DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
}
/*! \brief Delete a GL Context (GLRC) and remove it from the list
*
* \param glrc [IN] Pointer to GLRC to delete
*
* \retval TRUE Success
* \retval FALSE Failure
*/
static
BOOL
ROSGL_DeleteContext( GLRC *glrc )
{
/* unload icd */
if ((glrc->icd != NULL) && (!InterlockedDecrement((LONG*)&glrc->icd->refcount)))
{
/* This is the last context, remove the ICD*/
ROSGL_DeleteDCDataForICD( glrc->icd );
}
/* remove from list */
ROSGL_RemoveContext( glrc );
/* free memory */
HeapFree( GetProcessHeap(), 0, glrc );
return TRUE;
}
/*! \brief Check wether a GLRC is in the list
*
* \param glrc [IN] Pointer to GLRC to look for in the list
*
* \retval TRUE GLRC was found
* \retval FALSE GLRC was not found
*/
static
BOOL
ROSGL_ContainsContext( GLRC *glrc )
{
GLRC *p;
BOOL found = FALSE;
/* synchronize */
if (WaitForSingleObject( OPENGL32_processdata.glrc_mutex, INFINITE ) ==
WAIT_FAILED)
{
DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
return FALSE; /* FIXME: do we have to expect such an error and handle it? */
}
p = OPENGL32_processdata.glrc_list;
while (p != NULL)
{
if (p == glrc)
{
found = TRUE;
break;
}
p = p->next;
}
/* release mutex */
if (!ReleaseMutex( OPENGL32_processdata.glrc_mutex ))
DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
return found;
}
/*! \brief Get GL private DC data.
*
* This function adds an empty GLDCDATA to the list if there is no data for the
* given DC yet.
*
* \param hdc [IN] Handle to a Device Context for which to get the data
*
* \return Pointer to GLDCDATA on success
* \retval NULL on failure
*/
static
GLDCDATA *
ROSGL_GetPrivateDCData( HDC hdc )
{
GLDCDATA *data;
HANDLE handle;
/* check hdc */
if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
{
DBGPRINT( "Error: hdc is not a DC handle!" );
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
/* synchronize */
if (WaitForSingleObject( OPENGL32_processdata.dcdata_mutex, INFINITE ) ==
WAIT_FAILED)
{
DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
return NULL; /* FIXME: do we have to expect such an error and handle it? */
}
/* We must use the window to identify our data, as pixel format is
* specific to a window for device context */
handle = WindowFromDC(hdc);
if(!handle)
handle = hdc;
/* look for data in list */
data = OPENGL32_processdata.dcdata_list;
while (data != NULL)
{
if (data->handle == handle) /* found */
break;
data = data->next;
}
/* allocate new data if not found in list */
if (data == NULL)
{
data = HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS,
sizeof (GLDCDATA) );
if (data == NULL)
{
DBGPRINT( "Error: HeapAlloc() failed (%d)", GetLastError() );
}
else
{
data->handle = handle;
/* append data to list */
if (OPENGL32_processdata.dcdata_list == NULL)
OPENGL32_processdata.dcdata_list = data;
else
{
GLDCDATA *p = OPENGL32_processdata.dcdata_list;
while (p->next != NULL)
p = p->next;
p->next = data;
}
}
}
/* release mutex */
if (!ReleaseMutex( OPENGL32_processdata.dcdata_mutex ))
DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
return data;
}
/*! \brief Get ICD from HDC.
*
* This function asks the display driver which OpenGL ICD to load for the given
* HDC, loads it and returns a pointer to a GLDRIVERDATA struct on success.
*
* \param hdc [IN] Handle for DC for which to load/get the ICD
*
* \return Pointer to GLDRIVERDATA
* \retval NULL Failure.
*/
static
GLDRIVERDATA *
ROSGL_ICDForHDC( HDC hdc )
{
GLDCDATA *dcdata;
GLDRIVERDATA *drvdata;
dcdata = ROSGL_GetPrivateDCData( hdc );
if (dcdata == NULL)
return NULL;
if (dcdata->icd == NULL)
{
LPCWSTR driverName;
OPENGL_INFO info;
/* NOTE: This might be done by multiple threads simultaneously, but only the fastest
actually gets to set the ICD! */
driverName = _wgetenv( L"OPENGL32_DRIVER" );
if (driverName == NULL)
{
DWORD dwInput;
LONG ret;
/* get driver name */
dwInput = OPENGL_GETINFO;
ret = ExtEscape( hdc, QUERYESCSUPPORT, sizeof (dwInput), (LPCSTR)&dwInput, 0, NULL );
if (ret > 0)
{
dwInput = 0;
ret = ExtEscape( hdc, OPENGL_GETINFO, sizeof (dwInput),
(LPCSTR)&dwInput, sizeof (OPENGL_INFO),
(LPSTR)&info );
}
if (ret <= 0)
{
HKEY hKey;
DWORD type, size;
if (ret < 0)
{
DBGPRINT( "Warning: ExtEscape to get the drivername failed! (%d)", GetLastError() );
if (MessageBox( WindowFromDC( hdc ), L"Couldn't get installable client driver name!\nUsing default driver.",
L"OPENGL32.dll: Warning", MB_OKCANCEL | MB_ICONWARNING ) == IDCANCEL)
{
return NULL;
}
}
/* open registry key */
ret = RegOpenKeyExW( HKEY_LOCAL_MACHINE, OPENGL_DRIVERS_SUBKEY, 0, KEY_QUERY_VALUE, &hKey );
if (ret != ERROR_SUCCESS)
{
DBGPRINT( "Error: Couldn't open registry key '%ws'", OPENGL_DRIVERS_SUBKEY );
SetLastError( ret );
return NULL;
}
/* query value */
size = sizeof (info.DriverName);
ret = RegQueryValueExW( hKey, L"DefaultDriver", 0, &type, (LPBYTE)info.DriverName, &size );
RegCloseKey( hKey );
if (ret != ERROR_SUCCESS || type != REG_SZ)
{
DBGPRINT( "Error: Couldn't query DefaultDriver value or not a string" );
SetLastError( ret );
return NULL;
}
}
}
else
{
wcsncpy( info.DriverName, driverName, sizeof (info.DriverName) / sizeof (info.DriverName[0]) );
}
/* load driver (or get a reference) */
drvdata = OPENGL32_LoadICD( info.DriverName );
if (drvdata == NULL)
{
WCHAR Buffer[256];
snwprintf(Buffer, sizeof(Buffer)/sizeof(WCHAR),
L"Couldn't load driver \"%s\".", info.DriverName);
MessageBox(WindowFromDC( hdc ), Buffer,
L"OPENGL32.dll: Warning",
MB_OK | MB_ICONWARNING);
}
else
{
/* Atomically set the ICD!!! */
if (InterlockedCompareExchangePointer((PVOID*)&dcdata->icd,
(PVOID)drvdata,
NULL) != NULL)
{
/* Too bad, somebody else was faster... */
DBGTRACE("ICD is already set!\n");
}
}
}
return dcdata->icd;
}
/*! \brief SetContextCallBack passed to DrvSetContext.
*
* This function gets called by the OpenGL driver whenever the current GL
* context (dispatch table) is to be changed.
*
* \param table [IN] Function pointer table (first DWORD is number of functions)
*
* \return unkown (maybe void? ERROR_SUCCESS at the moment)
*/
DWORD
CALLBACK
ROSGL_SetContextCallBack( const ICDTable *table )
{
TEB *teb;
PROC *tebTable, *tebDispatchTable;
INT size;
teb = NtCurrentTeb();
tebTable = (PROC *)teb->glTable;
tebDispatchTable = (PROC *)teb->glDispatchTable;
DBGTRACE( "Called!" );
if (table != NULL)
{
DBGPRINT( "Function count: %d\n", table->num_funcs );
/* save table */
size = sizeof (PROC) * table->num_funcs;
memcpy( tebTable, table->dispatch_table, size );
memset( tebTable + table->num_funcs, 0, DISPATCH_TABLE_SIZE - size );
}
else
{
DBGPRINT( "Unsetting current context" );
memset( tebTable, 0, DISPATCH_TABLE_SIZE );
}
/* put in empty functions as long as we dont have a fallback */
#define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
if (tebTable[icdidx] == NULL) \
{ \
if (table != NULL) \
DBGPRINT( "Warning: GL proc '%s' is NULL", #func ); \
tebTable[icdidx] = (PROC)glEmptyFunc##stack; \
}
GLFUNCS_MACRO
#undef X
/* fill teb->glDispatchTable for fast calls */
#define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
if (tebidx >= 0) \
tebDispatchTable[tebidx] = tebTable[icdidx];
GLFUNCS_MACRO
#undef X
DBGPRINT( "Done." );
return ERROR_SUCCESS;
}
/*! \brief Returns the current pixelformat.
*
* \param hdc [IN] Handle to DC to get the pixelformat from
*
* \return Pixelformat index
* \retval 0 Failure
*/
int
WINAPI
rosglGetPixelFormat( HDC hdc )
{
GLDCDATA *dcdata;
DBGTRACE( "Called!" );
dcdata = ROSGL_GetPrivateDCData( hdc );
if (dcdata == NULL)
{
DBGPRINT( "Error: ROSGL_GetPrivateDCData failed!" );
return 0;
}
return dcdata->pixel_format;
}
/*! \brief Attempts to find the best matching pixel format for HDC
*
* This function is comparing each available format with the preferred one
* and returns the one which is closest to it.
* If PFD_DOUBLEBUFFER, PFD_STEREO or one of PFD_DRAW_TO_WINDOW,
* PFD_DRAW_TO_BITMAP, PFD_SUPPORT_GDI and PDF_SUPPORT_OPENGL is given then
* only formats which also support those will be enumerated (unless
* PFD_DOUBLEBUFFER_DONTCARE or PFD_STEREO_DONTCARE is also set)
*
* \param hdc [IN] Handle to DC for which to get a pixel format index
* \param pfd [IN] PFD describing what kind of format you want
*
* \return Pixel format index
* \retval 0 Failed to find a suitable format
*/
#define BUFFERDEPTH_SCORE(want, have) \
((want == 0) ? (0) : ((want < have) ? (1) : ((want > have) ? (3) : (0))))
/* Score if we want and not have it */
#define FLAG_SCORE(want, have, flag) \
(((want & ~have) & flag) ? (1) : (0))
/* Score if what we want is different than what we have, except when
_DONTCARE was set */
#define FLAG_SCORE_DONTCARE(want, have, flag) \
((!(have & flag ## _DONTCARE)) && ((want & flag) != (have & flag)) ? (1) : (0))
int
APIENTRY
rosglChoosePixelFormat( HDC hdc, CONST PIXELFORMATDESCRIPTOR *pfd )
{
GLDRIVERDATA *icd;
PIXELFORMATDESCRIPTOR icdPfd;
int i;
int best = 0;
int score, bestScore = 0x7fff; /* used to choose a pfd if no exact match */
int icdNumFormats;
DBGTRACE( "Called!" );
/* load ICD */
icd = ROSGL_ICDForHDC( hdc );
if (icd == NULL)
return 0;
/* check input */
if (pfd->nSize != sizeof (PIXELFORMATDESCRIPTOR) || pfd->nVersion != 1)
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
/* get number of formats */
icdNumFormats = icd->DrvDescribePixelFormat( hdc, 1,
sizeof (PIXELFORMATDESCRIPTOR), &icdPfd );
if (icdNumFormats == 0)
{
DBGPRINT( "Error: DrvDescribePixelFormat failed (%d)", GetLastError() );
return 0;
}
DBGPRINT( "Info: Enumerating %d pixelformats", icdNumFormats );
/* try to find best format */
for (i = 0; i < icdNumFormats; i++)
{
if (icd->DrvDescribePixelFormat( hdc, i + 1,
sizeof (PIXELFORMATDESCRIPTOR), &icdPfd ) == 0)
{
DBGPRINT( "Warning: DrvDescribePixelFormat failed (%d)",
GetLastError() );
break;
}
if ((pfd->dwFlags & PFD_GENERIC_ACCELERATED) != 0) /* we do not support such kind of drivers */
{
continue;
}
score = 0; /* higher is worse */
/* compare flags */
score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_DRAW_TO_WINDOW);
score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_DRAW_TO_BITMAP);
score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_SUPPORT_GDI);
score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_SUPPORT_OPENGL);
score += FLAG_SCORE_DONTCARE(pfd->dwFlags, icdPfd.dwFlags, PFD_DOUBLEBUFFER);
score += FLAG_SCORE_DONTCARE(pfd->dwFlags, icdPfd.dwFlags, PFD_STEREO);
/* check other attribs */
if (pfd->iPixelType != icdPfd.iPixelType)
score += 5; /* this is really bad i think */
if (pfd->iLayerType != icdPfd.iLayerType)
score += 15; /* this is very very bad ;) */
score += BUFFERDEPTH_SCORE(pfd->cAlphaBits, icdPfd.cAlphaBits);
score += BUFFERDEPTH_SCORE(pfd->cAccumBits, icdPfd.cAccumBits);
score += BUFFERDEPTH_SCORE(pfd->cDepthBits, icdPfd.cDepthBits);
score += BUFFERDEPTH_SCORE(pfd->cStencilBits, icdPfd.cStencilBits);
score += BUFFERDEPTH_SCORE(pfd->cAuxBuffers, icdPfd.cAuxBuffers);
/* check score */
if (score < bestScore)
{
bestScore = score;
best = i + 1;
if (bestScore == 0)
break;
}
}
if (best == 0)
SetLastError( 0 ); /* FIXME: set appropriate error */
DBGPRINT( "Info: Suggesting pixelformat %d", best );
return best;
}
/*! \brief Copy data specified by mask from one GLRC to another.
*
* \param src [IN] Source GLRC
* \param src [OUT] Destination GLRC
* \param mask [IN] Bitfield like given to glPushAttrib()
*
* \retval TRUE Success
* \retval FALSE Failure
*/
BOOL
APIENTRY
rosglCopyContext( HGLRC hsrc, HGLRC hdst, UINT mask )
{
GLRC *src = (GLRC *)hsrc;
GLRC *dst = (GLRC *)hdst;
/* check glrcs */
if (!ROSGL_ContainsContext( src ))
{
DBGPRINT( "Error: src GLRC not found!" );
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
if (!ROSGL_ContainsContext( dst ))
{
DBGPRINT( "Error: dst GLRC not found!" );
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
/* I think this is only possible within one ICD */
if (src->icd != dst->icd)
{
DBGPRINT( "Error: src and dst GLRC use different ICDs!" );
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
/* copy data (call ICD) */
return src->icd->DrvCopyContext( src->hglrc, dst->hglrc, mask );
}
/*! \brief Create a new GL Rendering Context.
*
* This function can create over- or underlay surfaces.
*
* \param hdc [IN] Handle for DC for which to create context
* \param layer [IN] Layer number to bind (draw?) to
*
* \return Handle for the created GLRC
* \retval NULL Failure
*/
HGLRC
APIENTRY
rosglCreateLayerContext( HDC hdc, int layer )
{
GLDRIVERDATA *icd = NULL;
GLRC *glrc;
HGLRC drvHglrc = NULL;
DBGTRACE( "Called!" );
/* if (GetObjectType( hdc ) != OBJ_DC)
{
DBGPRINT( "Error: hdc is not a DC handle!" );
return NULL;
}
*/
/* load ICD */
icd = ROSGL_ICDForHDC( hdc );
if (icd == NULL)
{
DBGPRINT( "Couldn't get ICD by HDC :-(" );
/* FIXME: fallback? */
return NULL;
}
/* create new GLRC */
glrc = ROSGL_NewContext();
if (glrc == NULL)
return NULL;
/* Don't forget to refcount it, icd will be released when last context is deleted */
InterlockedIncrement((LONG*)&icd->refcount);
/* You can't create a context without first setting a valid pixel format */
if(rosglGetPixelFormat(hdc) == 0)
{
ROSGL_DeleteContext( glrc );
SetLastError(ERROR_INVALID_PIXEL_FORMAT);
return NULL;
}
/* create context */
if (icd->DrvCreateLayerContext != NULL)
drvHglrc = icd->DrvCreateLayerContext( hdc, layer );
if (drvHglrc == NULL)
{
if (layer == 0 && icd->DrvCreateContext != NULL)
drvHglrc = icd->DrvCreateContext( hdc );
else
DBGPRINT( "Warning: CreateLayerContext not supported by ICD!" );
}
if (drvHglrc == NULL)
{
/* FIXME: fallback to mesa? */
DBGPRINT( "Error: DrvCreate[Layer]Context failed! (%d)", GetLastError() );
ROSGL_DeleteContext( glrc );
return NULL;
}
/* we have our GLRC in glrc and the ICD's GLRC in drvHglrc */
glrc->hglrc = drvHglrc;
glrc->icd = icd;
return (HGLRC)glrc;
}
/*! \brief Create a new GL Rendering Context.
*
* \param hdc [IN] Handle for DC for which to create context
*
* \return Handle for the created GLRC
* \retval NULL Failure
*/
HGLRC
APIENTRY
rosglCreateContext( HDC hdc )
{
return rosglCreateLayerContext( hdc, 0 );
}
/*! \brief Delete an OpenGL context
*
* \param hglrc [IN] Handle to GLRC to delete;
*
* \retval TRUE Success
* \retval FALSE Failure (i.e. GLRC is current for a thread)
*/
BOOL
APIENTRY
rosglDeleteContext( HGLRC hglrc )
{
GLRC *glrc = (GLRC *)hglrc;
/* check if we know about this context */
if (!ROSGL_ContainsContext( glrc ))
{
DBGPRINT( "Error: hglrc not found!" );
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
/* On windows, this is allowed to delete a context which is current */
if (glrc->is_current)
{
/* But only for its own thread */
if(glrc->thread_id != GetCurrentThreadId())
{
DBGPRINT( "Error: GLRC is current for DC 0x%08x", glrc->hdc );
SetLastError( ERROR_INVALID_FUNCTION );
return FALSE;
}
/* Unset it before going further */
rosglMakeCurrent(NULL, NULL);
}
/* release ICD's context */
if (glrc->hglrc != NULL)
{
if (!glrc->icd->DrvDeleteContext( glrc->hglrc ))
{
DBGPRINT( "Warning: DrvDeleteContext() failed (%d)", GetLastError() );
return FALSE;
}
}
/* free resources */
return ROSGL_DeleteContext( glrc );
}
BOOL
APIENTRY
rosglDescribeLayerPlane( HDC hdc, int iPixelFormat, int iLayerPlane,
UINT nBytes, LPLAYERPLANEDESCRIPTOR plpd )
{
UNIMPLEMENTED;
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
return FALSE;
}
/*! \brief Gets information about a pixelformat.
*
* \param hdc [IN] Handle to DC
* \param iFormat [IN] Pixelformat index
* \param nBytes [IN] sizeof (pfd) - at most nBytes are copied into pfd
* \param pfd [OUT] Pointer to a PIXELFORMATDESCRIPTOR
*
* \return Maximum pixelformat index/number of formats
* \retval 0 Failure
*/
int
APIENTRY
rosglDescribePixelFormat( HDC hdc, int iFormat, UINT nBytes,
LPPIXELFORMATDESCRIPTOR pfd )
{
int ret = 0;
GLDRIVERDATA *icd = ROSGL_ICDForHDC( hdc );
if (icd != NULL)
{
ret = icd->DrvDescribePixelFormat( hdc, iFormat, nBytes, pfd );
if (ret == 0)
DBGPRINT( "Error: DrvDescribePixelFormat(format=%d) failed (%d)", iFormat, GetLastError() );
}
else
{
SetLastError( ERROR_INVALID_FUNCTION );
}
return ret;
}
/*! \brief Return the thread's current GLRC
*
* \return Handle for thread's current GLRC
* \retval NULL No current GLRC set
*/
HGLRC
APIENTRY
rosglGetCurrentContext()
{
return NtCurrentTeb()->glCurrentRC;
}
/*! \brief Return the thread's current DC
*
* \return Handle for thread's current DC
* \retval NULL No current DC/GLRC set
*/
HDC
APIENTRY
rosglGetCurrentDC()
{
GLRC* glrc = (GLRC*)NtCurrentTeb()->glCurrentRC;
if(glrc) return glrc->hdc;
return NULL;
}
int
APIENTRY
rosglGetLayerPaletteEntries( HDC hdc, int iLayerPlane, int iStart,
int cEntries, COLORREF *pcr )
{
UNIMPLEMENTED;
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
return 0;
}
/*! \brief Get the address for an OpenGL extension function.
*
* The addresses this function returns are only valid within the same thread
* which it was called from.
*
* \param proc [IN] Name of the function to look for
*
* \return The address of the proc
* \retval NULL Failure
*/
PROC
APIENTRY
rosglGetProcAddress( LPCSTR proc )
{
PROC func;
GLRC* glrc = (GLRC*)NtCurrentTeb()->glCurrentRC;
/* FIXME we should Flush the gl here */
if (glrc == NULL)
{
DBGPRINT( "Error: No current GLRC!" );
SetLastError( ERROR_INVALID_FUNCTION );
return NULL;
}
func = glrc->icd->DrvGetProcAddress( proc );
if (func != NULL)
{
DBGPRINT( "Info: Proc \"%s\" loaded from ICD.", proc );
return func;
}
/* FIXME: Should we return wgl/gl 1.1 functions? */
SetLastError( ERROR_PROC_NOT_FOUND );
return NULL;
}
PROC
APIENTRY
rosglGetDefaultProcAddress( LPCSTR proc )
{
PROC func;
GLRC* glrc = (GLRC*)NtCurrentTeb()->glCurrentRC;
/* wglGetDefaultProcAddress does not flush the gl */
if (glrc == NULL)
{
DBGPRINT( "Error: No current GLRC!" );
SetLastError( ERROR_INVALID_FUNCTION );
return NULL;
}
func = glrc->icd->DrvGetProcAddress( proc );
if (func != NULL)
{
DBGPRINT( "Info: Proc \"%s\" loaded from ICD.", proc );
return func;
}
/* FIXME: Should we return wgl/gl 1.1 functions? */
SetLastError( ERROR_PROC_NOT_FOUND );
return NULL;
}
/*! \brief Make the given GLRC the threads current GLRC for hdc
*
* \param hdc [IN] Handle for a DC to be drawn on
* \param hglrc [IN] Handle for a GLRC to make current
*
* \retval TRUE Success
* \retval FALSE Failure
*/
BOOL
APIENTRY
rosglMakeCurrent( HDC hdc, HGLRC hglrc )
{
GLRC *glrc = (GLRC *)hglrc;
ICDTable *icdTable = NULL;
DBGTRACE( "Called!" );
/* Is t a new context ? */
if (glrc != NULL)
{
/* check hdc */
if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
{
DBGPRINT( "Error: hdc is not a DC handle!" );
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
/* check if we know about this glrc */
if (!ROSGL_ContainsContext( glrc ))
{
DBGPRINT( "Error: hglrc not found!" );
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
/* check if it is available */
if (glrc->is_current && glrc->thread_id != GetCurrentThreadId()) /* used by another thread */
{
DBGPRINT( "Error: hglrc is current for thread 0x%08x", glrc->thread_id );
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
/* Unset previous one */
if (NtCurrentTeb()->glCurrentRC != NULL)
{
GLRC *oldglrc = (GLRC*)NtCurrentTeb()->glCurrentRC;
oldglrc->is_current = FALSE;
oldglrc->thread_id = 0;
oldglrc->hdc = NULL;
oldglrc->icd->DrvReleaseContext(oldglrc->hglrc);
}
/* call the ICD */
if (glrc->hglrc != NULL)
{
DBGPRINT( "Info: Calling DrvSetContext!" );
SetLastError( ERROR_SUCCESS );
icdTable = glrc->icd->DrvSetContext( hdc, glrc->hglrc,
(void *)ROSGL_SetContextCallBack );
if (icdTable == NULL)
{
DBGPRINT( "Error: DrvSetContext failed (%d)\n", GetLastError() );
NtCurrentTeb()->glCurrentRC = NULL;
return FALSE;
}
DBGPRINT( "Info: DrvSetContext succeeded!" );
}
/* make it current */
glrc->is_current = TRUE;
glrc->thread_id = GetCurrentThreadId();
glrc->hdc = hdc;
NtCurrentTeb()->glCurrentRC = (HGLRC)glrc;
}
else if(NtCurrentTeb()->glCurrentRC)
{
/* This is a call to unset the context */
GLRC *oldglrc = (GLRC*)NtCurrentTeb()->glCurrentRC;
oldglrc->is_current = FALSE;
oldglrc->thread_id = 0;
oldglrc->hdc = NULL;
oldglrc->icd->DrvReleaseContext(oldglrc->hglrc);
NtCurrentTeb()->glCurrentRC = NULL;
}
else
{
/*
* To make wine tests happy.
* Now, who cares if MakeCurrentContext(NULL, NULL) fails when current context is already NULL
*/
if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
{
DBGPRINT( "Error: hdc is not a DC handle!" );
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
}
if (ROSGL_SetContextCallBack( icdTable ) != ERROR_SUCCESS && icdTable == NULL)
{
DBGPRINT( "Warning: ROSGL_SetContextCallBack failed!" );
}
return TRUE;
}
BOOL
APIENTRY
rosglRealizeLayerPalette( HDC hdc, int iLayerPlane, BOOL bRealize )
{
UNIMPLEMENTED;
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
return FALSE;
}
int
APIENTRY
rosglSetLayerPaletteEntries( HDC hdc, int iLayerPlane, int iStart,
int cEntries, CONST COLORREF *pcr )
{
UNIMPLEMENTED;
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
return 0;
}
/*! \brief Set a DCs pixelformat
*
* \param hdc [IN] Handle to DC for which to set the format
* \param iFormat [IN] Index of the pixelformat to set
* \param pfd [IN] Not sure what this is for
*
* \retval TRUE Success
* \retval FALSE Failure
*/
BOOL
WINAPI
rosglSetPixelFormat( HDC hdc, int iFormat, CONST PIXELFORMATDESCRIPTOR *pfd )
{
GLDCDATA *dcdata;
GLDRIVERDATA* icd;
DBGTRACE( "Called!" );
/* Get private DC data */
dcdata = ROSGL_GetPrivateDCData( hdc );
if (dcdata == NULL)
{
DBGPRINT( "Error: ROSGL_GetPrivateDCData() failed!" );
return FALSE;
}
/* you can set the same pixel format twice, but you can't modify it */
if(dcdata->pixel_format) return dcdata->pixel_format == iFormat;
icd = ROSGL_ICDForHDC(hdc);
if(icd == NULL)
return 0;
/* Call ICD function */
if (!icd->DrvSetPixelFormat( hdc, iFormat, pfd ))
{
DBGPRINT( "Warning: DrvSetPixelFormat(format=%d) failed (%d)",
iFormat, GetLastError() );
return FALSE;
}
dcdata->pixel_format = iFormat;
return TRUE;
}
/*! \brief Enable display-list sharing between multiple GLRCs
*
* This will only work if both GLRCs are from the same driver.
*
* \param hglrc1 [IN] GLRC number 1
* \param hglrc2 [IN] GLRC number 2
*
* \retval TRUE Success
* \retval FALSE Failure
*/
BOOL
APIENTRY
rosglShareLists( HGLRC hglrc1, HGLRC hglrc2 )
{
GLRC *glrc1 = (GLRC *)hglrc1;
GLRC *glrc2 = (GLRC *)hglrc2;
/* check glrcs */
if (!ROSGL_ContainsContext( glrc1 ))
{
DBGPRINT( "Error: hglrc1 not found!" );
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
if (!ROSGL_ContainsContext( glrc2 ))
{
DBGPRINT( "Error: hglrc2 not found!" );
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
/* I think this is only possible within one ICD */
if (glrc1->icd != glrc2->icd)
{
DBGPRINT( "Error: hglrc1 and hglrc2 use different ICDs!" );
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
/* share lists (call ICD) */
return glrc1->icd->DrvShareLists( glrc1->hglrc, glrc2->hglrc );
}
/*! \brief Flushes GL and swaps front/back buffer if appropriate
*
* \param hdc [IN] Handle to device context to swap buffers for
*
* \retval TRUE Success
* \retval FALSE Failure
*/
BOOL
APIENTRY
rosglSwapBuffers( HDC hdc )
{
GLDRIVERDATA *icd = ROSGL_ICDForHDC( hdc );
DBGTRACE( "Called!" );
if (icd != NULL)
{
DBGPRINT( "Swapping buffers!" );
if (!icd->DrvSwapBuffers( hdc ))
{
DBGPRINT( "Error: DrvSwapBuffers failed (%d)", GetLastError() );
return FALSE;
}
return TRUE;
}
/* FIXME: implement own functionality? */
SetLastError( ERROR_INVALID_FUNCTION );
return FALSE;
}
BOOL
APIENTRY
rosglSwapLayerBuffers( HDC hdc, UINT fuPlanes )
{
BOOL ret = FALSE;
if(fuPlanes & WGL_SWAP_MAIN_PLANE)
ret = rosglSwapBuffers(hdc);
if(fuPlanes &~WGL_SWAP_MAIN_PLANE)
DBGTRACE("wglSwapLayerBuffers is not fully implemented\n");
return ret;
}
#ifdef __cplusplus
}; /* extern "C" */
#endif /* __cplusplus */
/* EOF */