/* * Mesa 3-D graphics library * Version: 6.5.3 * * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Off-Screen Mesa rendering / Rendering into client memory space * * Note on thread safety: this driver is thread safe. All * functions are reentrant. The notion of current context is * managed by the core _mesa_make_current() and _mesa_get_current_context() * functions. Those functions are thread-safe. */ #include "main/glheader.h" #include "GL/osmesa.h" #include "main/context.h" #include "main/extensions.h" #include "main/formats.h" #include "main/framebuffer.h" #include "main/imports.h" #include "main/mtypes.h" #include "main/renderbuffer.h" #include "swrast/swrast.h" #include "swrast_setup/swrast_setup.h" #include "swrast/s_context.h" #include "swrast/s_lines.h" #include "swrast/s_triangle.h" #include "tnl/tnl.h" #include "tnl/t_context.h" #include "tnl/t_pipeline.h" #include "drivers/common/driverfuncs.h" #include "drivers/common/meta.h" #include "vbo/vbo.h" /** * OSMesa rendering context, derived from core Mesa GLcontext. */ struct osmesa_context { GLcontext mesa; /*< Base class - this must be first */ GLvisual *gl_visual; /*< Describes the buffers */ struct gl_renderbuffer *rb; /*< The user's colorbuffer */ GLframebuffer *gl_buffer; /*< The framebuffer, containing user's rb */ GLenum format; /*< User-specified context format */ GLint userRowLength; /*< user-specified number of pixels per row */ GLint rInd, gInd, bInd, aInd;/*< index offsets for RGBA formats */ GLvoid *rowaddr[MAX_HEIGHT]; /*< address of first pixel in each image row */ GLboolean yup; /*< TRUE -> Y increases upward */ /*< FALSE -> Y increases downward */ }; static INLINE OSMesaContext OSMESA_CONTEXT(GLcontext *ctx) { /* Just cast, since we're using structure containment */ return (OSMesaContext) ctx; } /**********************************************************************/ /*** Private Device Driver Functions ***/ /**********************************************************************/ static const GLubyte * get_string( GLcontext *ctx, GLenum name ) { (void) ctx; switch (name) { case GL_RENDERER: #if CHAN_BITS == 32 return (const GLubyte *) "Mesa OffScreen32"; #elif CHAN_BITS == 16 return (const GLubyte *) "Mesa OffScreen16"; #else return (const GLubyte *) "Mesa OffScreen"; #endif default: return NULL; } } static void osmesa_update_state( GLcontext *ctx, GLuint new_state ) { /* easy - just propogate */ _swrast_InvalidateState( ctx, new_state ); _swsetup_InvalidateState( ctx, new_state ); _tnl_InvalidateState( ctx, new_state ); _vbo_InvalidateState( ctx, new_state ); } /**********************************************************************/ /***** Read/write spans/arrays of pixels *****/ /**********************************************************************/ /* 8-bit RGBA */ #define NAME(PREFIX) PREFIX##_RGBA8 #define RB_TYPE GLubyte #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLubyte *P = (GLubyte *) osmesa->rowaddr[Y] + 4 * (X) #define INC_PIXEL_PTR(P) P += 4 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[0] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[2] = VALUE[BCOMP]; \ DST[3] = VALUE[ACOMP] #define STORE_PIXEL_RGB(DST, X, Y, VALUE) \ DST[0] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[2] = VALUE[BCOMP]; \ DST[3] = 255 #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[0]; \ DST[GCOMP] = SRC[1]; \ DST[BCOMP] = SRC[2]; \ DST[ACOMP] = SRC[3] #include "swrast/s_spantemp.h" /* 16-bit RGBA */ #define NAME(PREFIX) PREFIX##_RGBA16 #define RB_TYPE GLushort #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLushort *P = (GLushort *) osmesa->rowaddr[Y] + 4 * (X) #define INC_PIXEL_PTR(P) P += 4 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[0] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[2] = VALUE[BCOMP]; \ DST[3] = VALUE[ACOMP] #define STORE_PIXEL_RGB(DST, X, Y, VALUE) \ DST[0] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[2] = VALUE[BCOMP]; \ DST[3] = 65535 #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[0]; \ DST[GCOMP] = SRC[1]; \ DST[BCOMP] = SRC[2]; \ DST[ACOMP] = SRC[3] #include "swrast/s_spantemp.h" /* 32-bit RGBA */ #define NAME(PREFIX) PREFIX##_RGBA32 #define RB_TYPE GLfloat #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLfloat *P = (GLfloat *) osmesa->rowaddr[Y] + 4 * (X) #define INC_PIXEL_PTR(P) P += 4 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[0] = MAX2((VALUE[RCOMP]), 0.0F); \ DST[1] = MAX2((VALUE[GCOMP]), 0.0F); \ DST[2] = MAX2((VALUE[BCOMP]), 0.0F); \ DST[3] = CLAMP((VALUE[ACOMP]), 0.0F, 1.0F) #define STORE_PIXEL_RGB(DST, X, Y, VALUE) \ DST[0] = MAX2((VALUE[RCOMP]), 0.0F); \ DST[1] = MAX2((VALUE[GCOMP]), 0.0F); \ DST[2] = MAX2((VALUE[BCOMP]), 0.0F); \ DST[3] = 1.0F #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[0]; \ DST[GCOMP] = SRC[1]; \ DST[BCOMP] = SRC[2]; \ DST[ACOMP] = SRC[3] #include "swrast/s_spantemp.h" /* 8-bit BGRA */ #define NAME(PREFIX) PREFIX##_BGRA8 #define RB_TYPE GLubyte #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLubyte *P = (GLubyte *) osmesa->rowaddr[Y] + 4 * (X) #define INC_PIXEL_PTR(P) P += 4 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[2] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[0] = VALUE[BCOMP]; \ DST[3] = VALUE[ACOMP] #define STORE_PIXEL_RGB(DST, X, Y, VALUE) \ DST[2] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[0] = VALUE[BCOMP]; \ DST[3] = 255 #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[2]; \ DST[GCOMP] = SRC[1]; \ DST[BCOMP] = SRC[0]; \ DST[ACOMP] = SRC[3] #include "swrast/s_spantemp.h" /* 16-bit BGRA */ #define NAME(PREFIX) PREFIX##_BGRA16 #define RB_TYPE GLushort #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLushort *P = (GLushort *) osmesa->rowaddr[Y] + 4 * (X) #define INC_PIXEL_PTR(P) P += 4 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[2] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[0] = VALUE[BCOMP]; \ DST[3] = VALUE[ACOMP] #define STORE_PIXEL_RGB(DST, X, Y, VALUE) \ DST[2] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[0] = VALUE[BCOMP]; \ DST[3] = 65535 #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[2]; \ DST[GCOMP] = SRC[1]; \ DST[BCOMP] = SRC[0]; \ DST[ACOMP] = SRC[3] #include "swrast/s_spantemp.h" /* 32-bit BGRA */ #define NAME(PREFIX) PREFIX##_BGRA32 #define RB_TYPE GLfloat #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLfloat *P = (GLfloat *) osmesa->rowaddr[Y] + 4 * (X) #define INC_PIXEL_PTR(P) P += 4 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[2] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[0] = VALUE[BCOMP]; \ DST[3] = VALUE[ACOMP] #define STORE_PIXEL_RGB(DST, X, Y, VALUE) \ DST[2] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[0] = VALUE[BCOMP]; \ DST[3] = 1.0F #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[2]; \ DST[GCOMP] = SRC[1]; \ DST[BCOMP] = SRC[0]; \ DST[ACOMP] = SRC[3] #include "swrast/s_spantemp.h" /* 8-bit ARGB */ #define NAME(PREFIX) PREFIX##_ARGB8 #define RB_TYPE GLubyte #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLubyte *P = (GLubyte *) osmesa->rowaddr[Y] + 4 * (X) #define INC_PIXEL_PTR(P) P += 4 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[1] = VALUE[RCOMP]; \ DST[2] = VALUE[GCOMP]; \ DST[3] = VALUE[BCOMP]; \ DST[0] = VALUE[ACOMP] #define STORE_PIXEL_RGB(DST, X, Y, VALUE) \ DST[1] = VALUE[RCOMP]; \ DST[2] = VALUE[GCOMP]; \ DST[3] = VALUE[BCOMP]; \ DST[0] = 255 #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[1]; \ DST[GCOMP] = SRC[2]; \ DST[BCOMP] = SRC[3]; \ DST[ACOMP] = SRC[0] #include "swrast/s_spantemp.h" /* 16-bit ARGB */ #define NAME(PREFIX) PREFIX##_ARGB16 #define RB_TYPE GLushort #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLushort *P = (GLushort *) osmesa->rowaddr[Y] + 4 * (X) #define INC_PIXEL_PTR(P) P += 4 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[1] = VALUE[RCOMP]; \ DST[2] = VALUE[GCOMP]; \ DST[3] = VALUE[BCOMP]; \ DST[0] = VALUE[ACOMP] #define STORE_PIXEL_RGB(DST, X, Y, VALUE) \ DST[1] = VALUE[RCOMP]; \ DST[2] = VALUE[GCOMP]; \ DST[3] = VALUE[BCOMP]; \ DST[0] = 65535 #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[1]; \ DST[GCOMP] = SRC[2]; \ DST[BCOMP] = SRC[3]; \ DST[ACOMP] = SRC[0] #include "swrast/s_spantemp.h" /* 32-bit ARGB */ #define NAME(PREFIX) PREFIX##_ARGB32 #define RB_TYPE GLfloat #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLfloat *P = (GLfloat *) osmesa->rowaddr[Y] + 4 * (X) #define INC_PIXEL_PTR(P) P += 4 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[1] = VALUE[RCOMP]; \ DST[2] = VALUE[GCOMP]; \ DST[3] = VALUE[BCOMP]; \ DST[0] = VALUE[ACOMP] #define STORE_PIXEL_RGB(DST, X, Y, VALUE) \ DST[1] = VALUE[RCOMP]; \ DST[2] = VALUE[GCOMP]; \ DST[3] = VALUE[BCOMP]; \ DST[0] = 1.0F #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[1]; \ DST[GCOMP] = SRC[2]; \ DST[BCOMP] = SRC[3]; \ DST[ACOMP] = SRC[0] #include "swrast/s_spantemp.h" /* 8-bit RGB */ #define NAME(PREFIX) PREFIX##_RGB8 #define RB_TYPE GLubyte #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLubyte *P = (GLubyte *) osmesa->rowaddr[Y] + 3 * (X) #define INC_PIXEL_PTR(P) P += 3 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[0] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[2] = VALUE[BCOMP] #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[0]; \ DST[GCOMP] = SRC[1]; \ DST[BCOMP] = SRC[2]; \ DST[ACOMP] = 255 #include "swrast/s_spantemp.h" /* 16-bit RGB */ #define NAME(PREFIX) PREFIX##_RGB16 #define RB_TYPE GLushort #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLushort *P = (GLushort *) osmesa->rowaddr[Y] + 3 * (X) #define INC_PIXEL_PTR(P) P += 3 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[0] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[2] = VALUE[BCOMP] #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[0]; \ DST[GCOMP] = SRC[1]; \ DST[BCOMP] = SRC[2]; \ DST[ACOMP] = 65535U #include "swrast/s_spantemp.h" /* 32-bit RGB */ #define NAME(PREFIX) PREFIX##_RGB32 #define RB_TYPE GLfloat #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLfloat *P = (GLfloat *) osmesa->rowaddr[Y] + 3 * (X) #define INC_PIXEL_PTR(P) P += 3 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[0] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[2] = VALUE[BCOMP] #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[0]; \ DST[GCOMP] = SRC[1]; \ DST[BCOMP] = SRC[2]; \ DST[ACOMP] = 1.0F #include "swrast/s_spantemp.h" /* 8-bit BGR */ #define NAME(PREFIX) PREFIX##_BGR8 #define RB_TYPE GLubyte #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLubyte *P = (GLubyte *) osmesa->rowaddr[Y] + 3 * (X) #define INC_PIXEL_PTR(P) P += 3 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[2] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[0] = VALUE[BCOMP] #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[2]; \ DST[GCOMP] = SRC[1]; \ DST[BCOMP] = SRC[0]; \ DST[ACOMP] = 255 #include "swrast/s_spantemp.h" /* 16-bit BGR */ #define NAME(PREFIX) PREFIX##_BGR16 #define RB_TYPE GLushort #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLushort *P = (GLushort *) osmesa->rowaddr[Y] + 3 * (X) #define INC_PIXEL_PTR(P) P += 3 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[2] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[0] = VALUE[BCOMP] #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[2]; \ DST[GCOMP] = SRC[1]; \ DST[BCOMP] = SRC[0]; \ DST[ACOMP] = 65535 #include "swrast/s_spantemp.h" /* 32-bit BGR */ #define NAME(PREFIX) PREFIX##_BGR32 #define RB_TYPE GLfloat #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLfloat *P = (GLfloat *) osmesa->rowaddr[Y] + 3 * (X) #define INC_PIXEL_PTR(P) P += 3 #define STORE_PIXEL(DST, X, Y, VALUE) \ DST[2] = VALUE[RCOMP]; \ DST[1] = VALUE[GCOMP]; \ DST[0] = VALUE[BCOMP] #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = SRC[2]; \ DST[GCOMP] = SRC[1]; \ DST[BCOMP] = SRC[0]; \ DST[ACOMP] = 1.0F #include "swrast/s_spantemp.h" /* 16-bit 5/6/5 RGB */ #define NAME(PREFIX) PREFIX##_RGB_565 #define RB_TYPE GLubyte #define SPAN_VARS \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define INIT_PIXEL_PTR(P, X, Y) \ GLushort *P = (GLushort *) osmesa->rowaddr[Y] + (X) #define INC_PIXEL_PTR(P) P += 1 #define STORE_PIXEL(DST, X, Y, VALUE) \ *DST = ( (((VALUE[RCOMP]) & 0xf8) << 8) | (((VALUE[GCOMP]) & 0xfc) << 3) | ((VALUE[BCOMP]) >> 3) ) #define FETCH_PIXEL(DST, SRC) \ DST[RCOMP] = ( (((*SRC) >> 8) & 0xf8) | (((*SRC) >> 11) & 0x7) ); \ DST[GCOMP] = ( (((*SRC) >> 3) & 0xfc) | (((*SRC) >> 5) & 0x3) ); \ DST[BCOMP] = ( (((*SRC) << 3) & 0xf8) | (((*SRC) ) & 0x7) ); \ DST[ACOMP] = CHAN_MAX #include "swrast/s_spantemp.h" /** * Macros for optimized line/triangle rendering. * Only for 8-bit channel, RGBA, BGRA, ARGB formats. */ #define PACK_RGBA(DST, R, G, B, A) \ do { \ (DST)[osmesa->rInd] = R; \ (DST)[osmesa->gInd] = G; \ (DST)[osmesa->bInd] = B; \ (DST)[osmesa->aInd] = A; \ } while (0) #define PIXELADDR4(X,Y) ((GLchan *) osmesa->rowaddr[Y] + 4 * (X)) /** * Draw a flat-shaded, RGB line into an osmesa buffer. */ #define NAME flat_rgba_line #define CLIP_HACK 1 #define SETUP_CODE \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); \ const GLchan *color = vert1->color; #define PLOT(X, Y) \ do { \ GLchan *p = PIXELADDR4(X, Y); \ PACK_RGBA(p, color[0], color[1], color[2], color[3]); \ } while (0) #ifdef WIN32 #include "..\swrast\s_linetemp.h" #else #include "swrast/s_linetemp.h" #endif /** * Draw a flat-shaded, Z-less, RGB line into an osmesa buffer. */ #define NAME flat_rgba_z_line #define CLIP_HACK 1 #define INTERP_Z 1 #define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE #define SETUP_CODE \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); \ const GLchan *color = vert1->color; #define PLOT(X, Y) \ do { \ if (Z < *zPtr) { \ GLchan *p = PIXELADDR4(X, Y); \ PACK_RGBA(p, color[RCOMP], color[GCOMP], \ color[BCOMP], color[ACOMP]); \ *zPtr = Z; \ } \ } while (0) #ifdef WIN32 #include "..\swrast\s_linetemp.h" #else #include "swrast/s_linetemp.h" #endif /** * Analyze context state to see if we can provide a fast line drawing * function. Otherwise, return NULL. */ static swrast_line_func osmesa_choose_line_function( GLcontext *ctx ) { const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); const SWcontext *swrast = SWRAST_CONTEXT(ctx); if (osmesa->rb->DataType != GL_UNSIGNED_BYTE) return NULL; if (ctx->RenderMode != GL_RENDER) return NULL; if (ctx->Line.SmoothFlag) return NULL; if (ctx->Texture._EnabledUnits) return NULL; if (ctx->Light.ShadeModel != GL_FLAT) return NULL; if (ctx->Line.Width != 1.0F) return NULL; if (ctx->Line.StippleFlag) return NULL; if (ctx->Line.SmoothFlag) return NULL; if (osmesa->format != OSMESA_RGBA && osmesa->format != OSMESA_BGRA && osmesa->format != OSMESA_ARGB) return NULL; if (swrast->_RasterMask==DEPTH_BIT && ctx->Depth.Func==GL_LESS && ctx->Depth.Mask==GL_TRUE && ctx->Visual.depthBits == DEFAULT_SOFTWARE_DEPTH_BITS) { return (swrast_line_func) flat_rgba_z_line; } if (swrast->_RasterMask == 0) { return (swrast_line_func) flat_rgba_line; } return (swrast_line_func) NULL; } /**********************************************************************/ /***** Optimized triangle rendering *****/ /**********************************************************************/ /* * Smooth-shaded, z-less triangle, RGBA color. */ #define NAME smooth_rgba_z_triangle #define INTERP_Z 1 #define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE #define INTERP_RGB 1 #define INTERP_ALPHA 1 #define SETUP_CODE \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); #define RENDER_SPAN( span ) { \ GLuint i; \ GLchan *img = PIXELADDR4(span.x, span.y); \ for (i = 0; i < span.end; i++, img += 4) { \ const GLuint z = FixedToDepth(span.z); \ if (z < zRow[i]) { \ PACK_RGBA(img, FixedToChan(span.red), \ FixedToChan(span.green), FixedToChan(span.blue), \ FixedToChan(span.alpha)); \ zRow[i] = z; \ } \ span.red += span.redStep; \ span.green += span.greenStep; \ span.blue += span.blueStep; \ span.alpha += span.alphaStep; \ span.z += span.zStep; \ } \ } #ifdef WIN32 #include "..\swrast\s_tritemp.h" #else #include "swrast/s_tritemp.h" #endif /* * Flat-shaded, z-less triangle, RGBA color. */ #define NAME flat_rgba_z_triangle #define INTERP_Z 1 #define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE #define SETUP_CODE \ const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); \ GLuint pixel; \ PACK_RGBA((GLchan *) &pixel, v2->color[0], v2->color[1], \ v2->color[2], v2->color[3]); #define RENDER_SPAN( span ) { \ GLuint i; \ GLuint *img = (GLuint *) PIXELADDR4(span.x, span.y); \ for (i = 0; i < span.end; i++) { \ const GLuint z = FixedToDepth(span.z); \ if (z < zRow[i]) { \ img[i] = pixel; \ zRow[i] = z; \ } \ span.z += span.zStep; \ } \ } #ifdef WIN32 #include "..\swrast\s_tritemp.h" #else #include "swrast/s_tritemp.h" #endif /** * Return pointer to an optimized triangle function if possible. */ static swrast_tri_func osmesa_choose_triangle_function( GLcontext *ctx ) { const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); const SWcontext *swrast = SWRAST_CONTEXT(ctx); if (osmesa->rb->DataType != GL_UNSIGNED_BYTE) return (swrast_tri_func) NULL; if (ctx->RenderMode != GL_RENDER) return (swrast_tri_func) NULL; if (ctx->Polygon.SmoothFlag) return (swrast_tri_func) NULL; if (ctx->Polygon.StippleFlag) return (swrast_tri_func) NULL; if (ctx->Texture._EnabledUnits) return (swrast_tri_func) NULL; if (osmesa->format != OSMESA_RGBA && osmesa->format != OSMESA_BGRA && osmesa->format != OSMESA_ARGB) return (swrast_tri_func) NULL; if (ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) return (swrast_tri_func) NULL; if (swrast->_RasterMask == DEPTH_BIT && ctx->Depth.Func == GL_LESS && ctx->Depth.Mask == GL_TRUE && ctx->Visual.depthBits == DEFAULT_SOFTWARE_DEPTH_BITS) { if (ctx->Light.ShadeModel == GL_SMOOTH) { return (swrast_tri_func) smooth_rgba_z_triangle; } else { return (swrast_tri_func) flat_rgba_z_triangle; } } return (swrast_tri_func) NULL; } /* Override for the swrast triangle-selection function. Try to use one * of our internal triangle functions, otherwise fall back to the * standard swrast functions. */ static void osmesa_choose_triangle( GLcontext *ctx ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); swrast->Triangle = osmesa_choose_triangle_function( ctx ); if (!swrast->Triangle) _swrast_choose_triangle( ctx ); } static void osmesa_choose_line( GLcontext *ctx ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); swrast->Line = osmesa_choose_line_function( ctx ); if (!swrast->Line) _swrast_choose_line( ctx ); } /** * Recompute the values of the context's rowaddr array. */ static void compute_row_addresses( OSMesaContext osmesa ) { GLint bytesPerPixel, bytesPerRow, i; GLubyte *origin = (GLubyte *) osmesa->rb->Data; GLint bpc; /* bytes per channel */ GLint rowlength; /* in pixels */ GLint height = osmesa->rb->Height; if (osmesa->userRowLength) rowlength = osmesa->userRowLength; else rowlength = osmesa->rb->Width; if (osmesa->rb->DataType == GL_UNSIGNED_BYTE) bpc = 1; else if (osmesa->rb->DataType == GL_UNSIGNED_SHORT) bpc = 2; else if (osmesa->rb->DataType == GL_FLOAT) bpc = 4; else { _mesa_problem(&osmesa->mesa, "Unexpected datatype in osmesa::compute_row_addresses"); return; } if ((osmesa->format == OSMESA_RGB) || (osmesa->format == OSMESA_BGR)) { /* RGB mode */ bytesPerPixel = 3 * bpc; } else if (osmesa->format == OSMESA_RGB_565) { /* 5/6/5 RGB pixel in 16 bits */ bytesPerPixel = 2; } else { /* RGBA mode */ bytesPerPixel = 4 * bpc; } bytesPerRow = rowlength * bytesPerPixel; if (osmesa->yup) { /* Y=0 is bottom line of window */ for (i = 0; i < height; i++) { osmesa->rowaddr[i] = (GLvoid *) ((GLubyte *) origin + i * bytesPerRow); } } else { /* Y=0 is top line of window */ for (i = 0; i < height; i++) { GLint j = height - i - 1; osmesa->rowaddr[i] = (GLvoid *) ((GLubyte *) origin + j * bytesPerRow); } } } /** * Don't use _mesa_delete_renderbuffer since we can't free rb->Data. */ static void osmesa_delete_renderbuffer(struct gl_renderbuffer *rb) { free(rb); } /** * Allocate renderbuffer storage. We don't actually allocate any storage * since we're using a user-provided buffer. * Just set up all the gl_renderbuffer methods. */ static GLboolean osmesa_renderbuffer_storage(GLcontext *ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { const OSMesaContext osmesa = OSMESA_CONTEXT(ctx); GLint bpc; /* bits per channel */ if (rb->DataType == GL_UNSIGNED_BYTE) bpc = 8; else if (rb->DataType == GL_UNSIGNED_SHORT) bpc = 16; else bpc = 32; /* Note: we can ignoring internalFormat for "window-system" renderbuffers */ (void) internalFormat; if (osmesa->format == OSMESA_RGBA) { if (rb->DataType == GL_UNSIGNED_BYTE) { rb->GetRow = get_row_RGBA8; rb->GetValues = get_values_RGBA8; rb->PutRow = put_row_RGBA8; rb->PutRowRGB = put_row_rgb_RGBA8; rb->PutMonoRow = put_mono_row_RGBA8; rb->PutValues = put_values_RGBA8; rb->PutMonoValues = put_mono_values_RGBA8; } else if (rb->DataType == GL_UNSIGNED_SHORT) { rb->GetRow = get_row_RGBA16; rb->GetValues = get_values_RGBA16; rb->PutRow = put_row_RGBA16; rb->PutRowRGB = put_row_rgb_RGBA16; rb->PutMonoRow = put_mono_row_RGBA16; rb->PutValues = put_values_RGBA16; rb->PutMonoValues = put_mono_values_RGBA16; } else { rb->GetRow = get_row_RGBA32; rb->GetValues = get_values_RGBA32; rb->PutRow = put_row_RGBA32; rb->PutRowRGB = put_row_rgb_RGBA32; rb->PutMonoRow = put_mono_row_RGBA32; rb->PutValues = put_values_RGBA32; rb->PutMonoValues = put_mono_values_RGBA32; } } else if (osmesa->format == OSMESA_BGRA) { if (rb->DataType == GL_UNSIGNED_BYTE) { rb->GetRow = get_row_BGRA8; rb->GetValues = get_values_BGRA8; rb->PutRow = put_row_BGRA8; rb->PutRowRGB = put_row_rgb_BGRA8; rb->PutMonoRow = put_mono_row_BGRA8; rb->PutValues = put_values_BGRA8; rb->PutMonoValues = put_mono_values_BGRA8; } else if (rb->DataType == GL_UNSIGNED_SHORT) { rb->GetRow = get_row_BGRA16; rb->GetValues = get_values_BGRA16; rb->PutRow = put_row_BGRA16; rb->PutRowRGB = put_row_rgb_BGRA16; rb->PutMonoRow = put_mono_row_BGRA16; rb->PutValues = put_values_BGRA16; rb->PutMonoValues = put_mono_values_BGRA16; } else { rb->GetRow = get_row_BGRA32; rb->GetValues = get_values_BGRA32; rb->PutRow = put_row_BGRA32; rb->PutRowRGB = put_row_rgb_BGRA32; rb->PutMonoRow = put_mono_row_BGRA32; rb->PutValues = put_values_BGRA32; rb->PutMonoValues = put_mono_values_BGRA32; } } else if (osmesa->format == OSMESA_ARGB) { if (rb->DataType == GL_UNSIGNED_BYTE) { rb->GetRow = get_row_ARGB8; rb->GetValues = get_values_ARGB8; rb->PutRow = put_row_ARGB8; rb->PutRowRGB = put_row_rgb_ARGB8; rb->PutMonoRow = put_mono_row_ARGB8; rb->PutValues = put_values_ARGB8; rb->PutMonoValues = put_mono_values_ARGB8; } else if (rb->DataType == GL_UNSIGNED_SHORT) { rb->GetRow = get_row_ARGB16; rb->GetValues = get_values_ARGB16; rb->PutRow = put_row_ARGB16; rb->PutRowRGB = put_row_rgb_ARGB16; rb->PutMonoRow = put_mono_row_ARGB16; rb->PutValues = put_values_ARGB16; rb->PutMonoValues = put_mono_values_ARGB16; } else { rb->GetRow = get_row_ARGB32; rb->GetValues = get_values_ARGB32; rb->PutRow = put_row_ARGB32; rb->PutRowRGB = put_row_rgb_ARGB32; rb->PutMonoRow = put_mono_row_ARGB32; rb->PutValues = put_values_ARGB32; rb->PutMonoValues = put_mono_values_ARGB32; } } else if (osmesa->format == OSMESA_RGB) { if (rb->DataType == GL_UNSIGNED_BYTE) { rb->GetRow = get_row_RGB8; rb->GetValues = get_values_RGB8; rb->PutRow = put_row_RGB8; rb->PutRowRGB = put_row_rgb_RGB8; rb->PutMonoRow = put_mono_row_RGB8; rb->PutValues = put_values_RGB8; rb->PutMonoValues = put_mono_values_RGB8; } else if (rb->DataType == GL_UNSIGNED_SHORT) { rb->GetRow = get_row_RGB16; rb->GetValues = get_values_RGB16; rb->PutRow = put_row_RGB16; rb->PutRowRGB = put_row_rgb_RGB16; rb->PutMonoRow = put_mono_row_RGB16; rb->PutValues = put_values_RGB16; rb->PutMonoValues = put_mono_values_RGB16; } else { rb->GetRow = get_row_RGB32; rb->GetValues = get_values_RGB32; rb->PutRow = put_row_RGB32; rb->PutRowRGB = put_row_rgb_RGB32; rb->PutMonoRow = put_mono_row_RGB32; rb->PutValues = put_values_RGB32; rb->PutMonoValues = put_mono_values_RGB32; } } else if (osmesa->format == OSMESA_BGR) { if (rb->DataType == GL_UNSIGNED_BYTE) { rb->GetRow = get_row_BGR8; rb->GetValues = get_values_BGR8; rb->PutRow = put_row_BGR8; rb->PutRowRGB = put_row_rgb_BGR8; rb->PutMonoRow = put_mono_row_BGR8; rb->PutValues = put_values_BGR8; rb->PutMonoValues = put_mono_values_BGR8; } else if (rb->DataType == GL_UNSIGNED_SHORT) { rb->GetRow = get_row_BGR16; rb->GetValues = get_values_BGR16; rb->PutRow = put_row_BGR16; rb->PutRowRGB = put_row_rgb_BGR16; rb->PutMonoRow = put_mono_row_BGR16; rb->PutValues = put_values_BGR16; rb->PutMonoValues = put_mono_values_BGR16; } else { rb->GetRow = get_row_BGR32; rb->GetValues = get_values_BGR32; rb->PutRow = put_row_BGR32; rb->PutRowRGB = put_row_rgb_BGR32; rb->PutMonoRow = put_mono_row_BGR32; rb->PutValues = put_values_BGR32; rb->PutMonoValues = put_mono_values_BGR32; } } else if (osmesa->format == OSMESA_RGB_565) { ASSERT(rb->DataType == GL_UNSIGNED_BYTE); rb->GetRow = get_row_RGB_565; rb->GetValues = get_values_RGB_565; rb->PutRow = put_row_RGB_565; rb->PutRowRGB = put_row_rgb_RGB_565; rb->PutMonoRow = put_mono_row_RGB_565; rb->PutValues = put_values_RGB_565; rb->PutMonoValues = put_mono_values_RGB_565; } else { _mesa_problem(ctx, "bad pixel format in osmesa renderbuffer_storage"); } rb->Width = width; rb->Height = height; compute_row_addresses( osmesa ); return GL_TRUE; } /** * Allocate a new renderbuffer to describe the user-provided color buffer. */ static struct gl_renderbuffer * new_osmesa_renderbuffer(GLcontext *ctx, GLenum format, GLenum type) { const GLuint name = 0; struct gl_renderbuffer *rb = _mesa_new_renderbuffer(ctx, name); if (rb) { rb->RefCount = 1; rb->Delete = osmesa_delete_renderbuffer; rb->AllocStorage = osmesa_renderbuffer_storage; rb->InternalFormat = GL_RGBA; rb->Format = MESA_FORMAT_RGBA8888; rb->_BaseFormat = GL_RGBA; rb->DataType = type; } return rb; } /**********************************************************************/ /***** Public Functions *****/ /**********************************************************************/ /** * Create an Off-Screen Mesa rendering context. The only attribute needed is * an RGBA vs Color-Index mode flag. * * Input: format - Must be GL_RGBA * sharelist - specifies another OSMesaContext with which to share * display lists. NULL indicates no sharing. * Return: an OSMesaContext or 0 if error */ GLAPI OSMesaContext GLAPIENTRY OSMesaCreateContext( GLenum format, OSMesaContext sharelist ) { return OSMesaCreateContextExt(format, DEFAULT_SOFTWARE_DEPTH_BITS, 8, 0, sharelist); } /** * New in Mesa 3.5 * * Create context and specify size of ancillary buffers. */ GLAPI OSMesaContext GLAPIENTRY OSMesaCreateContextExt( GLenum format, GLint depthBits, GLint stencilBits, GLint accumBits, OSMesaContext sharelist ) { OSMesaContext osmesa; struct dd_function_table functions; GLint rind, gind, bind, aind; GLint redBits = 0, greenBits = 0, blueBits = 0, alphaBits =0; GLenum type = CHAN_TYPE; rind = gind = bind = aind = 0; if (format==OSMESA_RGBA) { redBits = CHAN_BITS; greenBits = CHAN_BITS; blueBits = CHAN_BITS; alphaBits = CHAN_BITS; rind = 0; gind = 1; bind = 2; aind = 3; } else if (format==OSMESA_BGRA) { redBits = CHAN_BITS; greenBits = CHAN_BITS; blueBits = CHAN_BITS; alphaBits = CHAN_BITS; bind = 0; gind = 1; rind = 2; aind = 3; } else if (format==OSMESA_ARGB) { redBits = CHAN_BITS; greenBits = CHAN_BITS; blueBits = CHAN_BITS; alphaBits = CHAN_BITS; aind = 0; rind = 1; gind = 2; bind = 3; } else if (format==OSMESA_RGB) { redBits = CHAN_BITS; greenBits = CHAN_BITS; blueBits = CHAN_BITS; alphaBits = 0; rind = 0; gind = 1; bind = 2; } else if (format==OSMESA_BGR) { redBits = CHAN_BITS; greenBits = CHAN_BITS; blueBits = CHAN_BITS; alphaBits = 0; rind = 2; gind = 1; bind = 0; } #if CHAN_TYPE == GL_UNSIGNED_BYTE else if (format==OSMESA_RGB_565) { redBits = 5; greenBits = 6; blueBits = 5; alphaBits = 0; rind = 0; /* not used */ gind = 0; bind = 0; } #endif else { return NULL; } osmesa = (OSMesaContext) CALLOC_STRUCT(osmesa_context); if (osmesa) { osmesa->gl_visual = _mesa_create_visual( GL_TRUE, /* rgbMode */ GL_FALSE, /* double buffer */ GL_FALSE, /* stereo */ redBits, greenBits, blueBits, alphaBits, 0, depthBits, stencilBits, accumBits, accumBits, accumBits, alphaBits ? accumBits : 0, 1 /* num samples */ ); if (!osmesa->gl_visual) { free(osmesa); return NULL; } /* Initialize device driver function table */ _mesa_init_driver_functions(&functions); /* override with our functions */ functions.GetString = get_string; functions.UpdateState = osmesa_update_state; functions.GetBufferSize = NULL; if (!_mesa_initialize_context(&osmesa->mesa, osmesa->gl_visual, sharelist ? &sharelist->mesa : (GLcontext *) NULL, &functions, (void *) osmesa)) { _mesa_destroy_visual( osmesa->gl_visual ); free(osmesa); return NULL; } _mesa_enable_sw_extensions(&(osmesa->mesa)); _mesa_enable_1_3_extensions(&(osmesa->mesa)); _mesa_enable_1_4_extensions(&(osmesa->mesa)); _mesa_enable_1_5_extensions(&(osmesa->mesa)); _mesa_enable_2_0_extensions(&(osmesa->mesa)); _mesa_enable_2_1_extensions(&(osmesa->mesa)); osmesa->gl_buffer = _mesa_create_framebuffer(osmesa->gl_visual); if (!osmesa->gl_buffer) { _mesa_destroy_visual( osmesa->gl_visual ); _mesa_free_context_data( &osmesa->mesa ); free(osmesa); return NULL; } /* create front color buffer in user-provided memory (no back buffer) */ osmesa->rb = new_osmesa_renderbuffer(&osmesa->mesa, format, type); _mesa_add_renderbuffer(osmesa->gl_buffer, BUFFER_FRONT_LEFT, osmesa->rb); assert(osmesa->rb->RefCount == 2); _mesa_add_soft_renderbuffers(osmesa->gl_buffer, GL_FALSE, /* color */ osmesa->gl_visual->haveDepthBuffer, osmesa->gl_visual->haveStencilBuffer, osmesa->gl_visual->haveAccumBuffer, GL_FALSE, /* alpha */ GL_FALSE /* aux */ ); osmesa->format = format; osmesa->userRowLength = 0; osmesa->yup = GL_TRUE; osmesa->rInd = rind; osmesa->gInd = gind; osmesa->bInd = bind; osmesa->aInd = aind; _mesa_meta_init(&osmesa->mesa); /* Initialize the software rasterizer and helper modules. */ { GLcontext *ctx = &osmesa->mesa; SWcontext *swrast; TNLcontext *tnl; if (!_swrast_CreateContext( ctx ) || !_vbo_CreateContext( ctx ) || !_tnl_CreateContext( ctx ) || !_swsetup_CreateContext( ctx )) { _mesa_destroy_visual(osmesa->gl_visual); _mesa_free_context_data(ctx); free(osmesa); return NULL; } _swsetup_Wakeup( ctx ); /* use default TCL pipeline */ tnl = TNL_CONTEXT(ctx); tnl->Driver.RunPipeline = _tnl_run_pipeline; /* Extend the software rasterizer with our optimized line and triangle * drawing functions. */ swrast = SWRAST_CONTEXT( ctx ); swrast->choose_line = osmesa_choose_line; swrast->choose_triangle = osmesa_choose_triangle; } } return osmesa; } /** * Destroy an Off-Screen Mesa rendering context. * * \param osmesa the context to destroy */ GLAPI void GLAPIENTRY OSMesaDestroyContext( OSMesaContext osmesa ) { if (osmesa) { if (osmesa->rb) _mesa_reference_renderbuffer(&osmesa->rb, NULL); _mesa_meta_free( &osmesa->mesa ); _swsetup_DestroyContext( &osmesa->mesa ); _tnl_DestroyContext( &osmesa->mesa ); _vbo_DestroyContext( &osmesa->mesa ); _swrast_DestroyContext( &osmesa->mesa ); _mesa_destroy_visual( osmesa->gl_visual ); _mesa_reference_framebuffer( &osmesa->gl_buffer, NULL ); _mesa_free_context_data( &osmesa->mesa ); free( osmesa ); } } /** * Bind an OSMesaContext to an image buffer. The image buffer is just a * block of memory which the client provides. Its size must be at least * as large as width*height*sizeof(type). Its address should be a multiple * of 4 if using RGBA mode. * * Image data is stored in the order of glDrawPixels: row-major order * with the lower-left image pixel stored in the first array position * (ie. bottom-to-top). * * If the context's viewport hasn't been initialized yet, it will now be * initialized to (0,0,width,height). * * Input: osmesa - the rendering context * buffer - the image buffer memory * type - data type for pixel components * Normally, only GL_UNSIGNED_BYTE and GL_UNSIGNED_SHORT_5_6_5 * are supported. But if Mesa's been compiled with CHAN_BITS==16 * then type may be GL_UNSIGNED_SHORT or GL_UNSIGNED_BYTE. And if * Mesa's been build with CHAN_BITS==32 then type may be GL_FLOAT, * GL_UNSIGNED_SHORT or GL_UNSIGNED_BYTE. * width, height - size of image buffer in pixels, at least 1 * Return: GL_TRUE if success, GL_FALSE if error because of invalid osmesa, * invalid buffer address, invalid type, width<1, height<1, * width>internal limit or height>internal limit. */ GLAPI GLboolean GLAPIENTRY OSMesaMakeCurrent( OSMesaContext osmesa, void *buffer, GLenum type, GLsizei width, GLsizei height ) { if (!osmesa || !buffer || width < 1 || height < 1 || width > MAX_WIDTH || height > MAX_HEIGHT) { return GL_FALSE; } if (osmesa->format == OSMESA_RGB_565 && type != GL_UNSIGNED_SHORT_5_6_5) { return GL_FALSE; } #if 0 if (!(type == GL_UNSIGNED_BYTE || (type == GL_UNSIGNED_SHORT && CHAN_BITS >= 16) || (type == GL_FLOAT && CHAN_BITS == 32))) { /* i.e. is sizeof(type) * 8 > CHAN_BITS? */ return GL_FALSE; } #endif osmesa_update_state( &osmesa->mesa, 0 ); /* Call this periodically to detect when the user has begun using * GL rendering from multiple threads. */ _glapi_check_multithread(); /* Set renderbuffer fields. Set width/height = 0 to force * osmesa_renderbuffer_storage() being called by _mesa_resize_framebuffer() */ osmesa->rb->Data = buffer; osmesa->rb->DataType = type; osmesa->rb->Width = osmesa->rb->Height = 0; /* Set the framebuffer's size. This causes the * osmesa_renderbuffer_storage() function to get called. */ _mesa_resize_framebuffer(&osmesa->mesa, osmesa->gl_buffer, width, height); osmesa->gl_buffer->Initialized = GL_TRUE; /* XXX TEMPORARY? */ _mesa_make_current( &osmesa->mesa, osmesa->gl_buffer, osmesa->gl_buffer ); /* Remove renderbuffer attachment, then re-add. This installs the * renderbuffer adaptor/wrapper if needed (for bpp conversion). */ _mesa_remove_renderbuffer(osmesa->gl_buffer, BUFFER_FRONT_LEFT); _mesa_add_renderbuffer(osmesa->gl_buffer, BUFFER_FRONT_LEFT, osmesa->rb); /* this updates the visual's red/green/blue/alphaBits fields */ _mesa_update_framebuffer_visual(osmesa->gl_buffer); /* update the framebuffer size */ _mesa_resize_framebuffer(&osmesa->mesa, osmesa->gl_buffer, width, height); return GL_TRUE; } GLAPI OSMesaContext GLAPIENTRY OSMesaGetCurrentContext( void ) { GLcontext *ctx = _mesa_get_current_context(); if (ctx) return (OSMesaContext) ctx; else return NULL; } GLAPI void GLAPIENTRY OSMesaPixelStore( GLint pname, GLint value ) { OSMesaContext osmesa = OSMesaGetCurrentContext(); switch (pname) { case OSMESA_ROW_LENGTH: if (value<0) { _mesa_error( &osmesa->mesa, GL_INVALID_VALUE, "OSMesaPixelStore(value)" ); return; } osmesa->userRowLength = value; break; case OSMESA_Y_UP: osmesa->yup = value ? GL_TRUE : GL_FALSE; break; default: _mesa_error( &osmesa->mesa, GL_INVALID_ENUM, "OSMesaPixelStore(pname)" ); return; } compute_row_addresses( osmesa ); } GLAPI void GLAPIENTRY OSMesaGetIntegerv( GLint pname, GLint *value ) { OSMesaContext osmesa = OSMesaGetCurrentContext(); switch (pname) { case OSMESA_WIDTH: if (osmesa->gl_buffer) *value = osmesa->gl_buffer->Width; else *value = 0; return; case OSMESA_HEIGHT: if (osmesa->gl_buffer) *value = osmesa->gl_buffer->Height; else *value = 0; return; case OSMESA_FORMAT: *value = osmesa->format; return; case OSMESA_TYPE: /* current color buffer's data type */ if (osmesa->rb) { *value = osmesa->rb->DataType; } else { *value = 0; } return; case OSMESA_ROW_LENGTH: *value = osmesa->userRowLength; return; case OSMESA_Y_UP: *value = osmesa->yup; return; case OSMESA_MAX_WIDTH: *value = MAX_WIDTH; return; case OSMESA_MAX_HEIGHT: *value = MAX_HEIGHT; return; default: _mesa_error(&osmesa->mesa, GL_INVALID_ENUM, "OSMesaGetIntergerv(pname)"); return; } } /** * Return the depth buffer associated with an OSMesa context. * Input: c - the OSMesa context * Output: width, height - size of buffer in pixels * bytesPerValue - bytes per depth value (2 or 4) * buffer - pointer to depth buffer values * Return: GL_TRUE or GL_FALSE to indicate success or failure. */ GLAPI GLboolean GLAPIENTRY OSMesaGetDepthBuffer( OSMesaContext c, GLint *width, GLint *height, GLint *bytesPerValue, void **buffer ) { struct gl_renderbuffer *rb = NULL; if (c->gl_buffer) rb = c->gl_buffer->Attachment[BUFFER_DEPTH].Renderbuffer; if (!rb || !rb->Data) { *width = 0; *height = 0; *bytesPerValue = 0; *buffer = 0; return GL_FALSE; } else { *width = rb->Width; *height = rb->Height; if (c->gl_visual->depthBits <= 16) *bytesPerValue = sizeof(GLushort); else *bytesPerValue = sizeof(GLuint); *buffer = rb->Data; return GL_TRUE; } } /** * Return the color buffer associated with an OSMesa context. * Input: c - the OSMesa context * Output: width, height - size of buffer in pixels * format - the pixel format (OSMESA_FORMAT) * buffer - pointer to color buffer values * Return: GL_TRUE or GL_FALSE to indicate success or failure. */ GLAPI GLboolean GLAPIENTRY OSMesaGetColorBuffer( OSMesaContext osmesa, GLint *width, GLint *height, GLint *format, void **buffer ) { if (osmesa->rb && osmesa->rb->Data) { *width = osmesa->rb->Width; *height = osmesa->rb->Height; *format = osmesa->format; *buffer = osmesa->rb->Data; return GL_TRUE; } else { *width = 0; *height = 0; *format = 0; *buffer = 0; return GL_FALSE; } } struct name_function { const char *Name; OSMESAproc Function; }; static struct name_function functions[] = { { "OSMesaCreateContext", (OSMESAproc) OSMesaCreateContext }, { "OSMesaCreateContextExt", (OSMESAproc) OSMesaCreateContextExt }, { "OSMesaDestroyContext", (OSMESAproc) OSMesaDestroyContext }, { "OSMesaMakeCurrent", (OSMESAproc) OSMesaMakeCurrent }, { "OSMesaGetCurrentContext", (OSMESAproc) OSMesaGetCurrentContext }, { "OSMesaPixelsStore", (OSMESAproc) OSMesaPixelStore }, { "OSMesaGetIntegerv", (OSMESAproc) OSMesaGetIntegerv }, { "OSMesaGetDepthBuffer", (OSMESAproc) OSMesaGetDepthBuffer }, { "OSMesaGetColorBuffer", (OSMESAproc) OSMesaGetColorBuffer }, { "OSMesaGetProcAddress", (OSMESAproc) OSMesaGetProcAddress }, { "OSMesaColorClamp", (OSMESAproc) OSMesaColorClamp }, { NULL, NULL } }; GLAPI OSMESAproc GLAPIENTRY OSMesaGetProcAddress( const char *funcName ) { int i; for (i = 0; functions[i].Name; i++) { if (strcmp(functions[i].Name, funcName) == 0) return functions[i].Function; } return _glapi_get_proc_address(funcName); } GLAPI void GLAPIENTRY OSMesaColorClamp(GLboolean enable) { OSMesaContext osmesa = OSMesaGetCurrentContext(); if (enable == GL_TRUE) { osmesa->mesa.Color.ClampFragmentColor = GL_TRUE; } else { osmesa->mesa.Color.ClampFragmentColor = GL_FIXED_ONLY_ARB; } }