blob: b1e5f5e20fb47d55452080777eb658da30c235f9 [file] [log] [blame]
/**************************************************************************
*
* Copyright 2008 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
* 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 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>
#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 "hud/hud_context.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"
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;
stw_lock_contexts(stw_dev);
src = stw_lookup_context_locked( dhrcSource );
dst = stw_lookup_context_locked( dhrcDest );
if (src && dst) {
/* FIXME */
assert(0);
(void) src;
(void) dst;
(void) fuMask;
}
stw_unlock_contexts(stw_dev);
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;
stw_lock_contexts(stw_dev);
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);
stw_unlock_contexts(stw_dev);
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,
0);
}
/**
* Called via DrvCreateContext(), DrvCreateLayerContext() and
* wglCreateContextAttribsARB() to actually create a rendering context.
* \param handle the desired DHGLRC handle to use for the context, or zero
* if a new handle should be allocated.
* \return the handle for the new context or zero if there was a problem.
*/
DHGLRC
stw_create_context_attribs(HDC hdc, INT iLayerPlane, DHGLRC hShareContext,
int majorVersion, int minorVersion,
int contextFlags, int profileMask,
DHGLRC handle)
{
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;
/*
* GDI only knows about displayable pixel formats, so determine the pixel
* format from the framebuffer.
*
* This also allows to use a OpenGL DLL / ICD without installing.
*/
fb = stw_framebuffer_from_hdc( hdc );
if (fb) {
iPixelFormat = fb->iPixelFormat;
stw_framebuffer_unlock(fb);
} else {
return 0;
}
pfi = stw_pixelformat_get_info( iPixelFormat );
if (hShareContext != 0) {
stw_lock_contexts(stw_dev);
shareCtx = stw_lookup_context_locked( hShareContext );
stw_unlock_contexts(stw_dev);
}
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;
switch (profileMask) {
case WGL_CONTEXT_CORE_PROFILE_BIT_ARB:
/* 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."
*/
if (majorVersion > 3 || (majorVersion == 3 && minorVersion >= 2)) {
attribs.profile = ST_PROFILE_OPENGL_CORE;
break;
}
/* fall-through */
case WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
/*
* The spec also says:
*
* "If version 3.1 is requested, the context returned may implement
* any of the following versions:
*
* * Version 3.1. The GL_ARB_compatibility extension may or may not
* be implemented, as determined by the implementation.
* * The core profile of version 3.2 or greater."
*
* But Mesa doesn't support GL_ARB_compatibility, while most prevalent
* Windows OpenGL implementations do, and unfortunately many Windows
* applications don't check whether they receive or not a context with
* GL_ARB_compatibility, so returning a core profile here does more harm
* than good.
*/
attribs.profile = ST_PROFILE_DEFAULT;
break;
case WGL_CONTEXT_ES_PROFILE_BIT_EXT:
if (majorVersion >= 2) {
attribs.profile = ST_PROFILE_OPENGL_ES2;
} else {
attribs.profile = ST_PROFILE_OPENGL_ES1;
}
break;
default:
assert(0);
goto no_st_ctx;
}
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;
if (ctx->st->cso_context) {
ctx->hud = hud_create(ctx->st->pipe, ctx->st->cso_context);
}
stw_lock_contexts(stw_dev);
if (handle) {
/* We're replacing the context data for this handle. See the
* wglCreateContextAttribsARB() function.
*/
struct stw_context *old_ctx =
stw_lookup_context_locked((unsigned) handle);
if (old_ctx) {
/* free the old context data associated with this handle */
if (old_ctx->hud) {
hud_destroy(old_ctx->hud);
}
ctx->st->destroy(old_ctx->st);
FREE(old_ctx);
}
/* replace table entry */
handle_table_set(stw_dev->ctx_table, (unsigned) handle, ctx);
}
else {
/* create new table entry */
handle = (DHGLRC) handle_table_add(stw_dev->ctx_table, ctx);
}
ctx->dhglrc = handle;
stw_unlock_contexts(stw_dev);
if (!ctx->dhglrc)
goto no_hglrc;
return ctx->dhglrc;
no_hglrc:
if (ctx->hud) {
hud_destroy(ctx->hud);
}
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;
stw_lock_contexts(stw_dev);
ctx = stw_lookup_context_locked(dhglrc);
handle_table_remove(stw_dev->ctx_table, dhglrc);
stw_unlock_contexts(stw_dev);
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);
if (ctx->hud) {
hud_destroy(ctx->hud);
}
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;
stw_lock_contexts(stw_dev);
ctx = stw_lookup_context_locked( dhglrc );
stw_unlock_contexts(stw_dev);
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 *old_ctx = NULL;
struct stw_context *ctx = NULL;
BOOL ret = FALSE;
if (!stw_dev)
return FALSE;
old_ctx = stw_current_context();
if (old_ctx != NULL) {
if (old_ctx->dhglrc == dhglrc) {
if (old_ctx->hdc == hdc) {
/* Return if already current. */
return TRUE;
}
} else {
old_ctx->st->flush(old_ctx->st, ST_FLUSH_FRONT, NULL);
}
}
if (dhglrc) {
struct stw_framebuffer *fb = NULL;
stw_lock_contexts(stw_dev);
ctx = stw_lookup_context_locked( dhglrc );
stw_unlock_contexts(stw_dev);
if (!ctx) {
goto fail;
}
/* This call locks fb's mutex */
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) {
stw_framebuffer_unlock(fb);
SetLastError(ERROR_INVALID_PIXEL_FORMAT);
goto fail;
}
/* Bind the new framebuffer */
ctx->hdc = hdc;
struct stw_framebuffer *old_fb = ctx->current_framebuffer;
if (old_fb != fb) {
stw_framebuffer_reference_locked(fb);
ctx->current_framebuffer = fb;
}
stw_framebuffer_unlock(fb);
/* Note: when we call this function we will wind up in the
* stw_st_framebuffer_validate_locked() function which will incur
* a recursive fb->mutex lock.
*/
ret = stw_dev->stapi->make_current(stw_dev->stapi, ctx->st,
fb->stfb, fb->stfb);
if (old_fb && old_fb != fb) {
stw_lock_framebuffers(stw_dev);
stw_framebuffer_lock(old_fb);
stw_framebuffer_release_locked(old_fb);
stw_unlock_framebuffers(stw_dev);
}
fail:
/* fb must be unlocked at this point. */
assert(!stw_own_mutex(&fb->mutex));
/* On failure, make the thread's current rendering context not current
* before returning.
*/
if (!ret) {
stw_make_current(NULL, 0);
}
} else {
ret = stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
}
/* Unreference the previous framebuffer if any. It must be done after
* make_current, as it can be referenced inside.
*/
if (old_ctx && old_ctx != ctx) {
struct stw_framebuffer *old_fb = old_ctx->current_framebuffer;
if (old_fb) {
old_ctx->current_framebuffer = NULL;
stw_lock_framebuffers(stw_dev);
stw_framebuffer_lock(old_fb);
stw_framebuffer_release_locked(old_fb);
stw_unlock_framebuffers(stw_dev);
}
}
return ret;
}
/**
* 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;
}