diff options
Diffstat (limited to 'src/mesa/drivers/osmesa/osmesa.c')
-rw-r--r-- | src/mesa/drivers/osmesa/osmesa.c | 1566 |
1 files changed, 1566 insertions, 0 deletions
diff --git a/src/mesa/drivers/osmesa/osmesa.c b/src/mesa/drivers/osmesa/osmesa.c new file mode 100644 index 0000000000..ead4050397 --- /dev/null +++ b/src/mesa/drivers/osmesa/osmesa.c @@ -0,0 +1,1566 @@ +/* + * 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; + switch (type) { + case GL_UNSIGNED_BYTE: + rb->Format = MESA_FORMAT_RGBA8888; + break; + case GL_UNSIGNED_SHORT: + rb->Format = MESA_FORMAT_RGBA_16; + break; + case GL_FLOAT: + rb->Format = MESA_FORMAT_RGBA_FLOAT32; + break; + default: + assert(0 && "Unexpected type in new_osmesa_renderbuffer()"); + 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; + + 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_FALSE, /* double buffer */ + GL_FALSE, /* stereo */ + redBits, + greenBits, + blueBits, + alphaBits, + 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 depth/stencil/accum buffers. We'll create the color + * buffer later in OSMesaMakeCurrent(). + */ + _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(); + + + /* Create a front/left color buffer which wraps the user-provided buffer. + * There is no back color buffer. + * If the user tries to use a 8, 16 or 32-bit/channel buffer that + * doesn't match what Mesa was compiled for (CHAN_BITS) the + * _mesa_add_renderbuffer() function will create a "wrapper" renderbuffer + * that converts rendering from CHAN_BITS to the user-requested channel + * size. + */ + osmesa->rb = new_osmesa_renderbuffer(&osmesa->mesa, osmesa->format, type); + _mesa_add_renderbuffer(osmesa->gl_buffer, BUFFER_FRONT_LEFT, osmesa->rb); + assert(osmesa->rb->RefCount == 2); + + /* Set renderbuffer fields. Set width/height = 0 to force + * osmesa_renderbuffer_storage() being called by _mesa_resize_framebuffer() + */ + osmesa->rb->Data = buffer; + 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; + } +} + + |