osmesa.c revision c6c0f947142c0cc82626c238804a68b4e8f53945
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.5
4 *
5 * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26/*
27 * Off-Screen Mesa rendering / Rendering into client memory space
28 *
29 * Note on thread safety:  this driver is thread safe.  All
30 * functions are reentrant.  The notion of current context is
31 * managed by the core _mesa_make_current() and _mesa_get_current_context()
32 * functions.  Those functions are thread-safe.
33 */
34
35
36#include "glheader.h"
37#include "GL/osmesa.h"
38#include "context.h"
39#include "extensions.h"
40#include "framebuffer.h"
41#include "fbobject.h"
42#include "imports.h"
43#include "mtypes.h"
44#include "renderbuffer.h"
45#include "array_cache/acache.h"
46#include "swrast/swrast.h"
47#include "swrast_setup/swrast_setup.h"
48#include "swrast/s_context.h"
49#include "swrast/s_depth.h"
50#include "swrast/s_lines.h"
51#include "swrast/s_triangle.h"
52#include "tnl/tnl.h"
53#include "tnl/t_context.h"
54#include "tnl/t_pipeline.h"
55#include "drivers/common/driverfuncs.h"
56
57
58
59/*
60 * This is the OS/Mesa context struct.
61 * Notice how it includes a GLcontext.  By doing this we're mimicking
62 * C++ inheritance/derivation.
63 * Later, we can cast a GLcontext pointer into an OSMesaContext pointer
64 * or vice versa.
65 */
66struct osmesa_context {
67   GLcontext mesa;		/* The core GL/Mesa context */
68   GLvisual *gl_visual;		/* Describes the buffers */
69   GLframebuffer *gl_buffer;	/* Depth, stencil, accum, etc buffers */
70   GLenum format;		/* either GL_RGBA or GL_COLOR_INDEX */
71   void *buffer;		/* the image buffer */
72   GLint width, height;		/* size of image buffer */
73   GLint rowlength;		/* number of pixels per row */
74   GLint userRowLength;		/* user-specified number of pixels per row */
75   GLint rInd, gInd, bInd, aInd;/* index offsets for RGBA formats */
76   GLchan *rowaddr[MAX_HEIGHT];	/* address of first pixel in each image row */
77   GLboolean yup;		/* TRUE  -> Y increases upward */
78				/* FALSE -> Y increases downward */
79};
80
81
82/* Just cast, since we're using structure containment */
83#define OSMESA_CONTEXT(ctx)  ((OSMesaContext) (ctx->DriverCtx))
84
85
86
87/**********************************************************************/
88/*** Private Device Driver Functions                                ***/
89/**********************************************************************/
90
91
92static const GLubyte *
93get_string( GLcontext *ctx, GLenum name )
94{
95   (void) ctx;
96   switch (name) {
97      case GL_RENDERER:
98#if CHAN_BITS == 32
99         return (const GLubyte *) "Mesa OffScreen32";
100#elif CHAN_BITS == 16
101         return (const GLubyte *) "Mesa OffScreen16";
102#else
103         return (const GLubyte *) "Mesa OffScreen";
104#endif
105      default:
106         return NULL;
107   }
108}
109
110
111static void
112osmesa_update_state( GLcontext *ctx, GLuint new_state )
113{
114   /* easy - just propogate */
115   _swrast_InvalidateState( ctx, new_state );
116   _swsetup_InvalidateState( ctx, new_state );
117   _ac_InvalidateState( ctx, new_state );
118   _tnl_InvalidateState( ctx, new_state );
119}
120
121
122/*
123 * Just return the current buffer size.
124 * There's no window to track the size of.
125 */
126static void
127get_buffer_size( GLframebuffer *buffer, GLuint *width, GLuint *height )
128{
129   /* don't use GET_CURRENT_CONTEXT(ctx) here - it's a problem on Windows */
130   GLcontext *ctx = (GLcontext *) _glapi_get_context();
131   (void) buffer;
132   if (ctx) {
133      OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
134      *width = osmesa->width;
135      *height = osmesa->height;
136   }
137}
138
139
140/**********************************************************************/
141/*****        Read/write spans/arrays of pixels                   *****/
142/**********************************************************************/
143
144/* RGBA */
145#define NAME(PREFIX) PREFIX##_RGBA
146#define FORMAT GL_RGBA
147#define SPAN_VARS \
148   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
149#define INIT_PIXEL_PTR(P, X, Y) \
150   GLchan *P = osmesa->rowaddr[Y] + 4 * (X)
151#define INC_PIXEL_PTR(P) P += 4
152#if CHAN_TYPE == GL_FLOAT
153#define STORE_PIXEL(DST, X, Y, VALUE) \
154   DST[0] = MAX2((VALUE[RCOMP]), 0.0F); \
155   DST[1] = MAX2((VALUE[GCOMP]), 0.0F); \
156   DST[2] = MAX2((VALUE[BCOMP]), 0.0F); \
157   DST[3] = CLAMP((VALUE[ACOMP]), 0.0F, CHAN_MAXF)
158#define STORE_PIXEL_RGB(DST, X, Y, VALUE) \
159   DST[0] = MAX2((VALUE[RCOMP]), 0.0F); \
160   DST[1] = MAX2((VALUE[GCOMP]), 0.0F); \
161   DST[2] = MAX2((VALUE[BCOMP]), 0.0F); \
162   DST[3] = CHAN_MAXF
163#else
164#define STORE_PIXEL(DST, X, Y, VALUE) \
165   DST[0] = VALUE[RCOMP];  \
166   DST[1] = VALUE[GCOMP];  \
167   DST[2] = VALUE[BCOMP];  \
168   DST[3] = VALUE[ACOMP]
169#define STORE_PIXEL_RGB(DST, X, Y, VALUE) \
170   DST[0] = VALUE[RCOMP];  \
171   DST[1] = VALUE[GCOMP];  \
172   DST[2] = VALUE[BCOMP];  \
173   DST[3] = CHAN_MAX
174#endif
175#define FETCH_PIXEL(DST, SRC) \
176   DST[RCOMP] = SRC[0];  \
177   DST[GCOMP] = SRC[1];  \
178   DST[BCOMP] = SRC[2];  \
179   DST[ACOMP] = SRC[3]
180#include "swrast/s_spantemp.h"
181
182/* BGRA */
183#define NAME(PREFIX) PREFIX##_BGRA
184#define FORMAT GL_RGBA
185#define SPAN_VARS \
186   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
187#define INIT_PIXEL_PTR(P, X, Y) \
188   GLchan *P = osmesa->rowaddr[Y] + 4 * (X)
189#define INC_PIXEL_PTR(P) P += 4
190#define STORE_PIXEL(DST, X, Y, VALUE) \
191   DST[2] = VALUE[RCOMP];  \
192   DST[1] = VALUE[GCOMP];  \
193   DST[0] = VALUE[BCOMP];  \
194   DST[3] = VALUE[ACOMP]
195#define STORE_PIXEL_RGB(DST, X, Y, VALUE) \
196   DST[2] = VALUE[RCOMP];  \
197   DST[1] = VALUE[GCOMP];  \
198   DST[0] = VALUE[BCOMP];  \
199   DST[3] = CHAN_MAX
200#define FETCH_PIXEL(DST, SRC) \
201   DST[RCOMP] = SRC[2];  \
202   DST[GCOMP] = SRC[1];  \
203   DST[BCOMP] = SRC[0];  \
204   DST[ACOMP] = SRC[3]
205#include "swrast/s_spantemp.h"
206
207/* ARGB */
208#define NAME(PREFIX) PREFIX##_ARGB
209#define FORMAT GL_RGBA
210#define SPAN_VARS \
211   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
212#define INIT_PIXEL_PTR(P, X, Y) \
213   GLchan *P = osmesa->rowaddr[Y] + 4 * (X)
214#define INC_PIXEL_PTR(P) P += 4
215#define STORE_PIXEL(DST, X, Y, VALUE) \
216   DST[1] = VALUE[RCOMP];  \
217   DST[2] = VALUE[GCOMP];  \
218   DST[3] = VALUE[BCOMP];  \
219   DST[0] = VALUE[ACOMP]
220#define STORE_PIXEL_RGB(DST, X, Y, VALUE) \
221   DST[1] = VALUE[RCOMP];  \
222   DST[2] = VALUE[GCOMP];  \
223   DST[3] = VALUE[BCOMP];  \
224   DST[0] = CHAN_MAX
225#define FETCH_PIXEL(DST, SRC) \
226   DST[RCOMP] = SRC[1];  \
227   DST[GCOMP] = SRC[2];  \
228   DST[BCOMP] = SRC[3];  \
229   DST[ACOMP] = SRC[0]
230#include "swrast/s_spantemp.h"
231
232/* RGB */
233#define NAME(PREFIX) PREFIX##_RGB
234#define FORMAT GL_RGBA
235#define SPAN_VARS \
236   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
237#define INIT_PIXEL_PTR(P, X, Y) \
238   GLchan *P = osmesa->rowaddr[Y] + 4 * (X)
239#define INC_PIXEL_PTR(P) P += 3
240#define STORE_PIXEL(DST, X, Y, VALUE) \
241   DST[0] = VALUE[RCOMP];  \
242   DST[1] = VALUE[GCOMP];  \
243   DST[2] = VALUE[BCOMP]
244#define FETCH_PIXEL(DST, SRC) \
245   DST[RCOMP] = SRC[0];  \
246   DST[GCOMP] = SRC[1];  \
247   DST[BCOMP] = SRC[2];  \
248   DST[ACOMP] = CHAN_MAX
249#include "swrast/s_spantemp.h"
250
251/* BGR */
252#define NAME(PREFIX) PREFIX##_BGR
253#define FORMAT GL_RGBA
254#define SPAN_VARS \
255   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
256#define INIT_PIXEL_PTR(P, X, Y) \
257   GLchan *P = osmesa->rowaddr[Y] + 4 * (X)
258#define INC_PIXEL_PTR(P) P += 3
259#define STORE_PIXEL(DST, X, Y, VALUE) \
260   DST[2] = VALUE[RCOMP];  \
261   DST[1] = VALUE[GCOMP];  \
262   DST[0] = VALUE[BCOMP]
263#define FETCH_PIXEL(DST, SRC) \
264   DST[RCOMP] = SRC[2];  \
265   DST[GCOMP] = SRC[1];  \
266   DST[BCOMP] = SRC[0];  \
267   DST[ACOMP] = CHAN_MAX
268#include "swrast/s_spantemp.h"
269
270/* 16-bit RGB */
271#if CHAN_TYPE == GL_UNSIGNED_BYTE
272#define NAME(PREFIX) PREFIX##_RGB_565
273#define FORMAT GL_RGBA
274#define SPAN_VARS \
275   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
276#define INIT_PIXEL_PTR(P, X, Y) \
277   GLushort *P = (GLushort *) osmesa->rowaddr[Y] + (X)
278#define INC_PIXEL_PTR(P) P += 1
279#define STORE_PIXEL(DST, X, Y, VALUE) \
280   *DST = ( (((VALUE[RCOMP]) & 0xf8) << 8) | (((VALUE[GCOMP]) & 0xfc) << 3) | ((VALUE[BCOMP]) >> 3) )
281#define FETCH_PIXEL(DST, SRC) \
282   DST[RCOMP] = ( (((*SRC) >> 8) & 0xf8) | (((*SRC) >> 11) & 0x7) ); \
283   DST[GCOMP] = ( (((*SRC) >> 3) & 0xfc) | (((*SRC) >>  5) & 0x3) ); \
284   DST[BCOMP] = ( (((*SRC) << 3) & 0xf8) | (((*SRC)      ) & 0x7) ); \
285   DST[ACOMP] = CHAN_MAX
286#include "swrast/s_spantemp.h"
287#endif /* CHAN_TYPE == GL_UNSIGNED_BYTE */
288
289/* color index */
290#define NAME(PREFIX) PREFIX##_CI
291#define FORMAT GL_COLOR_INDEX8_EXT
292#define SPAN_VARS \
293   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
294#define INIT_PIXEL_PTR(P, X, Y) \
295   GLubyte *P = (GLubyte *) osmesa->rowaddr[Y] + (X)
296#define INC_PIXEL_PTR(P) P += 1
297#define STORE_PIXEL(DST, X, Y, VALUE) \
298   *DST = VALUE[0]
299#define FETCH_PIXEL(DST, SRC) \
300   DST = SRC[0]
301#include "swrast/s_spantemp.h"
302
303
304
305
306/**********************************************************************/
307/*****                   Optimized line rendering                 *****/
308/**********************************************************************/
309
310
311#if CHAN_TYPE == GL_FLOAT
312#define PACK_RGBA(DST, R, G, B, A)	\
313do {					\
314   (DST)[0] = MAX2( R, 0.0F );		\
315   (DST)[1] = MAX2( G, 0.0F );		\
316   (DST)[2] = MAX2( B, 0.0F );		\
317   (DST)[3] = CLAMP(A, 0.0F, CHAN_MAXF);\
318} while (0)
319#else
320#define PACK_RGBA(DST, R, G, B, A)	\
321do {					\
322   (DST)[osmesa->rInd] = R;		\
323   (DST)[osmesa->gInd] = G;		\
324   (DST)[osmesa->bInd] = B;		\
325   (DST)[osmesa->aInd] = A;		\
326} while (0)
327#endif
328
329#define PACK_RGB(DST, R, G, B)  \
330do {				\
331   (DST)[0] = R;		\
332   (DST)[1] = G;		\
333   (DST)[2] = B;		\
334} while (0)
335
336#define PACK_BGR(DST, R, G, B)  \
337do {				\
338   (DST)[0] = B;		\
339   (DST)[1] = G;		\
340   (DST)[2] = R;		\
341} while (0)
342
343#define PACK_RGB_565(DST, R, G, B)					\
344do {									\
345   (DST) = (((int) (R) << 8) & 0xf800) | (((int) (G) << 3) & 0x7e0) | ((int) (B) >> 3);\
346} while (0)
347
348#define UNPACK_RED(P)      ( (P)[osmesa->rInd] )
349#define UNPACK_GREEN(P)    ( (P)[osmesa->gInd] )
350#define UNPACK_BLUE(P)     ( (P)[osmesa->bInd] )
351#define UNPACK_ALPHA(P)    ( (P)[osmesa->aInd] )
352
353#define PIXELADDR1(X,Y)  (osmesa->rowaddr[Y] + (X))
354#define PIXELADDR2(X,Y)  (osmesa->rowaddr[Y] + 2 * (X))
355#define PIXELADDR3(X,Y)  (osmesa->rowaddr[Y] + 3 * (X))
356#define PIXELADDR4(X,Y)  (osmesa->rowaddr[Y] + 4 * (X))
357
358
359/*
360 * Draw a flat-shaded, RGB line into an osmesa buffer.
361 */
362#define NAME flat_rgba_line
363#define CLIP_HACK 1
364#define SETUP_CODE						\
365   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);		\
366   const GLchan *color = vert1->color;
367
368#define PLOT(X, Y)						\
369do {								\
370   GLchan *p = PIXELADDR4(X, Y);				\
371   PACK_RGBA(p, color[0], color[1], color[2], color[3]);	\
372} while (0)
373
374#ifdef WIN32
375#include "..\swrast\s_linetemp.h"
376#else
377#include "swrast/s_linetemp.h"
378#endif
379
380
381
382/*
383 * Draw a flat-shaded, Z-less, RGB line into an osmesa buffer.
384 */
385#define NAME flat_rgba_z_line
386#define CLIP_HACK 1
387#define INTERP_Z 1
388#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
389#define SETUP_CODE					\
390   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);	\
391   const GLchan *color = vert1->color;
392
393#define PLOT(X, Y)					\
394do {							\
395   if (Z < *zPtr) {					\
396      GLchan *p = PIXELADDR4(X, Y);			\
397      PACK_RGBA(p, color[RCOMP], color[GCOMP],		\
398                   color[BCOMP], color[ACOMP]);		\
399      *zPtr = Z;					\
400   }							\
401} while (0)
402
403#ifdef WIN32
404#include "..\swrast\s_linetemp.h"
405#else
406#include "swrast/s_linetemp.h"
407#endif
408
409
410
411/*
412 * Analyze context state to see if we can provide a fast line drawing
413 * function, like those in lines.c.  Otherwise, return NULL.
414 */
415static swrast_line_func
416osmesa_choose_line_function( GLcontext *ctx )
417{
418   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
419   const SWcontext *swrast = SWRAST_CONTEXT(ctx);
420
421   if (CHAN_BITS != 8)                    return NULL;
422   if (ctx->RenderMode != GL_RENDER)      return NULL;
423   if (ctx->Line.SmoothFlag)              return NULL;
424   if (ctx->Texture._EnabledUnits)        return NULL;
425   if (ctx->Light.ShadeModel != GL_FLAT)  return NULL;
426   if (ctx->Line.Width != 1.0F)           return NULL;
427   if (ctx->Line.StippleFlag)             return NULL;
428   if (ctx->Line.SmoothFlag)              return NULL;
429   if (osmesa->format != OSMESA_RGBA &&
430       osmesa->format != OSMESA_BGRA &&
431       osmesa->format != OSMESA_ARGB)     return NULL;
432
433   if (swrast->_RasterMask==DEPTH_BIT
434       && ctx->Depth.Func==GL_LESS
435       && ctx->Depth.Mask==GL_TRUE
436       && ctx->Visual.depthBits == DEFAULT_SOFTWARE_DEPTH_BITS) {
437      return (swrast_line_func) flat_rgba_z_line;
438   }
439
440   if (swrast->_RasterMask == 0) {
441      return (swrast_line_func) flat_rgba_line;
442   }
443
444   return (swrast_line_func) NULL;
445}
446
447
448/**********************************************************************/
449/*****                 Optimized triangle rendering               *****/
450/**********************************************************************/
451
452
453/*
454 * Smooth-shaded, z-less triangle, RGBA color.
455 */
456#define NAME smooth_rgba_z_triangle
457#define INTERP_Z 1
458#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
459#define INTERP_RGB 1
460#define INTERP_ALPHA 1
461#define SETUP_CODE \
462   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
463#define RENDER_SPAN( span ) {					\
464   GLuint i;							\
465   GLchan *img = PIXELADDR4(span.x, span.y); 			\
466   for (i = 0; i < span.end; i++, img += 4) {			\
467      const GLuint z = FixedToDepth(span.z);			\
468      if (z < zRow[i]) {					\
469         PACK_RGBA(img, FixedToChan(span.red),			\
470            FixedToChan(span.green), FixedToChan(span.blue),	\
471            FixedToChan(span.alpha));				\
472         zRow[i] = z;						\
473      }								\
474      span.red += span.redStep;					\
475      span.green += span.greenStep;				\
476      span.blue += span.blueStep;				\
477      span.alpha += span.alphaStep;				\
478      span.z += span.zStep;					\
479   }                                                            \
480}
481#ifdef WIN32
482#include "..\swrast\s_tritemp.h"
483#else
484#include "swrast/s_tritemp.h"
485#endif
486
487
488
489/*
490 * Flat-shaded, z-less triangle, RGBA color.
491 */
492#define NAME flat_rgba_z_triangle
493#define INTERP_Z 1
494#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
495#define SETUP_CODE						\
496   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);		\
497   GLuint pixel;						\
498   PACK_RGBA((GLchan *) &pixel, v2->color[0], v2->color[1],	\
499                                v2->color[2], v2->color[3]);
500
501#define RENDER_SPAN( span ) {				\
502   GLuint i;						\
503   GLuint *img = (GLuint *) PIXELADDR4(span.x, span.y);	\
504   for (i = 0; i < span.end; i++) {			\
505      const GLuint z = FixedToDepth(span.z);		\
506      if (z < zRow[i]) {				\
507         img[i] = pixel;				\
508         zRow[i] = z;					\
509      }							\
510      span.z += span.zStep;				\
511   }                                                    \
512}
513#ifdef WIN32
514#include "..\swrast\s_tritemp.h"
515#else
516#include "swrast/s_tritemp.h"
517#endif
518
519
520
521/*
522 * Return pointer to an accelerated triangle function if possible.
523 */
524static swrast_tri_func
525osmesa_choose_triangle_function( GLcontext *ctx )
526{
527   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
528   const SWcontext *swrast = SWRAST_CONTEXT(ctx);
529
530   if (CHAN_BITS != 8)                  return (swrast_tri_func) NULL;
531   if (ctx->RenderMode != GL_RENDER)    return (swrast_tri_func) NULL;
532   if (ctx->Polygon.SmoothFlag)         return (swrast_tri_func) NULL;
533   if (ctx->Polygon.StippleFlag)        return (swrast_tri_func) NULL;
534   if (ctx->Texture._EnabledUnits)      return (swrast_tri_func) NULL;
535   if (osmesa->format != OSMESA_RGBA &&
536       osmesa->format != OSMESA_BGRA &&
537       osmesa->format != OSMESA_ARGB)   return (swrast_tri_func) NULL;
538   if (ctx->Polygon.CullFlag &&
539       ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK)
540                                        return (swrast_tri_func) NULL;
541
542   if (swrast->_RasterMask == DEPTH_BIT &&
543       ctx->Depth.Func == GL_LESS &&
544       ctx->Depth.Mask == GL_TRUE &&
545       ctx->Visual.depthBits == DEFAULT_SOFTWARE_DEPTH_BITS) {
546      if (ctx->Light.ShadeModel == GL_SMOOTH) {
547         return (swrast_tri_func) smooth_rgba_z_triangle;
548      }
549      else {
550         return (swrast_tri_func) flat_rgba_z_triangle;
551      }
552   }
553   return (swrast_tri_func) NULL;
554}
555
556
557
558/* Override for the swrast triangle-selection function.  Try to use one
559 * of our internal triangle functions, otherwise fall back to the
560 * standard swrast functions.
561 */
562static void
563osmesa_choose_triangle( GLcontext *ctx )
564{
565   SWcontext *swrast = SWRAST_CONTEXT(ctx);
566
567   swrast->Triangle = osmesa_choose_triangle_function( ctx );
568   if (!swrast->Triangle)
569      _swrast_choose_triangle( ctx );
570}
571
572static void
573osmesa_choose_line( GLcontext *ctx )
574{
575   SWcontext *swrast = SWRAST_CONTEXT(ctx);
576
577   swrast->Line = osmesa_choose_line_function( ctx );
578   if (!swrast->Line)
579      _swrast_choose_line( ctx );
580}
581
582
583/**
584 * Don't use _mesa_delete_renderbuffer since we can't free rb->Data.
585 */
586static void
587osmesa_delete_renderbuffer(struct gl_renderbuffer *rb)
588{
589   _mesa_free(rb);
590}
591
592
593/**
594 * Allocate renderbuffer storage.  We don't actually allocate any storage
595 * since we're using a user-provided buffer.
596 * Just set up all the gl_renderbuffer methods.
597 */
598static GLboolean
599osmesa_renderbuffer_storage(GLcontext *ctx, struct gl_renderbuffer *rb,
600                            GLenum internalFormat, GLuint width, GLuint height)
601{
602   const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
603
604   if (osmesa->format == OSMESA_RGBA) {
605      rb->GetRow = get_row_RGBA;
606      rb->GetValues = get_values_RGBA;
607      rb->PutRow = put_row_RGBA;
608      rb->PutRowRGB = put_row_rgb_RGBA;
609      rb->PutMonoRow = put_mono_row_RGBA;
610      rb->PutValues = put_values_RGBA;
611      rb->PutMonoValues = put_mono_values_RGBA;
612   }
613   else if (osmesa->format == OSMESA_BGRA) {
614      rb->GetRow = get_row_BGRA;
615      rb->GetValues = get_values_BGRA;
616      rb->PutRow = put_row_BGRA;
617      rb->PutRowRGB = put_row_rgb_BGRA;
618      rb->PutMonoRow = put_mono_row_BGRA;
619      rb->PutValues = put_values_BGRA;
620      rb->PutMonoValues = put_mono_values_BGRA;
621   }
622   else if (osmesa->format == OSMESA_ARGB) {
623      rb->GetRow = get_row_ARGB;
624      rb->GetValues = get_values_ARGB;
625      rb->PutRow = put_row_ARGB;
626      rb->PutRowRGB = put_row_rgb_ARGB;
627      rb->PutMonoRow = put_mono_row_ARGB;
628      rb->PutValues = put_values_ARGB;
629      rb->PutMonoValues = put_mono_values_ARGB;
630   }
631   else if (osmesa->format == OSMESA_RGB) {
632      rb->GetRow = get_row_RGB;
633      rb->GetValues = get_values_RGB;
634      rb->PutRow = put_row_RGB;
635      rb->PutRowRGB = put_row_rgb_RGB;
636      rb->PutMonoRow = put_mono_row_RGB;
637      rb->PutValues = put_values_RGB;
638      rb->PutMonoValues = put_mono_values_RGB;
639   }
640   else if (osmesa->format == OSMESA_BGR) {
641      rb->GetRow = get_row_BGR;
642      rb->GetValues = get_values_BGR;
643      rb->PutRow = put_row_BGR;
644      rb->PutRowRGB = put_row_rgb_BGR;
645      rb->PutMonoRow = put_mono_row_BGR;
646      rb->PutValues = put_values_BGR;
647      rb->PutMonoValues = put_mono_values_BGR;
648   }
649#if CHAN_TYPE == GL_UNSIGNED_BYTE
650   else if (osmesa->format == OSMESA_RGB_565) {
651      rb->GetRow = get_row_RGB_565;
652      rb->GetValues = get_values_RGB_565;
653      rb->PutRow = put_row_RGB_565;
654      rb->PutRow = put_row_rgb_RGB_565;
655      rb->PutMonoRow = put_mono_row_RGB_565;
656      rb->PutValues = put_values_RGB_565;
657      rb->PutMonoValues = put_mono_values_RGB_565;
658   }
659#endif
660   else if (osmesa->format == OSMESA_COLOR_INDEX) {
661      rb->GetRow = get_row_CI;
662      rb->GetValues = get_values_CI;
663      rb->PutRow = put_row_CI;
664      rb->PutMonoRow = put_mono_row_CI;
665      rb->PutValues = put_values_CI;
666      rb->PutMonoValues = put_mono_values_CI;
667   }
668   else {
669      _mesa_problem(ctx, "bad pixel format in osmesa renderbuffer_storage");
670   }
671
672   return GL_TRUE;
673}
674
675
676/**
677 * Allocate a new renderbuffer tpo describe the user-provided color buffer.
678 */
679static struct gl_renderbuffer *
680new_osmesa_renderbuffer(GLenum format)
681{
682   struct gl_renderbuffer *rb = CALLOC_STRUCT(gl_renderbuffer);
683   if (rb) {
684      const GLuint name = 0;
685      _mesa_init_renderbuffer(rb, name);
686
687      rb->Delete = osmesa_delete_renderbuffer;
688      rb->AllocStorage = osmesa_renderbuffer_storage;
689
690      if (format == OSMESA_COLOR_INDEX) {
691         rb->_BaseFormat = GL_COLOR_INDEX;
692         rb->InternalFormat = GL_COLOR_INDEX;
693         rb->DataType = GL_UNSIGNED_BYTE;
694      }
695      else {
696         rb->_BaseFormat = GL_RGBA;
697         rb->InternalFormat = GL_RGBA;
698         rb->DataType = CHAN_TYPE;
699      }
700   }
701   return rb;
702}
703
704
705
706/**********************************************************************/
707/*****                    Public Functions                        *****/
708/**********************************************************************/
709
710
711/*
712 * Create an Off-Screen Mesa rendering context.  The only attribute needed is
713 * an RGBA vs Color-Index mode flag.
714 *
715 * Input:  format - either GL_RGBA or GL_COLOR_INDEX
716 *         sharelist - specifies another OSMesaContext with which to share
717 *                     display lists.  NULL indicates no sharing.
718 * Return:  an OSMesaContext or 0 if error
719 */
720GLAPI OSMesaContext GLAPIENTRY
721OSMesaCreateContext( GLenum format, OSMesaContext sharelist )
722{
723   const GLint accumBits = (format == OSMESA_COLOR_INDEX) ? 0 : 16;
724   return OSMesaCreateContextExt(format, DEFAULT_SOFTWARE_DEPTH_BITS,
725                                 8, accumBits, sharelist);
726}
727
728
729
730/*
731 * New in Mesa 3.5
732 *
733 * Create context and specify size of ancillary buffers.
734 */
735GLAPI OSMesaContext GLAPIENTRY
736OSMesaCreateContextExt( GLenum format, GLint depthBits, GLint stencilBits,
737                        GLint accumBits, OSMesaContext sharelist )
738{
739   OSMesaContext osmesa;
740   struct dd_function_table functions;
741   GLint rind, gind, bind, aind;
742   GLint indexBits = 0, redBits = 0, greenBits = 0, blueBits = 0, alphaBits =0;
743   GLboolean rgbmode;
744
745   rind = gind = bind = aind = 0;
746   if (format==OSMESA_COLOR_INDEX) {
747      indexBits = 8;
748      rgbmode = GL_FALSE;
749   }
750   else if (format==OSMESA_RGBA) {
751      indexBits = 0;
752      redBits = CHAN_BITS;
753      greenBits = CHAN_BITS;
754      blueBits = CHAN_BITS;
755      alphaBits = CHAN_BITS;
756      rind = 0;
757      gind = 1;
758      bind = 2;
759      aind = 3;
760      rgbmode = GL_TRUE;
761   }
762   else if (format==OSMESA_BGRA) {
763      indexBits = 0;
764      redBits = CHAN_BITS;
765      greenBits = CHAN_BITS;
766      blueBits = CHAN_BITS;
767      alphaBits = CHAN_BITS;
768      bind = 0;
769      gind = 1;
770      rind = 2;
771      aind = 3;
772      rgbmode = GL_TRUE;
773   }
774   else if (format==OSMESA_ARGB) {
775      indexBits = 0;
776      redBits = CHAN_BITS;
777      greenBits = CHAN_BITS;
778      blueBits = CHAN_BITS;
779      alphaBits = CHAN_BITS;
780      aind = 0;
781      rind = 1;
782      gind = 2;
783      bind = 3;
784      rgbmode = GL_TRUE;
785   }
786   else if (format==OSMESA_RGB) {
787      indexBits = 0;
788      redBits = CHAN_BITS;
789      greenBits = CHAN_BITS;
790      blueBits = CHAN_BITS;
791      alphaBits = 0;
792      rind = 0;
793      gind = 1;
794      bind = 2;
795      rgbmode = GL_TRUE;
796   }
797   else if (format==OSMESA_BGR) {
798      indexBits = 0;
799      redBits = CHAN_BITS;
800      greenBits = CHAN_BITS;
801      blueBits = CHAN_BITS;
802      alphaBits = 0;
803      rind = 2;
804      gind = 1;
805      bind = 0;
806      rgbmode = GL_TRUE;
807   }
808#if CHAN_TYPE == GL_UNSIGNED_BYTE
809   else if (format==OSMESA_RGB_565) {
810      indexBits = 0;
811      redBits = 5;
812      greenBits = 6;
813      blueBits = 5;
814      alphaBits = 0;
815      rind = 0; /* not used */
816      gind = 0;
817      bind = 0;
818      rgbmode = GL_TRUE;
819   }
820#endif
821   else {
822      return NULL;
823   }
824
825   osmesa = (OSMesaContext) CALLOC_STRUCT(osmesa_context);
826   if (osmesa) {
827      osmesa->gl_visual = _mesa_create_visual( rgbmode,
828                                               GL_FALSE,    /* double buffer */
829                                               GL_FALSE,    /* stereo */
830                                               redBits,
831                                               greenBits,
832                                               blueBits,
833                                               alphaBits,
834                                               indexBits,
835                                               depthBits,
836                                               stencilBits,
837                                               accumBits,
838                                               accumBits,
839                                               accumBits,
840                                               alphaBits ? accumBits : 0,
841                                               1            /* num samples */
842                                               );
843      if (!osmesa->gl_visual) {
844         FREE(osmesa);
845         return NULL;
846      }
847
848      /* Initialize device driver function table */
849      _mesa_init_driver_functions(&functions);
850      /* override with our functions */
851      functions.GetString = get_string;
852      functions.UpdateState = osmesa_update_state;
853      functions.GetBufferSize = get_buffer_size;
854
855      if (!_mesa_initialize_context(&osmesa->mesa,
856                                    osmesa->gl_visual,
857                                    sharelist ? &sharelist->mesa
858                                              : (GLcontext *) NULL,
859                                    &functions, (void *) osmesa)) {
860         _mesa_destroy_visual( osmesa->gl_visual );
861         FREE(osmesa);
862         return NULL;
863      }
864
865      _mesa_enable_sw_extensions(&(osmesa->mesa));
866      _mesa_enable_1_3_extensions(&(osmesa->mesa));
867      _mesa_enable_1_4_extensions(&(osmesa->mesa));
868      _mesa_enable_1_5_extensions(&(osmesa->mesa));
869
870      osmesa->gl_buffer = _mesa_create_framebuffer(osmesa->gl_visual);
871      if (!osmesa->gl_buffer) {
872         _mesa_destroy_visual( osmesa->gl_visual );
873         _mesa_free_context_data( &osmesa->mesa );
874         FREE(osmesa);
875         return NULL;
876      }
877
878      /* create front color buffer in user-provided memory (no back buffer) */
879      _mesa_add_renderbuffer(osmesa->gl_buffer, BUFFER_FRONT_LEFT,
880                             new_osmesa_renderbuffer(format));
881      _mesa_add_soft_renderbuffers(osmesa->gl_buffer,
882                                   GL_FALSE, /* color */
883                                   osmesa->gl_visual->haveDepthBuffer,
884                                   osmesa->gl_visual->haveStencilBuffer,
885                                   osmesa->gl_visual->haveAccumBuffer,
886                                   GL_FALSE, /* alpha */
887                                   GL_FALSE /* aux */ );
888
889      osmesa->format = format;
890      osmesa->buffer = NULL;
891      osmesa->width = 0;
892      osmesa->height = 0;
893      osmesa->userRowLength = 0;
894      osmesa->rowlength = 0;
895      osmesa->yup = GL_TRUE;
896      osmesa->rInd = rind;
897      osmesa->gInd = gind;
898      osmesa->bInd = bind;
899      osmesa->aInd = aind;
900
901      /* Initialize the software rasterizer and helper modules. */
902      {
903	 GLcontext *ctx = &osmesa->mesa;
904         SWcontext *swrast;
905         TNLcontext *tnl;
906
907	 if (!_swrast_CreateContext( ctx ) ||
908             !_ac_CreateContext( ctx ) ||
909             !_tnl_CreateContext( ctx ) ||
910             !_swsetup_CreateContext( ctx )) {
911            _mesa_destroy_visual(osmesa->gl_visual);
912            _mesa_free_context_data(ctx);
913            _mesa_free(osmesa);
914            return NULL;
915         }
916
917	 _swsetup_Wakeup( ctx );
918
919         /* use default TCL pipeline */
920         tnl = TNL_CONTEXT(ctx);
921         tnl->Driver.RunPipeline = _tnl_run_pipeline;
922
923         /* Extend the software rasterizer with our optimized line and triangle
924          * drawing functions.
925          */
926         swrast = SWRAST_CONTEXT( ctx );
927         swrast->choose_line = osmesa_choose_line;
928         swrast->choose_triangle = osmesa_choose_triangle;
929      }
930   }
931   return osmesa;
932}
933
934
935/*
936 * Destroy an Off-Screen Mesa rendering context.
937 *
938 * Input:  ctx - the context to destroy
939 */
940GLAPI void GLAPIENTRY
941OSMesaDestroyContext( OSMesaContext ctx )
942{
943   if (ctx) {
944      _swsetup_DestroyContext( &ctx->mesa );
945      _tnl_DestroyContext( &ctx->mesa );
946      _ac_DestroyContext( &ctx->mesa );
947      _swrast_DestroyContext( &ctx->mesa );
948
949      _mesa_destroy_visual( ctx->gl_visual );
950      _mesa_destroy_framebuffer( ctx->gl_buffer );
951      _mesa_free_context_data( &ctx->mesa );
952      FREE( ctx );
953   }
954}
955
956
957/*
958 * Recompute the values of the context's rowaddr array.
959 */
960static void
961compute_row_addresses( OSMesaContext ctx )
962{
963   GLint bytesPerPixel, bytesPerRow, i;
964   GLubyte *origin = (GLubyte *) ctx->buffer;
965
966   if (ctx->format == OSMESA_COLOR_INDEX) {
967      /* CI mode */
968      bytesPerPixel = 1 * sizeof(GLubyte);
969   }
970   else if ((ctx->format == OSMESA_RGB) || (ctx->format == OSMESA_BGR)) {
971      /* RGB mode */
972      bytesPerPixel = 3 * sizeof(GLchan);
973   }
974   else if (ctx->format == OSMESA_RGB_565) {
975      /* 5/6/5 RGB pixel in 16 bits */
976      bytesPerPixel = 2;
977   }
978   else {
979      /* RGBA mode */
980      bytesPerPixel = 4 * sizeof(GLchan);
981   }
982
983   bytesPerRow = ctx->rowlength * bytesPerPixel;
984
985   if (ctx->yup) {
986      /* Y=0 is bottom line of window */
987      for (i = 0; i < MAX_HEIGHT; i++) {
988         ctx->rowaddr[i] = (GLchan *) ((GLubyte *) origin + i * bytesPerRow);
989      }
990   }
991   else {
992      /* Y=0 is top line of window */
993      for (i = 0; i < MAX_HEIGHT; i++) {
994         GLint j = ctx->height - i - 1;
995         ctx->rowaddr[i] = (GLchan *) ((GLubyte *) origin + j * bytesPerRow);
996      }
997   }
998}
999
1000
1001/*
1002 * Bind an OSMesaContext to an image buffer.  The image buffer is just a
1003 * block of memory which the client provides.  Its size must be at least
1004 * as large as width*height*sizeof(type).  Its address should be a multiple
1005 * of 4 if using RGBA mode.
1006 *
1007 * Image data is stored in the order of glDrawPixels:  row-major order
1008 * with the lower-left image pixel stored in the first array position
1009 * (ie. bottom-to-top).
1010 *
1011 * If the context's viewport hasn't been initialized yet, it will now be
1012 * initialized to (0,0,width,height).
1013 *
1014 * Input:  ctx - the rendering context
1015 *         buffer - the image buffer memory
1016 *         type - data type for pixel components
1017 *            Normally, only GL_UNSIGNED_BYTE and GL_UNSIGNED_SHORT_5_6_5
1018 *            are supported.  But if Mesa's been compiled with CHAN_BITS==16
1019 *            then type must be GL_UNSIGNED_SHORT.  And if Mesa's been build
1020 *            with CHAN_BITS==32 then type must be GL_FLOAT.
1021 *         width, height - size of image buffer in pixels, at least 1
1022 * Return:  GL_TRUE if success, GL_FALSE if error because of invalid ctx,
1023 *          invalid buffer address, invalid type, width<1, height<1,
1024 *          width>internal limit or height>internal limit.
1025 */
1026GLAPI GLboolean GLAPIENTRY
1027OSMesaMakeCurrent( OSMesaContext ctx, void *buffer, GLenum type,
1028                   GLsizei width, GLsizei height )
1029{
1030   if (!ctx || !buffer ||
1031       width < 1 || height < 1 ||
1032       width > MAX_WIDTH || height > MAX_HEIGHT) {
1033      return GL_FALSE;
1034   }
1035
1036   if (ctx->format == OSMESA_RGB_565) {
1037      if (type != GL_UNSIGNED_SHORT_5_6_5)
1038         return GL_FALSE;
1039   }
1040   else if (type != CHAN_TYPE) {
1041      return GL_FALSE;
1042   }
1043
1044   /* Need to set these before calling _mesa_make_current() since the first
1045    * time the context is bound, _mesa_make_current() will call our
1046    * get_buffer_size() function to initialize the viewport.  These are the
1047    * values returned by get_buffer_size():
1048    */
1049   ctx->buffer = buffer;
1050   ctx->width = width;
1051   ctx->height = height;
1052
1053   osmesa_update_state( &ctx->mesa, 0 );
1054
1055   /* Call this periodically to detect when the user has begun using
1056    * GL rendering from multiple threads.
1057    */
1058   _glapi_check_multithread();
1059
1060   _mesa_make_current( &ctx->mesa, ctx->gl_buffer, ctx->gl_buffer );
1061
1062   if (ctx->userRowLength)
1063      ctx->rowlength = ctx->userRowLength;
1064   else
1065      ctx->rowlength = width;
1066
1067   compute_row_addresses( ctx );
1068
1069   /* this will make ensure we recognize the new buffer size */
1070   _mesa_resize_framebuffer(&ctx->mesa, ctx->gl_buffer, width, height);
1071
1072   return GL_TRUE;
1073}
1074
1075
1076
1077GLAPI OSMesaContext GLAPIENTRY
1078OSMesaGetCurrentContext( void )
1079{
1080   GLcontext *ctx = _mesa_get_current_context();
1081   if (ctx)
1082      return (OSMesaContext) ctx;
1083   else
1084      return NULL;
1085}
1086
1087
1088
1089GLAPI void GLAPIENTRY
1090OSMesaPixelStore( GLint pname, GLint value )
1091{
1092   OSMesaContext osmesa = OSMesaGetCurrentContext();
1093
1094   switch (pname) {
1095      case OSMESA_ROW_LENGTH:
1096         if (value<0) {
1097            _mesa_error( &osmesa->mesa, GL_INVALID_VALUE,
1098                      "OSMesaPixelStore(value)" );
1099            return;
1100         }
1101         osmesa->userRowLength = value;
1102         osmesa->rowlength = value ? value : osmesa->width;
1103         break;
1104      case OSMESA_Y_UP:
1105         osmesa->yup = value ? GL_TRUE : GL_FALSE;
1106         break;
1107      default:
1108         _mesa_error( &osmesa->mesa, GL_INVALID_ENUM, "OSMesaPixelStore(pname)" );
1109         return;
1110   }
1111
1112   compute_row_addresses( osmesa );
1113}
1114
1115
1116GLAPI void GLAPIENTRY
1117OSMesaGetIntegerv( GLint pname, GLint *value )
1118{
1119   OSMesaContext osmesa = OSMesaGetCurrentContext();
1120
1121   switch (pname) {
1122      case OSMESA_WIDTH:
1123         *value = osmesa->width;
1124         return;
1125      case OSMESA_HEIGHT:
1126         *value = osmesa->height;
1127         return;
1128      case OSMESA_FORMAT:
1129         *value = osmesa->format;
1130         return;
1131      case OSMESA_TYPE:
1132         *value = CHAN_TYPE;
1133         return;
1134      case OSMESA_ROW_LENGTH:
1135         *value = osmesa->userRowLength;
1136         return;
1137      case OSMESA_Y_UP:
1138         *value = osmesa->yup;
1139         return;
1140      case OSMESA_MAX_WIDTH:
1141         *value = MAX_WIDTH;
1142         return;
1143      case OSMESA_MAX_HEIGHT:
1144         *value = MAX_HEIGHT;
1145         return;
1146      default:
1147         _mesa_error(&osmesa->mesa, GL_INVALID_ENUM, "OSMesaGetIntergerv(pname)");
1148         return;
1149   }
1150}
1151
1152/*
1153 * Return the depth buffer associated with an OSMesa context.
1154 * Input:  c - the OSMesa context
1155 * Output:  width, height - size of buffer in pixels
1156 *          bytesPerValue - bytes per depth value (2 or 4)
1157 *          buffer - pointer to depth buffer values
1158 * Return:  GL_TRUE or GL_FALSE to indicate success or failure.
1159 */
1160GLAPI GLboolean GLAPIENTRY
1161OSMesaGetDepthBuffer( OSMesaContext c, GLint *width, GLint *height,
1162                      GLint *bytesPerValue, void **buffer )
1163{
1164   struct gl_renderbuffer *rb = NULL;
1165
1166   if (c->gl_buffer)
1167      rb = c->gl_buffer->Attachment[BUFFER_DEPTH].Renderbuffer;
1168
1169   if (!rb || !rb->Data) {
1170      /*if ((!c->gl_buffer) || (!c->gl_buffer->DepthBuffer)) {*/
1171      *width = 0;
1172      *height = 0;
1173      *bytesPerValue = 0;
1174      *buffer = 0;
1175      return GL_FALSE;
1176   }
1177   else {
1178      *width = c->gl_buffer->Width;
1179      *height = c->gl_buffer->Height;
1180      if (c->gl_visual->depthBits <= 16)
1181         *bytesPerValue = sizeof(GLushort);
1182      else
1183         *bytesPerValue = sizeof(GLuint);
1184      *buffer = rb->Data;
1185      return GL_TRUE;
1186   }
1187}
1188
1189/*
1190 * Return the color buffer associated with an OSMesa context.
1191 * Input:  c - the OSMesa context
1192 * Output:  width, height - size of buffer in pixels
1193 *          format - the pixel format (OSMESA_FORMAT)
1194 *          buffer - pointer to color buffer values
1195 * Return:  GL_TRUE or GL_FALSE to indicate success or failure.
1196 */
1197GLAPI GLboolean GLAPIENTRY
1198OSMesaGetColorBuffer( OSMesaContext c, GLint *width,
1199                      GLint *height, GLint *format, void **buffer )
1200{
1201   if (!c->buffer) {
1202      *width = 0;
1203      *height = 0;
1204      *format = 0;
1205      *buffer = 0;
1206      return GL_FALSE;
1207   }
1208   else {
1209      *width = c->width;
1210      *height = c->height;
1211      *format = c->format;
1212      *buffer = c->buffer;
1213      return GL_TRUE;
1214   }
1215}
1216
1217
1218struct name_function
1219{
1220   const char *Name;
1221   OSMESAproc Function;
1222};
1223
1224static struct name_function functions[] = {
1225   { "OSMesaCreateContext", (OSMESAproc) OSMesaCreateContext },
1226   { "OSMesaCreateContextExt", (OSMESAproc) OSMesaCreateContextExt },
1227   { "OSMesaDestroyContext", (OSMESAproc) OSMesaDestroyContext },
1228   { "OSMesaMakeCurrent", (OSMESAproc) OSMesaMakeCurrent },
1229   { "OSMesaGetCurrentContext", (OSMESAproc) OSMesaGetCurrentContext },
1230   { "OSMesaPixelsStore", (OSMESAproc) OSMesaPixelStore },
1231   { "OSMesaGetIntegerv", (OSMESAproc) OSMesaGetIntegerv },
1232   { "OSMesaGetDepthBuffer", (OSMESAproc) OSMesaGetDepthBuffer },
1233   { "OSMesaGetColorBuffer", (OSMESAproc) OSMesaGetColorBuffer },
1234   { "OSMesaGetProcAddress", (OSMESAproc) OSMesaGetProcAddress },
1235   { NULL, NULL }
1236};
1237
1238
1239GLAPI OSMESAproc GLAPIENTRY
1240OSMesaGetProcAddress( const char *funcName )
1241{
1242   int i;
1243   for (i = 0; functions[i].Name; i++) {
1244      if (_mesa_strcmp(functions[i].Name, funcName) == 0)
1245         return functions[i].Function;
1246   }
1247   return _glapi_get_proc_address(funcName);
1248}
1249
1250
1251GLAPI void GLAPIENTRY
1252OSMesaColorClamp(GLboolean enable)
1253{
1254   OSMesaContext osmesa = OSMesaGetCurrentContext();
1255
1256   if (enable == GL_TRUE) {
1257      osmesa->mesa.Color.ClampFragmentColor = GL_TRUE;
1258   }
1259   else {
1260      osmesa->mesa.Color.ClampFragmentColor = GL_FIXED_ONLY_ARB;
1261   }
1262}
1263
1264
1265