2 * Offscreen OpenGL abstraction layer - WGL (windows) specific
4 * Copyright (c) 2010 Intel Corporation
6 * Gordon Williams <gordon.williams@collabora.co.uk>
7 * Ian Molton <ian.molton@collabora.co.uk>
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 #include "gloffscreen.h"
38 #include "GL/wglext.h"
40 #define MAX_ATTRIBS 12 /*Max attributes of pixel format we need*/
42 #ifdef MANGLE_OPENGL_SYMBOLS
43 #include "gl_mangled.h"
46 /* In Windows, you must create a window *before* you can create a pbuffer or
47 * get a context. So we create a hidden Window on startup (see glo_init/GloMain).
49 * Also, you can't share contexts that have different pixel formats, so we can't just
50 * create a new context from the window. We must create a whole new PBuffer just for
57 HWND hWnd; /* Our hidden window */
62 int Render_texture_support = 0;
67 /* Pixel format returned by wglChoosePixelFormat */
69 /* We need a pbuffer to make a context of the right pixelformat :( */
84 #define GLO_WINDOW_CLASS "QEmuGLClass"
85 #define DEFAULT_DEPTH_BUFFER (16)
87 PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
88 PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB;
89 PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
90 PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB;
91 PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB;
92 PFNWGLBINDTEXIMAGEARBPROC wglBindTexImageARB;
93 PFNWGLRELEASETEXIMAGEARBPROC wglReleaseTexImageARB;
94 PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
96 /* ------------------------------------------------------------------------ */
98 extern const char *glo_glXQueryExtensionsString(void);
100 extern void glo_surface_getcontents_readpixels(int formatFlags, int stride,
101 int bpp, int width, int height, void *data);
103 /* ------------------------------------------------------------------------ */
105 int glo_initialised(void) {
109 /* Sanity test of the host GL capabilities to see whether the gl offscreen
110 * could be well supported
112 int glo_sanity_test (void) {
113 PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
114 PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB;
115 PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
116 PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB;
117 PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB;
119 wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
120 wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress("wglGetPbufferDCARB");
121 wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress("wglReleasePbufferDCARB");
122 wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
123 wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress("wglDestroyPbufferARB");
124 if (!wglChoosePixelFormatARB ||
125 !wglGetPbufferDCARB ||
126 !wglReleasePbufferDCARB ||
127 !wglCreatePbufferARB ||
128 !wglDestroyPbufferARB) {
129 fprintf (stderr, "Unable to load the required WGL extensions\n");
132 // check the shader support. It is for mcompositor to run.
134 if (!wglGetProcAddress("glShaderSource")) {
135 fprintf (stderr, "Unable to find shader support\n");
141 /* Initialise gloffscreen */
144 PIXELFORMATDESCRIPTOR pfd;
148 printf( "gloffscreen already inited\n" );
149 //exit( EXIT_FAILURE );
153 glo.hInstance = GetModuleHandle(NULL); // Grab An Instance For Our Window
155 wcx.cbSize = sizeof(wcx);
157 wcx.lpfnWndProc = DefWindowProc;
160 wcx.hInstance = glo.hInstance;
163 wcx.hbrBackground = NULL;
164 wcx.lpszMenuName = NULL;
165 wcx.lpszClassName = GLO_WINDOW_CLASS;
167 RegisterClassEx(&wcx);
168 glo.hWnd = CreateWindow(
172 (HWND)NULL, (HMENU)NULL,
177 printf( "Unable to create window\n" );
178 //exit( EXIT_FAILURE );
181 glo.hDC = GetDC(glo.hWnd);
183 memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
184 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
186 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
187 pfd.iPixelType = PFD_TYPE_RGBA;
189 pfd.iLayerType = PFD_MAIN_PLANE;
190 unsigned int pixelFormat = ChoosePixelFormat(glo.hDC, &pfd);
191 DescribePixelFormat(glo.hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
192 if (!SetPixelFormat(glo.hDC, pixelFormat, &pfd))
195 glo.hContext = wglCreateContext(glo.hDC);
196 if (glo.hContext == NULL) {
197 printf( "Unable to create GL context\n" );
198 //exit( EXIT_FAILURE );
201 wglMakeCurrent(glo.hDC, glo.hContext);
204 // Need to share lists AND copy state
206 // load in the extensions we need
207 //const char *ext = wglGetExtensionsStringARB(hdc);
208 //"WGL_ARB_pixel_format" "WGL_ARB_pbuffer"
210 wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
211 wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress("wglGetPbufferDCARB");
212 wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress("wglReleasePbufferDCARB");
213 wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
214 wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress("wglDestroyPbufferARB");
215 wglBindTexImageARB = (PFNWGLBINDTEXIMAGEARBPROC)wglGetProcAddress("wglBindTexImageARB");
216 wglReleaseTexImageARB = (PFNWGLRELEASETEXIMAGEARBPROC)wglGetProcAddress("wglReleaseTexImageARB");
217 wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
219 if (!wglChoosePixelFormatARB ||
220 !wglGetPbufferDCARB ||
221 !wglReleasePbufferDCARB ||
222 !wglCreatePbufferARB ||
223 !wglDestroyPbufferARB ||
224 !wglGetExtensionsStringARB ) {
225 printf( "Unable to load the required WGL extensions\n" );
226 //exit( EXIT_FAILURE );
230 if(wglGetExtensionsStringARB)
232 ext_str = wglGetExtensionsStringARB(wglGetCurrentDC());
235 fprintf(stderr, "Failed tp get extensions string!\n");
236 Render_texture_support = 0;
240 if(strstr(ext_str, "WGL_ARB_render_texture") != NULL)
242 fprintf(stdout, "WGL_ARB_render_texture supported!\n");
243 Render_texture_support = 1;
247 fprintf(stderr, "WGL_ARB_render_texture not supported!\n");
248 Render_texture_support = 0;
254 if ( !wglBindTexImageARB ||
255 !wglReleaseTexImageARB )
256 fprintf (stderr, "Warning: no [Bind|Release]TexImageARB extensions.\n");
263 /* Uninitialise gloffscreen */
264 void glo_kill(void) {
266 wglMakeCurrent(NULL, NULL);
267 wglDeleteContext(glo.hContext);
271 ReleaseDC(glo.hWnd, glo.hDC);
275 DestroyWindow(glo.hWnd);
278 UnregisterClass(GLO_WINDOW_CLASS, glo.hInstance);
281 const char *glo_glXQueryExtensionsString(void) {
286 static const char *STANDARD_GL_FUNCTIONS ={
304 "glGetPolygonStipple\0"
315 "glEnableClientState\0"
316 "glDisableClientState\0"
323 "glPushClientAttrib\0"
324 "glPopClientAttrib\0"
336 /* Accumulation Buffer */
366 /* Drawing Functions */
528 /* Raster functions */
549 /* Texture mapping */
569 "glGetTexParameterfv\0"
570 "glGetTexParameteriv\0"
571 "glGetTexLevelParameterfv\0"
572 "glGetTexLevelParameteriv\0"
605 /* Selection and Feedback */
614 /* texture objects */
618 "glPrioritizeTextures\0"
619 "glAreTexturesResident\0"
621 /* texture mapping */
626 "glCopyTexSubImage1D\0"
627 "glCopyTexSubImage2D\0"
633 "glTexCoordPointer\0"
634 "glEdgeFlagPointer\0"
639 "glInterleavedArrays\0"
642 "glXQueryExtensionsString\0"
643 "glXQueryServerString\0"
644 "glXGetClientString\0"
646 "glXCreateNewContext\0"
648 "glXDestroyContext\0"
653 "glXQueryExtension\0"
654 "glXChooseFBConfig\0"
656 "glXGetFBConfigAttrib\0"
659 "glXGetVisualFromFBConfig\0"
664 "glXDestroyPbuffer\n"
668 /* Like wglGetProcAddress/glxGetProcAddress */
669 void *glo_getprocaddress(const char *procName) {
675 oldCtx = wglGetCurrentContext();
676 oldDC = wglGetCurrentDC();
677 if (oldDC!=glo.hDC || oldCtx!=glo.hContext)
678 wglMakeCurrent(glo.hDC, glo.hContext);
680 void *procAddr = wglGetProcAddress(procName);
682 if (oldDC!=glo.hDC || oldCtx!=glo.hContext)
683 wglMakeCurrent(oldDC, oldCtx);
685 /* wgl doesn't know about the glx functions - but
686 we never call these anyway (they're implemented in
687 opengl_exec), so all we need to do is return a nunzero value...
689 But we also have to check for 'standard' GL function names
690 too as wgl doesn't return those either! */
691 /* Caller in opengl_exec.c may query some base GL API, then call them
692 * directly. On windows, wglGetProcAddress usually return NULL in such
693 * case, then we return 1, which casue segfault when accessing (void*)1. We
694 * should call base GL API directly instead of GET_EXT_PTR + ptr_func_*.
695 * TODO: add LoadLibrary + GetProcAddress as call back.
698 const char *p = STANDARD_GL_FUNCTIONS;
700 if (!strcmp(procName, p)) {
704 // skip to the next '0' and then just over it
710 /*printf("wglGetProcAddress '%s' -> %p\n", procName, procAddr);
715 void glo_surface_updatecontents(GloSurface *surface) {
716 /* NOT IMPLEMENTED YET. */
717 printf("glo_surface_updatecontents() is not implemented for windows. \n");
720 /* ------------------------------------------------------------------------ */
722 /* Create a light-weight context just for creating surface */
723 GloContext *__glo_context_create(int formatFlags) {
725 // pixel format attributes
726 int pf_attri[2*MAX_ATTRIBS];
727 float pf_attrf[] = {0, 0};
728 unsigned int numReturned = 0;
729 int pb_attr[] = { 0 };
733 /*Initlized array because it needs to be terminated by 0*/
734 for(index = 0; index < 2*MAX_ATTRIBS; index ++)
738 pf_attri[2*index] = WGL_SUPPORT_OPENGL_ARB;
739 pf_attri[2*index +1 ] = TRUE;
742 pf_attri[2*index] = WGL_DRAW_TO_PBUFFER_ARB;
743 pf_attri[2*index +1 ] = TRUE;
746 pf_attri[2*index] = WGL_RED_BITS_ARB;
747 pf_attri[2*index +1 ] = 8;
750 pf_attri[2*index] = WGL_GREEN_BITS_ARB;
751 pf_attri[2*index +1 ] = 8;
754 pf_attri[2*index] = WGL_BLUE_BITS_ARB;
755 pf_attri[2*index +1 ] = 8;
758 pf_attri[2*index] = WGL_ALPHA_BITS_ARB;
759 pf_attri[2*index +1 ] = 8;
762 pf_attri[2*index] = WGL_DEPTH_BITS_ARB;
763 pf_attri[2*index +1 ] = 0;
766 pf_attri[2*index] = WGL_STENCIL_BITS_ARB;
767 pf_attri[2*index +1 ] = 0;
770 pf_attri[2*index] = WGL_DOUBLE_BUFFER_ARB;
771 pf_attri[2*index +1 ] = FALSE;
774 if(Render_texture_support)
776 fprintf(stdout, "Render to texture supported, add attributes in array!\n");
777 pf_attri[2*index] = WGL_DRAW_TO_PBUFFER_ARB;
778 pf_attri[2*index +1 ] = TRUE;
781 pf_attri[2*index] = WGL_BIND_TO_TEXTURE_RGBA_ARB;
782 pf_attri[2*index +1 ] = TRUE;
785 fprintf(stderr, "Render to Texture not supported, disable attributes in array!\n");
793 context = (GloContext*)malloc(sizeof(GloContext));
794 memset(context, 0, sizeof(GloContext));
795 context->formatFlags = formatFlags;
797 // set up the surface format from the flags we were given
798 glo_flags_get_rgba_bits(context->formatFlags, rgbaBits);
799 pf_attri[5] = rgbaBits[0];
800 pf_attri[7] = rgbaBits[1];
801 pf_attri[9] = rgbaBits[2];
802 pf_attri[11] = rgbaBits[3];
803 pf_attri[13] = glo_flags_get_depth_bits(context->formatFlags);
804 pf_attri[15] = glo_flags_get_stencil_bits(context->formatFlags);
806 // find out what pixel format to use
807 wglChoosePixelFormatARB( glo.hDC, pf_attri, pf_attrf, 1, &context->wglPixelFormat, &numReturned);
808 if( numReturned == 0 ) {
809 printf( "No matching configs found.\n" );
810 //exit( EXIT_FAILURE );
814 // We create a tiny pbuffer - just so we can make a context of the right pixel format
815 context->hPBuffer = wglCreatePbufferARB( glo.hDC, context->wglPixelFormat,
817 if( !context->hPBuffer ) {
818 printf( "Couldn't create the PBuffer\n" );
819 //exit( EXIT_FAILURE );
822 context->hDC = wglGetPbufferDCARB( context->hPBuffer );
823 if( !context->hDC ) {
824 printf( "Couldn't create the DC\n" );
825 //exit( EXIT_FAILURE );
832 /* Create an OpenGL context for a certain pixel format. formatflags are from the GLO_ constants */
833 GloContext *glo_context_create(int formatFlags, GloContext *shareLists) {
835 GloContext *context = __glo_context_create(formatFlags);
841 context->hContext = wglCreateContext(context->hDC);
842 if (context->hContext == NULL) {
843 printf( "Unable to create GL context\n" );
844 //exit( EXIT_FAILURE );
849 // Need to share lists...
850 wglShareLists(shareLists->hContext, context->hContext);
856 /* Destroy a previouslu created OpenGL context */
857 void glo_context_destroy(GloContext *context) {
858 if (!context) return;
860 wglMakeCurrent( NULL, NULL );
861 if( context->hPBuffer != NULL ) {
862 wglReleasePbufferDCARB( context->hPBuffer, context->hDC );
863 wglDestroyPbufferARB( context->hPBuffer );
865 if( context->hDC != NULL ) {
866 ReleaseDC( glo.hWnd, context->hDC );
868 if (context->hContext) {
869 wglDeleteContext(context->hContext);
874 /* ------------------------------------------------------------------------ */
876 /* Update the context in surface and handle previous context */
877 void glo_surface_update_context(GloSurface *surface, GloContext *context, int free_flags)
879 /* If previous context is light-weight context, just free it. If previous
880 * context is valid one binded with surface via MakeCurrent, we need unbind
881 * from original glstate */
883 if ( surface->context )
885 if ( free_flags ) /* light-weight context */
886 g_free(surface->context);
888 surface->context = context;
891 /* Create a surface with given width and height, formatflags are from the
893 GloSurface *glo_surface_create(int width, int height, GloContext *context) {
896 /* Need following 2 to support surface as texture */
897 WGL_TEXTURE_FORMAT_ARB, WGL_TEXTURE_RGBA_ARB,
898 WGL_TEXTURE_TARGET_ARB, WGL_TEXTURE_2D_ARB,
902 // Create the p-buffer...
903 surface = (GloSurface*)malloc(sizeof(GloSurface));
904 memset(surface, 0, sizeof(GloSurface));
905 surface->width = width;
906 surface->height = height;
907 surface->context = context;
909 surface->hPBuffer = wglCreatePbufferARB( glo.hDC, context->wglPixelFormat,
910 surface->width, surface->height, pb_attr );
911 if( !surface->hPBuffer ) {
912 printf( "Couldn't create the PBuffer\n" );
913 //exit( EXIT_FAILURE );
916 surface->hDC = wglGetPbufferDCARB( surface->hPBuffer );
917 if( !surface->hDC ) {
918 printf( "Couldn't create the DC\n" );
919 //exit( EXIT_FAILURE );
926 /* Destroy the given surface */
927 void glo_surface_destroy(GloSurface *surface) {
928 if (!surface) return;
930 wglMakeCurrent( NULL, NULL );
931 if( surface->hPBuffer != NULL ) {
932 wglReleasePbufferDCARB( surface->hPBuffer, surface->hDC );
933 wglDestroyPbufferARB( surface->hPBuffer );
935 if( surface->hDC != NULL ) {
936 ReleaseDC( glo.hWnd, surface->hDC );
941 /* Make the given surface current */
942 int glo_surface_makecurrent(GloSurface *surface) {
944 return wglMakeCurrent( surface->hDC, surface->context->hContext );
946 return wglMakeCurrent( NULL, NULL );
950 /* Get the contents of the given surface */
951 void glo_surface_getcontents(GloSurface *surface, int stride, int bpp, void *data) {
955 // Compatible / fallback method.
956 glo_surface_getcontents_readpixels(surface->context->formatFlags,
957 stride, bpp, surface->width,
958 surface->height, data);
961 /* Return the width and height of the given surface */
962 void glo_surface_get_size(GloSurface *surface, int *width, int *height) {
964 *width = surface->width;
966 *height = surface->height;
969 /* Bind the surface as texture */
970 void glo_surface_as_texture(GloContext *ctxt, GloSurface *surface)
973 int glFormat, glType;
974 glo_surface_updatecontents(surface);
975 /*XXX: change the fixed target: GL_TEXTURE_2D*/
976 glo_flags_get_readpixel_type(surface->context->formatFlags, &glFormat, &glType);
977 fprintf(stderr, "surface_as_texture:teximage:width=%d,height=%d,glFormat=0x%x,glType=0x%x.\n", surface->width, surface->height, glFormat, glType);
978 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->width, surface->height, 0, glFormat, glType, surface->image->data);
980 if(!Render_texture_support)
982 //fprintf(stderr, "Render to texture not supported on this machine, just return!\n");
986 if (!wglBindTexImageARB)
988 fprintf (stderr, "wglBindTexImageEXT not supported! Can't emulate glEGLImageTargetTexture2DOES!\n");
992 if ( !wglBindTexImageARB(surface->hPBuffer, WGL_FRONT_LEFT_ARB) )
994 fprintf(stderr, "wglBindTexImageARBr error=%d.\n", glGetError());
999 void glo_surface_release_texture(GloSurface *surface)
1001 if(!Render_texture_support)
1004 if (!wglReleaseTexImageARB)
1006 fprintf (stderr, "wglReleaseTexImageARB not supported! Can't emulate glEGLImageTargetTexture2DOES!\n");
1010 if ( !wglReleaseTexImageARB(surface->hPBuffer, WGL_FRONT_LEFT_ARB) )
1012 fprintf(stderr, "wglBindTexImageARBr error=%d.\n", glGetError());