OK, one more time. Simplify the state-backup system by just storing the full
[mesa.git] / src / mesa / drivers / ggi / ggimesa.c
index b13846060ed10008103d40c902c018afcde4a619..cb34c1a54108c64b2831cf29f2790c3a454df2a9 100644 (file)
@@ -1,6 +1,7 @@
 /* GGI-Driver for MESA
  * 
  * Copyright (C) 1997-1998  Uwe Maurer  -  uwe_maurer@t-online.de 
+ *                    2002  Filip Spacek
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #include <ggi/mesa/ggimesa_int.h>
 #include <ggi/mesa/debug.h>
 #include "extensions.h"
+#include "colormac.h"
+#include "imports.h"
 #include "matrix.h"
+#include "swrast/swrast.h"
+#include "swrast_setup/swrast_setup.h"
+#include "tnl/tnl.h"
+#include "tnl/t_context.h"
+#include "tnl/t_pipeline.h"
+#include "array_cache/acache.h"
+#include "teximage.h"
+#include "texformat.h"
+#include "texstore.h"
+
+/* We use LibGG to manage config files */
+#include <ggi/gg.h>
+
+
+/* XXX: Those #defines should be provided via 
+ * config.h
+ */
+#define GGIMESAPATHTAG "pAtHTAg"
+#define GGIMESACONFDIR "pAtHTAg/usr/local/etc/ggi"
+#define GGIMESATAGLEN  7
+#define GGIMESACONFFILE        "ggimesa.conf"
 
-#undef VIS
-#undef FLIP
-#define VIS (GGIMesa->ggi_vis)
-#define FLIP(y) (GGIMesa->flip_y-(y))
-
-GGIMesaContext GGIMesa = NULL;    /* the current context */
 
-ggi_extid ggiMesaID = -1;
+/* Static variables
+ */
 static int _ggimesaLibIsUp = 0;
 static void *_ggimesaConfigHandle;
-
-/* FIXME: These should really be defined in the make system using -Dxxx */
-#define GGIMESACONFFILE "/usr/local/etc/ggi/ggimesa.conf"
-#define GGIMESATAGLEN 0
-static char ggimesaconfstub[512] = GGIMESACONFFILE;
-static char *ggimesaconffile = ggimesaconfstub + GGIMESATAGLEN;
+static char _ggimesaconfstub[512] = GGIMESACONFDIR;
+static char *_ggimesaconfdir = _ggimesaconfstub+GGIMESATAGLEN;
 
 int _ggimesaDebugSync = 0;
 uint32 _ggimesaDebugState = 0;
 
-static void gl_ggiUpdateState(GLcontext *ctx);
-static int changed(ggi_visual_t vis, int whatchanged);
 
-static void gl_ggiGetSize(GLcontext *ctx, GLuint *width, GLuint *height)
+
+/* Extension ID. Defaulting to -1 should make segfault on abuse more likely...
+ */
+ggi_extid _ggiMesaID = -1;
+
+
+#define SUBLIB_PREFIX  "MesaGGIdl_"
+
+
+/*
+ * Returns the directory where global config files are kept
+ */
+const char *ggiMesaGetConfDir(void)
 {
-       GGIMESADPRINT_CORE("gl_ggiGetSize() called\n");
-       
-       *width = GGIMesa->width; 
-       *height = GGIMesa->height;      
+#ifdef __WIN32__
+       /* On Win32 we allow overriding of the compiled in path. */
+       const char *envdir = getenv("GGI_CONFDIR");
+       if (envdir) return envdir;
+#endif
+       return _ggimesaconfdir;
 }
 
-static void gl_ggiSetIndex(GLcontext *ctx, GLuint ci)
+
+/* Dummy function which returns -1
+   We use this to reset the function pointers */
+static int _ggi_error(void)
 {
-       GGIMESADPRINT_CORE("gl_ggiSetIndex() called\n");
+       GGIMESADPRINT_CORE("_ggi_error() called\n");
        
-       ggiSetGCForeground(VIS, ci);
-       GGICTX->color = (ggi_pixel)ci;
+       return -1;
 }
 
-static void gl_ggiSetClearIndex(GLcontext *ctx, GLuint ci)
+
+static int changed(ggi_visual_t vis, int whatchanged)
 {
-       GGIMESADPRINT_CORE("gl_ggiSetClearIndex() called\n");
-       
-       ggiSetGCForeground(VIS, ci);
-       GGICTX->clearcolor = (ggi_pixel)ci;
+       GLcontext *ctx;
+       ctx = _mesa_get_current_context();
+
+       GGIMESADPRINT_CORE("changed() called\n");
+               
+       switch (whatchanged) {
+       case GGI_CHG_APILIST:
+       {
+               char api[GGI_MAX_APILEN];
+               char args[GGI_MAX_APILEN];
+               int i;
+               const char *fname;
+               ggi_dlhandle *lib;
+
+               GLvisual *gl_vis = &(LIBGGI_MESAEXT(vis)->mesa_visual.gl_visual);
+               GLframebuffer *gl_fb = &(LIBGGI_MESAEXT(vis)->mesa_buffer);
+               
+               /* Initialize the framebuffer to provide all necessary
+                  buffers in software. The target libraries that are loaded
+                  next are free to modify this according to their
+                  capabilities. 
+                */
+                /* FIXME: if the target changes capabilities we'll leak 
+                   swrast's memory !!! Need to deallocate first */
+               _mesa_initialize_framebuffer(gl_fb, gl_vis,
+                                        gl_vis->depthBits > 0,
+                                        gl_vis->stencilBits > 0,
+                                        gl_vis->accumRedBits > 0,
+                                        gl_vis->alphaBits > 0);
+
+               for (i = 0; ggiGetAPI(vis, i, api, args) == 0; i++) {
+                       strcat(api, "-mesa");
+                       GGIMESADPRINT_CORE("GGIMesa: looking for"
+                                       "a sublib named %s\n", api);
+                       fname = ggMatchConfig(_ggimesaConfigHandle, api, NULL);
+                       if (fname == NULL) {
+                               /* No special implementation for this sublib */
+                               continue;
+                       }
+                       lib = ggiExtensionLoadDL(vis, fname, args, NULL,
+                                                SUBLIB_PREFIX);
+               }
+
+               /* The targets have cleared everything they can do from 
+                  the framebuffer structure so we provide the rest in sw
+                */
+               _swrast_alloc_buffers(gl_fb);
+               
+               break;
+       } 
+       }
+       return 0;
 }
 
-static void gl_ggiSetColor(GLcontext *ctx, GLubyte red, GLubyte green,
-                          GLubyte blue, GLubyte alpha)
+
+int ggiMesaInit()
 {
-       ggi_color rgb;
-       ggi_pixel col;
+       int err;
+       char *str;
+       char *conffile;
        
-       GGIMESADPRINT_CORE("gl_ggiSetColor() called\n");
+       GGIMESADPRINT_CORE("ggiMesaInit() called\n");
+       
+       _ggimesaLibIsUp++;
+       if (_ggimesaLibIsUp > 1) return 0; /* Initialize only at first call */
+       
+       str = getenv("GGIMESA_DEBUGSYNC");
+       if (str != NULL) {
+               _ggimesaDebugSync = 1;
+       }
+       
+       str = getenv("GGIMESA_DEBUG");
+       if (str != NULL) {
+               _ggimesaDebugState = atoi(str);
+               GGIMESADPRINT_CORE("%s Debugging=%d\n",
+                       _ggimesaDebugSync ? "sync" : "async",
+                       _ggimesaDebugState);
+       }
        
-       rgb.r = (uint16)red << SHIFT;
-       rgb.g = (uint16)green << SHIFT;
-       rgb.b = (uint16)blue << SHIFT;
-       col = ggiMapColor(VIS, &rgb);
-       ggiSetGCForeground(VIS, col);
-       GGICTX->color = col;
-}
 
-static void gl_ggiSetClearColor(GLcontext *ctx, GLubyte red, GLubyte green,
-                               GLubyte blue, GLubyte alpha)
-{
-       ggi_color rgb;
-       ggi_pixel col;
+       conffile = malloc(strlen(ggiMesaGetConfDir()) + 1
+                         + strlen(GGIMESACONFFILE) +1);
+       if (conffile == NULL) {
+               fprintf(stderr, "GGIMesa: unable to allocate memory for config filename.\n");
+               return GGI_ENOMEM;
+       }
+       sprintf(conffile, "%s%c%s",
+               ggiMesaGetConfDir(), '/', GGIMESACONFFILE);
+       err = ggLoadConfig(conffile, &_ggimesaConfigHandle);
+       if (err != GGI_OK) {
+               fprintf(stderr, "GGIMesa: Couldn't open %s\n",
+                       conffile);
+               free(conffile);
+               _ggimesaLibIsUp--;
+               return err;
+       }
+       free(conffile);
        
-       GGIMESADPRINT_CORE("gl_ggiSetClearColor() called\n");
+       _ggiMesaID = ggiExtensionRegister("GGIMesa",
+                                        sizeof(struct ggi_mesa_ext), changed);
+       if (_ggiMesaID < 0) {
+               fprintf(stderr, "GGIMesa: failed to register as extension\n");
+               _ggimesaLibIsUp--;
+               ggFreeConfig(_ggimesaConfigHandle);
+               return _ggiMesaID;
+       }
        
-       rgb.r = (uint16)red << SHIFT;
-       rgb.g = (uint16)green << SHIFT;
-       rgb.b = (uint16)blue << SHIFT;
-       col = ggiMapColor(VIS, &rgb);
-       ggiSetGCForeground(VIS, col);
-       GGICTX->clearcolor = col;
+       return 0;
 }
 
-static GLbitfield gl_ggiClear(GLcontext *ctx,GLbitfield mask, GLboolean all,
-                             GLint x, GLint y, GLint width, GLint height)
+int ggiMesaExit(void)
 {
-       GGIMESADPRINT_CORE("gl_ggiClear() called\n");
+       int rc;
 
-       if (mask & GL_COLOR_BUFFER_BIT) 
-       {
-               ggiSetGCForeground(VIS, GGICTX->clearcolor);
+       GGIMESADPRINT_CORE("ggiMesaExit() called\n");
 
-               if (all)
-               {
-                       ggiDrawBox(VIS, 0, GGIMesa->origin.y,
-                                  GGIMesa->width, GGIMesa->height);
-               }
-               else
-               {
-                       ggiDrawBox(VIS, x, FLIP(y), width, height);
-               }
+       if (!_ggimesaLibIsUp) return -1;
 
-               ggiSetGCForeground(VIS, GGICTX->color);
+       if (_ggimesaLibIsUp > 1) {
+               /* Exit only at last call */
+               _ggimesaLibIsUp--;
+               return 0;
        }
-       return mask & (~GL_COLOR_BUFFER_BIT);
+       
+       rc = ggiExtensionUnregister(_ggiMesaID);
+       ggFreeConfig(_ggimesaConfigHandle);
+
+       _ggimesaLibIsUp = 0;
+
+       return rc;
+}
+
+
+
+
+static void gl_ggiUpdateState(GLcontext *ctx, GLuint new_state);
+
+
+static void gl_ggiGetSize(GLframebuffer *fb, GLuint *width, GLuint *height)
+{
+       /* FIXME: this is a hack to work around the new interface */
+       GLcontext *ctx;
+       ggi_mesa_context_t ggi_ctx;
+       ctx = _mesa_get_current_context();
+       ggi_ctx = (ggi_mesa_context_t)ctx->DriverCtx;
+       
+       GGIMESADPRINT_CORE("gl_ggiGetSize() called\n");
+       
+       *width = LIBGGI_VIRTX(ggi_ctx->ggi_visual);
+       *height = LIBGGI_VIRTY(ggi_ctx->ggi_visual);
+       printf("returning %d, %d\n", *width, *height);
 }
 
-#if 0
-static GLboolean gl_ggiSetBuffer(GLcontext *ctx, GLenum mode)
+static void gl_ggiSetIndex(GLcontext *ctx, GLuint ci)
 {
-       GGIMESADPRINT_CORE("gl_ggiSetBuffer() called\n");
+       ggi_mesa_context_t ggi_ctx = (ggi_mesa_context_t)ctx->DriverCtx;
        
-       if (mode == GL_FRONT)
-         GGICTX->active_buffer = 1;
-       else
-         GGICTX->active_buffer = 0;
+       GGIMESADPRINT_CORE("gl_ggiSetIndex() called\n");
        
-       return GL_TRUE;
+       ggiSetGCForeground(ggi_ctx->ggi_visual, ci);
+       ggi_ctx->color = (ggi_pixel)ci;
 }
-#endif
 
-/* Set the buffer used for drawing */
-static GLboolean gl_ggiSetDrawBuffer(GLcontext *ctx, GLenum mode)
+static void gl_ggiSetClearIndex(GLcontext *ctx, GLuint ci)
+{      
+       ggi_mesa_context_t ggi_ctx = (ggi_mesa_context_t)ctx->DriverCtx;
+
+       GGIMESADPRINT_CORE("gl_ggiSetClearIndex() called\n");
+
+       ggiSetGCForeground(ggi_ctx->ggi_visual, ci);
+       ggi_ctx->clearcolor = (ggi_pixel)ci;
+}
+
+static void gl_ggiSetClearColor(GLcontext *ctx, const GLfloat color[4])
 {
-       GGIMESADPRINT_CORE("gl_ggiSetDrawBuffer() called\n");
+       ggi_mesa_context_t ggi_ctx = (ggi_mesa_context_t)ctx->DriverCtx;
+       ggi_color rgb;
+       ggi_pixel col;
+       GLubyte byteColor[3];
+
+       GGIMESADPRINT_CORE("gl_ggiSetClearColor() called\n");
        
-       if (mode == GL_FRONT_LEFT) 
-       {
-               GGICTX->active_buffer = 1;
-               return GL_TRUE;
-       }
-       else if (mode == GL_BACK_LEFT) 
-       {
-               GGICTX->active_buffer = 0;
-               return GL_TRUE;
-       }
-       else 
-       {
-               return GL_FALSE;
+       CLAMPED_FLOAT_TO_UBYTE(byteColor[0], color[0]);
+       CLAMPED_FLOAT_TO_UBYTE(byteColor[1], color[1]);
+       CLAMPED_FLOAT_TO_UBYTE(byteColor[2], color[2]);
+
+       rgb.r = (uint16)byteColor[0] << SHIFT;
+       rgb.g = (uint16)byteColor[1] << SHIFT;
+       rgb.b = (uint16)byteColor[2] << SHIFT;
+       col = ggiMapColor(ggi_ctx->ggi_visual, &rgb);
+       ggiSetGCForeground(ggi_ctx->ggi_visual, col);
+       ggi_ctx->clearcolor = col;
+}
+
+static void gl_ggiClear(GLcontext *ctx, GLbitfield mask, GLboolean all,
+                       GLint x, GLint y, GLint width, GLint height)
+{
+       ggi_mesa_context_t ggi_ctx = (ggi_mesa_context_t)ctx->DriverCtx;
+       
+       GGIMESADPRINT_CORE("gl_ggiClear() called\n");
+
+       if (mask & (DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT)) {
+               ggiSetGCForeground(ggi_ctx->ggi_visual, ggi_ctx->clearcolor);
+
+               if (all) {
+                       int w, h;
+                       w = LIBGGI_VIRTX(ggi_ctx->ggi_visual);
+                       h = LIBGGI_VIRTX(ggi_ctx->ggi_visual);
+                       ggiDrawBox(ggi_ctx->ggi_visual, 0, 0, w, h);
+               } else {
+                       ggiDrawBox(ggi_ctx->ggi_visual, x, y, //FLIP(y),
+                                  width, height);
+               }
+               ggiSetGCForeground(ggi_ctx->ggi_visual, ggi_ctx->color);
+
+               mask &= ~(DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT);
        }
+       _swrast_Clear(ctx, mask, all, x, y, width, height);
+       
 }
 
 
 /* Set the buffer used for reading */
 /* XXX support for separate read/draw buffers hasn't been tested */
-static void gl_ggiSetReadBuffer(GLcontext *ctx, GLframebuffer *buffer, GLenum mode)
+static GLboolean gl_ggiSetBuffer(GLcontext *ctx, GLframebuffer *buffer, GLuint bufferBit)
 {
-       GGIMESADPRINT_CORE("gl_ggiSetReadBuffer() called\n");
-       
-       if (mode == GL_FRONT_LEFT) 
+       ggi_mesa_context_t ggi_ctx = (ggi_mesa_context_t)ctx->DriverCtx;
+
+       printf("set read %d\n", bufferBit);
+       GGIMESADPRINT_CORE("gl_ggiSetBuffer() called\n");
+
+       if (bufferBit == DD_FRONT_LEFT_BIT) 
        {
-               GGICTX->active_buffer = 1;
+               ggiSetReadFrame(ggi_ctx->ggi_visual,
+                               ggiGetDisplayFrame(ggi_ctx->ggi_visual));
+               ggiSetWriteFrame(ggi_ctx->ggi_visual,
+                                ggiGetDisplayFrame(ggi_ctx->ggi_visual));
+               return GL_TRUE;
        }
-       else if (mode == GL_BACK_LEFT) 
+       else if (bufferBit == DD_BACK_LEFT_BIT)
        {
-               GGICTX->active_buffer = 0;
+               ggiSetReadFrame(ggi_ctx->ggi_visual,
+                               ggiGetDisplayFrame(ggi_ctx->ggi_visual)?0 : 1);
+               ggiSetWriteFrame(ggi_ctx->ggi_visual,
+                                ggiGetDisplayFrame(ggi_ctx->ggi_visual)?0 : 1);
+               return GL_TRUE;
        }
+       else
+               return GL_FALSE;
 }
 
 
 static const GLubyte * gl_ggiGetString(GLcontext *ctx, GLenum name)
 {
        GGIMESADPRINT_CORE("gl_ggiGetString() called\n");
-       
-       if (name == GL_RENDERER)
-               return (GLubyte *) "Mesa GGI";
-       else
+
+       if (name == GL_RENDERER) {
+               return (GLubyte *) "Mesa GGI";
+       } else {
                return NULL;
+       }
 }
 
 static void gl_ggiFlush(GLcontext *ctx)
 {
+       ggi_mesa_context_t ggi_ctx = (ggi_mesa_context_t)ctx->DriverCtx;
+
        GGIMESADPRINT_CORE("gl_ggiFlush() called\n");
        
-       ggiFlush(VIS);
+       ggiFlush(ggi_ctx->ggi_visual);
+}
+
+static void gl_ggiIndexMask(GLcontext *ctx, GLuint mask)
+{
+       GGIMESADPRINT_CORE("gl_ggiIndexMask() called\n");
+}
+
+static void gl_ggiColorMask(GLcontext *ctx, GLboolean rmask, GLboolean gmask,
+                           GLboolean bmask, GLboolean amask)
+{
+       GGIMESADPRINT_CORE("gl_ggiColorMask() called\n");
+}
+
+static void gl_ggiEnable(GLcontext *ctx, GLenum pname, GLboolean state)
+{
+       GGIMESADPRINT_CORE("gl_ggiEnable() called\n");
 }
 
 static void gl_ggiSetupPointers(GLcontext *ctx)
 {
+       TNLcontext *tnl;
+
        GGIMESADPRINT_CORE("gl_ggiSetupPointers() called\n");
-       
-       /* Initialize all the pointers in the DD struct.  Do this whenever */
-       /* a new context is made current or we change buffers via set_buffer! */
 
+       /* General information */
        ctx->Driver.GetString = gl_ggiGetString;
-       ctx->Driver.UpdateState = gl_ggiUpdateState;
-
+       ctx->Driver.GetBufferSize = gl_ggiGetSize;
+       ctx->Driver.Finish = gl_ggiFlush;
+       ctx->Driver.Flush = gl_ggiFlush;
+       
+       /* Software rasterizer pixel paths */
+       ctx->Driver.Accum = _swrast_Accum;
+       ctx->Driver.Bitmap = _swrast_Bitmap;
+       ctx->Driver.Clear = gl_ggiClear;
+       ctx->Driver.ResizeBuffers = _swrast_alloc_buffers;
+       ctx->Driver.CopyPixels = _swrast_CopyPixels;
+       ctx->Driver.DrawPixels = _swrast_DrawPixels;
+       ctx->Driver.ReadPixels = _swrast_ReadPixels;
+        ctx->Driver.DrawBuffer = _swrast_DrawBuffer;
+
+       /* Software texturing */
+       ctx->Driver.ChooseTextureFormat = _mesa_choose_tex_format;
+       ctx->Driver.TexImage1D = _mesa_store_teximage1d;
+       ctx->Driver.TexImage2D = _mesa_store_teximage2d;
+       ctx->Driver.TexImage3D = _mesa_store_teximage3d;
+       ctx->Driver.TexSubImage1D = _mesa_store_texsubimage1d;
+       ctx->Driver.TexSubImage2D = _mesa_store_texsubimage2d;
+       ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d;
+       ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage;
+
+        ctx->Driver.CompressedTexImage1D = _mesa_store_compressed_teximage1d;
+        ctx->Driver.CompressedTexImage2D = _mesa_store_compressed_teximage2d;
+        ctx->Driver.CompressedTexImage3D = _mesa_store_compressed_teximage3d;
+        ctx->Driver.CompressedTexSubImage1D = _mesa_store_compressed_texsubimage1d;
+        ctx->Driver.CompressedTexSubImage2D = _mesa_store_compressed_texsubimage2d;
+        ctx->Driver.CompressedTexSubImage3D = _mesa_store_compressed_texsubimage3d;
+
+       ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d;
+       ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d;
+       ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d;
+       ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d;
+       ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d;
+
+       /* Imaging extensions */
+       ctx->Driver.CopyColorTable = _swrast_CopyColorTable;
+       ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable;
+       ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D;
+       ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D;
+       
+       /* State change callbacks */
        ctx->Driver.ClearIndex = gl_ggiSetClearIndex; 
        ctx->Driver.ClearColor = gl_ggiSetClearColor;
-       ctx->Driver.Clear = gl_ggiClear;
+       ctx->Driver.IndexMask = gl_ggiIndexMask;
+       ctx->Driver.ColorMask = gl_ggiColorMask;
+       ctx->Driver.Enable = gl_ggiEnable;
        
-       ctx->Driver.SetDrawBuffer = gl_ggiSetDrawBuffer;
-       ctx->Driver.SetReadBuffer = gl_ggiSetReadBuffer;
+       ctx->Driver.UpdateState = gl_ggiUpdateState;
+
+       /* Initialize TNL driver interface */
+       tnl = TNL_CONTEXT(ctx);
+       tnl->Driver.RunPipeline = _tnl_run_pipeline;
        
-       ctx->Driver.GetBufferSize = gl_ggiGetSize;
-       ctx->Driver.Finish = gl_ggiFlush;
-       ctx->Driver.Flush = gl_ggiFlush;        
+       /* Install setup for tnl */
+       _swsetup_Wakeup(ctx);
 }
 
-static int gl_ggiInitInfo(GGIMesaContext ctx, struct ggi_mesa_info *info)
+static void get_mode_info(ggi_visual_t vis, int *r, int *g, int *b,
+                         GLboolean *rgb, GLboolean *db, int *ci)
 {
-       ggi_mode mode;
+       unsigned int i;
+       
+       *r = 0;
+       *g = 0;
+       *b = 0;
+
+       for(i = 0; i < sizeof(ggi_pixel)*8; ++i) {
+               int mask = 1 << i;
+               if (LIBGGI_PIXFMT(vis)->red_mask & mask)
+                       ++(*r);
+               if (LIBGGI_PIXFMT(vis)->green_mask & mask)
+                       ++(*g);
+               if (LIBGGI_PIXFMT(vis)->blue_mask & mask)
+                       ++(*b);
+       }
 
-       GGIMESADPRINT_CORE("gl_ggiInitInfo() called\n");
-       
-       ggiGetMode(ctx->ggi_vis, &mode);
+       *rgb = GT_SCHEME(LIBGGI_MODE(vis)->graphtype) == GT_TRUECOLOR;
+       *db = LIBGGI_MODE(vis)->frames > 1;
+       *ci = GT_SIZE(LIBGGI_MODE(vis)->graphtype);
+
+       printf("rgb (%d, %d, %d) db %d, rgb %d ci %d\n",*r,*g,*b,*db,*rgb,*ci);
+}
        
-       info->depth_bits = DEFAULT_SOFTWARE_DEPTH_BITS;
-       info->stencil_bits = STENCIL_BITS;
-       info->accum_bits = ACCUM_BITS;
 
-       if (info->rgb_flag)
-       {               
-               info->rgb_flag = GL_TRUE;
-               info->alpha_flag = GL_FALSE;
-               info->index_bits = 0;
+int ggiMesaAttach(ggi_visual_t vis)
+{
+       int rc;
 
-               info->red_bits = 8;
-               info->green_bits = 8;
-               info->blue_bits = 8;
+       GGIMESADPRINT_CORE("ggiMesaAttach() called\n");
 
-               info->alpha_bits = 0;
-       }
-       else
+       rc = ggiExtensionAttach(vis, _ggiMesaID);
+       if (rc == 0)
        {
-               info->alpha_flag = GL_FALSE;
+               int r, g, b, ci;
+               GLboolean rgb, db;
+               GLvisual *gl_visual;
+               
+               /* We are creating the primary instance */
+               memset(LIBGGI_MESAEXT(vis), 0, sizeof(struct ggi_mesa_ext));
+               LIBGGI_MESAEXT(vis)->update_state = (void *)_ggi_error;
+               LIBGGI_MESAEXT(vis)->setup_driver = (void *)_ggi_error;
 
-               info->index_bits = GT_SIZE(mode.graphtype);
-               info->red_bits = info->green_bits = 
-                 info->blue_bits = info->alpha_bits = 0;
+               /* Initialize default mesa visual */
+               get_mode_info(vis, &r, &g, &b, &rgb, &db, &ci);
+               gl_visual = &(LIBGGI_MESAEXT(vis)->mesa_visual.gl_visual);
+               _mesa_initialize_visual(gl_visual,
+                                       rgb, db, 0 /* No stereo */,
+                                       r, g, b, 0 /* No alpha */, ci,
+                                       0 /* No depth */, 0 /* No stencil */,
+                                       0, 0, 0, 0 /* No accum */, 0);
+               
+               /* Now fake an "API change" so the right libs get loaded */
+               changed(vis, GGI_CHG_APILIST);
        }
-
-       return 0;
+       
+       return rc;
 }
 
-int ggiMesaInit()
+int ggiMesaDetach(ggi_visual_t vis)
 {
-       int err;
-       char *str;
-       
-       GGIMESADPRINT_CORE("ggiMesaInit() called\n");
-       
-        str = getenv("GGIMESA_DEBUG");
-       if (str != NULL) {
-               _ggimesaDebugState = atoi(str);
-               GGIMESADPRINT_CORE("Debugging=%d\n", _ggimesaDebugState);
-       }
-       
-       str = getenv("GGIMESA_DEBUGSYNC");
-       if (str != NULL) {
-               _ggimesaDebugSync = 1;
-       }
-       
-       GGIMESADPRINT_CORE("ggiMesaInit()\n");
-       
-       _ggimesaLibIsUp++;
-       if (_ggimesaLibIsUp > 1)
-         return 0; /* Initialize only at first call */
-       
-       err = ggLoadConfig(ggimesaconffile, &_ggimesaConfigHandle);
-       if (err != GGI_OK)
-       {
-               GGIMESADPRINT_CORE("GGIMesa: Couldn't open %s\n", ggimesaconffile);
-               _ggimesaLibIsUp--;
-               return err;
-       }
-       
-       ggiMesaID = ggiExtensionRegister("GGIMesa", sizeof(struct mesa_ext), changed);
+       GGIMESADPRINT_CORE("ggiMesaDetach() called\n");
        
-       if (ggiMesaID < 0)
-       {
-               GGIMESADPRINT_CORE("GGIMesa: failed to register as extension\n");
-               _ggimesaLibIsUp--;
-               ggFreeConfig(_ggimesaConfigHandle);
-               return ggiMesaID;
-       }
+       return ggiExtensionDetach(vis, _ggiMesaID);
+}
+int ggiMesaExtendVisual(ggi_visual_t vis, GLboolean alpha_flag,
+                       GLboolean stereo_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)
+{
+        GLvisual *gl_vis = &(LIBGGI_MESAEXT(vis)->mesa_visual.gl_visual);
+       int r, g, b, ci;
+       GLboolean db, rgb;
+
+       get_mode_info(vis, &r, &g, &b, &rgb, &db, &ci);
+       
+       /* Initialize the visual with the provided information */       
+       _mesa_initialize_visual(gl_vis,
+                               rgb, db, stereo_flag,
+                               r, g, b, 0 /* FIXME */, ci,
+                               depth_size, stencil_size,
+                               accum_red_size, accum_green_size,
+                               accum_blue_size, accum_alpha_size, 0);
+
+       /* Now fake an "API change" so the right libs get loaded. After all,
+          extending the visual by all these new buffers could be considered
+          a "mode change" which requires an "API change".
+        */
+       changed(vis, GGI_CHG_APILIST);
        
        return 0;
 }
 
 
-GGIMesaContext GGIMesaCreateContext(void)
+ggi_mesa_context_t ggiMesaCreateContext(ggi_visual_t vis)
 {
-       GGIMesaContext ctx;
-       char *str;
+       ggi_mesa_context_t ctx;
+       int err;
 
        GGIMESADPRINT_CORE("ggiMesaCreateContext() called\n");
        
-       if (ggiMesaInit() < 0)          /* register extensions*/
-       {
-               return NULL;
-       }
-
-       ctx = (GGIMesaContext)calloc(1, sizeof(struct ggi_mesa_context));
+       ctx = (ggi_mesa_context_t)malloc(sizeof(struct ggi_mesa_context));
        if (!ctx) 
-         return NULL;
+               return NULL;
        
-       ctx->gl_vis = (GLvisual *)calloc(1, sizeof(GLvisual));
-       if (!ctx->gl_vis) 
-         return NULL;
-
-       ctx->viewport_init = GL_FALSE;  
-       ctx->gl_vis->DBflag = GL_FALSE;
+       ctx->ggi_visual = vis;
+       ctx->color = 0;
 
-       ctx->gl_ctx = _mesa_create_context(ctx->gl_vis, NULL, (void *)ctx, GL_TRUE);
-       if (!ctx->gl_ctx) 
-         return NULL;
+       ctx->gl_ctx =
+         _mesa_create_context(&(LIBGGI_MESAEXT(vis)->mesa_visual.gl_visual),
+                              NULL, (void *) ctx, GL_FALSE);
+       if (!ctx->gl_ctx)
+               goto free_context;
        
         _mesa_enable_sw_extensions(ctx->gl_ctx);
-
-       return ctx;
-}
-
-void GGIMesaDestroyContext(GGIMesaContext ctx)
-{
-       GGIMESADPRINT_CORE("ggiMesaDestroyContext() called\n");
-       
-       if (ctx) 
-       {
-               _mesa_destroy_visual(ctx->gl_vis);
-               _mesa_destroy_context(ctx->gl_ctx);
-               _mesa_destroy_framebuffer(ctx->gl_buffer);
-               if (ctx == GGIMesa) 
-                 GGIMesa = NULL;
-               if (ctx->ggi_vis) 
-                 ggiExtensionDetach(ctx->ggi_vis, ggiMesaID);
-               ggiExtensionUnregister(ggiMesaID);
-               free(ctx);
-       }
-}
-
-int GGIMesaSetVisual(GGIMesaContext ctx, ggi_visual_t vis,
-                    GLboolean rgb_flag, GLboolean db_flag)
-{
-       struct ggi_mesa_info info;
-       int err;
-       uint16 r,g,b;
-       ggi_color pal[256];
-       int i;
-       void *func;
-       ggi_mode mode;
-       int num_buf;
-
-       GGIMESADPRINT_CORE("ggiMesaSetVisual() called\n");
        
-       if (!ctx) return -1;
-       if (!vis) return -1;
+       _swrast_CreateContext(ctx->gl_ctx);
+       _ac_CreateContext(ctx->gl_ctx);
+       _tnl_CreateContext(ctx->gl_ctx);
+       _swsetup_CreateContext(ctx->gl_ctx);
        
-       if (ctx->ggi_vis)
-         ggiExtensionDetach(ctx->ggi_vis, ggiMesaID);
-
-       ctx->ggi_vis=vis;
-
-       err = ggiExtensionAttach(vis, ggiMesaID);
-       if (err < 0) 
-         return -1;
-       if (err == 0) 
-         changed(vis, GGI_CHG_APILIST);
-       
-       if (ctx->gl_vis)
-         _mesa_destroy_visual(ctx->gl_vis);
-
-       if (ctx->gl_buffer)
-         _mesa_destroy_framebuffer(ctx->gl_buffer);
-
-       info.rgb_flag = rgb_flag;
-       info.db_flag = db_flag;
-
-       err = gl_ggiInitInfo(ctx, &info);
-       if (err) 
-         return -1;
-
        gl_ggiSetupPointers(ctx->gl_ctx);
 
-       func = (void *)LIBGGI_MESAEXT(ctx->ggi_vis)->setup_driver;
-
-       if (!func)
-       {
+       /* Make sure that an appropriate sublib has been loaded */
+       if (!LIBGGI_MESAEXT(ctx->ggi_visual)->setup_driver){
                GGIMESADPRINT_CORE("setup_driver==NULL!\n");
                GGIMESADPRINT_CORE("Please check your config files!\n");
-               return -1;
+               goto free_context;
        }
 
-       err = LIBGGI_MESAEXT(ctx->ggi_vis)->setup_driver(ctx, &info);
-       if (err) 
-         return -1;
-
-       ctx->gl_vis = _mesa_create_visual(info.rgb_flag,
-                                          info.db_flag,
-                                          GL_FALSE, /*stereo*/
-                                          info.red_bits, info.green_bits,
-                                          info.blue_bits, info.alpha_bits,
-                                          info.index_bits,
-                                          info.depth_bits, 
-                                          info.stencil_bits,
-                                          info.accum_bits,
-                                          info.accum_bits,
-                                          info.accum_bits,
-                                          info.accum_bits,
-                                          1);
-       if (!ctx->gl_vis) 
-       {
-               GGIMESADPRINT_CORE("Can't create gl_visual!\n");
-               return -1;
+       /* Set up the sublib driver */
+       err = LIBGGI_MESAEXT(ctx->ggi_visual)->setup_driver(ctx);
+       if (err){
+               GGIMESADPRINT_CORE("setup_driver failed (err = %d)", err);
+               goto free_gl_context;
        }
 
-       ctx->gl_buffer = _mesa_create_framebuffer(ctx->gl_vis,
-                                              ctx->gl_vis->DepthBits > 0,
-                                              ctx->gl_vis->StencilBits > 0,
-                                              ctx->gl_vis->AccumRedBits > 0,
-                                              ctx->gl_vis->AlphaBits > 0);
-                                              
-
-       if (!ctx->gl_buffer) 
-       {
-               GGIMESADPRINT_CORE("Can't create gl_buffer!\n");
-               return -1;
-       }
-       
-       ggiGetMode(ctx->ggi_vis, &mode);
-       ctx->width = mode.visible.x;
-       ctx->height = mode.visible.y;
-       ctx->stride = mode.virt.x;
-       ctx->origin.x = 0;
-       ctx->origin.y = 0;
-       ctx->flip_y = ctx->origin.y + ctx->height - 1; 
-
-       ctx->color = 0;
-
-       ctx->lfb[0] = ctx->lfb[1] = NULL;
-       num_buf = ggiDBGetNumBuffers(ctx->ggi_vis);
-       
-       for (i = 0; i < num_buf; i++)
-       {
-               if (ggiDBGetBuffer(ctx->ggi_vis,i)->layout == blPixelLinearBuffer)
-               {
-                       ctx->stride = ggiDBGetBuffer(ctx->ggi_vis, i)->buffer.plb.stride /
-                       (ggiDBGetBuffer(ctx->ggi_vis, i)->buffer.plb.pixelformat->size / 8);
-                       ctx->lfb[0] = ggiDBGetBuffer(ctx->ggi_vis, i)->write;
-               }
-       }
-       
-       if (ctx->lfb[0] == NULL)
-       {
-               GGIMESADPRINT_CORE("No linear frame buffer!\n");
-               return -1;
-       }
+       return ctx;
        
-       /* FIXME: Use separate buffers */
-       ctx->lfb[1] = malloc(ctx->stride * ctx->height);
-       ctx->bufsize = (ctx->stride * ctx->height);
+free_gl_context:
+       _mesa_destroy_context(ctx->gl_ctx);
+free_context:
+       free(ctx);
        
-       ctx->gl_ctx->Visual = *ctx->gl_vis;
-       ctx->gl_ctx->Pixel.ReadBuffer = 
-       ctx->gl_ctx->Color.DrawBuffer = (db_flag) ? GL_BACK : GL_FRONT;
-
-       if (GGIMesa == ctx)
-         _mesa_make_current(ctx->gl_ctx, ctx->gl_buffer);
+       return NULL;
+}
 
-       if (rgb_flag && mode.graphtype==GT_8BIT)
-       {
-               for (i = r = 0; r < 8; r++)
-                 for (g = 0; g < 8; g++)
-                   for (b = 0; b < 4; b++, i++)
-               {
-                       pal[i].r = r << (GGI_COLOR_PRECISION - 3);      
-                       pal[i].g = g << (GGI_COLOR_PRECISION - 3);      
-                       pal[i].b = b << (GGI_COLOR_PRECISION - 2);      
-               }
-               ggiSetPalette(ctx->ggi_vis, 0, 256, pal);       
-       }
+void ggiMesaDestroyContext(ggi_mesa_context_t ctx)
+{
+       GGIMESADPRINT_CORE("ggiMesaDestroyContext() called\n");
+       
+       if(!ctx)
+               return;
 
-       return 0;
+       _mesa_destroy_context(ctx->gl_ctx);
+       free(ctx);
 }
 
-void GGIMesaMakeCurrent(GGIMesaContext ctx)
+void ggiMesaMakeCurrent(ggi_mesa_context_t ctx, ggi_visual_t vis)
 {
        GGIMESADPRINT_CORE("ggiMesaMakeCurrent(ctx = %p) called\n", ctx);
+
+       /* FIXME: clean up where are ggi_vis */
+       if (ctx->ggi_visual != vis) {
+               GGIMESADPRINT_CORE("Cannot migrate GL contexts\n");
+               return;
+       }
        
-       if (!ctx->ggi_vis) 
-         return;
-       
-       GGIMesa = ctx;
-       _mesa_make_current(ctx->gl_ctx, ctx->gl_buffer);
+       _mesa_make_current(ctx->gl_ctx, &LIBGGI_MESAEXT(vis)->mesa_buffer);
        
-       if (!ctx->viewport_init)
+       if (ctx->gl_ctx->Viewport.Width == 0)
        {
-               gl_Viewport(ctx->gl_ctx, 0, 0, ctx->width, ctx->height);
-               ctx->viewport_init = GL_TRUE;
+               _mesa_Viewport(0, 0,
+                              LIBGGI_VIRTX(vis),
+                              LIBGGI_VIRTY(vis));
+               ctx->gl_ctx->Scissor.Width = LIBGGI_VIRTX(vis);
+               ctx->gl_ctx->Scissor.Height = LIBGGI_VIRTY(vis);
        }
 }
 
 
-GGIMesaContext GGIMesaGetCurrentContext(void)
-{
-       GGIMESADPRINT_CORE("ggiMesaGetCurrentContext() called\n");
-       
-       return GGIMesa;
-}
-
 /*
  * Swap front/back buffers for current context if double buffered.
  */
-void GGIMesaSwapBuffers(void)
+void ggiMesaSwapBuffers(void)
 {
-       GGIMESADPRINT_CORE("ggiMesaSwapBuffers() called\n");    
+       GLcontext *ctx;
+       ggi_mesa_context_t ggi_ctx;
+       ctx = _mesa_get_current_context();
+       ggi_ctx = (ggi_mesa_context_t)ctx->DriverCtx;
        
-       _mesa_swapbuffers( GGIMesa->gl_ctx );
-       gl_ggiFlush(GGIMesa->gl_ctx);
+       GGIMESADPRINT_CORE("ggiMesaSwapBuffers() called\n");    
        
-       if (GGIMesa->gl_vis->DBflag)
-       {
-               memcpy(GGIMesa->lfb[0], GGIMesa->lfb[1], GGIMesa->bufsize);
-       }
+       _mesa_notifySwapBuffers(ctx);
+       gl_ggiFlush(ctx);
+
+       ggiSetDisplayFrame(ggi_ctx->ggi_visual,
+                          !ggiGetDisplayFrame(ggi_ctx->ggi_visual));
+       ggiSetWriteFrame(ggi_ctx->ggi_visual,
+                        !ggiGetWriteFrame(ggi_ctx->ggi_visual));
+       ggiSetReadFrame(ggi_ctx->ggi_visual,
+                        !ggiGetReadFrame(ggi_ctx->ggi_visual));
+
+       GGIMESADPRINT_CORE("swap disp: %d, write %d\n",
+                          ggiGetDisplayFrame(ggi_ctx->ggi_visual),
+                          ggiGetWriteFrame(ggi_ctx->ggi_visual));
 }
 
-static void gl_ggiUpdateState(GLcontext *ctx)
+static void gl_ggiUpdateState(GLcontext *ctx, GLuint new_state)
 {
-       void *func;
-
-       GGIMESADPRINT_CORE("gl_ggiUpdateState() called\n");
+       ggi_mesa_context_t ggi_ctx = (ggi_mesa_context_t)ctx->DriverCtx;
        
-       func = (void *)CTX_OPMESA(ctx)->update_state;
-
-       if (!func) {
+       GGIMESADPRINT_CORE("gl_ggiUpdateState() called\n");
+               
+       /* Propogate statechange information to swrast and swrast_setup
+        * modules.  The GGI driver has no internal GL-dependent state.
+        */
+       _swrast_InvalidateState(ctx, new_state);
+       _swsetup_InvalidateState(ctx, new_state);
+       _tnl_InvalidateState(ctx, new_state);
+       
+       /* XXX: Better use an assertion that bails out here on failure */
+       if (!LIBGGI_MESAEXT(ggi_ctx->ggi_visual)->update_state) {
                GGIMESADPRINT_CORE("update_state == NULL!\n");
                GGIMESADPRINT_CORE("Please check your config files!\n");
                ggiPanic("");
        }
 
-       CTX_OPMESA(ctx)->update_state(ctx);
-}
-
-static int changed(ggi_visual_t vis, int whatchanged)
-{
-       GGIMESADPRINT_CORE("changed() called\n");
-       
-       switch (whatchanged)
-       {
-               case GGI_CHG_APILIST:
-               {
-                       char api[256];
-                       char args[256];
-                       int i;
-                       const char *fname;
-                       ggi_dlhandle *lib;
-                       
-                       for (i = 0; ggiGetAPI(vis, i, api, args) == 0; i++)
-                       {
-                               strcat(api, "-mesa");
-                               fname = ggMatchConfig(_ggimesaConfigHandle, api, NULL);
-                               if (fname == NULL)
-                               {
-                                       /* No special implementation for this sublib */
-                                       continue;
-                               }
-                               lib = ggiExtensionLoadDL(vis, fname, args, NULL, GGI_SYMNAME_PREFIX);
-                       }
-               } 
-               break;
-       }
-       return 0;
-}
-
-
-int ggiMesaExit(void)
-{
-       int rc;
-       
-       GGIMESADPRINT_CORE("ggiMesaExit() called\n");
-       
-       if (!_ggimesaLibIsUp)
-         return -1;
-       
-       if (_ggimesaLibIsUp > 1)
-       {
-               /* Exit only at last call */
-               _ggimesaLibIsUp--;
-               return 0;
-       }
-       
-       rc = ggiExtensionUnregister(ggiMesaID);
-       ggFreeConfig(_ggimesaConfigHandle);
-       
-       _ggimesaLibIsUp = 0;
-       
-       return rc;
-}
-
-static int _ggi_error(void)
-{
-       GGIMESADPRINT_CORE("_ggi_error() called\n");
-       
-       return -1;
-}
-
-int ggiMesaAttach(ggi_visual_t vis)
-{
-       int rc;
-       
-       GGIMESADPRINT_CORE("ggiMesaAttach() called\n");
-       
-       rc = ggiExtensionAttach(vis, ggiMesaID);
-       if (rc == 0)
-       {
-               /* We are creating the primary instance */
-               memset(LIBGGI_MESAEXT(vis), 0, sizeof(mesaext));
-               LIBGGI_MESAEXT(vis)->update_state = (void *)_ggi_error;
-               LIBGGI_MESAEXT(vis)->setup_driver = (void *)_ggi_error;
-               
-               /* Now fake an "API change" so the right libs get loaded */
-               changed(vis, GGI_CHG_APILIST);
-       }
-       
-       return rc;
+       LIBGGI_MESAEXT(ggi_ctx->ggi_visual)->update_state(ggi_ctx);
 }
 
-int ggiMesaDetach(ggi_visual_t vis)
-{
-       GGIMESADPRINT_CORE("ggiMesaDetach() called\n");
-       
-       return ggiExtensionDetach(vis, ggiMesaID);
-}