3 * Copyright (C) 1997-1998 Uwe Maurer - uwe_maurer@t-online.de
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * ---------------------------------------------------------------------
20 * This code was derived from the following source of information:
22 * svgamesa.c and ddsample.c by Brian Paul
30 #include <ggi/mesa/ggimesa_int.h>
31 #include <ggi/mesa/debug.h>
32 #include "extensions.h"
37 #include "swrast/swrast.h"
38 #include "swrast_setup/swrast_setup.h"
40 #include "tnl/t_context.h"
41 #include "tnl/t_pipeline.h"
44 #include "texformat.h"
47 /* We use LibGG to manage config files */
51 /* XXX: Those #defines should be provided via
54 #define GGIMESAPATHTAG "pAtHTAg"
55 #define GGIMESACONFDIR "pAtHTAg/usr/local/etc/ggi"
56 #define GGIMESATAGLEN 7
57 #define GGIMESACONFFILE "ggimesa.conf"
62 static int _ggimesaLibIsUp
= 0;
63 static void *_ggimesaConfigHandle
;
64 static char _ggimesaconfstub
[512] = GGIMESACONFDIR
;
65 static char *_ggimesaconfdir
= _ggimesaconfstub
+GGIMESATAGLEN
;
67 int _ggimesaDebugSync
= 0;
68 uint32 _ggimesaDebugState
= 0;
72 /* Extension ID. Defaulting to -1 should make segfault on abuse more likely...
74 ggi_extid _ggiMesaID
= -1;
77 #define SUBLIB_PREFIX "MesaGGIdl_"
81 * Returns the directory where global config files are kept
84 const char *ggiMesaGetConfDir(void)
87 /* On Win32 we allow overriding of the compiled in path. */
88 const char *envdir
= getenv("GGI_CONFDIR");
89 if (envdir
) return envdir
;
91 return _ggimesaconfdir
;
95 /* Dummy function which returns -1
96 We use this to reset the function pointers */
97 static int _ggi_error(void)
99 GGIMESADPRINT_CORE("_ggi_error() called\n");
105 static int changed(ggi_visual_t vis
, int whatchanged
)
108 ctx
= _mesa_get_current_context();
110 GGIMESADPRINT_CORE("changed() called\n");
112 switch (whatchanged
) {
113 case GGI_CHG_APILIST
:
115 char api
[GGI_MAX_APILEN
];
116 char args
[GGI_MAX_APILEN
];
121 GLvisual
*gl_vis
= &(LIBGGI_MESAEXT(vis
)->mesa_visual
.gl_visual
);
122 GLframebuffer
*gl_fb
= &(LIBGGI_MESAEXT(vis
)->mesa_buffer
);
124 /* Initialize the framebuffer to provide all necessary
125 buffers in software. The target libraries that are loaded
126 next are free to modify this according to their
129 /* FIXME: if the target changes capabilities we'll leak
130 swrast's memory !!! Need to deallocate first */
131 _mesa_initialize_framebuffer(gl_fb
, gl_vis
,
132 gl_vis
->depthBits
> 0,
133 gl_vis
->stencilBits
> 0,
134 gl_vis
->accumRedBits
> 0,
135 gl_vis
->alphaBits
> 0);
137 for (i
= 0; ggiGetAPI(vis
, i
, api
, args
) == 0; i
++) {
138 strcat(api
, "-mesa");
139 GGIMESADPRINT_CORE("GGIMesa: looking for"
140 "a sublib named %s\n", api
);
141 fname
= ggMatchConfig(_ggimesaConfigHandle
, api
, NULL
);
143 /* No special implementation for this sublib */
146 lib
= ggiExtensionLoadDL(vis
, fname
, args
, NULL
,
150 /* The targets have cleared everything they can do from
151 the framebuffer structure so we provide the rest in sw
153 /*_swrast_alloc_buffers(gl_fb);*/
168 GGIMESADPRINT_CORE("ggiMesaInit() called\n");
171 if (_ggimesaLibIsUp
> 1) return 0; /* Initialize only at first call */
173 str
= getenv("GGIMESA_DEBUGSYNC");
175 _ggimesaDebugSync
= 1;
178 str
= getenv("GGIMESA_DEBUG");
180 _ggimesaDebugState
= atoi(str
);
181 GGIMESADPRINT_CORE("%s Debugging=%d\n",
182 _ggimesaDebugSync
? "sync" : "async",
187 conffile
= malloc(strlen(ggiMesaGetConfDir()) + 1
188 + strlen(GGIMESACONFFILE
) +1);
189 if (conffile
== NULL
) {
190 fprintf(stderr
, "GGIMesa: unable to allocate memory for config filename.\n");
193 sprintf(conffile
, "%s%c%s",
194 ggiMesaGetConfDir(), '/', GGIMESACONFFILE
);
195 err
= ggLoadConfig(conffile
, &_ggimesaConfigHandle
);
197 fprintf(stderr
, "GGIMesa: Couldn't open %s\n",
205 _ggiMesaID
= ggiExtensionRegister("GGIMesa",
206 sizeof(struct ggi_mesa_ext
), changed
);
207 if (_ggiMesaID
< 0) {
208 fprintf(stderr
, "GGIMesa: failed to register as extension\n");
210 ggFreeConfig(_ggimesaConfigHandle
);
217 int ggiMesaExit(void)
221 GGIMESADPRINT_CORE("ggiMesaExit() called\n");
223 if (!_ggimesaLibIsUp
) return -1;
225 if (_ggimesaLibIsUp
> 1) {
226 /* Exit only at last call */
231 rc
= ggiExtensionUnregister(_ggiMesaID
);
232 ggFreeConfig(_ggimesaConfigHandle
);
242 static void gl_ggiUpdateState(GLcontext
*ctx
, GLuint new_state
);
245 static void gl_ggiGetSize(GLframebuffer
*fb
, GLuint
*width
, GLuint
*height
)
247 /* FIXME: this is a hack to work around the new interface */
249 ggi_mesa_context_t ggi_ctx
;
250 ctx
= _mesa_get_current_context();
251 ggi_ctx
= (ggi_mesa_context_t
)ctx
->DriverCtx
;
253 GGIMESADPRINT_CORE("gl_ggiGetSize() called\n");
255 *width
= LIBGGI_VIRTX(ggi_ctx
->ggi_visual
);
256 *height
= LIBGGI_VIRTY(ggi_ctx
->ggi_visual
);
257 printf("returning %d, %d\n", *width
, *height
);
261 * We only implement this function as a mechanism to check if the
262 * framebuffer size has changed (and update corresponding state).
264 static void gl_ggiViewport(GLcontext
*ctx
, GLint x
, GLint y
, GLsizei w
, GLsizei h
)
266 GLuint newWidth
, newHeight
;
267 GLframebuffer
*buffer
= ctx
->WinSysDrawBuffer
;
268 gl_ggiGetSize( buffer
, &newWidth
, &newHeight
);
269 if (buffer
->Width
!= newWidth
|| buffer
->Height
!= newHeight
) {
270 _mesa_resize_framebuffer(ctx
, buffer
, newWidth
, newHeight
);
275 static void gl_ggiSetIndex(GLcontext
*ctx
, GLuint ci
)
277 ggi_mesa_context_t ggi_ctx
= (ggi_mesa_context_t
)ctx
->DriverCtx
;
279 GGIMESADPRINT_CORE("gl_ggiSetIndex() called\n");
281 ggiSetGCForeground(ggi_ctx
->ggi_visual
, ci
);
282 ggi_ctx
->color
= (ggi_pixel
)ci
;
285 static void gl_ggiSetClearIndex(GLcontext
*ctx
, GLuint ci
)
287 ggi_mesa_context_t ggi_ctx
= (ggi_mesa_context_t
)ctx
->DriverCtx
;
289 GGIMESADPRINT_CORE("gl_ggiSetClearIndex() called\n");
291 ggiSetGCForeground(ggi_ctx
->ggi_visual
, ci
);
292 ggi_ctx
->clearcolor
= (ggi_pixel
)ci
;
295 static void gl_ggiSetClearColor(GLcontext
*ctx
, const GLfloat color
[4])
297 ggi_mesa_context_t ggi_ctx
= (ggi_mesa_context_t
)ctx
->DriverCtx
;
300 GLubyte byteColor
[3];
302 GGIMESADPRINT_CORE("gl_ggiSetClearColor() called\n");
304 CLAMPED_FLOAT_TO_UBYTE(byteColor
[0], color
[0]);
305 CLAMPED_FLOAT_TO_UBYTE(byteColor
[1], color
[1]);
306 CLAMPED_FLOAT_TO_UBYTE(byteColor
[2], color
[2]);
308 rgb
.r
= (uint16
)byteColor
[0] << SHIFT
;
309 rgb
.g
= (uint16
)byteColor
[1] << SHIFT
;
310 rgb
.b
= (uint16
)byteColor
[2] << SHIFT
;
311 col
= ggiMapColor(ggi_ctx
->ggi_visual
, &rgb
);
312 ggiSetGCForeground(ggi_ctx
->ggi_visual
, col
);
313 ggi_ctx
->clearcolor
= col
;
316 static void gl_ggiClear(GLcontext
*ctx
, GLbitfield mask
)
318 ggi_mesa_context_t ggi_ctx
= (ggi_mesa_context_t
)ctx
->DriverCtx
;
319 int x
= ctx
->DrawBuffer
->_Xmin
;
320 int y
= ctx
->DrawBuffer
->_Ymin
;
321 int w
= ctx
->DrawBuffer
->_Xmax
- x
;
322 int h
= ctx
->DrawBuffer
->_Ymax
- y
;
323 GLboolean all
= (w
== ctx
->DrawBuffer
->Width
&& h
== ctx
->DrawBuffer
->height
)
325 GGIMESADPRINT_CORE("gl_ggiClear() called\n");
327 if (mask
& (DD_FRONT_LEFT_BIT
| DD_BACK_LEFT_BIT
)) {
328 ggiSetGCForeground(ggi_ctx
->ggi_visual
, ggi_ctx
->clearcolor
);
332 w
= LIBGGI_VIRTX(ggi_ctx
->ggi_visual
);
333 h
= LIBGGI_VIRTX(ggi_ctx
->ggi_visual
);
334 ggiDrawBox(ggi_ctx
->ggi_visual
, 0, 0, w
, h
);
336 ggiDrawBox(ggi_ctx
->ggi_visual
, x
, y
, //FLIP(y),
339 ggiSetGCForeground(ggi_ctx
->ggi_visual
, ggi_ctx
->color
);
341 mask
&= ~(DD_FRONT_LEFT_BIT
| DD_BACK_LEFT_BIT
);
343 _swrast_Clear(ctx
, mask
);
348 /* Set the buffer used for reading */
349 /* XXX support for separate read/draw buffers hasn't been tested */
350 static GLboolean
gl_ggiSetBuffer(GLcontext
*ctx
, GLframebuffer
*buffer
, GLuint bufferBit
)
352 ggi_mesa_context_t ggi_ctx
= (ggi_mesa_context_t
)ctx
->DriverCtx
;
354 printf("set read %d\n", bufferBit
);
355 GGIMESADPRINT_CORE("gl_ggiSetBuffer() called\n");
357 if (bufferBit
== DD_FRONT_LEFT_BIT
)
359 ggiSetReadFrame(ggi_ctx
->ggi_visual
,
360 ggiGetDisplayFrame(ggi_ctx
->ggi_visual
));
361 ggiSetWriteFrame(ggi_ctx
->ggi_visual
,
362 ggiGetDisplayFrame(ggi_ctx
->ggi_visual
));
365 else if (bufferBit
== DD_BACK_LEFT_BIT
)
367 ggiSetReadFrame(ggi_ctx
->ggi_visual
,
368 ggiGetDisplayFrame(ggi_ctx
->ggi_visual
)?0 : 1);
369 ggiSetWriteFrame(ggi_ctx
->ggi_visual
,
370 ggiGetDisplayFrame(ggi_ctx
->ggi_visual
)?0 : 1);
378 static const GLubyte
* gl_ggiGetString(GLcontext
*ctx
, GLenum name
)
380 GGIMESADPRINT_CORE("gl_ggiGetString() called\n");
382 if (name
== GL_RENDERER
) {
383 return (GLubyte
*) "Mesa GGI";
389 static void gl_ggiFlush(GLcontext
*ctx
)
391 ggi_mesa_context_t ggi_ctx
= (ggi_mesa_context_t
)ctx
->DriverCtx
;
393 GGIMESADPRINT_CORE("gl_ggiFlush() called\n");
395 ggiFlush(ggi_ctx
->ggi_visual
);
398 static void gl_ggiIndexMask(GLcontext
*ctx
, GLuint mask
)
400 GGIMESADPRINT_CORE("gl_ggiIndexMask() called\n");
403 static void gl_ggiColorMask(GLcontext
*ctx
, GLboolean rmask
, GLboolean gmask
,
404 GLboolean bmask
, GLboolean amask
)
406 GGIMESADPRINT_CORE("gl_ggiColorMask() called\n");
409 static void gl_ggiEnable(GLcontext
*ctx
, GLenum pname
, GLboolean state
)
411 GGIMESADPRINT_CORE("gl_ggiEnable() called\n");
414 static void gl_ggiSetupPointers(GLcontext
*ctx
)
418 GGIMESADPRINT_CORE("gl_ggiSetupPointers() called\n");
420 /* Plug in default driver functions */
421 _mesa_init_driver_functions(&ctx
->Driver
);
423 /* Plug in ggi-specific functions */
424 ctx
->Driver
.GetString
= gl_ggiGetString
;
425 ctx
->Driver
.GetBufferSize
= gl_ggiGetSize
;
426 ctx
->Driver
.Viewport
= gl_ggiViewport
;
427 ctx
->Driver
.Finish
= gl_ggiFlush
;
428 ctx
->Driver
.Flush
= gl_ggiFlush
;
429 ctx
->Driver
.Clear
= gl_ggiClear
;
430 ctx
->Driver
.ClearIndex
= gl_ggiSetClearIndex
;
431 ctx
->Driver
.ClearColor
= gl_ggiSetClearColor
;
432 ctx
->Driver
.IndexMask
= gl_ggiIndexMask
;
433 ctx
->Driver
.ColorMask
= gl_ggiColorMask
;
434 ctx
->Driver
.Enable
= gl_ggiEnable
;
435 ctx
->Driver
.UpdateState
= gl_ggiUpdateState
;
437 /* Initialize TNL driver interface */
438 tnl
= TNL_CONTEXT(ctx
);
439 tnl
->Driver
.RunPipeline
= _tnl_run_pipeline
;
441 /* Install setup for tnl */
442 _swsetup_Wakeup(ctx
);
445 static void get_mode_info(ggi_visual_t vis
, int *r
, int *g
, int *b
,
446 GLboolean
*rgb
, GLboolean
*db
, int *ci
)
454 for(i
= 0; i
< sizeof(ggi_pixel
)*8; ++i
) {
456 if (LIBGGI_PIXFMT(vis
)->red_mask
& mask
)
458 if (LIBGGI_PIXFMT(vis
)->green_mask
& mask
)
460 if (LIBGGI_PIXFMT(vis
)->blue_mask
& mask
)
464 *rgb
= GT_SCHEME(LIBGGI_MODE(vis
)->graphtype
) == GT_TRUECOLOR
;
465 *db
= LIBGGI_MODE(vis
)->frames
> 1;
466 *ci
= GT_SIZE(LIBGGI_MODE(vis
)->graphtype
);
468 printf("rgb (%d, %d, %d) db %d, rgb %d ci %d\n",*r
,*g
,*b
,*db
,*rgb
,*ci
);
472 int ggiMesaAttach(ggi_visual_t vis
)
476 GGIMESADPRINT_CORE("ggiMesaAttach() called\n");
478 rc
= ggiExtensionAttach(vis
, _ggiMesaID
);
485 /* We are creating the primary instance */
486 memset(LIBGGI_MESAEXT(vis
), 0, sizeof(struct ggi_mesa_ext
));
487 LIBGGI_MESAEXT(vis
)->update_state
= (void *)_ggi_error
;
488 LIBGGI_MESAEXT(vis
)->setup_driver
= (void *)_ggi_error
;
490 /* Initialize default mesa visual */
491 get_mode_info(vis
, &r
, &g
, &b
, &rgb
, &db
, &ci
);
492 gl_visual
= &(LIBGGI_MESAEXT(vis
)->mesa_visual
.gl_visual
);
493 _mesa_initialize_visual(gl_visual
,
494 rgb
, db
, 0 /* No stereo */,
495 r
, g
, b
, 0 /* No alpha */, ci
,
496 0 /* No depth */, 0 /* No stencil */,
497 0, 0, 0, 0 /* No accum */, 0);
499 /* Now fake an "API change" so the right libs get loaded */
500 changed(vis
, GGI_CHG_APILIST
);
506 int ggiMesaDetach(ggi_visual_t vis
)
508 GGIMESADPRINT_CORE("ggiMesaDetach() called\n");
510 return ggiExtensionDetach(vis
, _ggiMesaID
);
513 int ggiMesaExtendVisual(ggi_visual_t vis
, GLboolean alpha_flag
,
514 GLboolean stereo_flag
, GLint depth_size
,
515 GLint stencil_size
, GLint accum_red_size
,
516 GLint accum_green_size
, GLint accum_blue_size
,
517 GLint accum_alpha_size
, GLint num_samples
)
519 GLvisual
*gl_vis
= &(LIBGGI_MESAEXT(vis
)->mesa_visual
.gl_visual
);
523 get_mode_info(vis
, &r
, &g
, &b
, &rgb
, &db
, &ci
);
525 /* Initialize the visual with the provided information */
526 _mesa_initialize_visual(gl_vis
,
527 rgb
, db
, stereo_flag
,
528 r
, g
, b
, 0 /* FIXME */, ci
,
529 depth_size
, stencil_size
,
530 accum_red_size
, accum_green_size
,
531 accum_blue_size
, accum_alpha_size
, 0);
533 /* Now fake an "API change" so the right libs get loaded. After all,
534 extending the visual by all these new buffers could be considered
535 a "mode change" which requires an "API change".
537 changed(vis
, GGI_CHG_APILIST
);
543 ggi_mesa_context_t
ggiMesaCreateContext(ggi_visual_t vis
)
545 ggi_mesa_context_t ctx
;
548 GGIMESADPRINT_CORE("ggiMesaCreateContext() called\n");
550 ctx
= (ggi_mesa_context_t
)malloc(sizeof(struct ggi_mesa_context
));
554 ctx
->ggi_visual
= vis
;
558 _mesa_create_context(&(LIBGGI_MESAEXT(vis
)->mesa_visual
.gl_visual
),
559 NULL
, (void *) ctx
, GL_FALSE
);
563 _mesa_enable_sw_extensions(ctx
->gl_ctx
);
565 _swrast_CreateContext(ctx
->gl_ctx
);
566 _vbo_CreateContext(ctx
->gl_ctx
);
567 _tnl_CreateContext(ctx
->gl_ctx
);
568 _swsetup_CreateContext(ctx
->gl_ctx
);
570 gl_ggiSetupPointers(ctx
->gl_ctx
);
572 /* Make sure that an appropriate sublib has been loaded */
573 if (!LIBGGI_MESAEXT(ctx
->ggi_visual
)->setup_driver
){
574 GGIMESADPRINT_CORE("setup_driver==NULL!\n");
575 GGIMESADPRINT_CORE("Please check your config files!\n");
579 /* Set up the sublib driver */
580 err
= LIBGGI_MESAEXT(ctx
->ggi_visual
)->setup_driver(ctx
);
582 GGIMESADPRINT_CORE("setup_driver failed (err = %d)", err
);
583 goto free_gl_context
;
589 _mesa_destroy_context(ctx
->gl_ctx
);
596 void ggiMesaDestroyContext(ggi_mesa_context_t ctx
)
598 GGIMESADPRINT_CORE("ggiMesaDestroyContext() called\n");
603 _mesa_destroy_context(ctx
->gl_ctx
);
607 void ggiMesaMakeCurrent(ggi_mesa_context_t ctx
, ggi_visual_t vis
)
609 GGIMESADPRINT_CORE("ggiMesaMakeCurrent(ctx = %p) called\n", ctx
);
611 /* FIXME: clean up where are ggi_vis */
612 if (ctx
->ggi_visual
!= vis
) {
613 GGIMESADPRINT_CORE("Cannot migrate GL contexts\n");
617 _mesa_make_current(ctx
->gl_ctx
, &LIBGGI_MESAEXT(vis
)->mesa_buffer
);
622 * Swap front/back buffers for current context if double buffered.
624 void ggiMesaSwapBuffers(void)
627 ggi_mesa_context_t ggi_ctx
;
628 ctx
= _mesa_get_current_context();
629 ggi_ctx
= (ggi_mesa_context_t
)ctx
->DriverCtx
;
631 GGIMESADPRINT_CORE("ggiMesaSwapBuffers() called\n");
633 _mesa_notifySwapBuffers(ctx
);
636 ggiSetDisplayFrame(ggi_ctx
->ggi_visual
,
637 !ggiGetDisplayFrame(ggi_ctx
->ggi_visual
));
638 ggiSetWriteFrame(ggi_ctx
->ggi_visual
,
639 !ggiGetWriteFrame(ggi_ctx
->ggi_visual
));
640 ggiSetReadFrame(ggi_ctx
->ggi_visual
,
641 !ggiGetReadFrame(ggi_ctx
->ggi_visual
));
643 GGIMESADPRINT_CORE("swap disp: %d, write %d\n",
644 ggiGetDisplayFrame(ggi_ctx
->ggi_visual
),
645 ggiGetWriteFrame(ggi_ctx
->ggi_visual
));
648 static void gl_ggiUpdateState(GLcontext
*ctx
, GLuint new_state
)
650 ggi_mesa_context_t ggi_ctx
= (ggi_mesa_context_t
)ctx
->DriverCtx
;
652 GGIMESADPRINT_CORE("gl_ggiUpdateState() called\n");
654 /* Propogate statechange information to swrast and swrast_setup
655 * modules. The GGI driver has no internal GL-dependent state.
657 _swrast_InvalidateState(ctx
, new_state
);
658 _swsetup_InvalidateState(ctx
, new_state
);
659 _tnl_InvalidateState(ctx
, new_state
);
661 /* XXX: Better use an assertion that bails out here on failure */
662 if (!LIBGGI_MESAEXT(ggi_ctx
->ggi_visual
)->update_state
) {
663 GGIMESADPRINT_CORE("update_state == NULL!\n");
664 GGIMESADPRINT_CORE("Please check your config files!\n");
668 LIBGGI_MESAEXT(ggi_ctx
->ggi_visual
)->update_state(ggi_ctx
);