Changes to configure script and OpenGL for Win32

TODO: Need to implement gloffscreen_cgl for Mac.
This commit is contained in:
wayo 2013-03-31 22:35:07 -06:00 committed by espes
parent 6ec5ad1698
commit 59bc8d9539
7 changed files with 2341 additions and 22 deletions

11
configure vendored
View File

@ -2445,6 +2445,17 @@ if test "$opengl" != "no" ; then
#include <OpenGL/CGLCurrent.h>
#include <GLUT/glut.h>
int main(void) { return GL_VERSION != 0; }
EOF
elif test "$mingw32" = "yes" ; then
opengl_libs="-lglut32win -lOpenGL32 -lglu32 -lglew32 -lgdi32"
cat > $TMPC << EOF
#include <windows.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/wglext.h>
#include <GL/glut.h>
int main(void) { return GL_VERSION != 0; }
EOF
else
opengl_libs="-lGL -lX11"

View File

@ -37,13 +37,22 @@
#include <OpenGL/CGLCurrent.h>
#include <GLUT/glut.h>
#else
#ifdef _WIN32
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/wglext.h>
#include <GL/glut.h>
#else
#include <X11/Xlib.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <GL/glut.h>
#endif
#endif
#include "nv2a.h"
#include "gloffscreen.h"
//#define DEBUG_NV2A
#ifdef DEBUG_NV2A
@ -766,7 +775,7 @@ typedef struct GraphicsContext {
uint32_t zstencil_clear_value;
uint32_t color_clear_value;
CGLContextObj gl_context;
GloContext *gl_context;
GLuint gl_framebuffer;
GLuint gl_renderbuffer;
@ -1433,6 +1442,28 @@ static void kelvin_bind_fragment_shader(NV2AState *d, KelvinState *kelvin)
}
#ifdef _WIN32
/* Need to define it since its not available in GLU 1.2 Windows*/
GLboolean gluCheckExtension( const GLubyte *extName, const GLubyte *extString )
{
char *p = (char *) glGetString(GL_EXTENSIONS);
char *end;
if(p==NULL)
return GL_FALSE;
end = p + strlen(p);
while (p < end) {
int n = strcspn(p, " ");
if((strlen(extName) == n) && (strncmp(extName,p,n) == 0)) {
return GL_TRUE;
}
p += (n + 1);
}
return GL_FALSE;
}
#endif
static void kelvin_read_surface(NV2AState *d, KelvinState *kelvin)
{
/* read the renderbuffer into the set surface */
@ -1485,20 +1516,10 @@ static void kelvin_read_surface(NV2AState *d, KelvinState *kelvin)
static void pgraph_context_init(GraphicsContext *context)
{
/* TODO: context creation on linux */
CGLPixelFormatAttribute attributes[] = {
kCGLPFAAccelerated,
(CGLPixelFormatAttribute)0
};
CGLPixelFormatObj pix;
GLint num;
CGLChoosePixelFormat(attributes, &pix, &num);
CGLCreateContext(pix, NULL, &context->gl_context);
CGLDestroyPixelFormat(pix);
CGLSetCurrentContext(context->gl_context);
context->gl_context = glo_context_create(GLO_FF_DEFAULT);
/* TODO: create glo functions for Mac */
/* Check context capabilities */
const GLubyte *extensions;
@ -1523,8 +1544,6 @@ static void pgraph_context_init(GraphicsContext *context)
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attributes);
assert(max_vertex_attributes >= NV2A_VERTEXSHADER_ATTRIBUTES);
glGenFramebuffersEXT(1, &context->gl_framebuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, context->gl_framebuffer);
@ -1545,29 +1564,28 @@ static void pgraph_context_init(GraphicsContext *context)
assert(glGetError() == GL_NO_ERROR);
CGLSetCurrentContext(NULL);
glo_set_current(NULL);
}
static void pgraph_context_set_current(GraphicsContext *context)
{
if (context) {
CGLSetCurrentContext(context->gl_context);
glo_set_current(context->gl_context);
} else {
CGLSetCurrentContext(NULL);
glo_set_current(NULL);
}
}
static void pgraph_context_destroy(GraphicsContext *context)
{
CGLSetCurrentContext(context->gl_context);
glo_set_current(context->gl_context);
glDeleteRenderbuffersEXT(1, &context->gl_renderbuffer);
glDeleteFramebuffersEXT(1, &context->gl_framebuffer);
CGLSetCurrentContext(NULL);
glo_set_current(NULL);
CGLDestroyContext(context->gl_context);
glo_context_destroy(context->gl_context);
}
static void pgraph_method(NV2AState *d,

View File

@ -6,3 +6,4 @@ obj-$(CONFIG_KVM) += kvm.o hyperv.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
obj-$(CONFIG_LINUX_USER) += ioport-user.o
obj-$(CONFIG_BSD_USER) += ioport-user.o
obj-$(CONFIG_XBOX) += gloffscreen_common.o gloffscreen_wgl.o gloffscreen_glx.o gloffscreen_cgl.o

View File

@ -0,0 +1,586 @@
/*
* Offscreen OpenGL abstraction layer - WGL (windows) specific
*
* Copyright (c) 2010 Intel
* Written by:
* Gordon Williams <gordon.williams@collabora.co.uk>
* Ian Molton <ian.molton@collabora.co.uk>
*
* 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, sublicense, 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifdef __APPLE__
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <OpenGL/gl.h>
#include <OpenGL/OpenGL.h>
#include <OpenGL/CGLTypes.h>
#include <OpenGL/CGLCurrent.h>
#include <GLUT/glut.h>
#include "gloffscreen.h"
/* In Windows, you must create a window *before* you can create a pbuffer or
* get a context. So we create a hidden Window on startup (see glo_init/GloMain).
*
* Also, you can't share contexts that have different pixel formats, so we can't just
* create a new context from the window. We must create a whole new PBuffer just for
* a context :(
*/
struct GloMain {
int init;
// Not needed for CGL?
};
struct GloMain glo;
int glo_inited = 0;
struct _GloContext {
CGLContextObj cglContext;
};
struct _GloSurface {
GLuint width;
GLuint height;
GloContext *context;
};
/* ------------------------------------------------------------------------ */
//extern const char *glo_glXQueryExtensionsString(void);
extern void glo_surface_getcontents_readpixels(int formatFlags, int stride,
int bpp, int width, int height, void *data);
/* ------------------------------------------------------------------------ */
int glo_initialised(void) {
return glo_inited;
}
/* Initialise gloffscreen */
void glo_init(void) {
// TODO: CGL Implementation.
// Initialization needed for CGL?
if (glo_inited) {
printf( "gloffscreen already inited\n" );
exit( EXIT_FAILURE );
}
glo_inited = 1;
}
/* Uninitialise gloffscreen */
void glo_kill(void) {
// TODO: CGL Implementation.
}
static const char *STANDARD_GL_FUNCTIONS ={
/* Miscellaneous */
"glClearIndex\0"
"glClearColor\0"
"glClear\0"
"glIndexMask\0"
"glColorMask\0"
"glAlphaFunc\0"
"glBlendFunc\0"
"glLogicOp\0"
"glCullFace\0"
"glFrontFace\0"
"glPointSize\0"
"glLineWidth\0"
"glLineStipple\0"
"glPolygonMode\0"
"glPolygonOffset\0"
"glPolygonStipple\0"
"glGetPolygonStipple\0"
"glEdgeFlag\0"
"glEdgeFlagv\0"
"glScissor\0"
"glClipPlane\0"
"glGetClipPlane\0"
"glDrawBuffer\0"
"glReadBuffer\0"
"glEnable\0"
"glDisable\0"
"glIsEnabled\0"
"glEnableClientState\0"
"glDisableClientState\0"
"glGetBooleanv\0"
"glGetDoublev\0"
"glGetFloatv\0"
"glGetIntegerv\0"
"glPushAttrib\0"
"glPopAttrib\0"
"glPushClientAttrib\0"
"glPopClientAttrib\0"
"glRenderMode\0"
"glGetError\0"
"glGetString\0"
"glFinish\0"
"glFlush\0"
"glHint\0"
/* Depth Buffer */
"glClearDepth\0"
"glDepthFunc\0"
"glDepthMask\0"
"glDepthRange\0"
/* Accumulation Buffer */
"glClearAccum\0"
"glAccum\0"
/* Transformation */
"glMatrixMode\0"
"glOrtho\0"
"glFrustum\0"
"glViewport\0"
"glPushMatrix\0"
"glPopMatrix\0"
"glLoadIdentity\0"
"glLoadMatrixd\0"
"glLoadMatrixf\0"
"glMultMatrixd\0"
"glMultMatrixf\0"
"glRotated\0"
"glRotatef\0"
"glScaled\0"
"glScalef\0"
"glTranslated\0"
"glTranslatef\0"
/* Display Lists */
"glIsList\0"
"glDeleteLists\0"
"glGenLists\0"
"glNewList\0"
"glEndList\0"
"glCallList\0"
"glCallLists\0"
"glListBase\0"
/* Drawing Functions */
"glBegin\0"
"glEnd\0"
"glVertex2d\0"
"glVertex2f\0"
"glVertex2i\0"
"glVertex2s\0"
"glVertex3d\0"
"glVertex3f\0"
"glVertex3i\0"
"glVertex3s\0"
"glVertex4d\0"
"glVertex4f\0"
"glVertex4i\0"
"glVertex4s\0"
"glVertex2dv\0"
"glVertex2fv\0"
"glVertex2iv\0"
"glVertex2sv\0"
"glVertex3dv\0"
"glVertex3fv\0"
"glVertex3iv\0"
"glVertex3sv\0"
"glVertex4dv\0"
"glVertex4fv\0"
"glVertex4iv\0"
"glVertex4sv\0"
"glNormal3b\0"
"glNormal3d\0"
"glNormal3f\0"
"glNormal3i\0"
"glNormal3s\0"
"glNormal3bv\0"
"glNormal3dv\0"
"glNormal3fv\0"
"glNormal3iv\0"
"glNormal3sv\0"
"glIndexd\0"
"glIndexf\0"
"glIndexi\0"
"glIndexs\0"
"glIndexub\0"
"glIndexdv\0"
"glIndexfv\0"
"glIndexiv\0"
"glIndexsv\0"
"glIndexubv\0"
"glColor3b\0"
"glColor3d\0"
"glColor3f\0"
"glColor3i\0"
"glColor3s\0"
"glColor3ub\0"
"glColor3ui\0"
"glColor3us\0"
"glColor4b\0"
"glColor4d\0"
"glColor4f\0"
"glColor4i\0"
"glColor4s\0"
"glColor4ub\0"
"glColor4ui\0"
"glColor4us\0"
"glColor3bv\0"
"glColor3dv\0"
"glColor3fv\0"
"glColor3iv\0"
"glColor3sv\0"
"glColor3ubv\0"
"glColor3uiv\0"
"glColor3usv\0"
"glColor4bv\0"
"glColor4dv\0"
"glColor4fv\0"
"glColor4iv\0"
"glColor4sv\0"
"glColor4ubv\0"
"glColor4uiv\0"
"glColor4usv\0"
"glTexCoord1d\0"
"glTexCoord1f\0"
"glTexCoord1i\0"
"glTexCoord1s\0"
"glTexCoord2d\0"
"glTexCoord2f\0"
"glTexCoord2i\0"
"glTexCoord2s\0"
"glTexCoord3d\0"
"glTexCoord3f\0"
"glTexCoord3i\0"
"glTexCoord3s\0"
"glTexCoord4d\0"
"glTexCoord4f\0"
"glTexCoord4i\0"
"glTexCoord4s\0"
"glTexCoord1dv\0"
"glTexCoord1fv\0"
"glTexCoord1iv\0"
"glTexCoord1sv\0"
"glTexCoord2dv\0"
"glTexCoord2fv\0"
"glTexCoord2iv\0"
"glTexCoord2sv\0"
"glTexCoord3dv\0"
"glTexCoord3fv\0"
"glTexCoord3iv\0"
"glTexCoord3sv\0"
"glTexCoord4dv\0"
"glTexCoord4fv\0"
"glTexCoord4iv\0"
"glTexCoord4sv\0"
"glRasterPos2d\0"
"glRasterPos2f\0"
"glRasterPos2i\0"
"glRasterPos2s\0"
"glRasterPos3d\0"
"glRasterPos3f\0"
"glRasterPos3i\0"
"glRasterPos3s\0"
"glRasterPos4d\0"
"glRasterPos4f\0"
"glRasterPos4i\0"
"glRasterPos4s\0"
"glRasterPos2dv\0"
"glRasterPos2fv\0"
"glRasterPos2iv\0"
"glRasterPos2sv\0"
"glRasterPos3dv\0"
"glRasterPos3fv\0"
"glRasterPos3iv\0"
"glRasterPos3sv\0"
"glRasterPos4dv\0"
"glRasterPos4fv\0"
"glRasterPos4iv\0"
"glRasterPos4sv\0"
"glRectd\0"
"glRectf\0"
"glRecti\0"
"glRects\0"
"glRectdv\0"
"glRectfv\0"
"glRectiv\0"
"glRectsv\0"
/* Lighting */
"glShadeModel\0"
"glLightf\0"
"glLighti\0"
"glLightfv\0"
"glLightiv\0"
"glGetLightfv\0"
"glGetLightiv\0"
"glLightModelf\0"
"glLightModeli\0"
"glLightModelfv\0"
"glLightModeliv\0"
"glMaterialf\0"
"glMateriali\0"
"glMaterialfv\0"
"glMaterialiv\0"
"glGetMaterialfv\0"
"glGetMaterialiv\0"
"glColorMaterial\0"
/* Raster functions */
"glPixelZoom\0"
"glPixelStoref\0"
"glPixelStorei\0"
"glPixelTransferf\0"
"glPixelTransferi\0"
"glPixelMapfv\0"
"glPixelMapuiv\0"
"glPixelMapusv\0"
"glGetPixelMapfv\0"
"glGetPixelMapuiv\0"
"glGetPixelMapusv\0"
"glBitmap\0"
"glReadPixels\0"
"glDrawPixels\0"
"glCopyPixels\0"
/* Stenciling */
"glStencilFunc\0"
"glStencilMask\0"
"glStencilOp\0"
"glClearStencil\0"
/* Texture mapping */
"glTexGend\0"
"glTexGenf\0"
"glTexGeni\0"
"glTexGendv\0"
"glTexGenfv\0"
"glTexGeniv\0"
"glGetTexGendv\0"
"glGetTexGenfv\0"
"glGetTexGeniv\0"
"glTexEnvf\0"
"glTexEnvi\0"
"glTexEnvfv\0"
"glTexEnviv\0"
"glGetTexEnvfv\0"
"glGetTexEnviv\0"
"glTexParameterf\0"
"glTexParameteri\0"
"glTexParameterfv\0"
"glTexParameteriv\0"
"glGetTexParameterfv\0"
"glGetTexParameteriv\0"
"glGetTexLevelParameterfv\0"
"glGetTexLevelParameteriv\0"
"glTexImage1D\0"
"glTexImage2D\0"
"glGetTexImage\0"
/* Evaluators */
"glMap1d\0"
"glMap1f\0"
"glMap2d\0"
"glMap2f\0"
"glGetMapdv\0"
"glGetMapfv\0"
"glGetMapiv\0"
"glEvalCoord1d\0"
"glEvalCoord1f\0"
"glEvalCoord1dv\0"
"glEvalCoord1fv\0"
"glEvalCoord2d\0"
"glEvalCoord2f\0"
"glEvalCoord2dv\0"
"glEvalCoord2fv\0"
"glMapGrid1d\0"
"glMapGrid1f\0"
"glMapGrid2d\0"
"glMapGrid2f\0"
"glEvalPoint1\0"
"glEvalPoint2\0"
"glEvalMesh1\0"
"glEvalMesh2\0"
/* Fog */
"glFogf\0"
"glFogi\0"
"glFogfv\0"
"glFogiv\0"
/* Selection and Feedback */
"glFeedbackBuffer\0"
"glPassThrough\0"
"glSelectBuffer\0"
"glInitNames\0"
"glLoadName\0"
"glPushName\0"
"glPopName\0"
/* 1.1 functions */
/* texture objects */
"glGenTextures\0"
"glDeleteTextures\0"
"glBindTexture\0"
"glPrioritizeTextures\0"
"glAreTexturesResident\0"
"glIsTexture\0"
/* texture mapping */
"glTexSubImage1D\0"
"glTexSubImage2D\0"
"glCopyTexImage1D\0"
"glCopyTexImage2D\0"
"glCopyTexSubImage1D\0"
"glCopyTexSubImage2D\0"
/* vertex arrays */
"glVertexPointer\0"
"glNormalPointer\0"
"glColorPointer\0"
"glIndexPointer\0"
"glTexCoordPointer\0"
"glEdgeFlagPointer\0"
"glGetPointerv\0"
"glArrayElement\0"
"glDrawArrays\0"
"glDrawElements\0"
"glInterleavedArrays\0"
/* GLX */
"glXChooseVisual\0"
"glXQueryExtensionsString\0"
"glXQueryServerString\0"
"glXGetClientString\0"
"glXCreateContext\0"
"glXCreateNewContext\0"
"glXCopyContext\0"
"glXDestroyContext\0"
"glXQueryVersion\0"
"glXMakeCurrent\0"
"glXSwapBuffers\0"
"glXGetConfig\0"
"glXQueryExtension\0"
"glXChooseFBConfig\0"
"glXGetFBConfigs\0"
"glXGetFBConfigAttrib\0"
"glXQueryContext\0"
"glXQueryDrawable\0"
"glXGetVisualFromFBConfig\0"
"glXIsDirect\0"
"\0"
};
/* Like wglGetProcAddress/glxGetProcAddress */
void *glo_getprocaddress(const char *procName) {
// TODO: CGL Implementation.
void *procAddr = 0;
return procAddr;
}
/* ------------------------------------------------------------------------ */
/* Create an OpenGL context for a certain pixel format. formatflags are from the GLO_ constants */
GloContext *glo_context_create(int formatFlags) {
GloContext *context;
context = (GloContext*)malloc(sizeof(GloContext));
memset(context, 0, sizeof(GloContext));
// pixel format attributes
CGLPixelFormatAttribute attributes[] = {
kCGLPFAAccelerated,
(CGLPixelFormatAttribute)0
};
CGLPixelFormatObj pix;
GLint num;
CGLChoosePixelFormat(attributes, &pix, &num);
CGLCreateContext(pix, NULL, &context->cglContext);
CGLDestroyPixelFormat(pix);
if (!glo_inited)
glo_init();
glo_set_current(context);
return context;
}
/* Set current context */
void glo_set_current(GloContext *context)
{
if(context == NULL)
CGLSetCurrentContext(NULL);
else
CGLSetCurrentContext(context->cglContext);
}
/* Destroy a previously created OpenGL context */
void glo_context_destroy(GloContext *context) {
if (!context) return;
glo_set_current( NULL );
// TODO: CGL Implementation.
}
/* ------------------------------------------------------------------------ */
/* Create a surface with given width and height, formatflags are from the
* GLO_ constants */
GloSurface *glo_surface_create(int width, int height, GloContext *context) {
GloSurface *surface;
surface = (GloSurface*)malloc(sizeof(GloSurface));
// TODO: CGL Implementation.
return surface;
}
/* Destroy the given surface */
void glo_surface_destroy(GloSurface *surface) {
if (!surface) return;
// TODO: CGL Implementation.
}
/* Make the given surface current */
int glo_surface_makecurrent(GloSurface *surface) {
// TODO: CGL Implementation.
return 0;
}
/* Get the contents of the given surface */
void glo_surface_getcontents(GloSurface *surface, int stride, int bpp, void *data) {
if (!surface)
return;
// Compatible / fallback method.
glo_surface_getcontents_readpixels(surface->context->formatFlags,
stride, bpp, surface->width,
surface->height, data);
// TODO: CGL Implementation.
}
/* Return the width and height of the given surface */
void glo_surface_get_size(GloSurface *surface, int *width, int *height) {
if (width)
*width = surface->width;
if (height)
*height = surface->height;
}
/* Fake glXQueryExtensionsString() */
const char *glo_glXQueryExtensionsString(void) {
return "";
}
#endif

View File

@ -0,0 +1,360 @@
/*
* Offscreen OpenGL abstraction layer - Common utilities
*
* Copyright (c) 2010 Intel
* Written by:
* Gordon Williams <gordon.williams@collabora.co.uk>
* Ian Molton <ian.molton@collabora.co.uk>
*
* 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, sublicense, 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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 "gloffscreen.h"
#ifdef _WIN32
#include <windows.h>
#include <GL/gl.h>
#include <GL/glext.h>
#else
#include <GL/gl.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ---------------------------------------------------
// Copied from glx.h as we need them in windows too
/*
* Tokens for glXChooseVisual and glXGetConfig:
*/
#define GLX_USE_GL 1
#define GLX_BUFFER_SIZE 2
#define GLX_LEVEL 3
#define GLX_RGBA 4
#define GLX_DOUBLEBUFFER 5
#define GLX_STEREO 6
#define GLX_AUX_BUFFERS 7
#define GLX_RED_SIZE 8
#define GLX_GREEN_SIZE 9
#define GLX_BLUE_SIZE 10
#define GLX_ALPHA_SIZE 11
#define GLX_DEPTH_SIZE 12
#define GLX_STENCIL_SIZE 13
#define GLX_ACCUM_RED_SIZE 14
#define GLX_ACCUM_GREEN_SIZE 15
#define GLX_ACCUM_BLUE_SIZE 16
#define GLX_ACCUM_ALPHA_SIZE 17
// ---------------------------------------------------
extern void glo_surface_getcontents_readpixels(int formatFlags, int stride, int bpp,
int width, int height, void *data);
// ---------------------------------------------------
int glo_flags_get_depth_bits(int formatFlags) {
switch ( formatFlags & GLO_FF_DEPTH_MASK ) {
case GLO_FF_DEPTH_16: return 16;
case GLO_FF_DEPTH_24: return 24;
case GLO_FF_DEPTH_32: return 32;
default: return 0;
}
}
int glo_flags_get_stencil_bits(int formatFlags) {
switch ( formatFlags & GLO_FF_STENCIL_MASK ) {
case GLO_FF_STENCIL_8: return 8;
default: return 0;
}
}
void glo_flags_get_rgba_bits(int formatFlags, int *rgba) {
int alpha = (formatFlags & GLO_FF_ALPHA) != 0;
switch ( formatFlags & GLO_FF_BITS_MASK ) {
case GLO_FF_BITS_16:
rgba[0] = alpha ? 4 : 5;
rgba[1] = alpha ? 4 : 6;
rgba[2] = alpha ? 4 : 5;
rgba[3] = alpha ? 4 : 0;
break;
case GLO_FF_BITS_24:
// ignore alpha
rgba[0] = 8;
rgba[1] = 8;
rgba[2] = 8;
rgba[3] = 0;
break;
case GLO_FF_BITS_32:
rgba[0] = 8;
rgba[1] = 8;
rgba[2] = 8;
rgba[3] = 8;
break;
default:
rgba[0] = 8;
rgba[1] = 8;
rgba[2] = 8;
rgba[3] = 0;
break;
}
}
int glo_flags_get_bytes_per_pixel(int formatFlags) {
switch ( formatFlags & GLO_FF_BITS_MASK ) {
case GLO_FF_BITS_16: return 2;
case GLO_FF_BITS_24: return 3;
case GLO_FF_BITS_32: return 4;
default: return 3;
}
}
void glo_flags_get_readpixel_type(int formatFlags, int *glFormat, int *glType) {
GLenum gFormat, gType;
if (formatFlags & GLO_FF_ALPHA) {
switch ( formatFlags & GLO_FF_BITS_MASK ) {
case GLO_FF_BITS_16:
gFormat = GL_RGBA;
gType = GL_UNSIGNED_SHORT_4_4_4_4;
break;
case GLO_FF_BITS_24:
case GLO_FF_BITS_32:
default:
gFormat = GL_BGRA;
gType = GL_UNSIGNED_BYTE;
break;
}
} else {
switch ( formatFlags & GLO_FF_BITS_MASK ) {
case GLO_FF_BITS_16:
gFormat = GL_RGB;
gType = GL_UNSIGNED_SHORT_5_6_5;
break;
case GLO_FF_BITS_24:
case GLO_FF_BITS_32:
default:
gFormat = GL_BGR;
gType = GL_UNSIGNED_BYTE;
break;
}
}
if (glFormat) *glFormat = gFormat;
if (glType) *glType = gType;
}
int glo_flags_score(int formatFlagsExpected, int formatFlagsReal) {
if (formatFlagsExpected == formatFlagsReal) return 0;
int score = 1;
// we wanted alpha, but we didn't get it
if ((formatFlagsExpected&GLO_FF_ALPHA_MASK) <
(formatFlagsReal&GLO_FF_ALPHA_MASK))
score++;
// less bits than we expected
if ((formatFlagsExpected&GLO_FF_BITS_MASK) <
!(formatFlagsReal&GLO_FF_BITS_MASK))
score++;
// less depth bits than we expected
if ((formatFlagsExpected&GLO_FF_DEPTH_MASK) <
!(formatFlagsReal&GLO_FF_DEPTH_MASK))
score++;
// less stencil bits than we expected
if ((formatFlagsExpected&GLO_FF_STENCIL_MASK) <
!(formatFlagsReal&GLO_FF_STENCIL_MASK))
score++;
return score;
}
int glo_flags_get_from_glx(const int *fbConfig, int assumeBooleans) {
int bufferSize = 0;
int depthSize = 0;
int stencilSize = 0;
int rgbaSize[] = {0,0,0,0};
int flags = 0;
while (*fbConfig) {
int isSingle = 0;
switch (*fbConfig) {
case GLX_USE_GL:
isSingle = 1;
break;
case GLX_BUFFER_SIZE:
bufferSize = fbConfig[1];
break;
case GLX_LEVEL:
break;
case GLX_RGBA:
flags |= GLO_FF_ALPHA;
break;
case GLX_DOUBLEBUFFER:
isSingle = 1;
break;
case GLX_STEREO:
isSingle = 1;
break;
case GLX_AUX_BUFFERS:
break;
case GLX_RED_SIZE:
rgbaSize[0] = fbConfig[1];
break;
case GLX_GREEN_SIZE:
rgbaSize[1] = fbConfig[1];
break;
case GLX_BLUE_SIZE:
rgbaSize[2] = fbConfig[1];
break;
case GLX_ALPHA_SIZE:
rgbaSize[3] = fbConfig[1];
break;
case GLX_DEPTH_SIZE:
depthSize = fbConfig[1];
break;
case GLX_STENCIL_SIZE:
stencilSize = fbConfig[1];
break;
case GLX_ACCUM_RED_SIZE:
case GLX_ACCUM_GREEN_SIZE:
case GLX_ACCUM_BLUE_SIZE:
case GLX_ACCUM_ALPHA_SIZE:
break;
}
// go to next
if (isSingle && assumeBooleans)
fbConfig++;
else
fbConfig+=2;
}
if (rgbaSize[3])
flags |= GLO_FF_ALPHA;
// ensure we have room for *some* alpha
if ((flags & GLO_FF_ALPHA) && (rgbaSize[3]==0))
rgbaSize[3] = 1;
// Buffer size flag
if (bufferSize==0)
bufferSize = rgbaSize[0]+rgbaSize[1]+rgbaSize[2]+rgbaSize[3];
if (bufferSize==0)
bufferSize = (flags & GLO_FF_ALPHA) ? 32 : 24;
if (bufferSize<=16)
flags |= GLO_FF_BITS_16;
else if (bufferSize<=24)
flags |= GLO_FF_BITS_24;
else flags |= GLO_FF_BITS_32;
// Depth
if (depthSize<=16)
flags |= GLO_FF_DEPTH_16;
else if (depthSize<=24)
flags |= GLO_FF_DEPTH_24;
else flags |= GLO_FF_DEPTH_32;
// Stencil
if (stencilSize>0)
flags |= GLO_FF_STENCIL_8;
return flags;
}
void glo_surface_getcontents_readpixels(int formatFlags, int stride, int bpp,
int width, int height, void *data) {
int glFormat, glType, rl, pa;
static int once;
glo_flags_get_readpixel_type(formatFlags, &glFormat, &glType);
switch(bpp) {
case 24:
if(glFormat != GL_BGR) {
if(!once) {
fprintf(stderr, "Warning: compressing alpha\n");
once = 1;
}
glFormat = GL_BGR;
}
break;
case 32:
if(glFormat != GL_BGRA) {
fprintf(stderr, "Warning: expanding alpha!\n");
glFormat = GL_BGRA;
}
break;
default:
fprintf(stderr, "Warning: unsupported colourdepth\n");
break;
}
// Save guest processes GL state before we ReadPixels()
glGetIntegerv(GL_PACK_ROW_LENGTH, &rl);
glGetIntegerv(GL_PACK_ALIGNMENT, &pa);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
#ifdef GETCONTENTS_INDIVIDUAL
GLubyte *b = (GLubyte *)data;
int irow;
for(irow = height-1 ; irow >= 0 ; irow--) {
glReadPixels(0, irow, width, 1, glFormat, glType, b);
b += stride;
}
#else
// Faster buffer flip
GLubyte *b = (GLubyte *)data;
GLubyte *c = &((GLubyte *)data)[stride*(height-1)];
GLubyte *tmp = (GLubyte*)malloc(stride);
int irow;
glReadPixels(0, 0, width, height, glFormat, glType, data);
for(irow = 0; irow < height/2; irow++) {
memcpy(tmp, b, stride);
memcpy(b, c, stride);
memcpy(c, tmp, stride);
b += stride;
c -= stride;
}
free(tmp);
#endif
// Restore GL state
glPixelStorei(GL_PACK_ROW_LENGTH, rl);
glPixelStorei(GL_PACK_ALIGNMENT, pa);
}
int glo_get_glx_from_flags(int formatFlags, int glxEnum) {
int rgba[4];
glo_flags_get_rgba_bits(formatFlags, rgba);
switch (glxEnum) {
case GLX_USE_GL: return 1;
case GLX_BUFFER_SIZE: return glo_flags_get_bytes_per_pixel(formatFlags)*8;
case GLX_LEVEL: return 0;
case GLX_RGBA: return formatFlags & GLO_FF_ALPHA;
case GLX_DOUBLEBUFFER: return 1;
case GLX_STEREO: return 0;
case GLX_AUX_BUFFERS: return 0;
case GLX_RED_SIZE: return rgba[0];
case GLX_GREEN_SIZE: return rgba[1];
case GLX_BLUE_SIZE: return rgba[2];
case GLX_ALPHA_SIZE: return rgba[3];
case GLX_DEPTH_SIZE: return glo_flags_get_depth_bits(formatFlags);
case GLX_STENCIL_SIZE: return glo_flags_get_stencil_bits(formatFlags);
case GLX_ACCUM_RED_SIZE:
case GLX_ACCUM_GREEN_SIZE:
case GLX_ACCUM_BLUE_SIZE:
case GLX_ACCUM_ALPHA_SIZE:
return 0;
}
return 0;
}

View File

@ -0,0 +1,529 @@
/*
* Offscreen OpenGL abstraction layer - GLX specific
*
* Copyright (c) 2010 Intel
* Written by:
* Gordon Williams <gordon.williams@collabora.co.uk>
* Ian Molton <ian.molton@collabora.co.uk>
*
* 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, sublicense, 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#if !defined(_WIN32) || !defined(__APPLE__)
#include "gloffscreen.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
struct GloMain {
Display *dpy;
int use_ximage;
GloSurface *curr_surface;
};
struct GloMain glo;
int glo_inited = 0;
struct _GloContext {
GLuint formatFlags;
GLXFBConfig fbConfig;
GLXContext context;
};
struct _GloSurface {
GLuint width;
GLuint height;
GloContext *context;
Pixmap xPixmap;
GLXPixmap glxPixmap;
// For use by the 'fast' copy code.
XImage *image;
XShmSegmentInfo shminfo;
};
#define MAX_CTX 128
#define MAX_SURF 128
static GloContext *ctx_arr[MAX_CTX];
static GloSurface *sur_arr[MAX_SURF];
extern void glo_surface_getcontents_readpixels(int formatFlags, int stride,
int bpp, int width, int height, void *data);
static void glo_test_readback_methods(void);
/* ------------------------------------------------------------------------ */
int glo_initialised(void) {
return glo_inited;
}
/* Initialise gloffscreen */
void glo_init(void) {
if (glo_inited) {
printf( "gloffscreen already inited\n" );
exit( EXIT_FAILURE );
}
/* Open a connection to the X server */
glo.dpy = XOpenDisplay( NULL );
if ( glo.dpy == NULL ) {
printf( "Unable to open a connection to the X server\n" );
exit( EXIT_FAILURE );
}
glo_inited = 1;
glo_test_readback_methods();
}
/* Uninitialise gloffscreen */
void glo_kill(void) {
XCloseDisplay(glo.dpy);
glo.dpy = NULL;
}
/* Like wglGetProcAddress/glxGetProcAddress */
void *glo_getprocaddress(const char *procName) {
if (!glo_inited)
glo_init();
return glXGetProcAddressARB((const GLubyte *) procName);
}
/* ------------------------------------------------------------------------ */
/* Create an OpenGL context for a certain pixel format. formatflags are from the GLO_ constants */
GloContext *glo_context_create(int formatFlags, GloContext *shareLists) {
if (!glo_inited)
glo_init();
GLXFBConfig *fbConfigs;
int numReturned;
GloContext *context;
int rgbaBits[4];
int bufferAttributes[] = {
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 0,
GLX_STENCIL_SIZE, 0,
None
};
if (!glo_inited)
glo_init();
// set up the surface format from the flags we were given
glo_flags_get_rgba_bits(formatFlags, rgbaBits);
bufferAttributes[5] = rgbaBits[0];
bufferAttributes[7] = rgbaBits[1];
bufferAttributes[9] = rgbaBits[2];
bufferAttributes[11] = rgbaBits[3];
bufferAttributes[13] = glo_flags_get_depth_bits(formatFlags);
bufferAttributes[15] = glo_flags_get_stencil_bits(formatFlags);
//printf("Got R%d, G%d, B%d, A%d\n", rgbaBits[0], rgbaBits[1], rgbaBits[2], rgbaBits[3]);
fbConfigs = glXChooseFBConfig( glo.dpy, DefaultScreen(glo.dpy),
bufferAttributes, &numReturned );
if (numReturned==0) {
printf( "No matching configs found.\n" );
exit( EXIT_FAILURE );
}
context = (GloContext*)malloc(sizeof(GloContext));
memset(context, 0, sizeof(GloContext));
context->formatFlags = formatFlags;
context->fbConfig = fbConfigs[0];
/* Create a GLX context for OpenGL rendering */
context->context = glXCreateNewContext(glo.dpy, context->fbConfig,
GLX_RGBA_TYPE,
shareLists ? shareLists->context: NULL,
True );
if (!context->context) {
printf( "glXCreateNewContext failed\n" );
exit( EXIT_FAILURE );
}
{
int i;
for(i = 0 ; i < MAX_CTX ; i++)
if(ctx_arr[i] == NULL) {
ctx_arr[i] = context;
break;
}
}
fprintf(stderr, "Nct: %p\n", context->context);
return context;
}
/* Destroy a previously created OpenGL context */
void glo_context_destroy(GloContext *context) {
{
int i;
if (!context) fprintf(stderr, "CTX NOT FOUND NULL\n");;
for(i = 0 ; i < MAX_CTX ; i++)
if(ctx_arr[i] == context) {
ctx_arr[i] = NULL;
break;
}
if(i == MAX_CTX)
fprintf(stderr, "CTX NOT FOUND %p\n", context);
for(i = 0 ; i < MAX_SURF ; i++)
if(sur_arr[i])
if(sur_arr[i]->context == context)
fprintf(stderr, "In USE! %p\n", sur_arr[i]);
}
if (!context) return;
// TODO: check for GloSurfaces using this?
fprintf(stderr, "Dst: %p\n", context->context);
glXDestroyContext( glo.dpy, context->context);
free(context);
}
static void glo_surface_free_xshm_image(GloSurface *surface) {
XShmDetach(glo.dpy, &surface->shminfo);
surface->image->data = NULL;
XDestroyImage(surface->image);
shmdt(surface->shminfo.shmaddr);
shmctl(surface->shminfo.shmid, IPC_RMID, NULL);
}
//FIXMEIM - handle failure to allocate.
static void glo_surface_try_alloc_xshm_image(GloSurface *surface) {
if(surface->image)
glo_surface_free_xshm_image(surface);
surface->image =
XShmCreateImage(glo.dpy, DefaultVisual(glo.dpy, 0), 24, ZPixmap, NULL,
&surface->shminfo, surface->width, surface->height);
surface->shminfo.shmid = shmget(IPC_PRIVATE,
surface->image->bytes_per_line *
surface->height,
IPC_CREAT | 0777);
surface->shminfo.shmaddr = shmat(surface->shminfo.shmid, NULL, 0);
surface->image->data = surface->shminfo.shmaddr;
surface->shminfo.readOnly = False;
XShmAttach(glo.dpy, &surface->shminfo);
}
/* ------------------------------------------------------------------------ */
/* Create a surface with given width and height, formatflags are from the
* GLO_ constants */
GloSurface *glo_surface_create(int width, int height, GloContext *context) {
GloSurface *surface;
if (!context) return 0;
surface = (GloSurface*)malloc(sizeof(GloSurface));
memset(surface, 0, sizeof(GloSurface));
surface->width = width;
surface->height = height;
surface->context = context;
surface->xPixmap = XCreatePixmap( glo.dpy, DefaultRootWindow(glo.dpy),
width, height,
glo_flags_get_bytes_per_pixel(context->formatFlags)*8);
if (!surface->xPixmap) {
printf( "XCreatePixmap failed\n" );
exit( EXIT_FAILURE );
}
/* Create a GLX window to associate the frame buffer configuration
** with the created X window */
surface->glxPixmap = glXCreatePixmap( glo.dpy, context->fbConfig, surface->xPixmap, NULL );
fprintf(stderr, "Sct: %d %d\n", (int)surface->xPixmap, (int)surface->glxPixmap);
if (!surface->glxPixmap) {
printf( "glXCreatePixmap failed\n" );
exit( EXIT_FAILURE );
}
// If we're using XImages to pull the data from the graphics card...
glo_surface_try_alloc_xshm_image(surface);
{
int i;
for(i = 0 ; i < MAX_SURF ; i++)
if(sur_arr[i] == NULL) {
sur_arr[i] = surface;
break;
}
}
return surface;
}
/* Destroy the given surface */
void glo_surface_destroy(GloSurface *surface) {
GloSurface *old = NULL;
if(glo.curr_surface) {
if(surface->context != glo.curr_surface->context) {
fprintf(stderr, "destroy_surf: %p %p %d\n", surface, surface->context, (int)surface->glxPixmap);
old = glo.curr_surface;
}
}
glo_surface_makecurrent(surface);
{
int i;
for(i = 0 ; i < MAX_SURF ; i++)
if(sur_arr[i] == surface) {
sur_arr[i] = NULL;
break;
}
if(i == MAX_SURF)
fprintf(stderr, "SURF NOT FOUND %p\n", surface);
}
fprintf(stderr, "Sdst: %d %d\n", (int)surface->xPixmap, (int)surface->glxPixmap);
glXDestroyPixmap( glo.dpy, surface->glxPixmap);
XFreePixmap( glo.dpy, surface->xPixmap);
if(surface->image)
glo_surface_free_xshm_image(surface);
free(surface);
// glo_surface_makecurrent(old);
}
/* Make the given surface current */
int glo_surface_makecurrent(GloSurface *surface) {
int ret;
if (!glo_inited)
glo_init();
if (surface) {
{
int i;
for(i = 0 ; i < MAX_CTX ; i++) {
if(ctx_arr[i] == surface->context)
break;
}
if(i == MAX_CTX)
fprintf(stderr, "CTX unknown %p\n", surface->context);
for(i = 0 ; i < MAX_SURF ; i++) {
if(surface == sur_arr[i])
break;
}
if(i == MAX_SURF)
fprintf(stderr, "SURFACE unknown %p\n", surface);
}
ret = glXMakeCurrent(glo.dpy, surface->glxPixmap, surface->context->context);
glo.curr_surface = surface;
} else {
glo.curr_surface = NULL;
ret = glXMakeCurrent(glo.dpy, 0, NULL);
}
return ret;
}
/*
#define geti(a) \
do { \
int b; \
glGetIntegerv(a, &b); \
fprintf(stderr, "%s: %d\n", #a, b); \
} while (0);
*/
/* Get the contents of the given surface */
void glo_surface_getcontents(GloSurface *surface, int stride, int bpp, void *data) {
static int once;
XImage *img;
if (!surface)
return;
if(glo.use_ximage) {
glXWaitGL();
if(surface->image) {
XShmGetImage (glo.dpy, surface->xPixmap, surface->image, 0, 0, AllPlanes);
img = surface->image;
}
else {
img = XGetImage(glo.dpy, surface->xPixmap, 0, 0, surface->width, surface->height, AllPlanes, ZPixmap);
}
if (img) {
if(bpp != 32 && bpp != 24 && !once) {
fprintf(stderr, "Warning: unsupported colourdepth\n");
once = 1;
}
if(bpp == img->bits_per_pixel && stride == img->bytes_per_line)
{
memcpy(data, img->data, stride * surface->height);
}
else
{
int x, y;
for(y = 0 ; y < surface->height ; y++) {
for(x = 0 ; x < surface->width ; x++) {
char *src = ((char*)img->data) + (x*(img->bits_per_pixel/8)) + (y*img->bytes_per_line);
char *dst = ((char*)data) + x*(bpp/8) + (y*stride);
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
if(bpp == 32)
dst[3] = 0xff; // if guest is 32 bit and host is 24
}
}
}
// If we're not using Shm
if(!surface->image)
XDestroyImage(img);
return; // We're done.
}
// Uh oh... better fallback. Perhaps get glo.use_ximage to 0?
}
// Compatible / fallback method.
glo_surface_getcontents_readpixels(surface->context->formatFlags,
stride, bpp, surface->width,
surface->height, data);
}
// while(0) {
// char fname[30];
// int y;
// sprintf(fname, "dbg_%08x_%dx%d.rgb", surface, surface->width, surface->height);
// FILE *d = fopen(fname, "wb");
// for(y = 0 ; y < surface->height ; y++)
// fwrite(data + (y*stride), surface->width*3, 1, d);
// fclose(d);
// }
/* Return the width and height of the given surface */
void glo_surface_get_size(GloSurface *surface, int *width, int *height) {
if (width)
*width = surface->width;
if (height)
*height = surface->height;
}
/* Abstract glXQueryExtensionString() */
const char *glo_glXQueryExtensionsString(void) {
return glXQueryExtensionsString(glo.dpy, 0);
}
#define TX (17)
#define TY (16)
static int glo_can_readback(void) {
GloContext *context;
GloSurface *surface;
unsigned char *datain = (unsigned char *)malloc(4*TX*TY);
unsigned char *datain_flip = (unsigned char *)malloc(4*TX*TY); // flipped input data (for GL)
unsigned char *dataout = (unsigned char *)malloc(4*TX*TY);
unsigned char *p;
int x,y;
const int bufferAttributes[] = {
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 0,
GLX_STENCIL_SIZE, 0,
0,
};
int bufferFlags = glo_flags_get_from_glx(bufferAttributes, 0);
int bpp = glo_flags_get_bytes_per_pixel(bufferFlags);
int glFormat, glType;
memset(datain_flip, 0, TX*TY*4);
memset(datain, 0, TX*TY*4);
p = datain;
for (y=0;y<TY;y++) {
for (x=0;x<TX;x++) {
p[0] = x;
p[1] = y;
//if (y&1) { p[0]=0; p[1]=0; }
if (bpp>2) p[2] = 0;
if (bpp>3) p[3] = 0xFF;
p+=bpp;
}
memcpy(&datain_flip[((TY-1)-y)*bpp*TX], &datain[y*bpp*TX], bpp*TX);
}
context = glo_context_create(bufferFlags, 0);
surface = glo_surface_create(TX, TY, context);
glo_surface_makecurrent(surface);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,TX, 0,TY, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRasterPos2f(0,0);
glo_flags_get_readpixel_type(bufferFlags, &glFormat, &glType);
glDrawPixels(TX,TY,glFormat, glType, datain_flip);
glFlush();
memset(dataout, 0, bpp*TX*TY);
glo_surface_getcontents(surface, TX*4, bpp*8, dataout);
glo_surface_destroy(surface);
glo_context_destroy(context);
if (memcmp(datain, dataout, bpp*TX*TY)==0)
return 1;
return 0;
}
static void glo_test_readback_methods(void) {
glo.use_ximage = 1;
if(!glo_can_readback())
glo.use_ximage = 0;
fprintf(stderr, "VM GL: Using %s readback\n", glo.use_ximage?"XImage":"glReadPixels");
}
#endif

View File

@ -0,0 +1,814 @@
/*
* Offscreen OpenGL abstraction layer - WGL (windows) specific
*
* Copyright (c) 2010 Intel
* Written by:
* Gordon Williams <gordon.williams@collabora.co.uk>
* Ian Molton <ian.molton@collabora.co.uk>
*
* 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, sublicense, 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifdef _WIN32
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <wingdi.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/wglext.h>
#include <GL/glut.h>
#include "gloffscreen.h"
/* In Windows, you must create a window *before* you can create a pbuffer or
* get a context. So we create a hidden Window on startup (see glo_init/GloMain).
*
* Also, you can't share contexts that have different pixel formats, so we can't just
* create a new context from the window. We must create a whole new PBuffer just for
* a context :(
*/
struct GloMain {
HINSTANCE hInstance;
HDC hDC;
HWND hWnd; /* Our hidden window */
HGLRC hContext;
};
struct GloMain glo;
int glo_inited = 0;
struct _GloContext {
int formatFlags;
/* Pixel format returned by wglChoosePixelFormat */
int wglPixelFormat;
/* We need a pbuffer to make a context of the right pixelformat :( */
HPBUFFERARB hPBuffer;
HDC hDC;
HGLRC hContext;
};
struct _GloSurface {
GLuint width;
GLuint height;
GloContext *context;
HPBUFFERARB hPBuffer;
HDC hDC;
};
#define GLO_WINDOW_CLASS "QEmuGLClass"
#define DEFAULT_DEPTH_BUFFER (16)
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB;
PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB;
PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB;
/* ------------------------------------------------------------------------ */
//extern const char *glo_glXQueryExtensionsString(void);
extern void glo_surface_getcontents_readpixels(int formatFlags, int stride,
int bpp, int width, int height, void *data);
/* ------------------------------------------------------------------------ */
int glo_initialised(void) {
return glo_inited;
}
/* Initialise gloffscreen */
void glo_init(void) {
WNDCLASSEX wcx;
PIXELFORMATDESCRIPTOR pfd;
if (glo_inited) {
printf( "gloffscreen already inited\n" );
exit( EXIT_FAILURE );
}
glo.hInstance = GetModuleHandle(NULL); // Grab An Instance For Our Window
wcx.cbSize = sizeof(wcx);
wcx.style = 0;
wcx.lpfnWndProc = DefWindowProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = glo.hInstance;
wcx.hIcon = NULL;
wcx.hCursor = NULL;
wcx.hbrBackground = NULL;
wcx.lpszMenuName = NULL;
wcx.lpszClassName = GLO_WINDOW_CLASS;
wcx.hIconSm = NULL;
RegisterClassEx(&wcx);
glo.hWnd = CreateWindow(
GLO_WINDOW_CLASS,
"QEmuGL",
0,0,0,0,0,
(HWND)NULL, (HMENU)NULL,
glo.hInstance,
(LPVOID) NULL);
if (!glo.hWnd) {
printf( "Unable to create window\n" );
exit( EXIT_FAILURE );
}
glo.hDC = GetDC(glo.hWnd);
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.iLayerType = PFD_MAIN_PLANE;
unsigned int pixelFormat = ChoosePixelFormat(glo.hDC, &pfd);
DescribePixelFormat(glo.hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
if (!SetPixelFormat(glo.hDC, pixelFormat, &pfd))
return;
glo.hContext = wglCreateContext(glo.hDC);
if (glo.hContext == NULL) {
printf( "Unable to create GL context\n" );
exit( EXIT_FAILURE );
}
wglMakeCurrent(glo.hDC, glo.hContext);
// FIXME GW
// Need to share lists AND copy state
// load in the extensions we need
//const char *ext = wglGetExtensionsStringARB(hdc);
//"WGL_ARB_pixel_format" "WGL_ARB_pbuffer"
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress("wglGetPbufferDCARB");
wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress("wglReleasePbufferDCARB");
wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress("wglDestroyPbufferARB");
if (!wglChoosePixelFormatARB ||
!wglGetPbufferDCARB ||
!wglReleasePbufferDCARB ||
!wglCreatePbufferARB ||
!wglDestroyPbufferARB) {
printf( "Unable to load the required WGL extensions\n" );
exit( EXIT_FAILURE );
}
// Initialize glew
if (GLEW_OK != glewInit())
{
// GLEW failed!
printf("Glew init failed.");
exit(1);
}
glo_inited = 1;
}
/* Uninitialise gloffscreen */
void glo_kill(void) {
if (glo.hContext) {
wglMakeCurrent(NULL, NULL);
wglDeleteContext(glo.hContext);
glo.hContext = NULL;
}
if (glo.hDC) {
ReleaseDC(glo.hWnd, glo.hDC);
glo.hDC = NULL;
}
if (glo.hWnd) {
DestroyWindow(glo.hWnd);
glo.hWnd = NULL;
}
UnregisterClass(GLO_WINDOW_CLASS, glo.hInstance);
}
static const char *STANDARD_GL_FUNCTIONS ={
/* Miscellaneous */
"glClearIndex\0"
"glClearColor\0"
"glClear\0"
"glIndexMask\0"
"glColorMask\0"
"glAlphaFunc\0"
"glBlendFunc\0"
"glLogicOp\0"
"glCullFace\0"
"glFrontFace\0"
"glPointSize\0"
"glLineWidth\0"
"glLineStipple\0"
"glPolygonMode\0"
"glPolygonOffset\0"
"glPolygonStipple\0"
"glGetPolygonStipple\0"
"glEdgeFlag\0"
"glEdgeFlagv\0"
"glScissor\0"
"glClipPlane\0"
"glGetClipPlane\0"
"glDrawBuffer\0"
"glReadBuffer\0"
"glEnable\0"
"glDisable\0"
"glIsEnabled\0"
"glEnableClientState\0"
"glDisableClientState\0"
"glGetBooleanv\0"
"glGetDoublev\0"
"glGetFloatv\0"
"glGetIntegerv\0"
"glPushAttrib\0"
"glPopAttrib\0"
"glPushClientAttrib\0"
"glPopClientAttrib\0"
"glRenderMode\0"
"glGetError\0"
"glGetString\0"
"glFinish\0"
"glFlush\0"
"glHint\0"
/* Depth Buffer */
"glClearDepth\0"
"glDepthFunc\0"
"glDepthMask\0"
"glDepthRange\0"
/* Accumulation Buffer */
"glClearAccum\0"
"glAccum\0"
/* Transformation */
"glMatrixMode\0"
"glOrtho\0"
"glFrustum\0"
"glViewport\0"
"glPushMatrix\0"
"glPopMatrix\0"
"glLoadIdentity\0"
"glLoadMatrixd\0"
"glLoadMatrixf\0"
"glMultMatrixd\0"
"glMultMatrixf\0"
"glRotated\0"
"glRotatef\0"
"glScaled\0"
"glScalef\0"
"glTranslated\0"
"glTranslatef\0"
/* Display Lists */
"glIsList\0"
"glDeleteLists\0"
"glGenLists\0"
"glNewList\0"
"glEndList\0"
"glCallList\0"
"glCallLists\0"
"glListBase\0"
/* Drawing Functions */
"glBegin\0"
"glEnd\0"
"glVertex2d\0"
"glVertex2f\0"
"glVertex2i\0"
"glVertex2s\0"
"glVertex3d\0"
"glVertex3f\0"
"glVertex3i\0"
"glVertex3s\0"
"glVertex4d\0"
"glVertex4f\0"
"glVertex4i\0"
"glVertex4s\0"
"glVertex2dv\0"
"glVertex2fv\0"
"glVertex2iv\0"
"glVertex2sv\0"
"glVertex3dv\0"
"glVertex3fv\0"
"glVertex3iv\0"
"glVertex3sv\0"
"glVertex4dv\0"
"glVertex4fv\0"
"glVertex4iv\0"
"glVertex4sv\0"
"glNormal3b\0"
"glNormal3d\0"
"glNormal3f\0"
"glNormal3i\0"
"glNormal3s\0"
"glNormal3bv\0"
"glNormal3dv\0"
"glNormal3fv\0"
"glNormal3iv\0"
"glNormal3sv\0"
"glIndexd\0"
"glIndexf\0"
"glIndexi\0"
"glIndexs\0"
"glIndexub\0"
"glIndexdv\0"
"glIndexfv\0"
"glIndexiv\0"
"glIndexsv\0"
"glIndexubv\0"
"glColor3b\0"
"glColor3d\0"
"glColor3f\0"
"glColor3i\0"
"glColor3s\0"
"glColor3ub\0"
"glColor3ui\0"
"glColor3us\0"
"glColor4b\0"
"glColor4d\0"
"glColor4f\0"
"glColor4i\0"
"glColor4s\0"
"glColor4ub\0"
"glColor4ui\0"
"glColor4us\0"
"glColor3bv\0"
"glColor3dv\0"
"glColor3fv\0"
"glColor3iv\0"
"glColor3sv\0"
"glColor3ubv\0"
"glColor3uiv\0"
"glColor3usv\0"
"glColor4bv\0"
"glColor4dv\0"
"glColor4fv\0"
"glColor4iv\0"
"glColor4sv\0"
"glColor4ubv\0"
"glColor4uiv\0"
"glColor4usv\0"
"glTexCoord1d\0"
"glTexCoord1f\0"
"glTexCoord1i\0"
"glTexCoord1s\0"
"glTexCoord2d\0"
"glTexCoord2f\0"
"glTexCoord2i\0"
"glTexCoord2s\0"
"glTexCoord3d\0"
"glTexCoord3f\0"
"glTexCoord3i\0"
"glTexCoord3s\0"
"glTexCoord4d\0"
"glTexCoord4f\0"
"glTexCoord4i\0"
"glTexCoord4s\0"
"glTexCoord1dv\0"
"glTexCoord1fv\0"
"glTexCoord1iv\0"
"glTexCoord1sv\0"
"glTexCoord2dv\0"
"glTexCoord2fv\0"
"glTexCoord2iv\0"
"glTexCoord2sv\0"
"glTexCoord3dv\0"
"glTexCoord3fv\0"
"glTexCoord3iv\0"
"glTexCoord3sv\0"
"glTexCoord4dv\0"
"glTexCoord4fv\0"
"glTexCoord4iv\0"
"glTexCoord4sv\0"
"glRasterPos2d\0"
"glRasterPos2f\0"
"glRasterPos2i\0"
"glRasterPos2s\0"
"glRasterPos3d\0"
"glRasterPos3f\0"
"glRasterPos3i\0"
"glRasterPos3s\0"
"glRasterPos4d\0"
"glRasterPos4f\0"
"glRasterPos4i\0"
"glRasterPos4s\0"
"glRasterPos2dv\0"
"glRasterPos2fv\0"
"glRasterPos2iv\0"
"glRasterPos2sv\0"
"glRasterPos3dv\0"
"glRasterPos3fv\0"
"glRasterPos3iv\0"
"glRasterPos3sv\0"
"glRasterPos4dv\0"
"glRasterPos4fv\0"
"glRasterPos4iv\0"
"glRasterPos4sv\0"
"glRectd\0"
"glRectf\0"
"glRecti\0"
"glRects\0"
"glRectdv\0"
"glRectfv\0"
"glRectiv\0"
"glRectsv\0"
/* Lighting */
"glShadeModel\0"
"glLightf\0"
"glLighti\0"
"glLightfv\0"
"glLightiv\0"
"glGetLightfv\0"
"glGetLightiv\0"
"glLightModelf\0"
"glLightModeli\0"
"glLightModelfv\0"
"glLightModeliv\0"
"glMaterialf\0"
"glMateriali\0"
"glMaterialfv\0"
"glMaterialiv\0"
"glGetMaterialfv\0"
"glGetMaterialiv\0"
"glColorMaterial\0"
/* Raster functions */
"glPixelZoom\0"
"glPixelStoref\0"
"glPixelStorei\0"
"glPixelTransferf\0"
"glPixelTransferi\0"
"glPixelMapfv\0"
"glPixelMapuiv\0"
"glPixelMapusv\0"
"glGetPixelMapfv\0"
"glGetPixelMapuiv\0"
"glGetPixelMapusv\0"
"glBitmap\0"
"glReadPixels\0"
"glDrawPixels\0"
"glCopyPixels\0"
/* Stenciling */
"glStencilFunc\0"
"glStencilMask\0"
"glStencilOp\0"
"glClearStencil\0"
/* Texture mapping */
"glTexGend\0"
"glTexGenf\0"
"glTexGeni\0"
"glTexGendv\0"
"glTexGenfv\0"
"glTexGeniv\0"
"glGetTexGendv\0"
"glGetTexGenfv\0"
"glGetTexGeniv\0"
"glTexEnvf\0"
"glTexEnvi\0"
"glTexEnvfv\0"
"glTexEnviv\0"
"glGetTexEnvfv\0"
"glGetTexEnviv\0"
"glTexParameterf\0"
"glTexParameteri\0"
"glTexParameterfv\0"
"glTexParameteriv\0"
"glGetTexParameterfv\0"
"glGetTexParameteriv\0"
"glGetTexLevelParameterfv\0"
"glGetTexLevelParameteriv\0"
"glTexImage1D\0"
"glTexImage2D\0"
"glGetTexImage\0"
/* Evaluators */
"glMap1d\0"
"glMap1f\0"
"glMap2d\0"
"glMap2f\0"
"glGetMapdv\0"
"glGetMapfv\0"
"glGetMapiv\0"
"glEvalCoord1d\0"
"glEvalCoord1f\0"
"glEvalCoord1dv\0"
"glEvalCoord1fv\0"
"glEvalCoord2d\0"
"glEvalCoord2f\0"
"glEvalCoord2dv\0"
"glEvalCoord2fv\0"
"glMapGrid1d\0"
"glMapGrid1f\0"
"glMapGrid2d\0"
"glMapGrid2f\0"
"glEvalPoint1\0"
"glEvalPoint2\0"
"glEvalMesh1\0"
"glEvalMesh2\0"
/* Fog */
"glFogf\0"
"glFogi\0"
"glFogfv\0"
"glFogiv\0"
/* Selection and Feedback */
"glFeedbackBuffer\0"
"glPassThrough\0"
"glSelectBuffer\0"
"glInitNames\0"
"glLoadName\0"
"glPushName\0"
"glPopName\0"
/* 1.1 functions */
/* texture objects */
"glGenTextures\0"
"glDeleteTextures\0"
"glBindTexture\0"
"glPrioritizeTextures\0"
"glAreTexturesResident\0"
"glIsTexture\0"
/* texture mapping */
"glTexSubImage1D\0"
"glTexSubImage2D\0"
"glCopyTexImage1D\0"
"glCopyTexImage2D\0"
"glCopyTexSubImage1D\0"
"glCopyTexSubImage2D\0"
/* vertex arrays */
"glVertexPointer\0"
"glNormalPointer\0"
"glColorPointer\0"
"glIndexPointer\0"
"glTexCoordPointer\0"
"glEdgeFlagPointer\0"
"glGetPointerv\0"
"glArrayElement\0"
"glDrawArrays\0"
"glDrawElements\0"
"glInterleavedArrays\0"
/* GLX */
"glXChooseVisual\0"
"glXQueryExtensionsString\0"
"glXQueryServerString\0"
"glXGetClientString\0"
"glXCreateContext\0"
"glXCreateNewContext\0"
"glXCopyContext\0"
"glXDestroyContext\0"
"glXQueryVersion\0"
"glXMakeCurrent\0"
"glXSwapBuffers\0"
"glXGetConfig\0"
"glXQueryExtension\0"
"glXChooseFBConfig\0"
"glXGetFBConfigs\0"
"glXGetFBConfigAttrib\0"
"glXQueryContext\0"
"glXQueryDrawable\0"
"glXGetVisualFromFBConfig\0"
"glXIsDirect\0"
"\0"
};
/* Like wglGetProcAddress/glxGetProcAddress */
void *glo_getprocaddress(const char *procName) {
HGLRC oldCtx;
HDC oldDC;
if (!glo_inited)
glo_init();
oldCtx = wglGetCurrentContext();
oldDC = wglGetCurrentDC();
if (oldDC!=glo.hDC || oldCtx!=glo.hContext)
wglMakeCurrent(glo.hDC, glo.hContext);
void *procAddr = wglGetProcAddress(procName);
if (oldDC!=glo.hDC || oldCtx!=glo.hContext)
wglMakeCurrent(oldDC, oldCtx);
/* wgl doesn't know about the glx functions - but
we never call these anyway (they're implemented in
opengl_exec), so all we need to do is return a nunzero value...
But we also have to check for 'standard' GL function names
too as wgl doesn't return those either! */
if (procAddr==0) {
const char *p = STANDARD_GL_FUNCTIONS;
while (*p) {
if (!strcmp(procName, p)) {
procAddr = (void*)1;
break;
}
// skip to the next '0' and then just over it
while (*p) p++;
p++;
}
}
/*printf("wglGetProcAddress '%s' -> %p\n", procName, procAddr);
fflush(stdout);*/
return procAddr;
}
/* ------------------------------------------------------------------------ */
/* Create an OpenGL context for a certain pixel format. formatflags are from the GLO_ constants */
GloContext *glo_context_create(int formatFlags) {
GloContext *context;
// pixel format attributes
int pf_attri[] = {
WGL_SUPPORT_OPENGL_ARB, TRUE,
WGL_DRAW_TO_PBUFFER_ARB, TRUE,
WGL_RED_BITS_ARB, 8,
WGL_GREEN_BITS_ARB, 8,
WGL_BLUE_BITS_ARB, 8,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 0,
WGL_STENCIL_BITS_ARB, 0,
WGL_DOUBLE_BUFFER_ARB, FALSE,
0
};
float pf_attrf[] = {0, 0};
unsigned int numReturned = 0;
int pb_attr[] = { 0 };
int rgbaBits[4];
if (!glo_inited)
glo_init();
context = (GloContext*)malloc(sizeof(GloContext));
memset(context, 0, sizeof(GloContext));
context->formatFlags = formatFlags;
// set up the surface format from the flags we were given
glo_flags_get_rgba_bits(context->formatFlags, rgbaBits);
pf_attri[5] = rgbaBits[0];
pf_attri[7] = rgbaBits[1];
pf_attri[9] = rgbaBits[2];
pf_attri[11] = rgbaBits[3];
pf_attri[13] = glo_flags_get_depth_bits(context->formatFlags);
pf_attri[15] = glo_flags_get_stencil_bits(context->formatFlags);
// find out what pixel format to use
wglChoosePixelFormatARB( glo.hDC, pf_attri, pf_attrf, 1, &context->wglPixelFormat, &numReturned);
if( numReturned == 0 ) {
printf( "No matching configs found.\n" );
exit( EXIT_FAILURE );
}
// We create a tiny pbuffer - just so we can make a context of the right pixel format
context->hPBuffer = wglCreatePbufferARB( glo.hDC, context->wglPixelFormat,
16, 16, pb_attr );
if( !context->hPBuffer ) {
printf( "Couldn't create the PBuffer\n" );
exit( EXIT_FAILURE );
}
context->hDC = wglGetPbufferDCARB( context->hPBuffer );
if( !context->hDC ) {
printf( "Couldn't create the DC\n" );
exit( EXIT_FAILURE );
}
context->hContext = wglCreateContext(context->hDC);
if (context->hContext == NULL) {
printf( "Unable to create GL context\n" );
exit( EXIT_FAILURE );
}
/*
if (shareLists) {
// Need to share lists...
wglShareLists(shareLists->hContext, context->hContext);
}
*/
glo_set_current(context);
return context;
}
/* Set current context */
void glo_set_current(GloContext *context)
{
if(context == NULL)
wglMakeCurrent(NULL, NULL);
else
wglMakeCurrent(context->hDC, context->hContext);
}
/* Destroy a previously created OpenGL context */
void glo_context_destroy(GloContext *context) {
if (!context) return;
wglMakeCurrent( NULL, NULL );
if( context->hPBuffer != NULL ) {
wglReleasePbufferDCARB( context->hPBuffer, context->hDC );
wglDestroyPbufferARB( context->hPBuffer );
}
if( context->hDC != NULL ) {
ReleaseDC( glo.hWnd, context->hDC );
}
if (context->hContext) {
wglDeleteContext(context->hContext);
}
free(context);
}
/* ------------------------------------------------------------------------ */
/* Create a surface with given width and height, formatflags are from the
* GLO_ constants */
GloSurface *glo_surface_create(int width, int height, GloContext *context) {
GloSurface *surface;
int pb_attr[] = { 0 };
// Create the p-buffer...
surface = (GloSurface*)malloc(sizeof(GloSurface));
memset(surface, 0, sizeof(GloSurface));
surface->width = width;
surface->height = height;
surface->context = context;
surface->hPBuffer = wglCreatePbufferARB( glo.hDC, context->wglPixelFormat,
surface->width, surface->height, pb_attr );
if( !surface->hPBuffer ) {
printf( "Couldn't create the PBuffer\n" );
exit( EXIT_FAILURE );
}
surface->hDC = wglGetPbufferDCARB( surface->hPBuffer );
if( !surface->hDC ) {
printf( "Couldn't create the DC\n" );
exit( EXIT_FAILURE );
}
return surface;
}
/* Destroy the given surface */
void glo_surface_destroy(GloSurface *surface) {
if (!surface) return;
wglMakeCurrent( NULL, NULL );
if( surface->hPBuffer != NULL ) {
wglReleasePbufferDCARB( surface->hPBuffer, surface->hDC );
wglDestroyPbufferARB( surface->hPBuffer );
}
if( surface->hDC != NULL ) {
ReleaseDC( glo.hWnd, surface->hDC );
}
free(surface);
}
/* Make the given surface current */
int glo_surface_makecurrent(GloSurface *surface) {
if (surface) {
return wglMakeCurrent( surface->hDC, surface->context->hContext );
} else {
return wglMakeCurrent( NULL, NULL );
}
}
/* Get the contents of the given surface */
void glo_surface_getcontents(GloSurface *surface, int stride, int bpp, void *data) {
if (!surface)
return;
// Compatible / fallback method.
glo_surface_getcontents_readpixels(surface->context->formatFlags,
stride, bpp, surface->width,
surface->height, data);
}
/* Return the width and height of the given surface */
void glo_surface_get_size(GloSurface *surface, int *width, int *height) {
if (width)
*width = surface->width;
if (height)
*height = surface->height;
}
/* Fake glXQueryExtensionsString() */
const char *glo_glXQueryExtensionsString(void) {
return "";
}
#endif