diff --git a/configure b/configure index 837d30346b..f4d903ea36 100755 --- a/configure +++ b/configure @@ -2445,6 +2445,17 @@ if test "$opengl" != "no" ; then #include #include int main(void) { return GL_VERSION != 0; } +EOF + elif test "$mingw32" = "yes" ; then + opengl_libs="-lglut32win -lOpenGL32 -lglu32 -lglew32 -lgdi32" + cat > $TMPC << EOF +#include +#include +#include +#include +#include +#include +int main(void) { return GL_VERSION != 0; } EOF else opengl_libs="-lGL -lX11" diff --git a/hw/nv2a.c b/hw/nv2a.c index 5175864ffe..1db5911878 100644 --- a/hw/nv2a.c +++ b/hw/nv2a.c @@ -37,13 +37,22 @@ #include #include #else +#ifdef _WIN32 +#include +#include +#include +#include +#include +#else #include #include #include #include #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, diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs index c1d4f059da..c04b6265cf 100644 --- a/target-i386/Makefile.objs +++ b/target-i386/Makefile.objs @@ -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 \ No newline at end of file diff --git a/target-i386/gloffscreen_cgl.c b/target-i386/gloffscreen_cgl.c new file mode 100644 index 0000000000..62992e4847 --- /dev/null +++ b/target-i386/gloffscreen_cgl.c @@ -0,0 +1,586 @@ +/* + * Offscreen OpenGL abstraction layer - WGL (windows) specific + * + * Copyright (c) 2010 Intel + * Written by: + * Gordon Williams + * Ian Molton + * + * 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 +#include +#include + +#include +#include +#include +#include +#include + +#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 diff --git a/target-i386/gloffscreen_common.c b/target-i386/gloffscreen_common.c new file mode 100644 index 0000000000..cc00f401e6 --- /dev/null +++ b/target-i386/gloffscreen_common.c @@ -0,0 +1,360 @@ +/* + * Offscreen OpenGL abstraction layer - Common utilities + * + * Copyright (c) 2010 Intel + * Written by: + * Gordon Williams + * Ian Molton + * + * 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 +#include +#include +#else +#include +#endif + +#include +#include +#include + +// --------------------------------------------------- +// 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; +} + diff --git a/target-i386/gloffscreen_glx.c b/target-i386/gloffscreen_glx.c new file mode 100644 index 0000000000..23e48e9598 --- /dev/null +++ b/target-i386/gloffscreen_glx.c @@ -0,0 +1,529 @@ +/* + * Offscreen OpenGL abstraction layer - GLX specific + * + * Copyright (c) 2010 Intel + * Written by: + * Gordon Williams + * Ian Molton + * + * 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 +#include +#include + +#include +#include +#include +#include + +#include +#include + +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;y2) 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 diff --git a/target-i386/gloffscreen_wgl.c b/target-i386/gloffscreen_wgl.c new file mode 100644 index 0000000000..75837c0e4b --- /dev/null +++ b/target-i386/gloffscreen_wgl.c @@ -0,0 +1,814 @@ +/* + * Offscreen OpenGL abstraction layer - WGL (windows) specific + * + * Copyright (c) 2010 Intel + * Written by: + * Gordon Williams + * Ian Molton + * + * 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 +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#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