/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* 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
* 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>
#define WGL_WGLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/wglext.h>
#include "pipe/p_compiler.h"
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "util/u_memory.h"
#include "util/u_atomic.h"
#include "state_tracker/st_api.h"
#include "stw_icd.h"
#include "stw_device.h"
#include "stw_winsys.h"
#include "stw_framebuffer.h"
#include "stw_pixelformat.h"
#include "stw_context.h"
#include "stw_tls.h"
static INLINE struct stw_context *
stw_current_context(void)
{
struct st_context_iface *st;
st = (stw_dev) ? stw_dev->stapi->get_current(stw_dev->stapi) : NULL;
return (struct stw_context *) ((st) ? st->st_manager_private : NULL);
}
BOOL APIENTRY
DrvCopyContext(
DHGLRC dhrcSource,
DHGLRC dhrcDest,
UINT fuMask )
{
struct stw_context *src;
struct stw_context *dst;
BOOL ret = FALSE;
if (!stw_dev)
return FALSE;
pipe_mutex_lock( stw_dev->ctx_mutex );
src = stw_lookup_context_locked( dhrcSource );
dst = stw_lookup_context_locked( dhrcDest );
if (src && dst) {
/* FIXME */
assert(0);
(void) src;
(void) dst;
(void) fuMask;
}
pipe_mutex_unlock( stw_dev->ctx_mutex );
return ret;
}
BOOL APIENTRY
DrvShareLists(
DHGLRC dhglrc1,
DHGLRC dhglrc2 )
{
struct stw_context *ctx1;
struct stw_context *ctx2;
BOOL ret = FALSE;
if (!stw_dev)
return FALSE;
pipe_mutex_lock( stw_dev->ctx_mutex );
ctx1 = stw_lookup_context_locked( dhglrc1 );
ctx2 = stw_lookup_context_locked( dhglrc2 );
if (ctx1 && ctx2 && ctx2->st->share)
ret = ctx2->st->share(ctx2->st, ctx1->st);
pipe_mutex_unlock( stw_dev->ctx_mutex );
return ret;
}
DHGLRC APIENTRY
DrvCreateContext(
HDC hdc )
{
return DrvCreateLayerContext( hdc, 0 );
}
DHGLRC APIENTRY
DrvCreateLayerContext(
HDC hdc,
INT iLayerPlane )
{
return stw_create_context_attribs(hdc, iLayerPlane, 0, 1, 0, 0,
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
}
DHGLRC
stw_create_context_attribs(
HDC hdc,
INT iLayerPlane,
DHGLRC hShareContext,
int majorVersion, int minorVersion,
int contextFlags, int profileMask)
{
int iPixelFormat;
struct stw_framebuffer *fb;
const struct stw_pixelformat_info *pfi;
struct st_context_attribs attribs;
struct stw_context *ctx = NULL;
struct stw_context *shareCtx = NULL;
enum st_context_error ctx_err = 0;
if (!stw_dev)
return 0;
if (iLayerPlane != 0)
return 0;
iPixelFormat = GetPixelFormat(hdc);
if(!iPixelFormat)
return 0;
/*
* GDI only knows about displayable pixel formats, so determine the pixel
* format from the framebuffer.
*
* TODO: Remove the GetPixelFormat() above, and stop relying on GDI.
*/
fb = stw_framebuffer_from_hdc( hdc );
if (fb) {
assert(iPixelFormat == fb->iDisplayablePixelFormat);
iPixelFormat = fb->iPixelFormat;
stw_framebuffer_release(fb);
}
pfi = stw_pixelformat_get_info( iPixelFormat );
if (hShareContext != 0) {
pipe_mutex_lock( stw_dev->ctx_mutex );
shareCtx = stw_lookup_context_locked( hShareContext );
pipe_mutex_unlock( stw_dev->ctx_mutex );
}
ctx = CALLOC_STRUCT( stw_context );
if (ctx == NULL)
goto no_ctx;
ctx->hdc = hdc;
ctx->iPixelFormat = iPixelFormat;
memset(&attribs, 0, sizeof(attribs));
attribs.visual = pfi->stvis;
attribs.major = majorVersion;
attribs.minor = minorVersion;
if (contextFlags & WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB)
attribs.flags |= ST_CONTEXT_FLAG_FORWARD_COMPATIBLE;
if (contextFlags & WGL_CONTEXT_DEBUG_BIT_ARB)
attribs.flags |= ST_CONTEXT_FLAG_DEBUG;
/* There are no profiles before OpenGL 3.2. The
* WGL_ARB_create_context_profile spec says:
*
* "If the requested OpenGL version is less than 3.2,
* WGL_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality of the
* context is determined solely by the requested version."
*
* The spec also says:
*
* "The default value for WGL_CONTEXT_PROFILE_MASK_ARB is
* WGL_CONTEXT_CORE_PROFILE_BIT_ARB."
*/
attribs.profile = ST_PROFILE_DEFAULT;
if ((majorVersion > 3 || (majorVersion == 3 && minorVersion >= 2))
&& ((profileMask & WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB) == 0))
attribs.profile = ST_PROFILE_OPENGL_CORE;
ctx->st = stw_dev->stapi->create_context(stw_dev->stapi,
stw_dev->smapi, &attribs, &ctx_err, shareCtx ? shareCtx->st : NULL);
if (ctx->st == NULL)
goto no_st_ctx;
ctx->st->st_manager_private = (void *) ctx;
pipe_mutex_lock( stw_dev->ctx_mutex );
ctx->dhglrc = handle_table_add(stw_dev->ctx_table, ctx);
pipe_mutex_unlock( stw_dev->ctx_mutex );
if (!ctx->dhglrc)
goto no_hglrc;
return ctx->dhglrc;
no_hglrc:
ctx->st->destroy(ctx->st);
no_st_ctx:
FREE(ctx);
no_ctx:
return 0;
}
BOOL APIENTRY
DrvDeleteContext(
DHGLRC dhglrc )
{
struct stw_context *ctx ;
BOOL ret = FALSE;
if (!stw_dev)
return FALSE;
pipe_mutex_lock( stw_dev->ctx_mutex );
ctx = stw_lookup_context_locked(dhglrc);
handle_table_remove(stw_dev->ctx_table, dhglrc);
pipe_mutex_unlock( stw_dev->ctx_mutex );
if (ctx) {
struct stw_context *curctx = stw_current_context();
/* Unbind current if deleting current context. */
if (curctx == ctx)
stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
ctx->st->destroy(ctx->st);
FREE(ctx);
ret = TRUE;
}
return ret;
}
BOOL APIENTRY
DrvReleaseContext(
DHGLRC dhglrc )
{
struct stw_context *ctx;
if (!stw_dev)
return FALSE;
pipe_mutex_lock( stw_dev->ctx_mutex );
ctx = stw_lookup_context_locked( dhglrc );
pipe_mutex_unlock( stw_dev->ctx_mutex );
if (!ctx)
return FALSE;
/* The expectation is that ctx is the same context which is
* current for this thread. We should check that and return False
* if not the case.
*/
if (ctx != stw_current_context())
return FALSE;
if (stw_make_current( NULL, 0 ) == FALSE)
return FALSE;
return TRUE;
}
DHGLRC
stw_get_current_context( void )
{
struct stw_context *ctx;
ctx = stw_current_context();
if(!ctx)
return 0;
return ctx->dhglrc;
}
HDC
stw_get_current_dc( void )
{
struct stw_context *ctx;
ctx = stw_current_context();
if(!ctx)
return NULL;
return ctx->hdc;
}
BOOL
stw_make_current(
HDC hdc,
DHGLRC dhglrc )
{
struct stw_context *curctx = NULL;
struct stw_context *ctx = NULL;
struct stw_framebuffer *fb = NULL;
BOOL ret = FALSE;
if (!stw_dev)
return FALSE;
curctx = stw_current_context();
if (curctx != NULL) {
if (curctx->dhglrc == dhglrc) {
if (curctx->hdc == hdc) {
/* Return if already current. */
return TRUE;
}
} else {
curctx->st->flush(curctx->st, ST_FLUSH_FRONT, NULL);
}
}
if (dhglrc) {
pipe_mutex_lock( stw_dev->ctx_mutex );
ctx = stw_lookup_context_locked( dhglrc );
pipe_mutex_unlock( stw_dev->ctx_mutex );
if (!ctx) {
goto fail;
}
fb = stw_framebuffer_from_hdc( hdc );
if (fb) {
stw_framebuffer_update(fb);
}
else {
/* Applications should call SetPixelFormat before creating a context,
* but not all do, and the opengl32 runtime seems to use a default pixel
* format in some cases, so we must create a framebuffer for those here
*/
int iPixelFormat = GetPixelFormat(hdc);
if (iPixelFormat)
fb = stw_framebuffer_create( hdc, iPixelFormat );
if (!fb)
goto fail;
}
if (fb->iPixelFormat != ctx->iPixelFormat) {
SetLastError(ERROR_INVALID_PIXEL_FORMAT);
goto fail;
}
/* Bind the new framebuffer */
ctx->hdc = hdc;
ret = stw_dev->stapi->make_current(stw_dev->stapi, ctx->st,
fb->stfb, fb->stfb);
stw_framebuffer_reference(&ctx->current_framebuffer, fb);
} else {
ret = stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
}
fail:
if (fb) {
stw_framebuffer_release(fb);
}
/* On failure, make the thread's current rendering context not current
* before returning */
if (!ret) {
stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
ctx = NULL;
}
/* Unreference the previous framebuffer if any. It must be done after
* make_current, as it can be referenced inside.
*/
if (curctx && curctx != ctx) {
stw_framebuffer_reference(&curctx->current_framebuffer, NULL);
}
return ret;
}
/**
* Flush the current context if it is bound to the framebuffer.
*/
void
stw_flush_current_locked( struct stw_framebuffer *fb )
{
struct stw_context *ctx = stw_current_context();
if (ctx && ctx->current_framebuffer == fb) {
ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL);
}
}
/**
* Notify the current context that the framebuffer has become invalid.
*/
void
stw_notify_current_locked( struct stw_framebuffer *fb )
{
p_atomic_inc(&fb->stfb->stamp);
}
/**
* Although WGL allows different dispatch entrypoints per context
*/
static const GLCLTPROCTABLE cpt =
{
OPENGL_VERSION_110_ENTRIES,
{
&glNewList,
&glEndList,
&glCallList,
&glCallLists,
&glDeleteLists,
&glGenLists,
&glListBase,
&glBegin,
&glBitmap,
&glColor3b,
&glColor3bv,
&glColor3d,
&glColor3dv,
&glColor3f,
&glColor3fv,
&glColor3i,
&glColor3iv,
&glColor3s,
&glColor3sv,
&glColor3ub,
&glColor3ubv,
&glColor3ui,
&glColor3uiv,
&glColor3us,
&glColor3usv,
&glColor4b,
&glColor4bv,
&glColor4d,
&glColor4dv,
&glColor4f,
&glColor4fv,
&glColor4i,
&glColor4iv,
&glColor4s,
&glColor4sv,
&glColor4ub,
&glColor4ubv,
&glColor4ui,
&glColor4uiv,
&glColor4us,
&glColor4usv,
&glEdgeFlag,
&glEdgeFlagv,
&glEnd,
&glIndexd,
&glIndexdv,
&glIndexf,
&glIndexfv,
&glIndexi,
&glIndexiv,
&glIndexs,
&glIndexsv,
&glNormal3b,
&glNormal3bv,
&glNormal3d,
&glNormal3dv,
&glNormal3f,
&glNormal3fv,
&glNormal3i,
&glNormal3iv,
&glNormal3s,
&glNormal3sv,
&glRasterPos2d,
&glRasterPos2dv,
&glRasterPos2f,
&glRasterPos2fv,
&glRasterPos2i,
&glRasterPos2iv,
&glRasterPos2s,
&glRasterPos2sv,
&glRasterPos3d,
&glRasterPos3dv,
&glRasterPos3f,
&glRasterPos3fv,
&glRasterPos3i,
&glRasterPos3iv,
&glRasterPos3s,
&glRasterPos3sv,
&glRasterPos4d,
&glRasterPos4dv,
&glRasterPos4f,
&glRasterPos4fv,
&glRasterPos4i,
&glRasterPos4iv,
&glRasterPos4s,
&glRasterPos4sv,
&glRectd,
&glRectdv,
&glRectf,
&glRectfv,
&glRecti,
&glRectiv,
&glRects,
&glRectsv,
&glTexCoord1d,
&glTexCoord1dv,
&glTexCoord1f,
&glTexCoord1fv,
&glTexCoord1i,
&glTexCoord1iv,
&glTexCoord1s,
&glTexCoord1sv,
&glTexCoord2d,
&glTexCoord2dv,
&glTexCoord2f,
&glTexCoord2fv,
&glTexCoord2i,
&glTexCoord2iv,
&glTexCoord2s,
&glTexCoord2sv,
&glTexCoord3d,
&glTexCoord3dv,
&glTexCoord3f,
&glTexCoord3fv,
&glTexCoord3i,
&glTexCoord3iv,
&glTexCoord3s,
&glTexCoord3sv,
&glTexCoord4d,
&glTexCoord4dv,
&glTexCoord4f,
&glTexCoord4fv,
&glTexCoord4i,
&glTexCoord4iv,
&glTexCoord4s,
&glTexCoord4sv,
&glVertex2d,
&glVertex2dv,
&glVertex2f,
&glVertex2fv,
&glVertex2i,
&glVertex2iv,
&glVertex2s,
&glVertex2sv,
&glVertex3d,
&glVertex3dv,
&glVertex3f,
&glVertex3fv,
&glVertex3i,
&glVertex3iv,
&glVertex3s,
&glVertex3sv,
&glVertex4d,
&glVertex4dv,
&glVertex4f,
&glVertex4fv,
&glVertex4i,
&glVertex4iv,
&glVertex4s,
&glVertex4sv,
&glClipPlane,
&glColorMaterial,
&glCullFace,
&glFogf,
&glFogfv,
&glFogi,
&glFogiv,
&glFrontFace,
&glHint,
&glLightf,
&glLightfv,
&glLighti,
&glLightiv,
&glLightModelf,
&glLightModelfv,
&glLightModeli,
&glLightModeliv,
&glLineStipple,
&glLineWidth,
&glMaterialf,
&glMaterialfv,
&glMateriali,
&glMaterialiv,
&glPointSize,
&glPolygonMode,
&glPolygonStipple,
&glScissor,
&glShadeModel,
&glTexParameterf,
&glTexParameterfv,
&glTexParameteri,
&glTexParameteriv,
&glTexImage1D,
&glTexImage2D,
&glTexEnvf,
&glTexEnvfv,
&glTexEnvi,
&glTexEnviv,
&glTexGend,
&glTexGendv,
&glTexGenf,
&glTexGenfv,
&glTexGeni,
&glTexGeniv,
&glFeedbackBuffer,
&glSelectBuffer,
&glRenderMode,
&glInitNames,
&glLoadName,
&glPassThrough,
&glPopName,
&glPushName,
&glDrawBuffer,
&glClear,
&glClearAccum,
&glClearIndex,
&glClearColor,
&glClearStencil,
&glClearDepth,
&glStencilMask,
&glColorMask,
&glDepthMask,
&glIndexMask,
&glAccum,
&glDisable,
&glEnable,
&glFinish,
&glFlush,
&glPopAttrib,
&glPushAttrib,
&glMap1d,
&glMap1f,
&glMap2d,
&glMap2f,
&glMapGrid1d,
&glMapGrid1f,
&glMapGrid2d,
&glMapGrid2f,
&glEvalCoord1d,
&glEvalCoord1dv,
&glEvalCoord1f,
&glEvalCoord1fv,
&glEvalCoord2d,
&glEvalCoord2dv,
&glEvalCoord2f,
&glEvalCoord2fv,
&glEvalMesh1,
&glEvalPoint1,
&glEvalMesh2,
&glEvalPoint2,
&glAlphaFunc,
&glBlendFunc,
&glLogicOp,
&glStencilFunc,
&glStencilOp,
&glDepthFunc,
&glPixelZoom,
&glPixelTransferf,
&glPixelTransferi,
&glPixelStoref,
&glPixelStorei,
&glPixelMapfv,
&glPixelMapuiv,
&glPixelMapusv,
&glReadBuffer,
&glCopyPixels,
&glReadPixels,
&glDrawPixels,
&glGetBooleanv,
&glGetClipPlane,
&glGetDoublev,
&glGetError,
&glGetFloatv,
&glGetIntegerv,
&glGetLightfv,
&glGetLightiv,
&glGetMapdv,
&glGetMapfv,
&glGetMapiv,
&glGetMaterialfv,
&glGetMaterialiv,
&glGetPixelMapfv,
&glGetPixelMapuiv,
&glGetPixelMapusv,
&glGetPolygonStipple,
&glGetString,
&glGetTexEnvfv,
&glGetTexEnviv,
&glGetTexGendv,
&glGetTexGenfv,
&glGetTexGeniv,
&glGetTexImage,
&glGetTexParameterfv,
&glGetTexParameteriv,
&glGetTexLevelParameterfv,
&glGetTexLevelParameteriv,
&glIsEnabled,
&glIsList,
&glDepthRange,
&glFrustum,
&glLoadIdentity,
&glLoadMatrixf,
&glLoadMatrixd,
&glMatrixMode,
&glMultMatrixf,
&glMultMatrixd,
&glOrtho,
&glPopMatrix,
&glPushMatrix,
&glRotated,
&glRotatef,
&glScaled,
&glScalef,
&glTranslated,
&glTranslatef,
&glViewport,
&glArrayElement,
&glBindTexture,
&glColorPointer,
&glDisableClientState,
&glDrawArrays,
&glDrawElements,
&glEdgeFlagPointer,
&glEnableClientState,
&glIndexPointer,
&glIndexub,
&glIndexubv,
&glInterleavedArrays,
&glNormalPointer,
&glPolygonOffset,
&glTexCoordPointer,
&glVertexPointer,
&glAreTexturesResident,
&glCopyTexImage1D,
&glCopyTexImage2D,
&glCopyTexSubImage1D,
&glCopyTexSubImage2D,
&glDeleteTextures,
&glGenTextures,
&glGetPointerv,
&glIsTexture,
&glPrioritizeTextures,
&glTexSubImage1D,
&glTexSubImage2D,
&glPopClientAttrib,
&glPushClientAttrib
}
};
PGLCLTPROCTABLE APIENTRY
DrvSetContext(
HDC hdc,
DHGLRC dhglrc,
PFN_SETPROCTABLE pfnSetProcTable )
{
PGLCLTPROCTABLE r = (PGLCLTPROCTABLE)&cpt;
if (!stw_make_current( hdc, dhglrc ))
r = NULL;
return r;
}