| /* GGI-Driver for MESA |
| * |
| * Copyright (C) 1997-1998 Uwe Maurer - uwe_maurer@t-online.de |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the Free |
| * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| * --------------------------------------------------------------------- |
| * This code was derived from the following source of information: |
| * |
| * svgamesa.c and ddsample.c by Brian Paul |
| * |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "conf.h" |
| #endif |
| |
| #ifdef GGI |
| |
| #include <ggi/mesa/ggimesa_int.h> |
| #include <ggi/mesa/debug.h> |
| |
| #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 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; |
| |
| int gl_ggi_init = GL_FALSE; |
| int gl_ggi_debug = GL_FALSE; |
| |
| static void gl_ggiUpdateState(GLcontext *ctx); |
| static int changed(ggi_visual_t vis, int whatchanged); |
| |
| #if 0 |
| /* FIXME: Move this debugging stuff to include/ggi/mesa/internal/ */ |
| void gl_ggiPrint(char *format,...) |
| { |
| va_list args; |
| va_start(args,format); |
| fprintf(stderr,"GGIMesa: "); |
| vfprintf(stderr,format,args); |
| va_end(args); |
| } |
| |
| void gl_ggiDEBUG(char *format,...) |
| { |
| va_list args; |
| if (gl_ggi_debug) |
| { |
| va_start(args,format); |
| fprintf(stderr,"GGIMesa: "); |
| vfprintf(stderr,format,args); |
| va_end(args); |
| } |
| } |
| #endif |
| |
| static void gl_ggiGetSize(GLcontext *ctx, GLuint *width, GLuint *height) |
| { |
| *width = GGIMesa->width; |
| *height = GGIMesa->height; |
| } |
| |
| static void gl_ggiSetIndex(GLcontext *ctx, GLuint ci) |
| { |
| ggiSetGCForeground(VIS, ci); |
| GGICTX->color = (ggi_pixel)ci; |
| } |
| |
| static void gl_ggiSetClearIndex(GLcontext *ctx, GLuint ci) |
| { |
| ggiSetGCForeground(VIS, ci); |
| GGICTX->clearcolor = (ggi_pixel)ci; |
| } |
| |
| static void gl_ggiSetColor(GLcontext *ctx, GLubyte red, GLubyte green, |
| GLubyte blue, GLubyte alpha) |
| { |
| ggi_color rgb; |
| ggi_pixel col; |
| |
| 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; |
| 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; |
| } |
| |
| static GLbitfield gl_ggiClear(GLcontext *ctx,GLbitfield mask, GLboolean all, |
| GLint x, GLint y, GLint width, GLint height) |
| { |
| |
| if (mask & GL_COLOR_BUFFER_BIT) |
| { |
| ggiSetGCForeground(VIS, GGICTX->clearcolor); |
| |
| if (all) |
| { |
| ggiDrawBox(VIS, 0, GGIMesa->origin.y, |
| GGIMesa->width, GGIMesa->height); |
| } |
| else |
| { |
| ggiDrawBox(VIS, x, FLIP(y), width, height); |
| } |
| |
| ggiSetGCForeground(VIS, GGICTX->color); |
| } |
| return mask & (~GL_COLOR_BUFFER_BIT); |
| } |
| |
| #if 0 |
| static GLboolean gl_ggiSetBuffer(GLcontext *ctx, GLenum mode) |
| { |
| if (mode == GL_FRONT) |
| GGICTX->active_buffer = 1; |
| else |
| GGICTX->active_buffer = 0; |
| |
| return GL_TRUE; |
| } |
| #endif |
| |
| /* Set the buffer used for drawing */ |
| static GLboolean gl_ggiSetDrawBuffer(GLcontext *ctx, GLenum mode) |
| { |
| 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; |
| } |
| } |
| |
| |
| /* 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) |
| { |
| if (mode == GL_FRONT_LEFT) |
| { |
| GGICTX->active_buffer = 1; |
| } |
| else if (mode == GL_BACK_LEFT) |
| { |
| GGICTX->active_buffer = 0; |
| } |
| } |
| |
| |
| static const GLubyte * gl_ggiGetString(GLcontext *ctx, GLenum name) |
| { |
| if (name == GL_RENDERER) |
| return (GLubyte *) "Mesa GGI"; |
| else |
| return NULL; |
| } |
| |
| static void gl_ggiFlush(GLcontext *ctx) |
| { |
| ggiFlush(VIS); |
| } |
| |
| static void gl_ggiSetupPointers( GLcontext *ctx ) |
| { |
| /* Initialize all the pointers in the DD struct. Do this whenever */ |
| /* a new context is made current or we change buffers via set_buffer! */ |
| |
| ctx->Driver.GetString = gl_ggiGetString; |
| ctx->Driver.UpdateState = gl_ggiUpdateState; |
| |
| ctx->Driver.ClearIndex = gl_ggiSetClearIndex; |
| ctx->Driver.ClearColor = gl_ggiSetClearColor; |
| ctx->Driver.Clear = gl_ggiClear; |
| |
| ctx->Driver.SetDrawBuffer = gl_ggiSetDrawBuffer; |
| ctx->Driver.SetReadBuffer = gl_ggiSetReadBuffer; |
| |
| ctx->Driver.GetBufferSize = gl_ggiGetSize; |
| ctx->Driver.Finish = gl_ggiFlush; |
| ctx->Driver.Flush = gl_ggiFlush; |
| |
| } |
| |
| static int gl_ggiInitInfo(GGIMesaContext ctx, struct ggi_mesa_info *info) |
| { |
| ggi_mode mode; |
| |
| ggiGetMode(ctx->ggi_vis, &mode); |
| |
| 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; |
| |
| info->red_bits = 8; |
| info->green_bits = 8; |
| info->blue_bits = 8; |
| |
| info->alpha_bits = 0; |
| } |
| else |
| { |
| info->alpha_flag = GL_FALSE; |
| |
| info->index_bits = GT_SIZE(mode.graphtype); |
| info->red_bits = info->green_bits = |
| info->blue_bits = info->alpha_bits = 0; |
| } |
| |
| return 0; |
| } |
| |
| int ggiMesaInit() |
| { |
| int err; |
| |
| _ggimesaLibIsUp++; |
| if (_ggimesaLibIsUp > 1) |
| return 0; /* Initialize only at first call */ |
| |
| err = ggLoadConfig(ggimesaconffile, &_ggimesaConfigHandle); |
| if (err != GGI_OK) |
| { |
| fprintf(stderr, "GGIMesa: Couldn't open %s\n", ggimesaconffile); |
| _ggimesaLibIsUp--; |
| return err; |
| } |
| |
| ggiMesaID = ggiExtensionRegister("GGIMesa", sizeof(struct mesa_ext), changed); |
| |
| if (ggiMesaID < 0) |
| { |
| fprintf(stderr, "GGIMesa: failed to register as extension\n"); |
| _ggimesaLibIsUp--; |
| ggFreeConfig(_ggimesaConfigHandle); |
| return ggiMesaID; |
| } |
| |
| return 0; |
| } |
| |
| |
| GGIMesaContext GGIMesaCreateContext(void) |
| { |
| GGIMesaContext ctx; |
| char *s; |
| |
| s = getenv("GGIMESA_DEBUG"); |
| gl_ggi_debug = (s && atoi(s)); |
| |
| if (ggiMesaInit() < 0) /* register extensions*/ |
| { |
| return NULL; |
| } |
| |
| ctx = (GGIMesaContext)calloc(1, sizeof(struct ggi_mesa_context)); |
| if (!ctx) |
| 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->gl_ctx = _mesa_create_context(ctx->gl_vis, NULL, (void *)ctx, GL_TRUE); |
| if (!ctx->gl_ctx) |
| return NULL; |
| |
| return ctx; |
| } |
| |
| void GGIMesaDestroyContext(GGIMesaContext ctx) |
| { |
| 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; |
| |
| if (!ctx) return -1; |
| if (!vis) return -1; |
| |
| 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) |
| { |
| fprintf(stderr, "setup_driver==NULL!\n"); |
| fprintf(stderr, "Please check your config files!\n"); |
| return -1; |
| } |
| |
| 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) |
| { |
| fprintf(stderr, "Can't create gl_visual!\n"); |
| return -1; |
| } |
| |
| 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) |
| { |
| fprintf(stderr, "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) |
| { |
| fprintf(stderr, "No linear frame buffer!\n"); |
| return -1; |
| } |
| |
| /* FIXME: Use separate buffers */ |
| ctx->lfb[1] = malloc(ctx->stride * ctx->height); |
| ctx->bufsize = (ctx->stride * ctx->height); |
| |
| 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); |
| |
| 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); |
| } |
| |
| return 0; |
| } |
| |
| void GGIMesaMakeCurrent(GGIMesaContext ctx) |
| { |
| if (!ctx->ggi_vis) |
| return; |
| |
| GGIMesa = ctx; |
| _mesa_make_current(ctx->gl_ctx, ctx->gl_buffer); |
| |
| if (!ctx->viewport_init) |
| { |
| gl_Viewport(ctx->gl_ctx, 0, 0, ctx->width, ctx->height); |
| ctx->viewport_init = GL_TRUE; |
| } |
| } |
| |
| |
| GGIMesaContext GGIMesaGetCurrentContext(void) |
| { |
| return GGIMesa; |
| } |
| |
| /* |
| * Swap front/back buffers for current context if double buffered. |
| */ |
| void GGIMesaSwapBuffers(void) |
| { |
| GGIMESADPRINT_CORE("GGIMesaSwapBuffers\n"); |
| |
| _mesa_swapbuffers( GGIMesa->gl_ctx ); |
| gl_ggiFlush(GGIMesa->gl_ctx); |
| |
| if (GGIMesa->gl_vis->DBflag) |
| { |
| memcpy(GGIMesa->lfb[0], GGIMesa->lfb[1], GGIMesa->bufsize); |
| } |
| } |
| |
| static void gl_ggiUpdateState(GLcontext *ctx) |
| { |
| void *func; |
| |
| func = (void *)CTX_OPMESA(ctx)->update_state; |
| |
| if (!func) { |
| fprintf(stderr, "update_state == NULL!\n"); |
| fprintf(stderr, "Please check your config files!\n"); |
| ggiPanic(""); |
| } |
| |
| CTX_OPMESA(ctx)->update_state(ctx); |
| } |
| |
| static int changed(ggi_visual_t vis, int whatchanged) |
| { |
| 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; |
| |
| 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) |
| { |
| return -1; |
| } |
| |
| int ggiMesaAttach(ggi_visual_t vis) |
| { |
| int rc; |
| |
| 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; |
| } |
| |
| int ggiMesaDetach(ggi_visual_t vis) |
| { |
| return ggiExtensionDetach(vis, ggiMesaID); |
| } |
| |
| |
| #else |
| /* |
| * Need this to provide at least one external definition when GGI is |
| * not defined on the compiler command line. |
| */ |
| |
| int gl_ggi_dummy_function(void) |
| { |
| return 0; |
| } |
| |
| #endif |