diff options
author | Marek Olšák <[email protected]> | 2019-12-03 18:01:31 -0500 |
---|---|---|
committer | Marek Olšák <[email protected]> | 2020-05-13 13:46:53 -0400 |
commit | d6287a94b697ffe12a4e576a38943cdf4e90cdb0 (patch) | |
tree | bb84357d98dc74412e983693e09875bb355b467e /src/gallium/frontends/glx | |
parent | b408734e5e2fe1e1ef08080c4425ad8a7ed33579 (diff) |
gallium: rename 'state tracker' to 'frontend'
Acked-by: Eric Anholt <[email protected]>
Acked-by: Alyssa Rosenzweig <[email protected]>
Acked-by: Pierre-Eric Pelloux-Prayer <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4902>
Diffstat (limited to 'src/gallium/frontends/glx')
-rw-r--r-- | src/gallium/frontends/glx/xlib/Makefile.sources | 9 | ||||
-rw-r--r-- | src/gallium/frontends/glx/xlib/SConscript | 18 | ||||
-rw-r--r-- | src/gallium/frontends/glx/xlib/glx_api.c | 2777 | ||||
-rw-r--r-- | src/gallium/frontends/glx/xlib/glx_getproc.c | 212 | ||||
-rw-r--r-- | src/gallium/frontends/glx/xlib/glx_usefont.c | 373 | ||||
-rw-r--r-- | src/gallium/frontends/glx/xlib/meson.build | 27 | ||||
-rw-r--r-- | src/gallium/frontends/glx/xlib/xm_api.c | 1561 | ||||
-rw-r--r-- | src/gallium/frontends/glx/xlib/xm_api.h | 398 | ||||
-rw-r--r-- | src/gallium/frontends/glx/xlib/xm_public.h | 48 | ||||
-rw-r--r-- | src/gallium/frontends/glx/xlib/xm_st.c | 411 | ||||
-rw-r--r-- | src/gallium/frontends/glx/xlib/xm_st.h | 66 |
11 files changed, 5900 insertions, 0 deletions
diff --git a/src/gallium/frontends/glx/xlib/Makefile.sources b/src/gallium/frontends/glx/xlib/Makefile.sources new file mode 100644 index 00000000000..9e31a70eb3e --- /dev/null +++ b/src/gallium/frontends/glx/xlib/Makefile.sources @@ -0,0 +1,9 @@ +C_SOURCES := \ + glx_api.c \ + glx_getproc.c \ + glx_usefont.c \ + xm_api.c \ + xm_api.h \ + xm_public.h \ + xm_st.c \ + xm_st.h diff --git a/src/gallium/frontends/glx/xlib/SConscript b/src/gallium/frontends/glx/xlib/SConscript new file mode 100644 index 00000000000..1d5dd1df4fd --- /dev/null +++ b/src/gallium/frontends/glx/xlib/SConscript @@ -0,0 +1,18 @@ +####################################################################### +# SConscript for xlib state_tracker + +Import('*') + +env = env.Clone() + +env.Append(CPPPATH = [ + '#/src', + '#/src/mapi', + '#/src/mesa', +]) + +st_xlib = env.ConvenienceLibrary( + target = 'st_xlib', + source = env.ParseSourceList('Makefile.sources', 'C_SOURCES') +) +Export('st_xlib') diff --git a/src/gallium/frontends/glx/xlib/glx_api.c b/src/gallium/frontends/glx/xlib/glx_api.c new file mode 100644 index 00000000000..281111bdfb0 --- /dev/null +++ b/src/gallium/frontends/glx/xlib/glx_api.c @@ -0,0 +1,2777 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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. + */ + + +/** + * "Fake" GLX API implemented in terms of the XMesa*() functions. + */ + + + +#define GLX_GLXEXT_PROTOTYPES +#include "GL/glx.h" + +#include <stdio.h> +#include <string.h> +#include <X11/Xmd.h> +#include <GL/glxproto.h> + +#include "xm_api.h" +#include "main/errors.h" +#include "util/u_math.h" +#include "util/u_memory.h" + +/* An "Atrribs/Attribs" typo was fixed in glxproto.h in Nov 2014. + * This is in case we don't have the updated header. + */ +#if !defined(X_GLXCreateContextAttribsARB) && \ + defined(X_GLXCreateContextAtrribsARB) +#define X_GLXCreateContextAttribsARB X_GLXCreateContextAtrribsARB +#endif + +/* This indicates the client-side GLX API and GLX encoder version. */ +#define CLIENT_MAJOR_VERSION 1 +#define CLIENT_MINOR_VERSION 4 /* but don't have 1.3's pbuffers, etc yet */ + +/* This indicates the server-side GLX decoder version. + * GLX 1.4 indicates OpenGL 1.3 support + */ +#define SERVER_MAJOR_VERSION 1 +#define SERVER_MINOR_VERSION 4 + +/* Who implemented this GLX? */ +#define VENDOR "Brian Paul" + +#define EXTENSIONS \ + "GLX_MESA_copy_sub_buffer " \ + "GLX_MESA_pixmap_colormap " \ + "GLX_MESA_release_buffers " \ + "GLX_ARB_create_context " \ + "GLX_ARB_create_context_profile " \ + "GLX_ARB_get_proc_address " \ + "GLX_EXT_create_context_es_profile " \ + "GLX_EXT_create_context_es2_profile " \ + "GLX_EXT_texture_from_pixmap " \ + "GLX_EXT_visual_info " \ + "GLX_EXT_visual_rating " \ + /*"GLX_SGI_video_sync "*/ \ + "GLX_SGIX_fbconfig " \ + "GLX_SGIX_pbuffer " + +#define DEFAULT_DIRECT GL_TRUE + + +/** XXX this could be based on gallium's max texture size */ +#define PBUFFER_MAX_SIZE 16384 + + +/** + * The GLXContext typedef is defined as a pointer to this structure. + */ +struct __GLXcontextRec +{ + Display *currentDpy; + GLboolean isDirect; + GLXDrawable currentDrawable; + GLXDrawable currentReadable; + XID xid; + + XMesaContext xmesaContext; +}; + + + +static pipe_tsd ContextTSD; + +/** Set current context for calling thread */ +static void +SetCurrentContext(GLXContext c) +{ + pipe_tsd_set(&ContextTSD, c); +} + +/** Get current context for calling thread */ +static GLXContext +GetCurrentContext(void) +{ + return pipe_tsd_get(&ContextTSD); +} + + + +/**********************************************************************/ +/*** GLX Visual Code ***/ +/**********************************************************************/ + +#define DONT_CARE -1 + + +static XMesaVisual *VisualTable = NULL; +static int NumVisuals = 0; + + + +/* Macro to handle c_class vs class field name in XVisualInfo struct */ +#if defined(__cplusplus) || defined(c_plusplus) +#define CLASS c_class +#else +#define CLASS class +#endif + + + +/* + * Test if the given XVisualInfo is usable for Mesa rendering. + */ +static GLboolean +is_usable_visual( XVisualInfo *vinfo ) +{ + switch (vinfo->CLASS) { + case StaticGray: + case GrayScale: + /* Any StaticGray/GrayScale visual works in RGB or CI mode */ + return GL_TRUE; + case StaticColor: + case PseudoColor: + /* Any StaticColor/PseudoColor visual of at least 4 bits */ + if (vinfo->depth>=4) { + return GL_TRUE; + } + else { + return GL_FALSE; + } + case TrueColor: + case DirectColor: + /* Any depth of TrueColor or DirectColor works in RGB mode */ + return GL_TRUE; + default: + /* This should never happen */ + return GL_FALSE; + } +} + + +/* + * Given an XVisualInfo and RGB, Double, and Depth buffer flags, save the + * configuration in our list of GLX visuals. + */ +static XMesaVisual +save_glx_visual( Display *dpy, XVisualInfo *vinfo, + GLboolean rgbFlag, GLboolean alphaFlag, GLboolean dbFlag, + GLboolean stereoFlag, + GLint depth_size, GLint stencil_size, + GLint accumRedSize, GLint accumGreenSize, + GLint accumBlueSize, GLint accumAlphaSize, + GLint level, GLint numAuxBuffers, GLuint num_samples ) +{ + GLboolean ximageFlag = GL_TRUE; + XMesaVisual xmvis; + GLint i; + GLboolean comparePointers; + + if (!rgbFlag) + return NULL; + + if (dbFlag) { + /* Check if the MESA_BACK_BUFFER env var is set */ + char *backbuffer = getenv("MESA_BACK_BUFFER"); + if (backbuffer) { + if (backbuffer[0]=='p' || backbuffer[0]=='P') { + ximageFlag = GL_FALSE; + } + else if (backbuffer[0]=='x' || backbuffer[0]=='X') { + ximageFlag = GL_TRUE; + } + else { + _mesa_warning(NULL, "Mesa: invalid value for MESA_BACK_BUFFER environment variable, using an XImage."); + } + } + } + + if (stereoFlag) { + /* stereo not supported */ + return NULL; + } + + if (stencil_size > 0 && depth_size > 0) + depth_size = 24; + + /* Comparing IDs uses less memory but sometimes fails. */ + /* XXX revisit this after 3.0 is finished. */ + if (getenv("MESA_GLX_VISUAL_HACK")) + comparePointers = GL_TRUE; + else + comparePointers = GL_FALSE; + + /* Force the visual to have an alpha channel */ + if (rgbFlag && getenv("MESA_GLX_FORCE_ALPHA")) + alphaFlag = GL_TRUE; + + /* First check if a matching visual is already in the list */ + for (i=0; i<NumVisuals; i++) { + XMesaVisual v = VisualTable[i]; + if (v->display == dpy + && v->mesa_visual.level == level + && v->mesa_visual.numAuxBuffers == numAuxBuffers + && v->mesa_visual.samples == num_samples + && v->ximage_flag == ximageFlag + && v->mesa_visual.doubleBufferMode == dbFlag + && v->mesa_visual.stereoMode == stereoFlag + && (v->mesa_visual.alphaBits > 0) == alphaFlag + && (v->mesa_visual.depthBits >= depth_size || depth_size == 0) + && (v->mesa_visual.stencilBits >= stencil_size || stencil_size == 0) + && (v->mesa_visual.accumRedBits >= accumRedSize || accumRedSize == 0) + && (v->mesa_visual.accumGreenBits >= accumGreenSize || accumGreenSize == 0) + && (v->mesa_visual.accumBlueBits >= accumBlueSize || accumBlueSize == 0) + && (v->mesa_visual.accumAlphaBits >= accumAlphaSize || accumAlphaSize == 0)) { + /* now either compare XVisualInfo pointers or visual IDs */ + if ((!comparePointers && v->visinfo->visualid == vinfo->visualid) + || (comparePointers && v->vishandle == vinfo)) { + return v; + } + } + } + + /* Create a new visual and add it to the list. */ + + xmvis = XMesaCreateVisual( dpy, vinfo, rgbFlag, alphaFlag, dbFlag, + stereoFlag, ximageFlag, + depth_size, stencil_size, + accumRedSize, accumBlueSize, + accumBlueSize, accumAlphaSize, num_samples, level, + GLX_NONE_EXT ); + if (xmvis) { + /* Save a copy of the pointer now so we can find this visual again + * if we need to search for it in find_glx_visual(). + */ + xmvis->vishandle = vinfo; + /* Allocate more space for additional visual */ + VisualTable = realloc(VisualTable, sizeof(XMesaVisual) * (NumVisuals + 1)); + /* add xmvis to the list */ + VisualTable[NumVisuals] = xmvis; + NumVisuals++; + /* XXX minor hack, because XMesaCreateVisual doesn't support an + * aux buffers parameter. + */ + xmvis->mesa_visual.numAuxBuffers = numAuxBuffers; + } + return xmvis; +} + + +/** + * Return the default number of bits for the Z buffer. + * If defined, use the MESA_GLX_DEPTH_BITS env var value. + * Otherwise, use the DEFAULT_SOFTWARE_DEPTH_BITS constant. + * XXX probably do the same thing for stencil, accum, etc. + */ +static GLint +default_depth_bits(void) +{ + int zBits; + const char *zEnv = getenv("MESA_GLX_DEPTH_BITS"); + if (zEnv) + zBits = atoi(zEnv); + else + zBits = 24; + return zBits; +} + +static GLint +default_alpha_bits(void) +{ + int aBits; + const char *aEnv = getenv("MESA_GLX_ALPHA_BITS"); + if (aEnv) + aBits = atoi(aEnv); + else + aBits = 0; + return aBits; +} + +static GLint +default_accum_bits(void) +{ + return 16; +} + + + +/* + * Create a GLX visual from a regular XVisualInfo. + * This is called when Fake GLX is given an XVisualInfo which wasn't + * returned by glXChooseVisual. Since this is the first time we're + * considering this visual we'll take a guess at reasonable values + * for depth buffer size, stencil size, accum size, etc. + * This is the best we can do with a client-side emulation of GLX. + */ +static XMesaVisual +create_glx_visual( Display *dpy, XVisualInfo *visinfo ) +{ + GLint zBits = default_depth_bits(); + GLint accBits = default_accum_bits(); + GLboolean alphaFlag = default_alpha_bits() > 0; + + if (is_usable_visual( visinfo )) { + /* Configure this visual as RGB, double-buffered, depth-buffered. */ + /* This is surely wrong for some people's needs but what else */ + /* can be done? They should use glXChooseVisual(). */ + return save_glx_visual( dpy, visinfo, + GL_TRUE, /* rgb */ + alphaFlag, /* alpha */ + GL_TRUE, /* double */ + GL_FALSE, /* stereo */ + zBits, + 8, /* stencil bits */ + accBits, /* r */ + accBits, /* g */ + accBits, /* b */ + accBits, /* a */ + 0, /* level */ + 0, /* numAux */ + 0 /* numSamples */ + ); + } + else { + _mesa_warning(NULL, "Mesa: error in glXCreateContext: bad visual\n"); + return NULL; + } +} + + + +/* + * Find the GLX visual associated with an XVisualInfo. + */ +static XMesaVisual +find_glx_visual( Display *dpy, XVisualInfo *vinfo ) +{ + int i; + + /* try to match visual id */ + for (i=0;i<NumVisuals;i++) { + if (VisualTable[i]->display==dpy + && VisualTable[i]->visinfo->visualid == vinfo->visualid) { + return VisualTable[i]; + } + } + + /* if that fails, try to match pointers */ + for (i=0;i<NumVisuals;i++) { + if (VisualTable[i]->display==dpy && VisualTable[i]->vishandle==vinfo) { + return VisualTable[i]; + } + } + + return NULL; +} + + +/** + * Try to get an X visual which matches the given arguments. + */ +static XVisualInfo * +get_visual( Display *dpy, int scr, unsigned int depth, int xclass ) +{ + XVisualInfo temp, *vis; + long mask; + int n; + unsigned int default_depth; + int default_class; + + mask = VisualScreenMask | VisualDepthMask | VisualClassMask; + temp.screen = scr; + temp.depth = depth; + temp.CLASS = xclass; + + default_depth = DefaultDepth(dpy,scr); + default_class = DefaultVisual(dpy,scr)->CLASS; + + if (depth==default_depth && xclass==default_class) { + /* try to get root window's visual */ + temp.visualid = DefaultVisual(dpy,scr)->visualid; + mask |= VisualIDMask; + } + + vis = XGetVisualInfo( dpy, mask, &temp, &n ); + + /* In case bits/pixel > 24, make sure color channels are still <=8 bits. + * An SGI Infinite Reality system, for example, can have 30bpp pixels: + * 10 bits per color channel. Mesa's limited to a max of 8 bits/channel. + */ + if (vis && depth > 24 && (xclass==TrueColor || xclass==DirectColor)) { + if (util_bitcount((GLuint) vis->red_mask ) <= 8 && + util_bitcount((GLuint) vis->green_mask) <= 8 && + util_bitcount((GLuint) vis->blue_mask ) <= 8) { + return vis; + } + else { + free((void *) vis); + return NULL; + } + } + + return vis; +} + + +/* + * Retrieve the value of the given environment variable and find + * the X visual which matches it. + * Input: dpy - the display + * screen - the screen number + * varname - the name of the environment variable + * Return: an XVisualInfo pointer to NULL if error. + */ +static XVisualInfo * +get_env_visual(Display *dpy, int scr, const char *varname) +{ + char value[100], type[100]; + int depth, xclass = -1; + XVisualInfo *vis; + + if (!getenv( varname )) { + return NULL; + } + + strncpy( value, getenv(varname), 100 ); + value[99] = 0; + + sscanf( value, "%s %d", type, &depth ); + + if (strcmp(type,"TrueColor")==0) xclass = TrueColor; + else if (strcmp(type,"DirectColor")==0) xclass = DirectColor; + else if (strcmp(type,"PseudoColor")==0) xclass = PseudoColor; + else if (strcmp(type,"StaticColor")==0) xclass = StaticColor; + else if (strcmp(type,"GrayScale")==0) xclass = GrayScale; + else if (strcmp(type,"StaticGray")==0) xclass = StaticGray; + + if (xclass>-1 && depth>0) { + vis = get_visual( dpy, scr, depth, xclass ); + if (vis) { + return vis; + } + } + + _mesa_warning(NULL, "GLX unable to find visual class=%s, depth=%d.", + type, depth); + + return NULL; +} + + + +/* + * Select an X visual which satisfies the RGBA flag and minimum depth. + * Input: dpy, + * screen - X display and screen number + * min_depth - minimum visual depth + * preferred_class - preferred GLX visual class or DONT_CARE + * Return: pointer to an XVisualInfo or NULL. + */ +static XVisualInfo * +choose_x_visual( Display *dpy, int screen, int min_depth, + int preferred_class ) +{ + XVisualInfo *vis; + int xclass, visclass = 0; + int depth; + + /* First see if the MESA_RGB_VISUAL env var is defined */ + vis = get_env_visual( dpy, screen, "MESA_RGB_VISUAL" ); + if (vis) { + return vis; + } + /* Otherwise, search for a suitable visual */ + if (preferred_class==DONT_CARE) { + for (xclass=0;xclass<6;xclass++) { + switch (xclass) { + case 0: visclass = TrueColor; break; + case 1: visclass = DirectColor; break; + case 2: visclass = PseudoColor; break; + case 3: visclass = StaticColor; break; + case 4: visclass = GrayScale; break; + case 5: visclass = StaticGray; break; + } + if (min_depth==0) { + /* start with shallowest */ + for (depth=0;depth<=32;depth++) { + if (visclass==TrueColor && depth==8) { + /* Special case: try to get 8-bit PseudoColor before */ + /* 8-bit TrueColor */ + vis = get_visual( dpy, screen, 8, PseudoColor ); + if (vis) { + return vis; + } + } + vis = get_visual( dpy, screen, depth, visclass ); + if (vis) { + return vis; + } + } + } + else { + /* start with deepest */ + for (depth=32;depth>=min_depth;depth--) { + if (visclass==TrueColor && depth==8) { + /* Special case: try to get 8-bit PseudoColor before */ + /* 8-bit TrueColor */ + vis = get_visual( dpy, screen, 8, PseudoColor ); + if (vis) { + return vis; + } + } + vis = get_visual( dpy, screen, depth, visclass ); + if (vis) { + return vis; + } + } + } + } + } + else { + /* search for a specific visual class */ + switch (preferred_class) { + case GLX_TRUE_COLOR_EXT: visclass = TrueColor; break; + case GLX_DIRECT_COLOR_EXT: visclass = DirectColor; break; + case GLX_PSEUDO_COLOR_EXT: visclass = PseudoColor; break; + case GLX_STATIC_COLOR_EXT: visclass = StaticColor; break; + case GLX_GRAY_SCALE_EXT: visclass = GrayScale; break; + case GLX_STATIC_GRAY_EXT: visclass = StaticGray; break; + default: return NULL; + } + if (min_depth==0) { + /* start with shallowest */ + for (depth=0;depth<=32;depth++) { + vis = get_visual( dpy, screen, depth, visclass ); + if (vis) { + return vis; + } + } + } + else { + /* start with deepest */ + for (depth=32;depth>=min_depth;depth--) { + vis = get_visual( dpy, screen, depth, visclass ); + if (vis) { + return vis; + } + } + } + } + + /* didn't find a visual */ + return NULL; +} + + + + +/**********************************************************************/ +/*** Display-related functions ***/ +/**********************************************************************/ + + +/** + * Free all XMesaVisuals which are associated with the given display. + */ +static void +destroy_visuals_on_display(Display *dpy) +{ + int i; + for (i = 0; i < NumVisuals; i++) { + if (VisualTable[i]->display == dpy) { + /* remove this visual */ + int j; + free(VisualTable[i]); + for (j = i; j < NumVisuals - 1; j++) + VisualTable[j] = VisualTable[j + 1]; + NumVisuals--; + } + } +} + + +/** + * Called from XCloseDisplay() to let us free our display-related data. + */ +static int +close_display_callback(Display *dpy, XExtCodes *codes) +{ + xmesa_destroy_buffers_on_display(dpy); + destroy_visuals_on_display(dpy); + xmesa_close_display(dpy); + return 0; +} + + +/** + * Look for the named extension on given display and return a pointer + * to the _XExtension data, or NULL if extension not found. + */ +static _XExtension * +lookup_extension(Display *dpy, const char *extName) +{ + _XExtension *ext; + for (ext = dpy->ext_procs; ext; ext = ext->next) { + if (ext->name && strcmp(ext->name, extName) == 0) { + return ext; + } + } + return NULL; +} + + +/** + * Whenever we're given a new Display pointer, call this function to + * register our close_display_callback function. + */ +static void +register_with_display(Display *dpy) +{ + const char *extName = "MesaGLX"; + _XExtension *ext; + + ext = lookup_extension(dpy, extName); + if (!ext) { + XExtCodes *c = XAddExtension(dpy); + ext = dpy->ext_procs; /* new extension is at head of list */ + assert(c->extension == ext->codes.extension); + (void) c; + ext->name = strdup(extName); + ext->close_display = close_display_callback; + } +} + + +/** + * Fake an error. + */ +static int +generate_error(Display *dpy, + unsigned char error_code, + XID resourceid, + unsigned char minor_code, + Bool core) +{ + XErrorHandler handler; + int major_opcode; + int first_event; + int first_error; + XEvent event; + + handler = XSetErrorHandler(NULL); + XSetErrorHandler(handler); + if (!handler) { + return 0; + } + + if (!XQueryExtension(dpy, GLX_EXTENSION_NAME, &major_opcode, &first_event, &first_error)) { + major_opcode = 0; + first_event = 0; + first_error = 0; + } + + if (!core) { + error_code += first_error; + } + + memset(&event, 0, sizeof event); + + event.xerror.type = X_Error; + event.xerror.display = dpy; + event.xerror.resourceid = resourceid; + event.xerror.serial = NextRequest(dpy) - 1; + event.xerror.error_code = error_code; + event.xerror.request_code = major_opcode; + event.xerror.minor_code = minor_code; + + return handler(dpy, &event.xerror); +} + + +/**********************************************************************/ +/*** Begin Fake GLX API Functions ***/ +/**********************************************************************/ + + +/** + * Helper used by glXChooseVisual and glXChooseFBConfig. + * The fbConfig parameter must be GL_FALSE for the former and GL_TRUE for + * the later. + * In either case, the attribute list is terminated with the value 'None'. + */ +static XMesaVisual +choose_visual( Display *dpy, int screen, const int *list, GLboolean fbConfig ) +{ + const GLboolean rgbModeDefault = fbConfig; + const int *parselist; + XVisualInfo *vis; + int min_red=0, min_green=0, min_blue=0; + GLboolean rgb_flag = rgbModeDefault; + GLboolean alpha_flag = GL_FALSE; + GLboolean double_flag = GL_FALSE; + GLboolean stereo_flag = GL_FALSE; + GLint depth_size = 0; + GLint stencil_size = 0; + GLint accumRedSize = 0; + GLint accumGreenSize = 0; + GLint accumBlueSize = 0; + GLint accumAlphaSize = 0; + int level = 0; + int visual_type = DONT_CARE; + GLint caveat = DONT_CARE; + XMesaVisual xmvis = NULL; + int desiredVisualID = -1; + int numAux = 0; + GLint num_samples = 0; + + if (xmesa_init( dpy ) != 0) { + _mesa_warning(NULL, "Failed to initialize display"); + return NULL; + } + + parselist = list; + + while (*parselist) { + + if (fbConfig && + parselist[1] == GLX_DONT_CARE && + parselist[0] != GLX_LEVEL) { + /* For glXChooseFBConfig(), skip attributes whose value is + * GLX_DONT_CARE, unless it's GLX_LEVEL (which can legitimately be + * a negative value). + * + * From page 17 (23 of the pdf) of the GLX 1.4 spec: + * GLX DONT CARE may be specified for all attributes except GLX LEVEL. + */ + parselist += 2; + continue; + } + + switch (*parselist) { + case GLX_USE_GL: + if (fbConfig) { + /* invalid token */ + return NULL; + } + else { + /* skip */ + parselist++; + } + break; + case GLX_BUFFER_SIZE: + parselist++; + parselist++; + break; + case GLX_LEVEL: + parselist++; + level = *parselist++; + break; + case GLX_RGBA: + if (fbConfig) { + /* invalid token */ + return NULL; + } + else { + rgb_flag = GL_TRUE; + parselist++; + } + break; + case GLX_DOUBLEBUFFER: + parselist++; + if (fbConfig) { + double_flag = *parselist++; + } + else { + double_flag = GL_TRUE; + } + break; + case GLX_STEREO: + parselist++; + if (fbConfig) { + stereo_flag = *parselist++; + } + else { + stereo_flag = GL_TRUE; + } + break; + case GLX_AUX_BUFFERS: + parselist++; + numAux = *parselist++; + if (numAux > MAX_AUX_BUFFERS) + return NULL; + break; + case GLX_RED_SIZE: + parselist++; + min_red = *parselist++; + break; + case GLX_GREEN_SIZE: + parselist++; + min_green = *parselist++; + break; + case GLX_BLUE_SIZE: + parselist++; + min_blue = *parselist++; + break; + case GLX_ALPHA_SIZE: + parselist++; + { + GLint size = *parselist++; + alpha_flag = size ? GL_TRUE : GL_FALSE; + } + break; + case GLX_DEPTH_SIZE: + parselist++; + depth_size = *parselist++; + break; + case GLX_STENCIL_SIZE: + parselist++; + stencil_size = *parselist++; + break; + case GLX_ACCUM_RED_SIZE: + parselist++; + { + GLint size = *parselist++; + accumRedSize = MAX2( accumRedSize, size ); + } + break; + case GLX_ACCUM_GREEN_SIZE: + parselist++; + { + GLint size = *parselist++; + accumGreenSize = MAX2( accumGreenSize, size ); + } + break; + case GLX_ACCUM_BLUE_SIZE: + parselist++; + { + GLint size = *parselist++; + accumBlueSize = MAX2( accumBlueSize, size ); + } + break; + case GLX_ACCUM_ALPHA_SIZE: + parselist++; + { + GLint size = *parselist++; + accumAlphaSize = MAX2( accumAlphaSize, size ); + } + break; + + /* + * GLX_EXT_visual_info extension + */ + case GLX_X_VISUAL_TYPE_EXT: + parselist++; + visual_type = *parselist++; + break; + case GLX_TRANSPARENT_TYPE_EXT: + parselist++; + parselist++; + break; + case GLX_TRANSPARENT_INDEX_VALUE_EXT: + parselist++; + parselist++; + break; + case GLX_TRANSPARENT_RED_VALUE_EXT: + case GLX_TRANSPARENT_GREEN_VALUE_EXT: + case GLX_TRANSPARENT_BLUE_VALUE_EXT: + case GLX_TRANSPARENT_ALPHA_VALUE_EXT: + /* ignore */ + parselist++; + parselist++; + break; + + /* + * GLX_EXT_visual_info extension + */ + case GLX_VISUAL_CAVEAT_EXT: + parselist++; + caveat = *parselist++; /* ignored for now */ + break; + + /* + * GLX_ARB_multisample + */ + case GLX_SAMPLE_BUFFERS_ARB: + /* ignore */ + parselist++; + parselist++; + break; + case GLX_SAMPLES_ARB: + parselist++; + num_samples = *parselist++; + break; + + /* + * FBConfig attribs. + */ + case GLX_RENDER_TYPE: + if (!fbConfig) + return NULL; + parselist++; + if (*parselist & GLX_RGBA_BIT) { + rgb_flag = GL_TRUE; + } + else if (*parselist & GLX_COLOR_INDEX_BIT) { + rgb_flag = GL_FALSE; + } + else if (*parselist == 0) { + rgb_flag = GL_TRUE; + } + parselist++; + break; + case GLX_DRAWABLE_TYPE: + if (!fbConfig) + return NULL; + parselist++; + if (*parselist & ~(GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT)) { + return NULL; /* bad bit */ + } + parselist++; + break; + case GLX_FBCONFIG_ID: + case GLX_VISUAL_ID: + if (!fbConfig) + return NULL; + parselist++; + desiredVisualID = *parselist++; + break; + case GLX_X_RENDERABLE: + case GLX_MAX_PBUFFER_WIDTH: + case GLX_MAX_PBUFFER_HEIGHT: + case GLX_MAX_PBUFFER_PIXELS: + if (!fbConfig) + return NULL; /* invalid config option */ + parselist += 2; /* ignore the parameter */ + break; + + case GLX_BIND_TO_TEXTURE_RGB_EXT: + parselist++; /*skip*/ + break; + case GLX_BIND_TO_TEXTURE_RGBA_EXT: + parselist++; /*skip*/ + break; + case GLX_BIND_TO_MIPMAP_TEXTURE_EXT: + parselist++; /*skip*/ + break; + case GLX_BIND_TO_TEXTURE_TARGETS_EXT: + parselist++; + if (*parselist & ~(GLX_TEXTURE_1D_BIT_EXT | + GLX_TEXTURE_2D_BIT_EXT | + GLX_TEXTURE_RECTANGLE_BIT_EXT)) { + /* invalid bit */ + return NULL; + } + break; + case GLX_Y_INVERTED_EXT: + parselist++; /*skip*/ + break; + + case None: + /* end of list */ + break; + + default: + /* undefined attribute */ + _mesa_warning(NULL, "unexpected attrib 0x%x in choose_visual()", + *parselist); + return NULL; + } + } + + (void) caveat; + + if (num_samples < 0) { + _mesa_warning(NULL, "GLX_SAMPLES_ARB: number of samples must not be negative"); + return NULL; + } + + /* + * Since we're only simulating the GLX extension this function will never + * find any real GL visuals. Instead, all we can do is try to find an RGB + * or CI visual of appropriate depth. Other requested attributes such as + * double buffering, depth buffer, etc. will be associated with the X + * visual and stored in the VisualTable[]. + */ + if (desiredVisualID != -1) { + /* try to get a specific visual, by visualID */ + XVisualInfo temp; + int n; + temp.visualid = desiredVisualID; + temp.screen = screen; + vis = XGetVisualInfo(dpy, VisualIDMask | VisualScreenMask, &temp, &n); + if (vis) { + /* give the visual some useful GLX attributes */ + double_flag = GL_TRUE; + rgb_flag = GL_TRUE; + } + } + else if (level==0) { + /* normal color planes */ + /* Get an RGB visual */ + int min_rgb = min_red + min_green + min_blue; + if (min_rgb>1 && min_rgb<8) { + /* a special case to be sure we can get a monochrome visual */ + min_rgb = 1; + } + vis = choose_x_visual( dpy, screen, min_rgb, visual_type ); + } + else { + _mesa_warning(NULL, "overlay not supported"); + return NULL; + } + + if (vis) { + /* Note: we're not exactly obeying the glXChooseVisual rules here. + * When GLX_DEPTH_SIZE = 1 is specified we're supposed to choose the + * largest depth buffer size, which is 32bits/value. Instead, we + * return 16 to maintain performance with earlier versions of Mesa. + */ + if (stencil_size > 0) + depth_size = 24; /* if Z and stencil, always use 24+8 format */ + else if (depth_size > 24) + depth_size = 32; + else if (depth_size > 16) + depth_size = 24; + else if (depth_size > 0) { + depth_size = default_depth_bits(); + } + + if (!alpha_flag) { + alpha_flag = default_alpha_bits() > 0; + } + + /* we only support one size of stencil and accum buffers. */ + if (stencil_size > 0) + stencil_size = 8; + + if (accumRedSize > 0 || + accumGreenSize > 0 || + accumBlueSize > 0 || + accumAlphaSize > 0) { + + accumRedSize = + accumGreenSize = + accumBlueSize = default_accum_bits(); + + accumAlphaSize = alpha_flag ? accumRedSize : 0; + } + + xmvis = save_glx_visual( dpy, vis, rgb_flag, alpha_flag, double_flag, + stereo_flag, depth_size, stencil_size, + accumRedSize, accumGreenSize, + accumBlueSize, accumAlphaSize, level, numAux, + num_samples ); + } + + return xmvis; +} + + +PUBLIC XVisualInfo * +glXChooseVisual( Display *dpy, int screen, int *list ) +{ + XMesaVisual xmvis; + + /* register ourselves as an extension on this display */ + register_with_display(dpy); + + xmvis = choose_visual(dpy, screen, list, GL_FALSE); + if (xmvis) { + /* create a new vishandle - the cached one may be stale */ + xmvis->vishandle = malloc(sizeof(XVisualInfo)); + if (xmvis->vishandle) { + memcpy(xmvis->vishandle, xmvis->visinfo, sizeof(XVisualInfo)); + } + return xmvis->vishandle; + } + else + return NULL; +} + + +/** + * Helper function used by other glXCreateContext functions. + */ +static GLXContext +create_context(Display *dpy, XMesaVisual xmvis, + XMesaContext shareCtx, Bool direct, + unsigned major, unsigned minor, + unsigned profileMask, unsigned contextFlags) +{ + GLXContext glxCtx; + + if (!dpy || !xmvis) + return 0; + + glxCtx = CALLOC_STRUCT(__GLXcontextRec); + if (!glxCtx) + return 0; + + /* deallocate unused windows/buffers */ +#if 0 + XMesaGarbageCollect(); +#endif + + glxCtx->xmesaContext = XMesaCreateContext(xmvis, shareCtx, major, minor, + profileMask, contextFlags); + if (!glxCtx->xmesaContext) { + free(glxCtx); + return NULL; + } + + glxCtx->isDirect = DEFAULT_DIRECT; + glxCtx->currentDpy = dpy; + glxCtx->xid = (XID) glxCtx; /* self pointer */ + + return glxCtx; +} + + +PUBLIC GLXContext +glXCreateContext( Display *dpy, XVisualInfo *visinfo, + GLXContext shareCtx, Bool direct ) +{ + XMesaVisual xmvis; + + xmvis = find_glx_visual( dpy, visinfo ); + if (!xmvis) { + /* This visual wasn't found with glXChooseVisual() */ + xmvis = create_glx_visual( dpy, visinfo ); + if (!xmvis) { + /* unusable visual */ + return NULL; + } + } + + return create_context(dpy, xmvis, + shareCtx ? shareCtx->xmesaContext : NULL, + direct, + 1, 0, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 0x0); +} + + +/* GLX 1.3 and later */ +PUBLIC Bool +glXMakeContextCurrent( Display *dpy, GLXDrawable draw, + GLXDrawable read, GLXContext ctx ) +{ + GLXContext glxCtx = ctx; + GLXContext current = GetCurrentContext(); + static boolean firsttime = 1, no_rast = 0; + + if (firsttime) { + no_rast = getenv("SP_NO_RAST") != NULL; + firsttime = 0; + } + + if (ctx) { + XMesaBuffer drawBuffer = NULL, readBuffer = NULL; + XMesaContext xmctx = glxCtx->xmesaContext; + + /* either both must be null, or both must be non-null */ + if (!draw != !read) + return False; + + if (draw) { + /* Find the XMesaBuffer which corresponds to 'draw' */ + drawBuffer = XMesaFindBuffer( dpy, draw ); + if (!drawBuffer) { + /* drawable must be a new window! */ + drawBuffer = XMesaCreateWindowBuffer( xmctx->xm_visual, draw ); + if (!drawBuffer) { + /* Out of memory, or context/drawable depth mismatch */ + return False; + } + } + } + + if (read) { + /* Find the XMesaBuffer which corresponds to 'read' */ + readBuffer = XMesaFindBuffer( dpy, read ); + if (!readBuffer) { + /* drawable must be a new window! */ + readBuffer = XMesaCreateWindowBuffer( xmctx->xm_visual, read ); + if (!readBuffer) { + /* Out of memory, or context/drawable depth mismatch */ + return False; + } + } + } + + if (no_rast && current == ctx) + return True; + + /* Now make current! */ + if (XMesaMakeCurrent2(xmctx, drawBuffer, readBuffer)) { + ctx->currentDpy = dpy; + ctx->currentDrawable = draw; + ctx->currentReadable = read; + SetCurrentContext(ctx); + return True; + } + else { + return False; + } + } + else if (!ctx && !draw && !read) { + /* release current context w/out assigning new one. */ + XMesaMakeCurrent2( NULL, NULL, NULL ); + SetCurrentContext(NULL); + return True; + } + else { + /* We were given an invalid set of arguments */ + return False; + } +} + + +PUBLIC Bool +glXMakeCurrent( Display *dpy, GLXDrawable drawable, GLXContext ctx ) +{ + return glXMakeContextCurrent( dpy, drawable, drawable, ctx ); +} + + +PUBLIC GLXContext +glXGetCurrentContext(void) +{ + return GetCurrentContext(); +} + + +PUBLIC Display * +glXGetCurrentDisplay(void) +{ + GLXContext glxCtx = glXGetCurrentContext(); + + return glxCtx ? glxCtx->currentDpy : NULL; +} + + +PUBLIC Display * +glXGetCurrentDisplayEXT(void) +{ + return glXGetCurrentDisplay(); +} + + +PUBLIC GLXDrawable +glXGetCurrentDrawable(void) +{ + GLXContext gc = glXGetCurrentContext(); + return gc ? gc->currentDrawable : 0; +} + + +PUBLIC GLXDrawable +glXGetCurrentReadDrawable(void) +{ + GLXContext gc = glXGetCurrentContext(); + return gc ? gc->currentReadable : 0; +} + + +PUBLIC GLXDrawable +glXGetCurrentReadDrawableSGI(void) +{ + return glXGetCurrentReadDrawable(); +} + + +PUBLIC GLXPixmap +glXCreateGLXPixmap( Display *dpy, XVisualInfo *visinfo, Pixmap pixmap ) +{ + XMesaVisual v; + XMesaBuffer b; + + v = find_glx_visual( dpy, visinfo ); + if (!v) { + v = create_glx_visual( dpy, visinfo ); + if (!v) { + /* unusable visual */ + return 0; + } + } + + b = XMesaCreatePixmapBuffer( v, pixmap, 0 ); + if (!b) { + return 0; + } + return b->ws.drawable; +} + + +/*** GLX_MESA_pixmap_colormap ***/ + +PUBLIC GLXPixmap +glXCreateGLXPixmapMESA( Display *dpy, XVisualInfo *visinfo, + Pixmap pixmap, Colormap cmap ) +{ + XMesaVisual v; + XMesaBuffer b; + + v = find_glx_visual( dpy, visinfo ); + if (!v) { + v = create_glx_visual( dpy, visinfo ); + if (!v) { + /* unusable visual */ + return 0; + } + } + + b = XMesaCreatePixmapBuffer( v, pixmap, cmap ); + if (!b) { + return 0; + } + return b->ws.drawable; +} + + +PUBLIC void +glXDestroyGLXPixmap( Display *dpy, GLXPixmap pixmap ) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, pixmap); + if (b) { + XMesaDestroyBuffer(b); + } + else if (getenv("MESA_DEBUG")) { + _mesa_warning(NULL, "Mesa: glXDestroyGLXPixmap: invalid pixmap\n"); + } +} + + +PUBLIC void +glXCopyContext( Display *dpy, GLXContext src, GLXContext dst, + unsigned long mask ) +{ + XMesaContext xm_src = src->xmesaContext; + XMesaContext xm_dst = dst->xmesaContext; + (void) dpy; + if (GetCurrentContext() == src) { + glFlush(); + } + XMesaCopyContext(xm_src, xm_dst, mask); +} + + +PUBLIC Bool +glXQueryExtension( Display *dpy, int *errorBase, int *eventBase ) +{ + int op, ev, err; + /* Mesa's GLX isn't really an X extension but we try to act like one. */ + if (!XQueryExtension(dpy, GLX_EXTENSION_NAME, &op, &ev, &err)) + ev = err = 0; + if (errorBase) + *errorBase = err; + if (eventBase) + *eventBase = ev; + return True; /* we're faking GLX so always return success */ +} + + +PUBLIC void +glXDestroyContext( Display *dpy, GLXContext ctx ) +{ + if (ctx) { + GLXContext glxCtx = ctx; + (void) dpy; + XMesaDestroyContext( glxCtx->xmesaContext ); + XMesaGarbageCollect(); + free(glxCtx); + } +} + + +PUBLIC Bool +glXIsDirect( Display *dpy, GLXContext ctx ) +{ + return ctx ? ctx->isDirect : False; +} + + + +PUBLIC void +glXSwapBuffers( Display *dpy, GLXDrawable drawable ) +{ + XMesaBuffer buffer = XMesaFindBuffer( dpy, drawable ); + static boolean firsttime = 1, no_rast = 0; + + if (firsttime) { + no_rast = getenv("SP_NO_RAST") != NULL; + firsttime = 0; + } + + if (no_rast) + return; + + if (buffer) { + XMesaSwapBuffers(buffer); + } + else if (getenv("MESA_DEBUG")) { + _mesa_warning(NULL, "glXSwapBuffers: invalid drawable 0x%x\n", + (int) drawable); + } +} + + + +/*** GLX_MESA_copy_sub_buffer ***/ + +PUBLIC void +glXCopySubBufferMESA(Display *dpy, GLXDrawable drawable, + int x, int y, int width, int height) +{ + XMesaBuffer buffer = XMesaFindBuffer( dpy, drawable ); + if (buffer) { + XMesaCopySubBuffer(buffer, x, y, width, height); + } + else if (getenv("MESA_DEBUG")) { + _mesa_warning(NULL, "Mesa: glXCopySubBufferMESA: invalid drawable\n"); + } +} + + +PUBLIC Bool +glXQueryVersion( Display *dpy, int *maj, int *min ) +{ + (void) dpy; + /* Return GLX version, not Mesa version */ + assert(CLIENT_MAJOR_VERSION == SERVER_MAJOR_VERSION); + *maj = CLIENT_MAJOR_VERSION; + *min = MIN2( CLIENT_MINOR_VERSION, SERVER_MINOR_VERSION ); + return True; +} + + +/* + * Query the GLX attributes of the given XVisualInfo. + */ +static int +get_config( XMesaVisual xmvis, int attrib, int *value, GLboolean fbconfig ) +{ + assert(xmvis); + switch(attrib) { + case GLX_USE_GL: + if (fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = (int) True; + return 0; + case GLX_BUFFER_SIZE: + *value = xmvis->visinfo->depth; + return 0; + case GLX_LEVEL: + *value = xmvis->mesa_visual.level; + return 0; + case GLX_RGBA: + if (fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = True; + return 0; + case GLX_DOUBLEBUFFER: + *value = (int) xmvis->mesa_visual.doubleBufferMode; + return 0; + case GLX_STEREO: + *value = (int) xmvis->mesa_visual.stereoMode; + return 0; + case GLX_AUX_BUFFERS: + *value = xmvis->mesa_visual.numAuxBuffers; + return 0; + case GLX_RED_SIZE: + *value = xmvis->mesa_visual.redBits; + return 0; + case GLX_GREEN_SIZE: + *value = xmvis->mesa_visual.greenBits; + return 0; + case GLX_BLUE_SIZE: + *value = xmvis->mesa_visual.blueBits; + return 0; + case GLX_ALPHA_SIZE: + *value = xmvis->mesa_visual.alphaBits; + return 0; + case GLX_DEPTH_SIZE: + *value = xmvis->mesa_visual.depthBits; + return 0; + case GLX_STENCIL_SIZE: + *value = xmvis->mesa_visual.stencilBits; + return 0; + case GLX_ACCUM_RED_SIZE: + *value = xmvis->mesa_visual.accumRedBits; + return 0; + case GLX_ACCUM_GREEN_SIZE: + *value = xmvis->mesa_visual.accumGreenBits; + return 0; + case GLX_ACCUM_BLUE_SIZE: + *value = xmvis->mesa_visual.accumBlueBits; + return 0; + case GLX_ACCUM_ALPHA_SIZE: + *value = xmvis->mesa_visual.accumAlphaBits; + return 0; + + /* + * GLX_EXT_visual_info extension + */ + case GLX_X_VISUAL_TYPE_EXT: + switch (xmvis->visinfo->CLASS) { + case StaticGray: *value = GLX_STATIC_GRAY_EXT; return 0; + case GrayScale: *value = GLX_GRAY_SCALE_EXT; return 0; + case StaticColor: *value = GLX_STATIC_GRAY_EXT; return 0; + case PseudoColor: *value = GLX_PSEUDO_COLOR_EXT; return 0; + case TrueColor: *value = GLX_TRUE_COLOR_EXT; return 0; + case DirectColor: *value = GLX_DIRECT_COLOR_EXT; return 0; + } + return 0; + case GLX_TRANSPARENT_TYPE_EXT: + /* normal planes */ + *value = GLX_NONE_EXT; + return 0; + case GLX_TRANSPARENT_INDEX_VALUE_EXT: + /* undefined */ + return 0; + case GLX_TRANSPARENT_RED_VALUE_EXT: + /* undefined */ + return 0; + case GLX_TRANSPARENT_GREEN_VALUE_EXT: + /* undefined */ + return 0; + case GLX_TRANSPARENT_BLUE_VALUE_EXT: + /* undefined */ + return 0; + case GLX_TRANSPARENT_ALPHA_VALUE_EXT: + /* undefined */ + return 0; + + /* + * GLX_EXT_visual_info extension + */ + case GLX_VISUAL_CAVEAT_EXT: + /* test for zero, just in case */ + if (xmvis->mesa_visual.visualRating > 0) + *value = xmvis->mesa_visual.visualRating; + else + *value = GLX_NONE_EXT; + return 0; + + /* + * GLX_ARB_multisample + */ + case GLX_SAMPLE_BUFFERS_ARB: + *value = xmvis->mesa_visual.sampleBuffers; + return 0; + case GLX_SAMPLES_ARB: + *value = xmvis->mesa_visual.samples; + return 0; + + /* + * For FBConfigs: + */ + case GLX_SCREEN_EXT: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = xmvis->visinfo->screen; + break; + case GLX_DRAWABLE_TYPE: /*SGIX too */ + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; + break; + case GLX_RENDER_TYPE_SGIX: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = GLX_RGBA_BIT; + break; + case GLX_X_RENDERABLE_SGIX: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = True; /* XXX really? */ + break; + case GLX_FBCONFIG_ID_SGIX: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = xmvis->visinfo->visualid; + break; + case GLX_MAX_PBUFFER_WIDTH: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + /* XXX should be same as ctx->Const.MaxRenderbufferSize */ + *value = DisplayWidth(xmvis->display, xmvis->visinfo->screen); + break; + case GLX_MAX_PBUFFER_HEIGHT: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = DisplayHeight(xmvis->display, xmvis->visinfo->screen); + break; + case GLX_MAX_PBUFFER_PIXELS: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = DisplayWidth(xmvis->display, xmvis->visinfo->screen) * + DisplayHeight(xmvis->display, xmvis->visinfo->screen); + break; + case GLX_VISUAL_ID: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = xmvis->visinfo->visualid; + break; + + case GLX_BIND_TO_TEXTURE_RGB_EXT: + *value = True; /*XXX*/ + break; + case GLX_BIND_TO_TEXTURE_RGBA_EXT: + /* XXX review */ + *value = xmvis->mesa_visual.alphaBits > 0 ? True : False; + break; + case GLX_BIND_TO_MIPMAP_TEXTURE_EXT: + *value = True; /*XXX*/ + break; + case GLX_BIND_TO_TEXTURE_TARGETS_EXT: + *value = (GLX_TEXTURE_1D_BIT_EXT | + GLX_TEXTURE_2D_BIT_EXT | + GLX_TEXTURE_RECTANGLE_BIT_EXT); /*XXX*/ + break; + case GLX_Y_INVERTED_EXT: + *value = True; /*XXX*/ + break; + + default: + return GLX_BAD_ATTRIBUTE; + } + return Success; +} + + +PUBLIC int +glXGetConfig( Display *dpy, XVisualInfo *visinfo, + int attrib, int *value ) +{ + XMesaVisual xmvis; + int k; + if (!dpy || !visinfo) + return GLX_BAD_ATTRIBUTE; + + xmvis = find_glx_visual( dpy, visinfo ); + if (!xmvis) { + /* this visual wasn't obtained with glXChooseVisual */ + xmvis = create_glx_visual( dpy, visinfo ); + if (!xmvis) { + /* this visual can't be used for GL rendering */ + if (attrib==GLX_USE_GL) { + *value = (int) False; + return 0; + } + else { + return GLX_BAD_VISUAL; + } + } + } + + k = get_config(xmvis, attrib, value, GL_FALSE); + return k; +} + + +PUBLIC void +glXWaitGL( void ) +{ + XMesaContext xmesa = XMesaGetCurrentContext(); + XMesaFlush( xmesa ); +} + + + +PUBLIC void +glXWaitX( void ) +{ + XMesaContext xmesa = XMesaGetCurrentContext(); + XMesaFlush( xmesa ); +} + + +static const char * +get_extensions( void ) +{ + return EXTENSIONS; +} + + + +/* GLX 1.1 and later */ +PUBLIC const char * +glXQueryExtensionsString( Display *dpy, int screen ) +{ + (void) dpy; + (void) screen; + return get_extensions(); +} + + + +/* GLX 1.1 and later */ +PUBLIC const char * +glXQueryServerString( Display *dpy, int screen, int name ) +{ + static char version[1000]; + sprintf(version, "%d.%d %s", + SERVER_MAJOR_VERSION, SERVER_MINOR_VERSION, xmesa_get_name()); + + (void) dpy; + (void) screen; + + switch (name) { + case GLX_EXTENSIONS: + return get_extensions(); + case GLX_VENDOR: + return VENDOR; + case GLX_VERSION: + return version; + default: + return NULL; + } +} + + + +/* GLX 1.1 and later */ +PUBLIC const char * +glXGetClientString( Display *dpy, int name ) +{ + static char version[1000]; + sprintf(version, "%d.%d %s", CLIENT_MAJOR_VERSION, + CLIENT_MINOR_VERSION, xmesa_get_name()); + + (void) dpy; + + switch (name) { + case GLX_EXTENSIONS: + return get_extensions(); + case GLX_VENDOR: + return VENDOR; + case GLX_VERSION: + return version; + default: + return NULL; + } +} + + + +/* + * GLX 1.3 and later + */ + + +PUBLIC int +glXGetFBConfigAttrib(Display *dpy, GLXFBConfig config, + int attribute, int *value) +{ + XMesaVisual v = (XMesaVisual) config; + (void) dpy; + (void) config; + + if (!dpy || !config || !value) + return -1; + + return get_config(v, attribute, value, GL_TRUE); +} + + +PUBLIC GLXFBConfig * +glXGetFBConfigs( Display *dpy, int screen, int *nelements ) +{ + XVisualInfo *visuals, visTemplate; + const long visMask = VisualScreenMask; + int i; + + /* Get list of all X visuals */ + visTemplate.screen = screen; + visuals = XGetVisualInfo(dpy, visMask, &visTemplate, nelements); + if (*nelements > 0) { + XMesaVisual *results = malloc(*nelements * sizeof(XMesaVisual)); + if (!results) { + *nelements = 0; + return NULL; + } + for (i = 0; i < *nelements; i++) { + results[i] = create_glx_visual(dpy, visuals + i); + if (!results[i]) { + *nelements = i; + break; + } + } + return (GLXFBConfig *) results; + } + return NULL; +} + + +PUBLIC GLXFBConfig * +glXChooseFBConfig(Display *dpy, int screen, + const int *attribList, int *nitems) +{ + XMesaVisual xmvis; + + /* register ourselves as an extension on this display */ + register_with_display(dpy); + + if (!attribList || !attribList[0]) { + /* return list of all configs (per GLX_SGIX_fbconfig spec) */ + return glXGetFBConfigs(dpy, screen, nitems); + } + + xmvis = choose_visual(dpy, screen, attribList, GL_TRUE); + if (xmvis) { + GLXFBConfig *config = malloc(sizeof(XMesaVisual)); + if (!config) { + *nitems = 0; + return NULL; + } + *nitems = 1; + config[0] = (GLXFBConfig) xmvis; + return (GLXFBConfig *) config; + } + else { + *nitems = 0; + return NULL; + } +} + + +PUBLIC XVisualInfo * +glXGetVisualFromFBConfig( Display *dpy, GLXFBConfig config ) +{ + if (dpy && config) { + XMesaVisual xmvis = (XMesaVisual) config; +#if 0 + return xmvis->vishandle; +#else + /* create a new vishandle - the cached one may be stale */ + xmvis->vishandle = malloc(sizeof(XVisualInfo)); + if (xmvis->vishandle) { + memcpy(xmvis->vishandle, xmvis->visinfo, sizeof(XVisualInfo)); + } + return xmvis->vishandle; +#endif + } + else { + return NULL; + } +} + + +PUBLIC GLXWindow +glXCreateWindow(Display *dpy, GLXFBConfig config, Window win, + const int *attribList) +{ + XMesaVisual xmvis = (XMesaVisual) config; + XMesaBuffer xmbuf; + if (!xmvis) + return 0; + + xmbuf = XMesaCreateWindowBuffer(xmvis, win); + if (!xmbuf) + return 0; + + (void) dpy; + (void) attribList; /* Ignored in GLX 1.3 */ + + return win; /* A hack for now */ +} + + +PUBLIC void +glXDestroyWindow( Display *dpy, GLXWindow window ) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, (Drawable) window); + if (b) + XMesaDestroyBuffer(b); + /* don't destroy X window */ +} + + +/* XXX untested */ +PUBLIC GLXPixmap +glXCreatePixmap(Display *dpy, GLXFBConfig config, Pixmap pixmap, + const int *attribList) +{ + XMesaVisual v = (XMesaVisual) config; + XMesaBuffer b; + const int *attr; + int target = 0, format = 0, mipmap = 0; + int value; + + if (!dpy || !config || !pixmap) + return 0; + + for (attr = attribList; attr && *attr; attr++) { + switch (*attr) { + case GLX_TEXTURE_FORMAT_EXT: + attr++; + switch (*attr) { + case GLX_TEXTURE_FORMAT_NONE_EXT: + case GLX_TEXTURE_FORMAT_RGB_EXT: + case GLX_TEXTURE_FORMAT_RGBA_EXT: + format = *attr; + break; + default: + /* error */ + return 0; + } + break; + case GLX_TEXTURE_TARGET_EXT: + attr++; + switch (*attr) { + case GLX_TEXTURE_1D_EXT: + case GLX_TEXTURE_2D_EXT: + case GLX_TEXTURE_RECTANGLE_EXT: + target = *attr; + break; + default: + /* error */ + return 0; + } + break; + case GLX_MIPMAP_TEXTURE_EXT: + attr++; + if (*attr) + mipmap = 1; + break; + default: + /* error */ + return 0; + } + } + + if (format == GLX_TEXTURE_FORMAT_RGB_EXT) { + if (get_config(v, GLX_BIND_TO_TEXTURE_RGB_EXT, + &value, GL_TRUE) != Success + || !value) { + return 0; /* error! */ + } + } + else if (format == GLX_TEXTURE_FORMAT_RGBA_EXT) { + if (get_config(v, GLX_BIND_TO_TEXTURE_RGBA_EXT, + &value, GL_TRUE) != Success + || !value) { + return 0; /* error! */ + } + } + if (mipmap) { + if (get_config(v, GLX_BIND_TO_MIPMAP_TEXTURE_EXT, + &value, GL_TRUE) != Success + || !value) { + return 0; /* error! */ + } + } + if (target == GLX_TEXTURE_1D_EXT) { + if (get_config(v, GLX_BIND_TO_TEXTURE_TARGETS_EXT, + &value, GL_TRUE) != Success + || (value & GLX_TEXTURE_1D_BIT_EXT) == 0) { + return 0; /* error! */ + } + } + else if (target == GLX_TEXTURE_2D_EXT) { + if (get_config(v, GLX_BIND_TO_TEXTURE_TARGETS_EXT, + &value, GL_TRUE) != Success + || (value & GLX_TEXTURE_2D_BIT_EXT) == 0) { + return 0; /* error! */ + } + } + if (target == GLX_TEXTURE_RECTANGLE_EXT) { + if (get_config(v, GLX_BIND_TO_TEXTURE_TARGETS_EXT, + &value, GL_TRUE) != Success + || (value & GLX_TEXTURE_RECTANGLE_BIT_EXT) == 0) { + return 0; /* error! */ + } + } + + if (format || target || mipmap) { + /* texture from pixmap */ + b = XMesaCreatePixmapTextureBuffer(v, pixmap, 0, format, target, mipmap); + } + else { + b = XMesaCreatePixmapBuffer( v, pixmap, 0 ); + } + if (!b) { + return 0; + } + + return pixmap; +} + + +PUBLIC void +glXDestroyPixmap( Display *dpy, GLXPixmap pixmap ) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, (Drawable)pixmap); + if (b) + XMesaDestroyBuffer(b); + /* don't destroy X pixmap */ +} + + +PUBLIC GLXPbuffer +glXCreatePbuffer(Display *dpy, GLXFBConfig config, const int *attribList) +{ + XMesaVisual xmvis = (XMesaVisual) config; + XMesaBuffer xmbuf; + const int *attrib; + int width = 0, height = 0; + GLboolean useLargest = GL_FALSE, preserveContents = GL_FALSE; + + (void) dpy; + + for (attrib = attribList; *attrib; attrib++) { + switch (*attrib) { + case GLX_PBUFFER_WIDTH: + attrib++; + width = *attrib; + break; + case GLX_PBUFFER_HEIGHT: + attrib++; + height = *attrib; + break; + case GLX_PRESERVED_CONTENTS: + attrib++; + preserveContents = *attrib; + break; + case GLX_LARGEST_PBUFFER: + attrib++; + useLargest = *attrib; + break; + default: + return 0; + } + } + + if (width == 0 || height == 0) + return 0; + + if (width > PBUFFER_MAX_SIZE || height > PBUFFER_MAX_SIZE) { + /* If allocation would have failed and GLX_LARGEST_PBUFFER is set, + * allocate the largest possible buffer. + */ + if (useLargest) { + width = PBUFFER_MAX_SIZE; + height = PBUFFER_MAX_SIZE; + } + } + + xmbuf = XMesaCreatePBuffer( xmvis, 0, width, height); + /* A GLXPbuffer handle must be an X Drawable because that's what + * glXMakeCurrent takes. + */ + if (xmbuf) { + xmbuf->largestPbuffer = useLargest; + xmbuf->preservedContents = preserveContents; + return (GLXPbuffer) xmbuf->ws.drawable; + } + else { + return 0; + } +} + + +PUBLIC void +glXDestroyPbuffer( Display *dpy, GLXPbuffer pbuf ) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, pbuf); + if (b) { + XMesaDestroyBuffer(b); + } +} + + +PUBLIC void +glXQueryDrawable(Display *dpy, GLXDrawable draw, int attribute, + unsigned int *value) +{ + GLuint width, height; + XMesaBuffer xmbuf = XMesaFindBuffer(dpy, draw); + if (!xmbuf) { + generate_error(dpy, GLXBadDrawable, draw, X_GLXGetDrawableAttributes, False); + return; + } + + /* make sure buffer's dimensions are up to date */ + xmesa_get_window_size(dpy, xmbuf, &width, &height); + + switch (attribute) { + case GLX_WIDTH: + *value = width; + break; + case GLX_HEIGHT: + *value = height; + break; + case GLX_PRESERVED_CONTENTS: + *value = xmbuf->preservedContents; + break; + case GLX_LARGEST_PBUFFER: + *value = xmbuf->largestPbuffer; + break; + case GLX_FBCONFIG_ID: + *value = xmbuf->xm_visual->visinfo->visualid; + return; + case GLX_TEXTURE_FORMAT_EXT: + *value = xmbuf->TextureFormat; + break; + case GLX_TEXTURE_TARGET_EXT: + *value = xmbuf->TextureTarget; + break; + case GLX_MIPMAP_TEXTURE_EXT: + *value = xmbuf->TextureMipmap; + break; + + default: + generate_error(dpy, BadValue, 0, X_GLXCreateContextAttribsARB, true); + return; + } +} + + +PUBLIC GLXContext +glXCreateNewContext( Display *dpy, GLXFBConfig config, + int renderType, GLXContext shareCtx, Bool direct ) +{ + XMesaVisual xmvis = (XMesaVisual) config; + + if (!dpy || !config || + (renderType != GLX_RGBA_TYPE && renderType != GLX_COLOR_INDEX_TYPE)) + return 0; + + return create_context(dpy, xmvis, + shareCtx ? shareCtx->xmesaContext : NULL, + direct, + 1, 0, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 0x0); +} + + +PUBLIC int +glXQueryContext( Display *dpy, GLXContext ctx, int attribute, int *value ) +{ + GLXContext glxCtx = ctx; + XMesaContext xmctx = glxCtx->xmesaContext; + + (void) dpy; + (void) ctx; + + switch (attribute) { + case GLX_FBCONFIG_ID: + *value = xmctx->xm_visual->visinfo->visualid; + break; + case GLX_RENDER_TYPE: + *value = GLX_RGBA_TYPE; + break; + case GLX_SCREEN: + *value = 0; + return Success; + default: + return GLX_BAD_ATTRIBUTE; + } + return 0; +} + + +PUBLIC void +glXSelectEvent( Display *dpy, GLXDrawable drawable, unsigned long mask ) +{ + XMesaBuffer xmbuf = XMesaFindBuffer(dpy, drawable); + if (xmbuf) + xmbuf->selectedEvents = mask; +} + + +PUBLIC void +glXGetSelectedEvent(Display *dpy, GLXDrawable drawable, unsigned long *mask) +{ + XMesaBuffer xmbuf = XMesaFindBuffer(dpy, drawable); + if (xmbuf) + *mask = xmbuf->selectedEvents; + else + *mask = 0; +} + + + +/*** GLX_SGI_swap_control ***/ + +PUBLIC int +glXSwapIntervalSGI(int interval) +{ + (void) interval; + return 0; +} + + + +/*** GLX_SGI_video_sync ***/ + +static unsigned int FrameCounter = 0; + +PUBLIC int +glXGetVideoSyncSGI(unsigned int *count) +{ + /* this is a bogus implementation */ + *count = FrameCounter++; + return 0; +} + +PUBLIC int +glXWaitVideoSyncSGI(int divisor, int remainder, unsigned int *count) +{ + if (divisor <= 0 || remainder < 0) + return GLX_BAD_VALUE; + /* this is a bogus implementation */ + FrameCounter++; + while (FrameCounter % divisor != remainder) + FrameCounter++; + *count = FrameCounter; + return 0; +} + + + +/*** GLX_SGI_make_current_read ***/ + +PUBLIC Bool +glXMakeCurrentReadSGI(Display *dpy, GLXDrawable draw, GLXDrawable read, + GLXContext ctx) +{ + return glXMakeContextCurrent( dpy, draw, read, ctx ); +} + +/* not used +static GLXDrawable +glXGetCurrentReadDrawableSGI(void) +{ + return 0; +} +*/ + + +/*** GLX_SGIX_video_source ***/ +#if defined(_VL_H) + +PUBLIC GLXVideoSourceSGIX +glXCreateGLXVideoSourceSGIX(Display *dpy, int screen, VLServer server, + VLPath path, int nodeClass, VLNode drainNode) +{ + (void) dpy; + (void) screen; + (void) server; + (void) path; + (void) nodeClass; + (void) drainNode; + return 0; +} + +PUBLIC void +glXDestroyGLXVideoSourceSGIX(Display *dpy, GLXVideoSourceSGIX src) +{ + (void) dpy; + (void) src; +} + +#endif + + +/*** GLX_EXT_import_context ***/ + +PUBLIC void +glXFreeContextEXT(Display *dpy, GLXContext context) +{ + (void) dpy; + (void) context; +} + +PUBLIC GLXContextID +glXGetContextIDEXT(const GLXContext context) +{ + (void) context; + return 0; +} + +PUBLIC GLXContext +glXImportContextEXT(Display *dpy, GLXContextID contextID) +{ + (void) dpy; + (void) contextID; + return 0; +} + +PUBLIC int +glXQueryContextInfoEXT(Display *dpy, GLXContext context, int attribute, + int *value) +{ + (void) dpy; + (void) context; + (void) attribute; + (void) value; + return 0; +} + + + +/*** GLX_SGIX_fbconfig ***/ + +PUBLIC int +glXGetFBConfigAttribSGIX(Display *dpy, GLXFBConfigSGIX config, + int attribute, int *value) +{ + return glXGetFBConfigAttrib(dpy, config, attribute, value); +} + +PUBLIC GLXFBConfigSGIX * +glXChooseFBConfigSGIX(Display *dpy, int screen, int *attrib_list, + int *nelements) +{ + return (GLXFBConfig *) glXChooseFBConfig(dpy, screen, + attrib_list, nelements); +} + + +PUBLIC GLXPixmap +glXCreateGLXPixmapWithConfigSGIX(Display *dpy, GLXFBConfigSGIX config, + Pixmap pixmap) +{ + XMesaVisual xmvis = (XMesaVisual) config; + XMesaBuffer xmbuf = XMesaCreatePixmapBuffer(xmvis, pixmap, 0); + return xmbuf->ws.drawable; /* need to return an X ID */ +} + + +PUBLIC GLXContext +glXCreateContextWithConfigSGIX(Display *dpy, GLXFBConfigSGIX config, + int renderType, GLXContext shareCtx, + Bool direct) +{ + XMesaVisual xmvis = (XMesaVisual) config; + + if (!dpy || !config || + (renderType != GLX_RGBA_TYPE && renderType != GLX_COLOR_INDEX_TYPE)) + return 0; + + return create_context(dpy, xmvis, + shareCtx ? shareCtx->xmesaContext : NULL, + direct, + 1, 0, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 0x0); +} + + +PUBLIC XVisualInfo * +glXGetVisualFromFBConfigSGIX(Display *dpy, GLXFBConfigSGIX config) +{ + return glXGetVisualFromFBConfig(dpy, config); +} + + +PUBLIC GLXFBConfigSGIX +glXGetFBConfigFromVisualSGIX(Display *dpy, XVisualInfo *vis) +{ + XMesaVisual xmvis = find_glx_visual(dpy, vis); + if (!xmvis) { + /* This visual wasn't found with glXChooseVisual() */ + xmvis = create_glx_visual(dpy, vis); + } + + return (GLXFBConfigSGIX) xmvis; +} + + + +/*** GLX_SGIX_pbuffer ***/ + +PUBLIC GLXPbufferSGIX +glXCreateGLXPbufferSGIX(Display *dpy, GLXFBConfigSGIX config, + unsigned int width, unsigned int height, + int *attribList) +{ + XMesaVisual xmvis = (XMesaVisual) config; + XMesaBuffer xmbuf; + const int *attrib; + GLboolean useLargest = GL_FALSE, preserveContents = GL_FALSE; + + (void) dpy; + + for (attrib = attribList; attrib && *attrib; attrib++) { + switch (*attrib) { + case GLX_PRESERVED_CONTENTS_SGIX: + attrib++; + preserveContents = *attrib; /* ignored */ + break; + case GLX_LARGEST_PBUFFER_SGIX: + attrib++; + useLargest = *attrib; /* ignored */ + break; + default: + return 0; + } + } + + /* not used at this time */ + (void) useLargest; + (void) preserveContents; + + xmbuf = XMesaCreatePBuffer( xmvis, 0, width, height); + /* A GLXPbuffer handle must be an X Drawable because that's what + * glXMakeCurrent takes. + */ + return (GLXPbuffer) xmbuf->ws.drawable; +} + + +PUBLIC void +glXDestroyGLXPbufferSGIX(Display *dpy, GLXPbufferSGIX pbuf) +{ + XMesaBuffer xmbuf = XMesaFindBuffer(dpy, pbuf); + if (xmbuf) { + XMesaDestroyBuffer(xmbuf); + } +} + + +PUBLIC void +glXQueryGLXPbufferSGIX(Display *dpy, GLXPbufferSGIX pbuf, int attribute, + unsigned int *value) +{ + const XMesaBuffer xmbuf = XMesaFindBuffer(dpy, pbuf); + + if (!xmbuf) { + /* Generate GLXBadPbufferSGIX for bad pbuffer */ + return; + } + + switch (attribute) { + case GLX_PRESERVED_CONTENTS_SGIX: + *value = True; + break; + case GLX_LARGEST_PBUFFER_SGIX: + *value = xmesa_buffer_width(xmbuf) * xmesa_buffer_height(xmbuf); + break; + case GLX_WIDTH_SGIX: + *value = xmesa_buffer_width(xmbuf); + break; + case GLX_HEIGHT_SGIX: + *value = xmesa_buffer_height(xmbuf); + break; + case GLX_EVENT_MASK_SGIX: + *value = 0; /* XXX might be wrong */ + break; + default: + *value = 0; + } +} + + +PUBLIC void +glXSelectEventSGIX(Display *dpy, GLXDrawable drawable, unsigned long mask) +{ + XMesaBuffer xmbuf = XMesaFindBuffer(dpy, drawable); + if (xmbuf) { + /* Note: we'll never generate clobber events */ + xmbuf->selectedEvents = mask; + } +} + + +PUBLIC void +glXGetSelectedEventSGIX(Display *dpy, GLXDrawable drawable, + unsigned long *mask) +{ + XMesaBuffer xmbuf = XMesaFindBuffer(dpy, drawable); + if (xmbuf) { + *mask = xmbuf->selectedEvents; + } + else { + *mask = 0; + } +} + + + +/*** GLX_SGI_cushion ***/ + +PUBLIC void +glXCushionSGI(Display *dpy, Window win, float cushion) +{ + (void) dpy; + (void) win; + (void) cushion; +} + + + +/*** GLX_SGIX_video_resize ***/ + +PUBLIC int +glXBindChannelToWindowSGIX(Display *dpy, int screen, int channel, + Window window) +{ + (void) dpy; + (void) screen; + (void) channel; + (void) window; + return 0; +} + +PUBLIC int +glXChannelRectSGIX(Display *dpy, int screen, int channel, + int x, int y, int w, int h) +{ + (void) dpy; + (void) screen; + (void) channel; + (void) x; + (void) y; + (void) w; + (void) h; + return 0; +} + +PUBLIC int +glXQueryChannelRectSGIX(Display *dpy, int screen, int channel, + int *x, int *y, int *w, int *h) +{ + (void) dpy; + (void) screen; + (void) channel; + (void) x; + (void) y; + (void) w; + (void) h; + return 0; +} + +PUBLIC int +glXQueryChannelDeltasSGIX(Display *dpy, int screen, int channel, + int *dx, int *dy, int *dw, int *dh) +{ + (void) dpy; + (void) screen; + (void) channel; + (void) dx; + (void) dy; + (void) dw; + (void) dh; + return 0; +} + +PUBLIC int +glXChannelRectSyncSGIX(Display *dpy, int screen, int channel, GLenum synctype) +{ + (void) dpy; + (void) screen; + (void) channel; + (void) synctype; + return 0; +} + + + +/*** GLX_SGIX_dmbuffer **/ + +#if defined(_DM_BUFFER_H_) +PUBLIC Bool +glXAssociateDMPbufferSGIX(Display *dpy, GLXPbufferSGIX pbuffer, + DMparams *params, DMbuffer dmbuffer) +{ + (void) dpy; + (void) pbuffer; + (void) params; + (void) dmbuffer; + return False; +} +#endif + + +/*** GLX_SUN_get_transparent_index ***/ + +PUBLIC Status +glXGetTransparentIndexSUN(Display *dpy, Window overlay, Window underlay, + unsigned long *pTransparent) +{ + (void) dpy; + (void) overlay; + (void) underlay; + (void) pTransparent; + return 0; +} + + + +/*** GLX_MESA_release_buffers ***/ + +/* + * Release the depth, stencil, accum buffers attached to a GLXDrawable + * (a window or pixmap) prior to destroying the GLXDrawable. + */ +PUBLIC Bool +glXReleaseBuffersMESA( Display *dpy, GLXDrawable d ) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, d); + if (b) { + XMesaDestroyBuffer(b); + return True; + } + return False; +} + +/*** GLX_EXT_texture_from_pixmap ***/ + +PUBLIC void +glXBindTexImageEXT(Display *dpy, GLXDrawable drawable, int buffer, + const int *attrib_list) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, drawable); + if (b) + XMesaBindTexImage(dpy, b, buffer, attrib_list); +} + +PUBLIC void +glXReleaseTexImageEXT(Display *dpy, GLXDrawable drawable, int buffer) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, drawable); + if (b) + XMesaReleaseTexImage(dpy, b, buffer); +} + + + +/*** GLX_ARB_create_context ***/ + + +GLXContext +glXCreateContextAttribsARB(Display *dpy, GLXFBConfig config, + GLXContext shareCtx, Bool direct, + const int *attrib_list) +{ + XMesaVisual xmvis = (XMesaVisual) config; + int majorVersion = 1, minorVersion = 0; + int contextFlags = 0x0; + int profileMask = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + int renderType = GLX_RGBA_TYPE; + unsigned i; + Bool done = False; + const int contextFlagsAll = (GLX_CONTEXT_DEBUG_BIT_ARB | + GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB); + GLXContext ctx; + + /* parse attrib_list */ + for (i = 0; !done && attrib_list && attrib_list[i]; i++) { + switch (attrib_list[i]) { + case GLX_CONTEXT_MAJOR_VERSION_ARB: + majorVersion = attrib_list[++i]; + break; + case GLX_CONTEXT_MINOR_VERSION_ARB: + minorVersion = attrib_list[++i]; + break; + case GLX_CONTEXT_FLAGS_ARB: + contextFlags = attrib_list[++i]; + break; + case GLX_CONTEXT_PROFILE_MASK_ARB: + profileMask = attrib_list[++i]; + break; + case GLX_RENDER_TYPE: + renderType = attrib_list[++i]; + break; + case 0: + /* end of list */ + done = True; + break; + default: + /* bad attribute */ + generate_error(dpy, BadValue, 0, X_GLXCreateContextAttribsARB, True); + return NULL; + } + } + + /* check contextFlags */ + if (contextFlags & ~contextFlagsAll) { + generate_error(dpy, BadValue, 0, X_GLXCreateContextAttribsARB, True); + return NULL; + } + + /* check profileMask */ + if (profileMask != GLX_CONTEXT_CORE_PROFILE_BIT_ARB && + profileMask != GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB && + profileMask != GLX_CONTEXT_ES_PROFILE_BIT_EXT) { + generate_error(dpy, GLXBadProfileARB, 0, X_GLXCreateContextAttribsARB, False); + return NULL; + } + + /* check renderType */ + if (renderType != GLX_RGBA_TYPE && + renderType != GLX_COLOR_INDEX_TYPE) { + generate_error(dpy, BadValue, 0, X_GLXCreateContextAttribsARB, True); + return NULL; + } + + /* check version */ + if (majorVersion <= 0 || + minorVersion < 0 || + (profileMask != GLX_CONTEXT_ES_PROFILE_BIT_EXT && + ((majorVersion == 1 && minorVersion > 5) || + (majorVersion == 2 && minorVersion > 1) || + (majorVersion == 3 && minorVersion > 3) || + (majorVersion == 4 && minorVersion > 5) || + majorVersion > 4))) { + generate_error(dpy, BadMatch, 0, X_GLXCreateContextAttribsARB, True); + return NULL; + } + if (profileMask == GLX_CONTEXT_ES_PROFILE_BIT_EXT && + ((majorVersion == 1 && minorVersion > 1) || + (majorVersion == 2 && minorVersion > 0) || + (majorVersion == 3 && minorVersion > 1) || + majorVersion > 3)) { + /* GLX_EXT_create_context_es2_profile says nothing to justifying a + * different error code for invalid ES versions, but this is what NVIDIA + * does and piglit expects. + */ + generate_error(dpy, GLXBadProfileARB, 0, X_GLXCreateContextAttribsARB, False); + return NULL; + } + + if ((contextFlags & GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB) && + majorVersion < 3) { + generate_error(dpy, BadMatch, 0, X_GLXCreateContextAttribsARB, True); + return NULL; + } + + if (renderType == GLX_COLOR_INDEX_TYPE && majorVersion >= 3) { + generate_error(dpy, BadMatch, 0, X_GLXCreateContextAttribsARB, True); + return NULL; + } + + ctx = create_context(dpy, xmvis, + shareCtx ? shareCtx->xmesaContext : NULL, + direct, + majorVersion, minorVersion, + profileMask, contextFlags); + if (!ctx) { + generate_error(dpy, GLXBadFBConfig, 0, X_GLXCreateContextAttribsARB, False); + } + + return ctx; +} diff --git a/src/gallium/frontends/glx/xlib/glx_getproc.c b/src/gallium/frontends/glx/xlib/glx_getproc.c new file mode 100644 index 00000000000..6b94f2c1960 --- /dev/null +++ b/src/gallium/frontends/glx/xlib/glx_getproc.c @@ -0,0 +1,212 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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. + */ + + +/** + * glXGetProcAddress() + */ + + +#define GLX_GLXEXT_PROTOTYPES + +#include <string.h> +#include "pipe/p_compiler.h" +#include "GL/glx.h" +#include "glapi/glapi.h" + + +struct name_address_pair { + const char *Name; + __GLXextFuncPtr Address; +}; + + +static const struct name_address_pair GLX_functions[] = { + /*** GLX_VERSION_1_0 ***/ + { "glXChooseVisual", (__GLXextFuncPtr) glXChooseVisual }, + { "glXCopyContext", (__GLXextFuncPtr) glXCopyContext }, + { "glXCreateContext", (__GLXextFuncPtr) glXCreateContext }, + { "glXCreateGLXPixmap", (__GLXextFuncPtr) glXCreateGLXPixmap }, + { "glXDestroyContext", (__GLXextFuncPtr) glXDestroyContext }, + { "glXDestroyGLXPixmap", (__GLXextFuncPtr) glXDestroyGLXPixmap }, + { "glXGetConfig", (__GLXextFuncPtr) glXGetConfig }, + { "glXGetCurrentContext", (__GLXextFuncPtr) glXGetCurrentContext }, + { "glXGetCurrentDrawable", (__GLXextFuncPtr) glXGetCurrentDrawable }, + { "glXIsDirect", (__GLXextFuncPtr) glXIsDirect }, + { "glXMakeCurrent", (__GLXextFuncPtr) glXMakeCurrent }, + { "glXQueryExtension", (__GLXextFuncPtr) glXQueryExtension }, + { "glXQueryVersion", (__GLXextFuncPtr) glXQueryVersion }, + { "glXSwapBuffers", (__GLXextFuncPtr) glXSwapBuffers }, + { "glXUseXFont", (__GLXextFuncPtr) glXUseXFont }, + { "glXWaitGL", (__GLXextFuncPtr) glXWaitGL }, + { "glXWaitX", (__GLXextFuncPtr) glXWaitX }, + + /*** GLX_VERSION_1_1 ***/ + { "glXGetClientString", (__GLXextFuncPtr) glXGetClientString }, + { "glXQueryExtensionsString", (__GLXextFuncPtr) glXQueryExtensionsString }, + { "glXQueryServerString", (__GLXextFuncPtr) glXQueryServerString }, + + /*** GLX_VERSION_1_2 ***/ + { "glXGetCurrentDisplay", (__GLXextFuncPtr) glXGetCurrentDisplay }, + + /*** GLX_VERSION_1_3 ***/ + { "glXChooseFBConfig", (__GLXextFuncPtr) glXChooseFBConfig }, + { "glXCreateNewContext", (__GLXextFuncPtr) glXCreateNewContext }, + { "glXCreatePbuffer", (__GLXextFuncPtr) glXCreatePbuffer }, + { "glXCreatePixmap", (__GLXextFuncPtr) glXCreatePixmap }, + { "glXCreateWindow", (__GLXextFuncPtr) glXCreateWindow }, + { "glXDestroyPbuffer", (__GLXextFuncPtr) glXDestroyPbuffer }, + { "glXDestroyPixmap", (__GLXextFuncPtr) glXDestroyPixmap }, + { "glXDestroyWindow", (__GLXextFuncPtr) glXDestroyWindow }, + { "glXGetCurrentReadDrawable", (__GLXextFuncPtr) glXGetCurrentReadDrawable }, + { "glXGetFBConfigAttrib", (__GLXextFuncPtr) glXGetFBConfigAttrib }, + { "glXGetFBConfigs", (__GLXextFuncPtr) glXGetFBConfigs }, + { "glXGetSelectedEvent", (__GLXextFuncPtr) glXGetSelectedEvent }, + { "glXGetVisualFromFBConfig", (__GLXextFuncPtr) glXGetVisualFromFBConfig }, + { "glXMakeContextCurrent", (__GLXextFuncPtr) glXMakeContextCurrent }, + { "glXQueryContext", (__GLXextFuncPtr) glXQueryContext }, + { "glXQueryDrawable", (__GLXextFuncPtr) glXQueryDrawable }, + { "glXSelectEvent", (__GLXextFuncPtr) glXSelectEvent }, + + /*** GLX_VERSION_1_4 ***/ + { "glXGetProcAddress", (__GLXextFuncPtr) glXGetProcAddress }, + + /*** GLX_SGI_swap_control ***/ + { "glXSwapIntervalSGI", (__GLXextFuncPtr) glXSwapIntervalSGI }, + + /*** GLX_SGI_video_sync ***/ + { "glXGetVideoSyncSGI", (__GLXextFuncPtr) glXGetVideoSyncSGI }, + { "glXWaitVideoSyncSGI", (__GLXextFuncPtr) glXWaitVideoSyncSGI }, + + /*** GLX_SGI_make_current_read ***/ + { "glXMakeCurrentReadSGI", (__GLXextFuncPtr) glXMakeCurrentReadSGI }, + { "glXGetCurrentReadDrawableSGI", (__GLXextFuncPtr) glXGetCurrentReadDrawableSGI }, + + /*** GLX_SGIX_video_source ***/ +#if defined(_VL_H) + { "glXCreateGLXVideoSourceSGIX", (__GLXextFuncPtr) glXCreateGLXVideoSourceSGIX }, + { "glXDestroyGLXVideoSourceSGIX", (__GLXextFuncPtr) glXDestroyGLXVideoSourceSGIX }, +#endif + + /*** GLX_EXT_import_context ***/ + { "glXFreeContextEXT", (__GLXextFuncPtr) glXFreeContextEXT }, + { "glXGetContextIDEXT", (__GLXextFuncPtr) glXGetContextIDEXT }, + { "glXGetCurrentDisplayEXT", (__GLXextFuncPtr) glXGetCurrentDisplayEXT }, + { "glXImportContextEXT", (__GLXextFuncPtr) glXImportContextEXT }, + { "glXQueryContextInfoEXT", (__GLXextFuncPtr) glXQueryContextInfoEXT }, + + /*** GLX_SGIX_fbconfig ***/ + { "glXGetFBConfigAttribSGIX", (__GLXextFuncPtr) glXGetFBConfigAttribSGIX }, + { "glXChooseFBConfigSGIX", (__GLXextFuncPtr) glXChooseFBConfigSGIX }, + { "glXCreateGLXPixmapWithConfigSGIX", (__GLXextFuncPtr) glXCreateGLXPixmapWithConfigSGIX }, + { "glXCreateContextWithConfigSGIX", (__GLXextFuncPtr) glXCreateContextWithConfigSGIX }, + { "glXGetVisualFromFBConfigSGIX", (__GLXextFuncPtr) glXGetVisualFromFBConfigSGIX }, + { "glXGetFBConfigFromVisualSGIX", (__GLXextFuncPtr) glXGetFBConfigFromVisualSGIX }, + + /*** GLX_SGIX_pbuffer ***/ + { "glXCreateGLXPbufferSGIX", (__GLXextFuncPtr) glXCreateGLXPbufferSGIX }, + { "glXDestroyGLXPbufferSGIX", (__GLXextFuncPtr) glXDestroyGLXPbufferSGIX }, + { "glXQueryGLXPbufferSGIX", (__GLXextFuncPtr) glXQueryGLXPbufferSGIX }, + { "glXSelectEventSGIX", (__GLXextFuncPtr) glXSelectEventSGIX }, + { "glXGetSelectedEventSGIX", (__GLXextFuncPtr) glXGetSelectedEventSGIX }, + + /*** GLX_SGI_cushion ***/ + { "glXCushionSGI", (__GLXextFuncPtr) glXCushionSGI }, + + /*** GLX_SGIX_video_resize ***/ + { "glXBindChannelToWindowSGIX", (__GLXextFuncPtr) glXBindChannelToWindowSGIX }, + { "glXChannelRectSGIX", (__GLXextFuncPtr) glXChannelRectSGIX }, + { "glXQueryChannelRectSGIX", (__GLXextFuncPtr) glXQueryChannelRectSGIX }, + { "glXQueryChannelDeltasSGIX", (__GLXextFuncPtr) glXQueryChannelDeltasSGIX }, + { "glXChannelRectSyncSGIX", (__GLXextFuncPtr) glXChannelRectSyncSGIX }, + + /*** GLX_SGIX_dmbuffer **/ +#if defined(_DM_BUFFER_H_) + { "glXAssociateDMPbufferSGIX", (__GLXextFuncPtr) glXAssociateDMPbufferSGIX }, +#endif + + /*** GLX_SUN_get_transparent_index ***/ + { "glXGetTransparentIndexSUN", (__GLXextFuncPtr) glXGetTransparentIndexSUN }, + + /*** GLX_MESA_copy_sub_buffer ***/ + { "glXCopySubBufferMESA", (__GLXextFuncPtr) glXCopySubBufferMESA }, + + /*** GLX_MESA_pixmap_colormap ***/ + { "glXCreateGLXPixmapMESA", (__GLXextFuncPtr) glXCreateGLXPixmapMESA }, + + /*** GLX_MESA_release_buffers ***/ + { "glXReleaseBuffersMESA", (__GLXextFuncPtr) glXReleaseBuffersMESA }, + + /*** GLX_ARB_get_proc_address ***/ + { "glXGetProcAddressARB", (__GLXextFuncPtr) glXGetProcAddressARB }, + + /*** GLX_ARB_create_context ***/ + { "glXCreateContextAttribsARB", (__GLXextFuncPtr) glXCreateContextAttribsARB }, + + /*** GLX_EXT_texture_from_pixmap ***/ + { "glXBindTexImageEXT", (__GLXextFuncPtr) glXBindTexImageEXT }, + { "glXReleaseTexImageEXT", (__GLXextFuncPtr) glXReleaseTexImageEXT }, + + { NULL, NULL } /* end of list */ +}; + + + +/** + * Return address of named glX function, or NULL if not found. + */ +static __GLXextFuncPtr +_glxapi_get_proc_address(const char *funcName) +{ + GLuint i; + for (i = 0; GLX_functions[i].Name; i++) { + if (strcmp(GLX_functions[i].Name, funcName) == 0) + return GLX_functions[i].Address; + } + return NULL; +} + + +PUBLIC __GLXextFuncPtr +glXGetProcAddressARB(const GLubyte *procName) +{ + __GLXextFuncPtr f; + + f = _glxapi_get_proc_address((const char *) procName); + if (f) { + return f; + } + + f = (__GLXextFuncPtr) _glapi_get_proc_address((const char *) procName); + return f; +} + + +/* GLX 1.4 */ +PUBLIC +void (*glXGetProcAddress(const GLubyte *procName))() +{ + return glXGetProcAddressARB(procName); +} diff --git a/src/gallium/frontends/glx/xlib/glx_usefont.c b/src/gallium/frontends/glx/xlib/glx_usefont.c new file mode 100644 index 00000000000..9d35054b44d --- /dev/null +++ b/src/gallium/frontends/glx/xlib/glx_usefont.c @@ -0,0 +1,373 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 1995 Thorsten.Ohl @ Physik.TH-Darmstadt.de + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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. + */ + + +/** + * Fake implementation of glXUseXFont(). + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <GL/glx.h> +#include "main/errors.h" + + +/* Some debugging info. */ + +#ifdef DEBUG +#include <ctype.h> + +int debug_xfonts = 0; + +static void +dump_char_struct(XCharStruct * ch, char *prefix) +{ + printf("%slbearing = %d, rbearing = %d, width = %d\n", + prefix, ch->lbearing, ch->rbearing, ch->width); + printf("%sascent = %d, descent = %d, attributes = %u\n", + prefix, ch->ascent, ch->descent, (unsigned int) ch->attributes); +} + +static void +dump_font_struct(XFontStruct * font) +{ + printf("ascent = %d, descent = %d\n", font->ascent, font->descent); + printf("char_or_byte2 = (%u,%u)\n", + font->min_char_or_byte2, font->max_char_or_byte2); + printf("byte1 = (%u,%u)\n", font->min_byte1, font->max_byte1); + printf("all_chars_exist = %s\n", font->all_chars_exist ? "True" : "False"); + printf("default_char = %c (\\%03o)\n", + (char) (isprint(font->default_char) ? font->default_char : ' '), + font->default_char); + dump_char_struct(&font->min_bounds, "min> "); + dump_char_struct(&font->max_bounds, "max> "); +#if 0 + for (c = font->min_char_or_byte2; c <= font->max_char_or_byte2; c++) { + char prefix[8]; + sprintf(prefix, "%d> ", c); + dump_char_struct(&font->per_char[c], prefix); + } +#endif +} + +static void +dump_bitmap(unsigned int width, unsigned int height, GLubyte * bitmap) +{ + unsigned int x, y; + + printf(" "); + for (x = 0; x < 8 * width; x++) + printf("%o", 7 - (x % 8)); + putchar('\n'); + for (y = 0; y < height; y++) { + printf("%3o:", y); + for (x = 0; x < 8 * width; x++) + putchar((bitmap[width * (height - y - 1) + x / 8] & (1 << (7 - (x % + 8)))) + ? '*' : '.'); + printf(" "); + for (x = 0; x < width; x++) + printf("0x%02x, ", bitmap[width * (height - y - 1) + x]); + putchar('\n'); + } +} +#endif /* DEBUG */ + + +/* Implementation. */ + +/* Fill a BITMAP with a character C from thew current font + in the graphics context GC. WIDTH is the width in bytes + and HEIGHT is the height in bits. + + Note that the generated bitmaps must be used with + + glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE); + glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei (GL_UNPACK_ALIGNMENT, 1); + + Possible optimizations: + + * use only one reusable pixmap with the maximum dimensions. + * draw the entire font into a single pixmap (careful with + proportional fonts!). +*/ + + +/* + * Generate OpenGL-compatible bitmap. + */ +static void +fill_bitmap(Display * dpy, Window win, GC gc, + unsigned int width, unsigned int height, + int x0, int y0, unsigned int c, GLubyte * bitmap) +{ + XImage *image; + unsigned int x, y; + Pixmap pixmap; + XChar2b char2b; + + pixmap = XCreatePixmap(dpy, win, 8 * width, height, 1); + XSetForeground(dpy, gc, 0); + XFillRectangle(dpy, pixmap, gc, 0, 0, 8 * width, height); + XSetForeground(dpy, gc, 1); + + char2b.byte1 = (c >> 8) & 0xff; + char2b.byte2 = (c & 0xff); + + XDrawString16(dpy, pixmap, gc, x0, y0, &char2b, 1); + + image = XGetImage(dpy, pixmap, 0, 0, 8 * width, height, 1, XYPixmap); + if (image) { + /* Fill the bitmap (X11 and OpenGL are upside down wrt each other). */ + for (y = 0; y < height; y++) + for (x = 0; x < 8 * width; x++) + if (XGetPixel(image, x, y)) + bitmap[width * (height - y - 1) + x / 8] |= + (1 << (7 - (x % 8))); + XDestroyImage(image); + } + + XFreePixmap(dpy, pixmap); +} + +/* + * determine if a given glyph is valid and return the + * corresponding XCharStruct. + */ +static XCharStruct * +isvalid(XFontStruct * fs, unsigned int which) +{ + unsigned int rows, pages; + unsigned int byte1 = 0, byte2 = 0; + int i, valid = 1; + + rows = fs->max_byte1 - fs->min_byte1 + 1; + pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1; + + if (rows == 1) { + /* "linear" fonts */ + if ((fs->min_char_or_byte2 > which) || (fs->max_char_or_byte2 < which)) + valid = 0; + } + else { + /* "matrix" fonts */ + byte2 = which & 0xff; + byte1 = which >> 8; + if ((fs->min_char_or_byte2 > byte2) || + (fs->max_char_or_byte2 < byte2) || + (fs->min_byte1 > byte1) || (fs->max_byte1 < byte1)) + valid = 0; + } + + if (valid) { + if (fs->per_char) { + if (rows == 1) { + /* "linear" fonts */ + return (fs->per_char + (which - fs->min_char_or_byte2)); + } + else { + /* "matrix" fonts */ + i = ((byte1 - fs->min_byte1) * pages) + + (byte2 - fs->min_char_or_byte2); + return (fs->per_char + i); + } + } + else { + return (&fs->min_bounds); + } + } + return (NULL); +} + + +PUBLIC void +glXUseXFont(Font font, int first, int count, int listbase) +{ + Display *dpy; + Window win; + Pixmap pixmap; + GC gc; + XGCValues values; + unsigned long valuemask; + XFontStruct *fs; + GLint swapbytes, lsbfirst, rowlength; + GLint skiprows, skippixels, alignment; + unsigned int max_width, max_height, max_bm_width, max_bm_height; + GLubyte *bm; + int i; + + dpy = glXGetCurrentDisplay(); + if (!dpy) + return; /* I guess glXMakeCurrent wasn't called */ + i = DefaultScreen(dpy); + win = RootWindow(dpy, i); + + fs = XQueryFont(dpy, font); + if (!fs) { + _mesa_error(NULL, GL_INVALID_VALUE, + "Couldn't get font structure information"); + return; + } + + /* Allocate a bitmap that can fit all characters. */ + max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing; + max_height = fs->max_bounds.ascent + fs->max_bounds.descent; + max_bm_width = (max_width + 7) / 8; + max_bm_height = max_height; + + bm = malloc((max_bm_width * max_bm_height) * sizeof(GLubyte)); + if (!bm) { + XFreeFontInfo(NULL, fs, 1); + _mesa_error(NULL, GL_OUT_OF_MEMORY, + "Couldn't allocate bitmap in glXUseXFont()"); + return; + } + +#if 0 + /* get the page info */ + pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1; + firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2; + lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2; + rows = fs->max_byte1 - fs->min_byte1 + 1; + unsigned int first_char, last_char, pages, rows; +#endif + + /* Save the current packing mode for bitmaps. */ + glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes); + glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst); + glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength); + glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows); + glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels); + glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment); + + /* Enforce a standard packing mode which is compatible with + fill_bitmap() from above. This is actually the default mode, + except for the (non)alignment. */ + glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); + glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + pixmap = XCreatePixmap(dpy, win, 10, 10, 1); + values.foreground = BlackPixel(dpy, DefaultScreen(dpy)); + values.background = WhitePixel(dpy, DefaultScreen(dpy)); + values.font = fs->fid; + valuemask = GCForeground | GCBackground | GCFont; + gc = XCreateGC(dpy, pixmap, valuemask, &values); + XFreePixmap(dpy, pixmap); + +#ifdef DEBUG + if (debug_xfonts) + dump_font_struct(fs); +#endif + + for (i = 0; i < count; i++) { + unsigned int width, height, bm_width, bm_height; + GLfloat x0, y0, dx, dy; + XCharStruct *ch; + int x, y; + unsigned int c = first + i; + int list = listbase + i; + int valid; + + /* check on index validity and get the bounds */ + ch = isvalid(fs, c); + if (!ch) { + ch = &fs->max_bounds; + valid = 0; + } + else { + valid = 1; + } + +#ifdef DEBUG + if (debug_xfonts) { + char s[7]; + sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c); + dump_char_struct(ch, s); + } +#endif + + /* glBitmap()' parameters: + straight from the glXUseXFont(3) manpage. */ + width = ch->rbearing - ch->lbearing; + height = ch->ascent + ch->descent; + x0 = -ch->lbearing; + y0 = ch->descent - 0; /* XXX used to subtract 1 here */ + /* but that caused a conformace failure */ + dx = ch->width; + dy = 0; + + /* X11's starting point. */ + x = -ch->lbearing; + y = ch->ascent; + + /* Round the width to a multiple of eight. We will use this also + for the pixmap for capturing the X11 font. This is slightly + inefficient, but it makes the OpenGL part real easy. */ + bm_width = (width + 7) / 8; + bm_height = height; + + glNewList(list, GL_COMPILE); + if (valid && (bm_width > 0) && (bm_height > 0)) { + + memset(bm, '\0', bm_width * bm_height); + fill_bitmap(dpy, win, gc, bm_width, bm_height, x, y, c, bm); + + glBitmap(width, height, x0, y0, dx, dy, bm); +#ifdef DEBUG + if (debug_xfonts) { + printf("width/height = %u/%u\n", width, height); + printf("bm_width/bm_height = %u/%u\n", bm_width, bm_height); + dump_bitmap(bm_width, bm_height, bm); + } +#endif + } + else { + glBitmap(0, 0, 0.0, 0.0, dx, dy, NULL); + } + glEndList(); + } + + free(bm); + XFreeFontInfo(NULL, fs, 1); + XFreeGC(dpy, gc); + + /* Restore saved packing modes. */ + glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes); + glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst); + glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength); + glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels); + glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); +} diff --git a/src/gallium/frontends/glx/xlib/meson.build b/src/gallium/frontends/glx/xlib/meson.build new file mode 100644 index 00000000000..7b1fdb34ffe --- /dev/null +++ b/src/gallium/frontends/glx/xlib/meson.build @@ -0,0 +1,27 @@ +# Copyright © 2017 Intel Corporation + +# 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. + +libxlib = static_library( + 'xlib', + files('glx_api.c', 'glx_getproc.c', 'glx_usefont.c', 'xm_api.c', 'xm_st.c'), + c_args : c_vis_args, + include_directories : [inc_include, inc_src, inc_gallium, inc_gallium_aux, inc_mapi, inc_mesa], + dependencies : [dep_x11, dep_xext, dep_xcb, dep_glproto], +) diff --git a/src/gallium/frontends/glx/xlib/xm_api.c b/src/gallium/frontends/glx/xlib/xm_api.c new file mode 100644 index 00000000000..e0e0b2d992c --- /dev/null +++ b/src/gallium/frontends/glx/xlib/xm_api.c @@ -0,0 +1,1561 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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. + */ + +/** + * \file xm_api.c + * + * All the XMesa* API functions. + * + * + * NOTES: + * + * The window coordinate system origin (0,0) is in the lower-left corner + * of the window. X11's window coordinate origin is in the upper-left + * corner of the window. Therefore, most drawing functions in this + * file have to flip Y coordinates. + * + * + * Byte swapping: If the Mesa host and the X display use a different + * byte order then there's some trickiness to be aware of when using + * XImages. The byte ordering used for the XImage is that of the X + * display, not the Mesa host. + * The color-to-pixel encoding for True/DirectColor must be done + * according to the display's visual red_mask, green_mask, and blue_mask. + * If XPutPixel is used to put a pixel into an XImage then XPutPixel will + * do byte swapping if needed. If one wants to directly "poke" the pixel + * into the XImage's buffer then the pixel must be byte swapped first. + * + */ + +#ifdef __CYGWIN__ +#undef WIN32 +#undef __WIN32__ +#endif + +#include <stdio.h> +#include "xm_api.h" +#include "xm_st.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_screen.h" +#include "pipe/p_state.h" +#include "frontend/api.h" + +#include "util/u_atomic.h" +#include "util/u_inlines.h" +#include "util/u_math.h" +#include "util/u_memory.h" + +#include "hud/hud_context.h" + +#include "main/errors.h" + +#include "xm_public.h" +#include <GL/glx.h> + + +/* Driver interface routines, set up by xlib backend on library + * _init(). These are global in the same way that function names are + * global. + */ +static struct xm_driver driver; +static struct st_api *stapi; + +/* Default strict invalidate to false. This means we will not call + * XGetGeometry after every swapbuffers, which allows swapbuffers to + * remain asynchronous. For apps running at 100fps with synchronous + * swapping, a 10% boost is typical. For gears, I see closer to 20% + * speedup. + * + * Note that the work of copying data on swapbuffers doesn't disappear + * - this change just allows the X server to execute the PutImage + * asynchronously without us effectively blocked until its completion. + * + * This speeds up even llvmpipe's threaded rasterization as the + * swapbuffers operation was a large part of the serial component of + * an llvmpipe frame. + * + * The downside of this is correctness - applications which don't call + * glViewport on window resizes will get incorrect rendering. A + * better solution would be to have per-frame but asynchronous + * invalidation. Xcb almost looks as if it could provide this, but + * the API doesn't seem to quite be there. + */ +boolean xmesa_strict_invalidate = FALSE; + +void xmesa_set_driver( const struct xm_driver *templ ) +{ + driver = *templ; + stapi = driver.create_st_api(); + + xmesa_strict_invalidate = + debug_get_bool_option("XMESA_STRICT_INVALIDATE", FALSE); +} + + +static int +xmesa_get_param(struct st_manager *smapi, + enum st_manager_param param) +{ + switch(param) { + case ST_MANAGER_BROKEN_INVALIDATE: + return !xmesa_strict_invalidate; + default: + return 0; + } +} + +/* linked list of XMesaDisplay hooks per display */ +typedef struct _XMesaExtDisplayInfo { + struct _XMesaExtDisplayInfo *next; + Display *display; + struct xmesa_display mesaDisplay; +} XMesaExtDisplayInfo; + +typedef struct _XMesaExtInfo { + XMesaExtDisplayInfo *head; + int ndisplays; +} XMesaExtInfo; + +static XMesaExtInfo MesaExtInfo; + +/* hook to delete XMesaDisplay on XDestroyDisplay */ +extern void +xmesa_close_display(Display *display) +{ + XMesaExtDisplayInfo *info, *prev; + + /* These assertions are not valid since screen creation can fail and result + * in an empty list + assert(MesaExtInfo.ndisplays > 0); + assert(MesaExtInfo.head); + */ + + _XLockMutex(_Xglobal_lock); + /* first find display */ + prev = NULL; + for (info = MesaExtInfo.head; info; info = info->next) { + if (info->display == display) { + prev = info; + break; + } + } + + if (info == NULL) { + /* no display found */ + _XUnlockMutex(_Xglobal_lock); + return; + } + + /* remove display entry from list */ + if (prev != MesaExtInfo.head) { + prev->next = info->next; + } else { + MesaExtInfo.head = info->next; + } + MesaExtInfo.ndisplays--; + + _XUnlockMutex(_Xglobal_lock); + + /* don't forget to clean up mesaDisplay */ + XMesaDisplay xmdpy = &info->mesaDisplay; + + /** + * XXX: Don't destroy the screens here, since there may still + * be some dangling screen pointers that are used after this point + * if (xmdpy->screen) { + * xmdpy->screen->destroy(xmdpy->screen); + * } + */ + + if (xmdpy->smapi->destroy) + xmdpy->smapi->destroy(xmdpy->smapi); + free(xmdpy->smapi); + + XFree((char *) info); +} + +static XMesaDisplay +xmesa_init_display( Display *display ) +{ + static mtx_t init_mutex = _MTX_INITIALIZER_NP; + XMesaDisplay xmdpy; + XMesaExtDisplayInfo *info; + + if (display == NULL) { + return NULL; + } + + mtx_lock(&init_mutex); + + /* Look for XMesaDisplay which corresponds to this display */ + info = MesaExtInfo.head; + while(info) { + if (info->display == display) { + /* Found it */ + mtx_unlock(&init_mutex); + return &info->mesaDisplay; + } + info = info->next; + } + + /* Not found. Create new XMesaDisplay */ + /* first allocate X-related resources and hook destroy callback */ + + /* allocate mesa display info */ + info = (XMesaExtDisplayInfo *) Xmalloc(sizeof(XMesaExtDisplayInfo)); + if (info == NULL) { + mtx_unlock(&init_mutex); + return NULL; + } + info->display = display; + + xmdpy = &info->mesaDisplay; /* to be filled out below */ + xmdpy->display = display; + xmdpy->pipe = NULL; + + xmdpy->smapi = CALLOC_STRUCT(st_manager); + if (!xmdpy->smapi) { + Xfree(info); + mtx_unlock(&init_mutex); + return NULL; + } + + xmdpy->screen = driver.create_pipe_screen(display); + if (!xmdpy->screen) { + free(xmdpy->smapi); + Xfree(info); + mtx_unlock(&init_mutex); + return NULL; + } + + /* At this point, both smapi and screen are known to be valid */ + xmdpy->smapi->screen = xmdpy->screen; + xmdpy->smapi->get_param = xmesa_get_param; + (void) mtx_init(&xmdpy->mutex, mtx_plain); + + /* chain to the list of displays */ + _XLockMutex(_Xglobal_lock); + info->next = MesaExtInfo.head; + MesaExtInfo.head = info; + MesaExtInfo.ndisplays++; + _XUnlockMutex(_Xglobal_lock); + + mtx_unlock(&init_mutex); + + return xmdpy; +} + + +/**********************************************************************/ +/***** X Utility Functions *****/ +/**********************************************************************/ + + +/** + * Return the host's byte order as LSBFirst or MSBFirst ala X. + */ +static int host_byte_order( void ) +{ + int i = 1; + char *cptr = (char *) &i; + return (*cptr==1) ? LSBFirst : MSBFirst; +} + + + + +/** + * Return the true number of bits per pixel for XImages. + * For example, if we request a 24-bit deep visual we may actually need/get + * 32bpp XImages. This function returns the appropriate bpp. + * Input: dpy - the X display + * visinfo - desribes the visual to be used for XImages + * Return: true number of bits per pixel for XImages + */ +static int +bits_per_pixel( XMesaVisual xmv ) +{ + Display *dpy = xmv->display; + XVisualInfo * visinfo = xmv->visinfo; + XImage *img; + int bitsPerPixel; + /* Create a temporary XImage */ + img = XCreateImage( dpy, visinfo->visual, visinfo->depth, + ZPixmap, 0, /*format, offset*/ + malloc(8), /*data*/ + 1, 1, /*width, height*/ + 32, /*bitmap_pad*/ + 0 /*bytes_per_line*/ + ); + assert(img); + /* grab the bits/pixel value */ + bitsPerPixel = img->bits_per_pixel; + /* free the XImage */ + free( img->data ); + img->data = NULL; + XDestroyImage( img ); + return bitsPerPixel; +} + + + +/* + * Determine if a given X window ID is valid (window exists). + * Do this by calling XGetWindowAttributes() for the window and + * checking if we catch an X error. + * Input: dpy - the display + * win - the window to check for existence + * Return: GL_TRUE - window exists + * GL_FALSE - window doesn't exist + */ +static GLboolean WindowExistsFlag; + +static int window_exists_err_handler( Display* dpy, XErrorEvent* xerr ) +{ + (void) dpy; + if (xerr->error_code == BadWindow) { + WindowExistsFlag = GL_FALSE; + } + return 0; +} + +static GLboolean window_exists( Display *dpy, Window win ) +{ + XWindowAttributes wa; + int (*old_handler)( Display*, XErrorEvent* ); + WindowExistsFlag = GL_TRUE; + old_handler = XSetErrorHandler(window_exists_err_handler); + XGetWindowAttributes( dpy, win, &wa ); /* dummy request */ + XSetErrorHandler(old_handler); + return WindowExistsFlag; +} + +static Status +get_drawable_size( Display *dpy, Drawable d, uint *width, uint *height ) +{ + Window root; + Status stat; + int xpos, ypos; + unsigned int w, h, bw, depth; + stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth); + *width = w; + *height = h; + return stat; +} + + +/** + * Return the size of the window (or pixmap) that corresponds to the + * given XMesaBuffer. + * \param width returns width in pixels + * \param height returns height in pixels + */ +void +xmesa_get_window_size(Display *dpy, XMesaBuffer b, + GLuint *width, GLuint *height) +{ + XMesaDisplay xmdpy = xmesa_init_display(dpy); + Status stat; + + mtx_lock(&xmdpy->mutex); + stat = get_drawable_size(dpy, b->ws.drawable, width, height); + mtx_unlock(&xmdpy->mutex); + + if (!stat) { + /* probably querying a window that's recently been destroyed */ + _mesa_warning(NULL, "XGetGeometry failed!\n"); + *width = *height = 1; + } +} + +#define GET_REDMASK(__v) __v->mesa_visual.redMask +#define GET_GREENMASK(__v) __v->mesa_visual.greenMask +#define GET_BLUEMASK(__v) __v->mesa_visual.blueMask + + +/** + * Choose the pixel format for the given visual. + * This will tell the gallium driver how to pack pixel data into + * drawing surfaces. + */ +static GLuint +choose_pixel_format(XMesaVisual v) +{ + boolean native_byte_order = (host_byte_order() == + ImageByteOrder(v->display)); + + if ( GET_REDMASK(v) == 0x0000ff + && GET_GREENMASK(v) == 0x00ff00 + && GET_BLUEMASK(v) == 0xff0000 + && v->BitsPerPixel == 32) { + if (native_byte_order) { + /* no byteswapping needed */ + return PIPE_FORMAT_RGBA8888_UNORM; + } + else { + return PIPE_FORMAT_ABGR8888_UNORM; + } + } + else if ( GET_REDMASK(v) == 0xff0000 + && GET_GREENMASK(v) == 0x00ff00 + && GET_BLUEMASK(v) == 0x0000ff + && v->BitsPerPixel == 32) { + if (native_byte_order) { + /* no byteswapping needed */ + return PIPE_FORMAT_BGRA8888_UNORM; + } + else { + return PIPE_FORMAT_ARGB8888_UNORM; + } + } + else if ( GET_REDMASK(v) == 0x0000ff00 + && GET_GREENMASK(v) == 0x00ff0000 + && GET_BLUEMASK(v) == 0xff000000 + && v->BitsPerPixel == 32) { + if (native_byte_order) { + /* no byteswapping needed */ + return PIPE_FORMAT_ARGB8888_UNORM; + } + else { + return PIPE_FORMAT_BGRA8888_UNORM; + } + } + else if ( GET_REDMASK(v) == 0xf800 + && GET_GREENMASK(v) == 0x07e0 + && GET_BLUEMASK(v) == 0x001f + && native_byte_order + && v->BitsPerPixel == 16) { + /* 5-6-5 RGB */ + return PIPE_FORMAT_B5G6R5_UNORM; + } + + return PIPE_FORMAT_NONE; +} + + +/** + * Choose a depth/stencil format that satisfies the given depth and + * stencil sizes. + */ +static enum pipe_format +choose_depth_stencil_format(XMesaDisplay xmdpy, int depth, int stencil, + int sample_count) +{ + const enum pipe_texture_target target = PIPE_TEXTURE_2D; + const unsigned tex_usage = PIPE_BIND_DEPTH_STENCIL; + enum pipe_format formats[8], fmt; + int count, i; + + count = 0; + + if (depth <= 16 && stencil == 0) { + formats[count++] = PIPE_FORMAT_Z16_UNORM; + } + if (depth <= 24 && stencil == 0) { + formats[count++] = PIPE_FORMAT_X8Z24_UNORM; + formats[count++] = PIPE_FORMAT_Z24X8_UNORM; + } + if (depth <= 24 && stencil <= 8) { + formats[count++] = PIPE_FORMAT_S8_UINT_Z24_UNORM; + formats[count++] = PIPE_FORMAT_Z24_UNORM_S8_UINT; + } + if (depth <= 32 && stencil == 0) { + formats[count++] = PIPE_FORMAT_Z32_UNORM; + } + + fmt = PIPE_FORMAT_NONE; + for (i = 0; i < count; i++) { + if (xmdpy->screen->is_format_supported(xmdpy->screen, formats[i], + target, sample_count, + sample_count, tex_usage)) { + fmt = formats[i]; + break; + } + } + + return fmt; +} + + + +/**********************************************************************/ +/***** Linked list of XMesaBuffers *****/ +/**********************************************************************/ + +static XMesaBuffer XMesaBufferList = NULL; + + +/** + * Allocate a new XMesaBuffer object which corresponds to the given drawable. + * Note that XMesaBuffer is derived from struct gl_framebuffer. + * The new XMesaBuffer will not have any size (Width=Height=0). + * + * \param d the corresponding X drawable (window or pixmap) + * \param type either WINDOW, PIXMAP or PBUFFER, describing d + * \param vis the buffer's visual + * \param cmap the window's colormap, if known. + * \return new XMesaBuffer or NULL if any problem + */ +static XMesaBuffer +create_xmesa_buffer(Drawable d, BufferType type, + XMesaVisual vis, Colormap cmap) +{ + XMesaDisplay xmdpy = xmesa_init_display(vis->display); + XMesaBuffer b; + + assert(type == WINDOW || type == PIXMAP || type == PBUFFER); + + if (!xmdpy) + return NULL; + + b = (XMesaBuffer) CALLOC_STRUCT(xmesa_buffer); + if (!b) + return NULL; + + b->ws.drawable = d; + b->ws.visual = vis->visinfo->visual; + b->ws.depth = vis->visinfo->depth; + + b->xm_visual = vis; + b->type = type; + b->cmap = cmap; + + get_drawable_size(vis->display, d, &b->width, &b->height); + + /* + * Create framebuffer, but we'll plug in our own renderbuffers below. + */ + b->stfb = xmesa_create_st_framebuffer(xmdpy, b); + + /* GLX_EXT_texture_from_pixmap */ + b->TextureTarget = 0; + b->TextureFormat = GLX_TEXTURE_FORMAT_NONE_EXT; + b->TextureMipmap = 0; + + /* insert buffer into linked list */ + b->Next = XMesaBufferList; + XMesaBufferList = b; + + return b; +} + + +/** + * Find an XMesaBuffer by matching X display and colormap but NOT matching + * the notThis buffer. + */ +XMesaBuffer +xmesa_find_buffer(Display *dpy, Colormap cmap, XMesaBuffer notThis) +{ + XMesaBuffer b; + for (b = XMesaBufferList; b; b = b->Next) { + if (b->xm_visual->display == dpy && + b->cmap == cmap && + b != notThis) { + return b; + } + } + return NULL; +} + + +/** + * Remove buffer from linked list, delete if no longer referenced. + */ +static void +xmesa_free_buffer(XMesaBuffer buffer) +{ + XMesaBuffer prev = NULL, b; + + for (b = XMesaBufferList; b; b = b->Next) { + if (b == buffer) { + /* unlink buffer from list */ + if (prev) + prev->Next = buffer->Next; + else + XMesaBufferList = buffer->Next; + + /* Since the X window for the XMesaBuffer is going away, we don't + * want to dereference this pointer in the future. + */ + b->ws.drawable = 0; + + /* Notify the st manager that the associated framebuffer interface + * object is no longer valid. + */ + stapi->destroy_drawable(stapi, buffer->stfb); + + /* XXX we should move the buffer to a delete-pending list and destroy + * the buffer until it is no longer current. + */ + xmesa_destroy_st_framebuffer(buffer->stfb); + + free(buffer); + + return; + } + /* continue search */ + prev = b; + } + /* buffer not found in XMesaBufferList */ + _mesa_problem(NULL,"xmesa_free_buffer() - buffer not found\n"); +} + + + +/**********************************************************************/ +/***** Misc Private Functions *****/ +/**********************************************************************/ + + +/** + * When a context is bound for the first time, we can finally finish + * initializing the context's visual and buffer information. + * \param v the XMesaVisual to initialize + * \param b the XMesaBuffer to initialize (may be NULL) + * \param window the window/pixmap we're rendering into + * \param cmap the colormap associated with the window/pixmap + * \return GL_TRUE=success, GL_FALSE=failure + */ +static GLboolean +initialize_visual_and_buffer(XMesaVisual v, XMesaBuffer b, + Drawable window, Colormap cmap) +{ + assert(!b || b->xm_visual == v); + + /* Save true bits/pixel */ + v->BitsPerPixel = bits_per_pixel(v); + assert(v->BitsPerPixel > 0); + + /* RGB WINDOW: + * We support RGB rendering into almost any kind of visual. + */ + const int xclass = v->visualType; + if (xclass != GLX_TRUE_COLOR && xclass != GLX_DIRECT_COLOR) { + _mesa_warning(NULL, + "XMesa: RGB mode rendering not supported in given visual.\n"); + return GL_FALSE; + } + + if (v->BitsPerPixel == 32) { + /* We use XImages for all front/back buffers. If an X Window or + * X Pixmap is 32bpp, there's no guarantee that the alpha channel + * will be preserved. For XImages we're in luck. + */ + v->mesa_visual.alphaBits = 8; + } + + /* + * If MESA_INFO env var is set print out some debugging info + * which can help Brian figure out what's going on when a user + * reports bugs. + */ + if (getenv("MESA_INFO")) { + printf("X/Mesa visual = %p\n", (void *) v); + printf("X/Mesa level = %d\n", v->mesa_visual.level); + printf("X/Mesa depth = %d\n", v->visinfo->depth); + printf("X/Mesa bits per pixel = %d\n", v->BitsPerPixel); + } + + return GL_TRUE; +} + + + +#define NUM_VISUAL_TYPES 6 + +/** + * Convert an X visual type to a GLX visual type. + * + * \param visualType X visual type (i.e., \c TrueColor, \c StaticGray, etc.) + * to be converted. + * \return If \c visualType is a valid X visual type, a GLX visual type will + * be returned. Otherwise \c GLX_NONE will be returned. + * + * \note + * This code was lifted directly from lib/GL/glx/glcontextmodes.c in the + * DRI CVS tree. + */ +static GLint +xmesa_convert_from_x_visual_type( int visualType ) +{ + static const int glx_visual_types[ NUM_VISUAL_TYPES ] = { + GLX_STATIC_GRAY, GLX_GRAY_SCALE, + GLX_STATIC_COLOR, GLX_PSEUDO_COLOR, + GLX_TRUE_COLOR, GLX_DIRECT_COLOR + }; + + return ( (unsigned) visualType < NUM_VISUAL_TYPES ) + ? glx_visual_types[ visualType ] : GLX_NONE; +} + + +/**********************************************************************/ +/***** Public Functions *****/ +/**********************************************************************/ + + +/* + * Create a new X/Mesa visual. + * Input: display - X11 display + * visinfo - an XVisualInfo pointer + * rgb_flag - GL_TRUE = RGB mode, + * GL_FALSE = color index mode + * alpha_flag - alpha buffer requested? + * db_flag - GL_TRUE = double-buffered, + * GL_FALSE = single buffered + * stereo_flag - stereo visual? + * ximage_flag - GL_TRUE = use an XImage for back buffer, + * GL_FALSE = use an off-screen pixmap for back buffer + * depth_size - requested bits/depth values, or zero + * stencil_size - requested bits/stencil values, or zero + * accum_red_size - requested bits/red accum values, or zero + * accum_green_size - requested bits/green accum values, or zero + * accum_blue_size - requested bits/blue accum values, or zero + * accum_alpha_size - requested bits/alpha accum values, or zero + * num_samples - number of samples/pixel if multisampling, or zero + * level - visual level, usually 0 + * visualCaveat - ala the GLX extension, usually GLX_NONE + * Return; a new XMesaVisual or 0 if error. + */ +PUBLIC +XMesaVisual XMesaCreateVisual( Display *display, + XVisualInfo * visinfo, + GLboolean rgb_flag, + GLboolean alpha_flag, + GLboolean db_flag, + GLboolean stereo_flag, + GLboolean ximage_flag, + GLint depth_size, + GLint stencil_size, + GLint accum_red_size, + GLint accum_green_size, + GLint accum_blue_size, + GLint accum_alpha_size, + GLint num_samples, + GLint level, + GLint visualCaveat ) +{ + XMesaDisplay xmdpy = xmesa_init_display(display); + XMesaVisual v; + GLint red_bits, green_bits, blue_bits, alpha_bits; + + if (!xmdpy) + return NULL; + + if (!rgb_flag) + return NULL; + + /* For debugging only */ + if (getenv("MESA_XSYNC")) { + /* This makes debugging X easier. + * In your debugger, set a breakpoint on _XError to stop when an + * X protocol error is generated. + */ + XSynchronize( display, 1 ); + } + + v = (XMesaVisual) CALLOC_STRUCT(xmesa_visual); + if (!v) { + return NULL; + } + + v->display = display; + + /* Save a copy of the XVisualInfo struct because the user may Xfree() + * the struct but we may need some of the information contained in it + * at a later time. + */ + v->visinfo = malloc(sizeof(*visinfo)); + if (!v->visinfo) { + free(v); + return NULL; + } + memcpy(v->visinfo, visinfo, sizeof(*visinfo)); + + v->ximage_flag = ximage_flag; + + v->mesa_visual.redMask = visinfo->red_mask; + v->mesa_visual.greenMask = visinfo->green_mask; + v->mesa_visual.blueMask = visinfo->blue_mask; + v->visualID = visinfo->visualid; + v->screen = visinfo->screen; + +#if !(defined(__cplusplus) || defined(c_plusplus)) + v->visualType = xmesa_convert_from_x_visual_type(visinfo->class); +#else + v->visualType = xmesa_convert_from_x_visual_type(visinfo->c_class); +#endif + + v->mesa_visual.visualRating = visualCaveat; + + if (alpha_flag) + v->mesa_visual.alphaBits = 8; + + (void) initialize_visual_and_buffer( v, NULL, 0, 0 ); + + { + const int xclass = v->visualType; + if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) { + red_bits = util_bitcount(GET_REDMASK(v)); + green_bits = util_bitcount(GET_GREENMASK(v)); + blue_bits = util_bitcount(GET_BLUEMASK(v)); + } + else { + /* this is an approximation */ + int depth; + depth = v->visinfo->depth; + red_bits = depth / 3; + depth -= red_bits; + green_bits = depth / 2; + depth -= green_bits; + blue_bits = depth; + alpha_bits = 0; + assert( red_bits + green_bits + blue_bits == v->visinfo->depth ); + } + alpha_bits = v->mesa_visual.alphaBits; + } + + /* initialize visual */ + { + struct gl_config *vis = &v->mesa_visual; + + vis->doubleBufferMode = db_flag; + vis->stereoMode = stereo_flag; + + vis->redBits = red_bits; + vis->greenBits = green_bits; + vis->blueBits = blue_bits; + vis->alphaBits = alpha_bits; + vis->rgbBits = red_bits + green_bits + blue_bits; + + vis->depthBits = depth_size; + vis->stencilBits = stencil_size; + + vis->accumRedBits = accum_red_size; + vis->accumGreenBits = accum_green_size; + vis->accumBlueBits = accum_blue_size; + vis->accumAlphaBits = accum_alpha_size; + + vis->numAuxBuffers = 0; + vis->level = 0; + vis->sampleBuffers = num_samples > 1; + vis->samples = num_samples; + } + + v->stvis.buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK; + if (db_flag) + v->stvis.buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK; + if (stereo_flag) { + v->stvis.buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK; + if (db_flag) + v->stvis.buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK; + } + + v->stvis.color_format = choose_pixel_format(v); + + /* Check format support at requested num_samples (for multisample) */ + if (!xmdpy->screen->is_format_supported(xmdpy->screen, + v->stvis.color_format, + PIPE_TEXTURE_2D, num_samples, + num_samples, + PIPE_BIND_RENDER_TARGET)) + v->stvis.color_format = PIPE_FORMAT_NONE; + + if (v->stvis.color_format == PIPE_FORMAT_NONE) { + free(v->visinfo); + free(v); + return NULL; + } + + v->stvis.depth_stencil_format = + choose_depth_stencil_format(xmdpy, depth_size, stencil_size, + num_samples); + + v->stvis.accum_format = (accum_red_size + + accum_green_size + accum_blue_size + accum_alpha_size) ? + PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE; + + v->stvis.samples = num_samples; + v->stvis.render_buffer = ST_ATTACHMENT_INVALID; + + /* XXX minor hack */ + v->mesa_visual.level = level; + return v; +} + + +PUBLIC +void XMesaDestroyVisual( XMesaVisual v ) +{ + free(v->visinfo); + free(v); +} + + +/** + * Return the informative name. + */ +const char * +xmesa_get_name(void) +{ + return stapi->name; +} + + +/** + * Do per-display initializations. + */ +int +xmesa_init( Display *display ) +{ + return xmesa_init_display(display) ? 0 : 1; +} + + +/** + * Create a new XMesaContext. + * \param v the XMesaVisual + * \param share_list another XMesaContext with which to share display + * lists or NULL if no sharing is wanted. + * \return an XMesaContext or NULL if error. + */ +PUBLIC +XMesaContext XMesaCreateContext( XMesaVisual v, XMesaContext share_list, + GLuint major, GLuint minor, + GLuint profileMask, GLuint contextFlags) +{ + XMesaDisplay xmdpy = xmesa_init_display(v->display); + struct st_context_attribs attribs; + enum st_context_error ctx_err = 0; + XMesaContext c; + + if (!xmdpy) + goto no_xmesa_context; + + /* Note: the XMesaContext contains a Mesa struct gl_context struct (inheritance) */ + c = (XMesaContext) CALLOC_STRUCT(xmesa_context); + if (!c) + goto no_xmesa_context; + + c->xm_visual = v; + c->xm_buffer = NULL; /* set later by XMesaMakeCurrent */ + c->xm_read_buffer = NULL; + + memset(&attribs, 0, sizeof(attribs)); + attribs.visual = v->stvis; + attribs.major = major; + attribs.minor = minor; + if (contextFlags & GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB) + attribs.flags |= ST_CONTEXT_FLAG_FORWARD_COMPATIBLE; + if (contextFlags & GLX_CONTEXT_DEBUG_BIT_ARB) + attribs.flags |= ST_CONTEXT_FLAG_DEBUG; + if (contextFlags & GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB) + attribs.flags |= ST_CONTEXT_FLAG_ROBUST_ACCESS; + + switch (profileMask) { + case GLX_CONTEXT_CORE_PROFILE_BIT_ARB: + /* There are no profiles before OpenGL 3.2. The + * GLX_ARB_create_context_profile spec says: + * + * "If the requested OpenGL version is less than 3.2, + * GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality + * of the context is determined solely by the requested version." + */ + if (major > 3 || (major == 3 && minor >= 2)) { + attribs.profile = ST_PROFILE_OPENGL_CORE; + break; + } + /* fall-through */ + case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: + /* + * The spec also says: + * + * "If version 3.1 is requested, the context returned may implement + * any of the following versions: + * + * * Version 3.1. The GL_ARB_compatibility extension may or may not + * be implemented, as determined by the implementation. + * * The core profile of version 3.2 or greater." + * + * and because Mesa doesn't support GL_ARB_compatibility, the only chance to + * honour a 3.1 context is through core profile. + */ + if (major == 3 && minor == 1) { + attribs.profile = ST_PROFILE_OPENGL_CORE; + } else { + attribs.profile = ST_PROFILE_DEFAULT; + } + break; + case GLX_CONTEXT_ES_PROFILE_BIT_EXT: + if (major >= 2) { + attribs.profile = ST_PROFILE_OPENGL_ES2; + } else { + attribs.profile = ST_PROFILE_OPENGL_ES1; + } + break; + default: + assert(0); + goto no_st; + } + + c->st = stapi->create_context(stapi, xmdpy->smapi, &attribs, + &ctx_err, (share_list) ? share_list->st : NULL); + if (c->st == NULL) + goto no_st; + + c->st->st_manager_private = (void *) c; + + c->hud = hud_create(c->st->cso_context, NULL); + + return c; + +no_st: + free(c); +no_xmesa_context: + return NULL; +} + + + +PUBLIC +void XMesaDestroyContext( XMesaContext c ) +{ + if (c->hud) { + hud_destroy(c->hud, NULL); + } + + c->st->destroy(c->st); + + /* FIXME: We should destroy the screen here, but if we do so, surfaces may + * outlive it, causing segfaults + struct pipe_screen *screen = c->st->pipe->screen; + screen->destroy(screen); + */ + + free(c); +} + + + +/** + * Private function for creating an XMesaBuffer which corresponds to an + * X window or pixmap. + * \param v the window's XMesaVisual + * \param w the window we're wrapping + * \return new XMesaBuffer or NULL if error + */ +PUBLIC XMesaBuffer +XMesaCreateWindowBuffer(XMesaVisual v, Window w) +{ + XWindowAttributes attr; + XMesaBuffer b; + Colormap cmap; + int depth; + + assert(v); + assert(w); + + /* Check that window depth matches visual depth */ + XGetWindowAttributes( v->display, w, &attr ); + depth = attr.depth; + if (v->visinfo->depth != depth) { + _mesa_warning(NULL, "XMesaCreateWindowBuffer: depth mismatch between visual (%d) and window (%d)!\n", + v->visinfo->depth, depth); + return NULL; + } + + /* Find colormap */ + if (attr.colormap) { + cmap = attr.colormap; + } + else { + _mesa_warning(NULL, "Window %u has no colormap!\n", (unsigned int) w); + /* this is weird, a window w/out a colormap!? */ + /* OK, let's just allocate a new one and hope for the best */ + cmap = XCreateColormap(v->display, w, attr.visual, AllocNone); + } + + b = create_xmesa_buffer((Drawable) w, WINDOW, v, cmap); + if (!b) + return NULL; + + if (!initialize_visual_and_buffer( v, b, (Drawable) w, cmap )) { + xmesa_free_buffer(b); + return NULL; + } + + return b; +} + + + +/** + * Create a new XMesaBuffer from an X pixmap. + * + * \param v the XMesaVisual + * \param p the pixmap + * \param cmap the colormap, may be 0 if using a \c GLX_TRUE_COLOR or + * \c GLX_DIRECT_COLOR visual for the pixmap + * \returns new XMesaBuffer or NULL if error + */ +PUBLIC XMesaBuffer +XMesaCreatePixmapBuffer(XMesaVisual v, Pixmap p, Colormap cmap) +{ + XMesaBuffer b; + + assert(v); + + b = create_xmesa_buffer((Drawable) p, PIXMAP, v, cmap); + if (!b) + return NULL; + + if (!initialize_visual_and_buffer(v, b, (Drawable) p, cmap)) { + xmesa_free_buffer(b); + return NULL; + } + + return b; +} + + +/** + * For GLX_EXT_texture_from_pixmap + */ +XMesaBuffer +XMesaCreatePixmapTextureBuffer(XMesaVisual v, Pixmap p, + Colormap cmap, + int format, int target, int mipmap) +{ + GET_CURRENT_CONTEXT(ctx); + XMesaBuffer b; + + assert(v); + + b = create_xmesa_buffer((Drawable) p, PIXMAP, v, cmap); + if (!b) + return NULL; + + /* get pixmap size */ + xmesa_get_window_size(v->display, b, &b->width, &b->height); + + if (target == 0) { + /* examine dims */ + if (ctx->Extensions.ARB_texture_non_power_of_two) { + target = GLX_TEXTURE_2D_EXT; + } + else if ( util_bitcount(b->width) == 1 + && util_bitcount(b->height) == 1) { + /* power of two size */ + if (b->height == 1) { + target = GLX_TEXTURE_1D_EXT; + } + else { + target = GLX_TEXTURE_2D_EXT; + } + } + else if (ctx->Extensions.NV_texture_rectangle) { + target = GLX_TEXTURE_RECTANGLE_EXT; + } + else { + /* non power of two textures not supported */ + XMesaDestroyBuffer(b); + return 0; + } + } + + b->TextureTarget = target; + b->TextureFormat = format; + b->TextureMipmap = mipmap; + + if (!initialize_visual_and_buffer(v, b, (Drawable) p, cmap)) { + xmesa_free_buffer(b); + return NULL; + } + + return b; +} + + + +XMesaBuffer +XMesaCreatePBuffer(XMesaVisual v, Colormap cmap, + unsigned int width, unsigned int height) +{ + Window root; + Drawable drawable; /* X Pixmap Drawable */ + XMesaBuffer b; + + /* allocate pixmap for front buffer */ + root = RootWindow( v->display, v->visinfo->screen ); + drawable = XCreatePixmap(v->display, root, width, height, + v->visinfo->depth); + if (!drawable) + return NULL; + + b = create_xmesa_buffer(drawable, PBUFFER, v, cmap); + if (!b) + return NULL; + + if (!initialize_visual_and_buffer(v, b, drawable, cmap)) { + xmesa_free_buffer(b); + return NULL; + } + + return b; +} + + + +/* + * Deallocate an XMesaBuffer structure and all related info. + */ +PUBLIC void +XMesaDestroyBuffer(XMesaBuffer b) +{ + xmesa_free_buffer(b); +} + + +/** + * Notify the binding context to validate the buffer. + */ +void +xmesa_notify_invalid_buffer(XMesaBuffer b) +{ + p_atomic_inc(&b->stfb->stamp); +} + + +/** + * Query the current drawable size and notify the binding context. + */ +void +xmesa_check_buffer_size(XMesaBuffer b) +{ + GLuint old_width, old_height; + + if (!b) + return; + + if (b->type == PBUFFER) + return; + + old_width = b->width; + old_height = b->height; + + xmesa_get_window_size(b->xm_visual->display, b, &b->width, &b->height); + + if (b->width != old_width || b->height != old_height) + xmesa_notify_invalid_buffer(b); +} + + +/* + * Bind buffer b to context c and make c the current rendering context. + */ +PUBLIC +GLboolean XMesaMakeCurrent2( XMesaContext c, XMesaBuffer drawBuffer, + XMesaBuffer readBuffer ) +{ + XMesaContext old_ctx = XMesaGetCurrentContext(); + + if (old_ctx && old_ctx != c) { + XMesaFlush(old_ctx); + old_ctx->xm_buffer = NULL; + old_ctx->xm_read_buffer = NULL; + } + + if (c) { + if (!drawBuffer != !readBuffer) { + return GL_FALSE; /* must specify zero or two buffers! */ + } + + if (c == old_ctx && + c->xm_buffer == drawBuffer && + c->xm_read_buffer == readBuffer) + return GL_TRUE; + + xmesa_check_buffer_size(drawBuffer); + if (readBuffer != drawBuffer) + xmesa_check_buffer_size(readBuffer); + + c->xm_buffer = drawBuffer; + c->xm_read_buffer = readBuffer; + + stapi->make_current(stapi, c->st, + drawBuffer ? drawBuffer->stfb : NULL, + readBuffer ? readBuffer->stfb : NULL); + + /* Solution to Stephane Rehel's problem with glXReleaseBuffersMESA(): */ + if (drawBuffer) + drawBuffer->wasCurrent = GL_TRUE; + } + else { + /* Detach */ + stapi->make_current(stapi, NULL, NULL, NULL); + + } + return GL_TRUE; +} + + +/* + * Unbind the context c from its buffer. + */ +GLboolean XMesaUnbindContext( XMesaContext c ) +{ + /* A no-op for XFree86 integration purposes */ + return GL_TRUE; +} + + +XMesaContext XMesaGetCurrentContext( void ) +{ + struct st_context_iface *st = stapi->get_current(stapi); + return (XMesaContext) (st) ? st->st_manager_private : NULL; +} + + + +/** + * Swap front and back color buffers and have winsys display front buffer. + * If there's no front color buffer no swap actually occurs. + */ +PUBLIC +void XMesaSwapBuffers( XMesaBuffer b ) +{ + XMesaContext xmctx = XMesaGetCurrentContext(); + + /* Need to draw HUD before flushing */ + if (xmctx && xmctx->hud) { + struct pipe_resource *back = + xmesa_get_framebuffer_resource(b->stfb, ST_ATTACHMENT_BACK_LEFT); + hud_run(xmctx->hud, NULL, back); + } + + if (xmctx && xmctx->xm_buffer == b) { + xmctx->st->flush( xmctx->st, ST_FLUSH_FRONT, NULL, NULL, NULL); + } + + xmesa_swap_st_framebuffer(b->stfb); +} + + + +/* + * Copy sub-region of back buffer to front buffer + */ +void XMesaCopySubBuffer( XMesaBuffer b, int x, int y, int width, int height ) +{ + XMesaContext xmctx = XMesaGetCurrentContext(); + + xmctx->st->flush( xmctx->st, ST_FLUSH_FRONT, NULL, NULL, NULL); + + xmesa_copy_st_framebuffer(b->stfb, + ST_ATTACHMENT_BACK_LEFT, ST_ATTACHMENT_FRONT_LEFT, + x, b->height - y - height, width, height); +} + + + +void XMesaFlush( XMesaContext c ) +{ + if (c && c->xm_visual->display) { + XMesaDisplay xmdpy = xmesa_init_display(c->xm_visual->display); + struct pipe_fence_handle *fence = NULL; + + c->st->flush(c->st, ST_FLUSH_FRONT, &fence, NULL, NULL); + if (fence) { + xmdpy->screen->fence_finish(xmdpy->screen, NULL, fence, + PIPE_TIMEOUT_INFINITE); + xmdpy->screen->fence_reference(xmdpy->screen, &fence, NULL); + } + XFlush( c->xm_visual->display ); + } +} + + + + + +XMesaBuffer XMesaFindBuffer( Display *dpy, Drawable d ) +{ + XMesaBuffer b; + for (b = XMesaBufferList; b; b = b->Next) { + if (b->ws.drawable == d && b->xm_visual->display == dpy) { + return b; + } + } + return NULL; +} + + +/** + * Free/destroy all XMesaBuffers associated with given display. + */ +void xmesa_destroy_buffers_on_display(Display *dpy) +{ + XMesaBuffer b, next; + for (b = XMesaBufferList; b; b = next) { + next = b->Next; + if (b->xm_visual->display == dpy) { + xmesa_free_buffer(b); + /* delete head of list? */ + if (XMesaBufferList == b) { + XMesaBufferList = next; + } + } + } +} + + +/* + * Look for XMesaBuffers whose X window has been destroyed. + * Deallocate any such XMesaBuffers. + */ +void XMesaGarbageCollect( void ) +{ + XMesaBuffer b, next; + for (b=XMesaBufferList; b; b=next) { + next = b->Next; + if (b->xm_visual && + b->xm_visual->display && + b->ws.drawable && + b->type == WINDOW) { + XSync(b->xm_visual->display, False); + if (!window_exists( b->xm_visual->display, b->ws.drawable )) { + /* found a dead window, free the ancillary info */ + XMesaDestroyBuffer( b ); + } + } + } +} + + +static enum st_attachment_type xmesa_attachment_type(int glx_attachment) +{ + switch(glx_attachment) { + case GLX_FRONT_LEFT_EXT: + return ST_ATTACHMENT_FRONT_LEFT; + case GLX_FRONT_RIGHT_EXT: + return ST_ATTACHMENT_FRONT_RIGHT; + case GLX_BACK_LEFT_EXT: + return ST_ATTACHMENT_BACK_LEFT; + case GLX_BACK_RIGHT_EXT: + return ST_ATTACHMENT_BACK_RIGHT; + default: + assert(0); + return ST_ATTACHMENT_FRONT_LEFT; + } +} + + +PUBLIC void +XMesaBindTexImage(Display *dpy, XMesaBuffer drawable, int buffer, + const int *attrib_list) +{ + struct st_context_iface *st = stapi->get_current(stapi); + struct st_framebuffer_iface* stfbi = drawable->stfb; + struct pipe_resource *res; + int x, y, w, h; + enum st_attachment_type st_attachment = xmesa_attachment_type(buffer); + + x = 0; + y = 0; + w = drawable->width; + h = drawable->height; + + /* We need to validate our attachments before using them, + * in case the texture doesn't exist yet. */ + xmesa_st_framebuffer_validate_textures(stfbi, w, h, 1 << st_attachment); + res = xmesa_get_attachment(stfbi, st_attachment); + + if (res) { + struct pipe_context* pipe = xmesa_get_context(stfbi); + enum pipe_format internal_format = res->format; + struct pipe_transfer *tex_xfer; + char *map; + int line, byte_width; + XImage *img; + + internal_format = choose_pixel_format(drawable->xm_visual); + + map = pipe_transfer_map(pipe, res, + 0, 0, /* level, layer */ + PIPE_TRANSFER_WRITE, + x, y, + w, h, &tex_xfer); + if (!map) + return; + + /* Grab the XImage that we want to turn into a texture. */ + img = XGetImage(dpy, + drawable->ws.drawable, + x, y, + w, h, + AllPlanes, + ZPixmap); + + if (!img) { + pipe_transfer_unmap(pipe, tex_xfer); + return; + } + + /* The pipe transfer has a pitch rounded up to the nearest 64 pixels. */ + byte_width = w * ((img->bits_per_pixel + 7) / 8); + + for (line = 0; line < h; line++) + memcpy(&map[line * tex_xfer->stride], + &img->data[line * img->bytes_per_line], + byte_width); + + pipe_transfer_unmap(pipe, tex_xfer); + + st->teximage(st, + ST_TEXTURE_2D, + 0, /* level */ + internal_format, + res, + FALSE /* no mipmap */); + + } +} + + + +PUBLIC void +XMesaReleaseTexImage(Display *dpy, XMesaBuffer drawable, int buffer) +{ +} + + +void +XMesaCopyContext(XMesaContext src, XMesaContext dst, unsigned long mask) +{ + if (dst->st->copy) + dst->st->copy(dst->st, src->st, mask); +} diff --git a/src/gallium/frontends/glx/xlib/xm_api.h b/src/gallium/frontends/glx/xlib/xm_api.h new file mode 100644 index 00000000000..04eefda0b07 --- /dev/null +++ b/src/gallium/frontends/glx/xlib/xm_api.h @@ -0,0 +1,398 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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. + */ + + + +/* Sample Usage: + +In addition to the usual X calls to select a visual, create a colormap +and create a window, you must do the following to use the X/Mesa interface: + +1. Call XMesaCreateVisual() to make an XMesaVisual from an XVisualInfo. + +2. Call XMesaCreateContext() to create an X/Mesa rendering context, given + the XMesaVisual. + +3. Call XMesaCreateWindowBuffer() to create an XMesaBuffer from an X window + and XMesaVisual. + +4. Call XMesaMakeCurrent() to bind the XMesaBuffer to an XMesaContext and + to make the context the current one. + +5. Make gl* calls to render your graphics. + +6. Use XMesaSwapBuffers() when double buffering to swap front/back buffers. + +7. Before the X window is destroyed, call XMesaDestroyBuffer(). + +8. Before exiting, call XMesaDestroyVisual and XMesaDestroyContext. + +*/ + + + + +#ifndef XM_API_H +#define XM_API_H + + +#include "main/mtypes.h" /* for gl_config */ +#include "frontend/api.h" +#include "os/os_thread.h" + +#include "frontend/xlibsw_api.h" + +# include <X11/Xlib.h> +# include <X11/Xlibint.h> +# include <X11/Xutil.h> + +struct hud_context; + +typedef struct xmesa_display *XMesaDisplay; +typedef struct xmesa_buffer *XMesaBuffer; +typedef struct xmesa_context *XMesaContext; +typedef struct xmesa_visual *XMesaVisual; + + +struct xmesa_display { + mtx_t mutex; + + Display *display; + struct pipe_screen *screen; + struct st_manager *smapi; + + struct pipe_context *pipe; +}; + + +/* + * Create a new X/Mesa visual. + * Input: display - X11 display + * visinfo - an XVisualInfo pointer + * rgb_flag - GL_TRUE = RGB mode, + * GL_FALSE = color index mode + * alpha_flag - alpha buffer requested? + * db_flag - GL_TRUE = double-buffered, + * GL_FALSE = single buffered + * stereo_flag - stereo visual? + * ximage_flag - GL_TRUE = use an XImage for back buffer, + * GL_FALSE = use an off-screen pixmap for back buffer + * depth_size - requested bits/depth values, or zero + * stencil_size - requested bits/stencil values, or zero + * accum_red_size - requested bits/red accum values, or zero + * accum_green_size - requested bits/green accum values, or zero + * accum_blue_size - requested bits/blue accum values, or zero + * accum_alpha_size - requested bits/alpha accum values, or zero + * num_samples - number of samples/pixel if multisampling, or zero + * level - visual level, usually 0 + * visualCaveat - ala the GLX extension, usually GLX_NONE_EXT + * Return; a new XMesaVisual or 0 if error. + */ +extern XMesaVisual XMesaCreateVisual( Display *display, + XVisualInfo * visinfo, + GLboolean rgb_flag, + GLboolean alpha_flag, + GLboolean db_flag, + GLboolean stereo_flag, + GLboolean ximage_flag, + GLint depth_size, + GLint stencil_size, + GLint accum_red_size, + GLint accum_green_size, + GLint accum_blue_size, + GLint accum_alpha_size, + GLint num_samples, + GLint level, + GLint visualCaveat ); + +/* + * Destroy an XMesaVisual, but not the associated XVisualInfo. + */ +extern void XMesaDestroyVisual( XMesaVisual v ); + + + +/* + * Create a new XMesaContext for rendering into an X11 window. + * + * Input: visual - an XMesaVisual + * share_list - another XMesaContext with which to share display + * lists or NULL if no sharing is wanted. + * Return: an XMesaContext or NULL if error. + */ +extern XMesaContext XMesaCreateContext( XMesaVisual v, + XMesaContext share_list, + GLuint major, GLuint minor, + GLuint profileMask, + GLuint contextFlags); + + +/* + * Destroy a rendering context as returned by XMesaCreateContext() + */ +extern void XMesaDestroyContext( XMesaContext c ); + + + +/* + * Create an XMesaBuffer from an X window. + */ +extern XMesaBuffer XMesaCreateWindowBuffer( XMesaVisual v, Window w ); + + +/* + * Create an XMesaBuffer from an X pixmap. + */ +extern XMesaBuffer XMesaCreatePixmapBuffer( XMesaVisual v, + Pixmap p, + Colormap cmap ); + + +/* + * Destroy an XMesaBuffer, but not the corresponding window or pixmap. + */ +extern void XMesaDestroyBuffer( XMesaBuffer b ); + + +/* + * Return the XMesaBuffer handle which corresponds to an X drawable, if any. + * + * New in Mesa 2.3. + */ +extern XMesaBuffer XMesaFindBuffer( Display *dpy, + Drawable d ); + + + +/* + * Bind two buffers (read and draw) to a context and make the + * context the current one. + * New in Mesa 3.3 + */ +extern GLboolean XMesaMakeCurrent2( XMesaContext c, + XMesaBuffer drawBuffer, + XMesaBuffer readBuffer ); + + +/* + * Unbind the current context from its buffer. + */ +extern GLboolean XMesaUnbindContext( XMesaContext c ); + + +/* + * Return a handle to the current context. + */ +extern XMesaContext XMesaGetCurrentContext( void ); + + +/* + * Swap the front and back buffers for the given buffer. No action is + * taken if the buffer is not double buffered. + */ +extern void XMesaSwapBuffers( XMesaBuffer b ); + + +/* + * Copy a sub-region of the back buffer to the front buffer. + * + * New in Mesa 2.6 + */ +extern void XMesaCopySubBuffer( XMesaBuffer b, + int x, + int y, + int width, + int height ); + + + + + +/* + * Flush/sync a context + */ +extern void XMesaFlush( XMesaContext c ); + + + +/* + * Scan for XMesaBuffers whose window/pixmap has been destroyed, then free + * any memory used by that buffer. + * + * New in Mesa 2.3. + */ +extern void XMesaGarbageCollect( void ); + + + +/* + * Create a pbuffer. + * New in Mesa 4.1 + */ +extern XMesaBuffer XMesaCreatePBuffer(XMesaVisual v, Colormap cmap, + unsigned int width, unsigned int height); + + + +/* + * Texture from Pixmap + * New in Mesa 7.1 + */ +extern void +XMesaBindTexImage(Display *dpy, XMesaBuffer drawable, int buffer, + const int *attrib_list); + +extern void +XMesaReleaseTexImage(Display *dpy, XMesaBuffer drawable, int buffer); + + +extern XMesaBuffer +XMesaCreatePixmapTextureBuffer(XMesaVisual v, Pixmap p, + Colormap cmap, + int format, int target, int mipmap); + + +extern void +XMesaCopyContext(XMesaContext src, XMesaContext dst, unsigned long mask); + + +/*********************************************************************** + */ + +/** + * Visual inforation, derived from GLvisual. + * Basically corresponds to an XVisualInfo. + */ +struct xmesa_visual { + struct gl_config mesa_visual;/* Device independent visual parameters */ + int screen, visualID, visualType; + Display *display; /* The X11 display */ + XVisualInfo * visinfo; /* X's visual info (pointer to private copy) */ + XVisualInfo *vishandle; /* Only used in fakeglx.c */ + GLint BitsPerPixel; /* True bits per pixel for XImages */ + + GLboolean ximage_flag; /* Use XImage for back buffer (not pixmap)? */ + + struct st_visual stvis; +}; + + +/** + * Context info, derived from st_context. + * Basically corresponds to a GLXContext. + */ +struct xmesa_context { + struct st_context_iface *st; + XMesaVisual xm_visual; /** pixel format info */ + XMesaBuffer xm_buffer; /** current drawbuffer */ + XMesaBuffer xm_read_buffer; /** current readbuffer */ + struct hud_context *hud; +}; + + +/** + * Types of X/GLX drawables we might render into. + */ +typedef enum { + WINDOW, /* An X window */ + GLXWINDOW, /* GLX window */ + PIXMAP, /* GLX pixmap */ + PBUFFER /* GLX Pbuffer */ +} BufferType; + + +/** + * Framebuffer information, derived from. + * Basically corresponds to a GLXDrawable. + */ +struct xmesa_buffer { + struct st_framebuffer_iface *stfb; + struct xlib_drawable ws; + + GLboolean wasCurrent; /* was ever the current buffer? */ + XMesaVisual xm_visual; /* the X/Mesa visual */ + Colormap cmap; /* the X colormap */ + BufferType type; /* window, pixmap, pbuffer or glxwindow */ + + GLboolean largestPbuffer; /**< for pbuffers */ + GLboolean preservedContents; /**< for pbuffers */ + + XImage *tempImage; + unsigned long selectedEvents;/* for pbuffers only */ + + + GC gc; /* scratch GC for span, line, tri drawing */ + + /* GLX_EXT_texture_from_pixmap */ + GLint TextureTarget; /** GLX_TEXTURE_1D_EXT, for example */ + GLint TextureFormat; /** GLX_TEXTURE_FORMAT_RGB_EXT, for example */ + GLint TextureMipmap; /** 0 or 1 */ + + struct xmesa_buffer *Next; /* Linked list pointer: */ + + unsigned width, height; +}; + + + +extern const char * +xmesa_get_name(void); + +extern int +xmesa_init(Display *dpy); + +extern XMesaBuffer +xmesa_find_buffer(Display *dpy, Colormap cmap, XMesaBuffer notThis); + +extern void +xmesa_get_window_size(Display *dpy, XMesaBuffer b, + GLuint *width, GLuint *height); + +extern void +xmesa_notify_invalid_buffer(XMesaBuffer b); + +extern void +xmesa_check_buffer_size(XMesaBuffer b); + +extern void +xmesa_destroy_buffers_on_display(Display *dpy); + +extern void +xmesa_close_display(Display *dpy); + +static inline GLuint +xmesa_buffer_width(XMesaBuffer b) +{ + return b->width; +} + +static inline GLuint +xmesa_buffer_height(XMesaBuffer b) +{ + return b->height; +} + +extern boolean xmesa_strict_invalidate; + +#endif diff --git a/src/gallium/frontends/glx/xlib/xm_public.h b/src/gallium/frontends/glx/xlib/xm_public.h new file mode 100644 index 00000000000..9afc5f5d7cf --- /dev/null +++ b/src/gallium/frontends/glx/xlib/xm_public.h @@ -0,0 +1,48 @@ + +/************************************************************************** + * + * Copyright 2006 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef XM_PUBLIC_H +#define XM_PUBLIC_H + +#include <X11/Xlib.h> + +struct pipe_screen; +struct st_api; + +/* This is the driver interface required by the glx/xlib state tracker. + */ +struct xm_driver { + struct pipe_screen *(*create_pipe_screen)( Display *display ); + struct st_api *(*create_st_api)( void ); +}; + +extern void +xmesa_set_driver( const struct xm_driver *driver ); + + +#endif /* XM_PUBLIC_H */ diff --git a/src/gallium/frontends/glx/xlib/xm_st.c b/src/gallium/frontends/glx/xlib/xm_st.c new file mode 100644 index 00000000000..4fe7b57f24c --- /dev/null +++ b/src/gallium/frontends/glx/xlib/xm_st.c @@ -0,0 +1,411 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2010 LunarG Inc. + * + * 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. + * + * Authors: + * Chia-I Wu <[email protected]> + */ + +#include "xm_api.h" +#include "xm_st.h" + +#include "util/u_inlines.h" +#include "util/u_atomic.h" +#include "util/u_memory.h" + +struct xmesa_st_framebuffer { + XMesaDisplay display; + XMesaBuffer buffer; + struct pipe_screen *screen; + + struct st_visual stvis; + enum pipe_texture_target target; + + unsigned texture_width, texture_height, texture_mask; + struct pipe_resource *textures[ST_ATTACHMENT_COUNT]; + + struct pipe_resource *display_resource; +}; + + +static inline struct xmesa_st_framebuffer * +xmesa_st_framebuffer(struct st_framebuffer_iface *stfbi) +{ + return (struct xmesa_st_framebuffer *) stfbi->st_manager_private; +} + + +/** + * Display (present) an attachment to the xlib_drawable of the framebuffer. + */ +static bool +xmesa_st_framebuffer_display(struct st_framebuffer_iface *stfbi, + enum st_attachment_type statt) +{ + struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); + struct pipe_resource *ptex = xstfb->textures[statt]; + struct pipe_resource *pres; + + if (!ptex) + return true; + + pres = xstfb->display_resource; + /* (re)allocate the surface for the texture to be displayed */ + if (!pres || pres != ptex) { + pipe_resource_reference(&xstfb->display_resource, ptex); + pres = xstfb->display_resource; + } + + xstfb->screen->flush_frontbuffer(xstfb->screen, pres, 0, 0, &xstfb->buffer->ws, NULL); + return true; +} + + +/** + * Copy the contents between the attachments. + */ +static void +xmesa_st_framebuffer_copy_textures(struct st_framebuffer_iface *stfbi, + enum st_attachment_type src_statt, + enum st_attachment_type dst_statt, + unsigned x, unsigned y, + unsigned width, unsigned height) +{ + struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); + struct pipe_resource *src_ptex = xstfb->textures[src_statt]; + struct pipe_resource *dst_ptex = xstfb->textures[dst_statt]; + struct pipe_box src_box; + struct pipe_context *pipe; + + if (!src_ptex || !dst_ptex) + return; + + pipe = xmesa_get_context(stfbi); + + u_box_2d(x, y, width, height, &src_box); + + if (src_ptex && dst_ptex) + pipe->resource_copy_region(pipe, dst_ptex, 0, x, y, 0, + src_ptex, 0, &src_box); +} + + +/** + * Remove outdated textures and create the requested ones. + * This is a helper used during framebuffer validation. + */ +bool +xmesa_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi, + unsigned width, unsigned height, + unsigned mask) +{ + struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); + struct pipe_resource templ; + enum st_attachment_type i; + + /* remove outdated textures */ + if (xstfb->texture_width != width || xstfb->texture_height != height) { + for (i = 0; i < ST_ATTACHMENT_COUNT; i++) + pipe_resource_reference(&xstfb->textures[i], NULL); + } + + memset(&templ, 0, sizeof(templ)); + templ.target = xstfb->target; + templ.width0 = width; + templ.height0 = height; + templ.depth0 = 1; + templ.array_size = 1; + templ.last_level = 0; + templ.nr_samples = xstfb->stvis.samples; + templ.nr_storage_samples = xstfb->stvis.samples; + + for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { + enum pipe_format format; + unsigned bind; + + /* the texture already exists or not requested */ + if (xstfb->textures[i] || !(mask & (1 << i))) { + /* remember the texture */ + if (xstfb->textures[i]) + mask |= (1 << i); + continue; + } + + switch (i) { + case ST_ATTACHMENT_FRONT_LEFT: + case ST_ATTACHMENT_BACK_LEFT: + case ST_ATTACHMENT_FRONT_RIGHT: + case ST_ATTACHMENT_BACK_RIGHT: + format = xstfb->stvis.color_format; + bind = PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_RENDER_TARGET; + break; + case ST_ATTACHMENT_DEPTH_STENCIL: + format = xstfb->stvis.depth_stencil_format; + bind = PIPE_BIND_DEPTH_STENCIL; + break; + default: + format = PIPE_FORMAT_NONE; + break; + } + + if (format != PIPE_FORMAT_NONE) { + templ.format = format; + templ.bind = bind; + + xstfb->textures[i] = + xstfb->screen->resource_create(xstfb->screen, &templ); + if (!xstfb->textures[i]) + return FALSE; + } + } + + xstfb->texture_width = width; + xstfb->texture_height = height; + xstfb->texture_mask = mask; + + return true; +} + + +/** + * Check that a framebuffer's attachments match the window's size. + * + * Called via st_framebuffer_iface::validate() + * + * \param statts array of framebuffer attachments + * \param count number of framebuffer attachments in statts[] + * \param out returns resources for each of the attachments + */ +static bool +xmesa_st_framebuffer_validate(struct st_context_iface *stctx, + struct st_framebuffer_iface *stfbi, + const enum st_attachment_type *statts, + unsigned count, + struct pipe_resource **out) +{ + struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); + unsigned statt_mask, new_mask, i; + bool resized; + bool ret; + + /* build mask of ST_ATTACHMENT bits */ + statt_mask = 0x0; + for (i = 0; i < count; i++) + statt_mask |= 1 << statts[i]; + + /* record newly allocated textures */ + new_mask = statt_mask & ~xstfb->texture_mask; + + /* If xmesa_strict_invalidate is not set, we will not yet have + * called XGetGeometry(). Do so here: + */ + if (!xmesa_strict_invalidate) + xmesa_check_buffer_size(xstfb->buffer); + + resized = (xstfb->buffer->width != xstfb->texture_width || + xstfb->buffer->height != xstfb->texture_height); + + /* revalidate textures */ + if (resized || new_mask) { + ret = xmesa_st_framebuffer_validate_textures(stfbi, + xstfb->buffer->width, xstfb->buffer->height, statt_mask); + if (!ret) + return ret; + + if (!resized) { + enum st_attachment_type back, front; + + back = ST_ATTACHMENT_BACK_LEFT; + front = ST_ATTACHMENT_FRONT_LEFT; + /* copy the contents if front is newly allocated and back is not */ + if ((statt_mask & (1 << back)) && + (new_mask & (1 << front)) && + !(new_mask & (1 << back))) { + xmesa_st_framebuffer_copy_textures(stfbi, back, front, + 0, 0, xstfb->texture_width, xstfb->texture_height); + } + } + } + + for (i = 0; i < count; i++) + pipe_resource_reference(&out[i], xstfb->textures[statts[i]]); + + return true; +} + + +/** + * Called via st_framebuffer_iface::flush_front() + */ +static bool +xmesa_st_framebuffer_flush_front(struct st_context_iface *stctx, + struct st_framebuffer_iface *stfbi, + enum st_attachment_type statt) +{ + struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); + bool ret; + + ret = xmesa_st_framebuffer_display(stfbi, statt); + + if (ret && xmesa_strict_invalidate) + xmesa_check_buffer_size(xstfb->buffer); + + return ret; +} + +static uint32_t xmesa_stfbi_ID = 0; + +struct st_framebuffer_iface * +xmesa_create_st_framebuffer(XMesaDisplay xmdpy, XMesaBuffer b) +{ + struct st_framebuffer_iface *stfbi; + struct xmesa_st_framebuffer *xstfb; + + assert(xmdpy->display == b->xm_visual->display); + + stfbi = CALLOC_STRUCT(st_framebuffer_iface); + xstfb = CALLOC_STRUCT(xmesa_st_framebuffer); + if (!stfbi || !xstfb) { + free(stfbi); + free(xstfb); + return NULL; + } + + xstfb->display = xmdpy; + xstfb->buffer = b; + xstfb->screen = xmdpy->screen; + xstfb->stvis = b->xm_visual->stvis; + if (xstfb->screen->get_param(xstfb->screen, PIPE_CAP_NPOT_TEXTURES)) + xstfb->target = PIPE_TEXTURE_2D; + else + xstfb->target = PIPE_TEXTURE_RECT; + + stfbi->visual = &xstfb->stvis; + stfbi->flush_front = xmesa_st_framebuffer_flush_front; + stfbi->validate = xmesa_st_framebuffer_validate; + stfbi->ID = p_atomic_inc_return(&xmesa_stfbi_ID); + stfbi->state_manager = xmdpy->smapi; + p_atomic_set(&stfbi->stamp, 1); + stfbi->st_manager_private = (void *) xstfb; + + return stfbi; +} + + +void +xmesa_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi) +{ + struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); + int i; + + pipe_resource_reference(&xstfb->display_resource, NULL); + + for (i = 0; i < ST_ATTACHMENT_COUNT; i++) + pipe_resource_reference(&xstfb->textures[i], NULL); + + free(xstfb); + free(stfbi); +} + + +/** + * Return the pipe_surface which corresponds to the given + * framebuffer attachment. + */ +struct pipe_resource * +xmesa_get_framebuffer_resource(struct st_framebuffer_iface *stfbi, + enum st_attachment_type att) +{ + struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); + return xstfb->textures[att]; +} + + +void +xmesa_swap_st_framebuffer(struct st_framebuffer_iface *stfbi) +{ + struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); + bool ret; + + ret = xmesa_st_framebuffer_display(stfbi, ST_ATTACHMENT_BACK_LEFT); + if (ret) { + struct pipe_resource **front, **back, *tmp; + + front = &xstfb->textures[ST_ATTACHMENT_FRONT_LEFT]; + back = &xstfb->textures[ST_ATTACHMENT_BACK_LEFT]; + /* swap textures only if the front texture has been allocated */ + if (*front) { + tmp = *front; + *front = *back; + *back = tmp; + + /* the current context should validate the buffer after swapping */ + if (!xmesa_strict_invalidate) + xmesa_notify_invalid_buffer(xstfb->buffer); + } + + if (xmesa_strict_invalidate) + xmesa_check_buffer_size(xstfb->buffer); + } +} + + +void +xmesa_copy_st_framebuffer(struct st_framebuffer_iface *stfbi, + enum st_attachment_type src, + enum st_attachment_type dst, + int x, int y, int w, int h) +{ + xmesa_st_framebuffer_copy_textures(stfbi, src, dst, x, y, w, h); + if (dst == ST_ATTACHMENT_FRONT_LEFT) + xmesa_st_framebuffer_display(stfbi, dst); +} + + +struct pipe_resource* +xmesa_get_attachment(struct st_framebuffer_iface *stfbi, + enum st_attachment_type st_attachment) +{ + struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); + struct pipe_resource *res; + + res = xstfb->textures[st_attachment]; + return res; +} + + +struct pipe_context* +xmesa_get_context(struct st_framebuffer_iface *stfbi) +{ + struct pipe_context *pipe; + struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi); + + pipe = xstfb->display->pipe; + if (!pipe) { + pipe = xstfb->screen->context_create(xstfb->screen, NULL, 0); + if (!pipe) + return NULL; + xstfb->display->pipe = pipe; + } + return pipe; +} diff --git a/src/gallium/frontends/glx/xlib/xm_st.h b/src/gallium/frontends/glx/xlib/xm_st.h new file mode 100644 index 00000000000..6d92a38e0dd --- /dev/null +++ b/src/gallium/frontends/glx/xlib/xm_st.h @@ -0,0 +1,66 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2010 LunarG Inc. + * + * 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. + * + * Authors: + * Chia-I Wu <[email protected]> + */ + +#ifndef _XM_ST_H_ +#define _XM_ST_H_ + +#include "pipe/p_compiler.h" +#include "frontend/api.h" + +#include "xm_api.h" + +struct st_framebuffer_iface * +xmesa_create_st_framebuffer(XMesaDisplay xmdpy, XMesaBuffer b); + +void +xmesa_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi); + +struct pipe_resource * +xmesa_get_framebuffer_resource(struct st_framebuffer_iface *stfbi, + enum st_attachment_type att); + +void +xmesa_swap_st_framebuffer(struct st_framebuffer_iface *stfbi); + +void +xmesa_copy_st_framebuffer(struct st_framebuffer_iface *stfbi, + enum st_attachment_type src, + enum st_attachment_type dst, + int x, int y, int w, int h); + +struct pipe_resource* +xmesa_get_attachment(struct st_framebuffer_iface *stfbi, + enum st_attachment_type st_attachment); + +struct pipe_context* +xmesa_get_context(struct st_framebuffer_iface* stfbi); + +bool +xmesa_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi, + unsigned width, unsigned height, + unsigned mask); +#endif /* _XM_ST_H_ */ |