Files
third_party_mesa3d/src/mesa/drivers/osmesa/osmesa.c
Emil Velikov fa9df82f67 mesa: fold _glapi_check_multithread() back into _mesa_make_current
With commit c6c0f94714, back in 2006 Brian removed the
_glapi_check_multithread() call from core mesa - _mesa_make_current.

It was done to remove fairly awkward #ifdef guard which caused subtle
differences in core mesa.

Since that guard is long gone, we can drop the duplication and
reintroduce the call in core.

Note that the function is was missing when using EGL + classic dri HW
drivers. Yet on TLS builds it's a no-op, so we're safe.

Any non TLS users - more or less anything !Linux (or even musl on Linux
up-to semi-recently) may have experienced problems.

v2: don't remove the call from swrast - move it to core (Eric)

Cc: Eric Anholt <eric@anholt.net>
Cc: Brian Paul <brianp@vmware.com>
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
2018-10-03 13:38:05 +01:00

1309 lines
38 KiB
C

/*
* Mesa 3-D graphics library
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS 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 <stdio.h>
#include "main/glheader.h"
#include "GL/osmesa.h"
#include "main/api_exec.h"
#include "main/context.h"
#include "main/extensions.h"
#include "main/formats.h"
#include "main/framebuffer.h"
#include "main/imports.h"
#include "main/macros.h"
#include "main/mipmap.h"
#include "main/mtypes.h"
#include "main/renderbuffer.h"
#include "main/version.h"
#include "main/vtxfmt.h"
#include "swrast/swrast.h"
#include "swrast_setup/swrast_setup.h"
#include "swrast/s_context.h"
#include "swrast/s_lines.h"
#include "swrast/s_renderbuffer.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"
#define OSMESA_RENDERBUFFER_CLASS 0x053
/**
* OSMesa rendering context, derived from core Mesa struct gl_context.
*/
struct osmesa_context
{
struct gl_context mesa; /*< Base class - this must be first */
struct gl_config *gl_visual; /*< Describes the buffers */
struct swrast_renderbuffer *srb; /*< The user's colorbuffer */
struct gl_framebuffer *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[SWRAST_MAX_HEIGHT]; /*< address of first pixel in each image row */
GLboolean yup; /*< TRUE -> Y increases upward */
/*< FALSE -> Y increases downward */
GLenum DataType;
};
static inline OSMesaContext
OSMESA_CONTEXT(struct gl_context *ctx)
{
/* Just cast, since we're using structure containment */
return (OSMesaContext) ctx;
}
/**********************************************************************/
/*** Private Device Driver Functions ***/
/**********************************************************************/
static const GLubyte *
get_string( struct gl_context *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(struct gl_context *ctx, GLuint new_state)
{
if (new_state & (_NEW_SCISSOR | _NEW_BUFFERS | _NEW_VIEWPORT))
_mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer);
/* easy - just propogate */
_swrast_InvalidateState( ctx, new_state );
_swsetup_InvalidateState( ctx, new_state );
_tnl_InvalidateState( ctx, new_state );
}
static void
osmesa_update_state_wrapper(struct gl_context *ctx)
{
osmesa_update_state(ctx, ctx->NewState);
}
/**
* 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)
#include "swrast/s_linetemp.h"
/**
* 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)
#include "swrast/s_linetemp.h"
/**
* 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( struct gl_context *ctx )
{
const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
const SWcontext *swrast = SWRAST_CONTEXT(ctx);
if (ctx->DrawBuffer &&
ctx->DrawBuffer->Visual.redBits == 32) {
/* the special-case line functions in this file don't work
* for float color channels.
*/
return NULL;
}
if (ctx->RenderMode != GL_RENDER ||
ctx->Texture._MaxEnabledTexImageUnit == -1 ||
ctx->Light.ShadeModel != GL_FLAT ||
ctx->Line.Width != 1.0F ||
ctx->Line.StippleFlag ||
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 flat_rgba_z_line;
}
if (swrast->_RasterMask == 0) {
return 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; \
} \
}
#include "swrast/s_tritemp.h"
/*
* 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; \
} \
}
#include "swrast/s_tritemp.h"
/**
* Return pointer to an optimized triangle function if possible.
*/
static swrast_tri_func
osmesa_choose_triangle_function( struct gl_context *ctx )
{
const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
const SWcontext *swrast = SWRAST_CONTEXT(ctx);
if (ctx->DrawBuffer &&
ctx->DrawBuffer->Visual.redBits == 32) {
/* the special-case triangle functions in this file don't work
* for float color channels.
*/
return NULL;
}
if (ctx->RenderMode != GL_RENDER ||
ctx->Polygon.SmoothFlag ||
ctx->Polygon.StippleFlag ||
ctx->Texture._MaxEnabledTexImageUnit != -1) {
return NULL;
}
if (osmesa->format != OSMESA_RGBA &&
osmesa->format != OSMESA_BGRA &&
osmesa->format != OSMESA_ARGB) {
return NULL;
}
if (ctx->Polygon.CullFlag &&
ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) {
return 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 smooth_rgba_z_triangle;
}
else {
return flat_rgba_z_triangle;
}
}
return 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( struct gl_context *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( struct gl_context *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 bytesPerRow, i;
GLubyte *origin = (GLubyte *) osmesa->srb->Buffer;
GLint rowlength; /* in pixels */
GLint height = osmesa->srb->Base.Height;
if (osmesa->userRowLength)
rowlength = osmesa->userRowLength;
else
rowlength = osmesa->srb->Base.Width;
bytesPerRow = rowlength * _mesa_get_format_bytes(osmesa->srb->Base.Format);
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->Buffer.
*/
static void
osmesa_delete_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
{
_mesa_delete_renderbuffer(ctx, 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(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLenum internalFormat, GLuint width, GLuint height)
{
const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
/* Note: we can ignoring internalFormat for "window-system" renderbuffers */
(void) internalFormat;
/* Given the user-provided format and type, figure out which MESA_FORMAT_x
* to use.
* XXX There aren't Mesa formats for all the possible combinations here!
* XXX Specifically, there's only RGBA-order 16-bit/channel and float
* XXX formats.
* XXX The 8-bit/channel formats should all be OK.
*/
if (osmesa->format == OSMESA_RGBA) {
if (osmesa->DataType == GL_UNSIGNED_BYTE) {
if (_mesa_little_endian())
rb->Format = MESA_FORMAT_R8G8B8A8_UNORM;
else
rb->Format = MESA_FORMAT_A8B8G8R8_UNORM;
}
else if (osmesa->DataType == GL_UNSIGNED_SHORT) {
rb->Format = MESA_FORMAT_RGBA_UNORM16;
}
else {
rb->Format = MESA_FORMAT_RGBA_FLOAT32;
}
}
else if (osmesa->format == OSMESA_BGRA) {
if (osmesa->DataType == GL_UNSIGNED_BYTE) {
if (_mesa_little_endian())
rb->Format = MESA_FORMAT_B8G8R8A8_UNORM;
else
rb->Format = MESA_FORMAT_A8R8G8B8_UNORM;
}
else if (osmesa->DataType == GL_UNSIGNED_SHORT) {
_mesa_warning(ctx, "Unsupported OSMesa format BGRA/GLushort");
rb->Format = MESA_FORMAT_RGBA_UNORM16; /* not exactly right */
}
else {
_mesa_warning(ctx, "Unsupported OSMesa format BGRA/GLfloat");
rb->Format = MESA_FORMAT_RGBA_FLOAT32; /* not exactly right */
}
}
else if (osmesa->format == OSMESA_ARGB) {
if (osmesa->DataType == GL_UNSIGNED_BYTE) {
if (_mesa_little_endian())
rb->Format = MESA_FORMAT_A8R8G8B8_UNORM;
else
rb->Format = MESA_FORMAT_B8G8R8A8_UNORM;
}
else if (osmesa->DataType == GL_UNSIGNED_SHORT) {
_mesa_warning(ctx, "Unsupported OSMesa format ARGB/GLushort");
rb->Format = MESA_FORMAT_RGBA_UNORM16; /* not exactly right */
}
else {
_mesa_warning(ctx, "Unsupported OSMesa format ARGB/GLfloat");
rb->Format = MESA_FORMAT_RGBA_FLOAT32; /* not exactly right */
}
}
else if (osmesa->format == OSMESA_RGB) {
if (osmesa->DataType == GL_UNSIGNED_BYTE) {
rb->Format = MESA_FORMAT_BGR_UNORM8;
}
else if (osmesa->DataType == GL_UNSIGNED_SHORT) {
_mesa_warning(ctx, "Unsupported OSMesa format RGB/GLushort");
rb->Format = MESA_FORMAT_RGBA_UNORM16; /* not exactly right */
}
else {
_mesa_warning(ctx, "Unsupported OSMesa format RGB/GLfloat");
rb->Format = MESA_FORMAT_RGBA_FLOAT32; /* not exactly right */
}
}
else if (osmesa->format == OSMESA_BGR) {
if (osmesa->DataType == GL_UNSIGNED_BYTE) {
rb->Format = MESA_FORMAT_RGB_UNORM8;
}
else if (osmesa->DataType == GL_UNSIGNED_SHORT) {
_mesa_warning(ctx, "Unsupported OSMesa format BGR/GLushort");
rb->Format = MESA_FORMAT_RGBA_UNORM16; /* not exactly right */
}
else {
_mesa_warning(ctx, "Unsupported OSMesa format BGR/GLfloat");
rb->Format = MESA_FORMAT_RGBA_FLOAT32; /* not exactly right */
}
}
else if (osmesa->format == OSMESA_RGB_565) {
assert(osmesa->DataType == GL_UNSIGNED_BYTE);
rb->Format = MESA_FORMAT_B5G6R5_UNORM;
}
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 swrast_renderbuffer *
new_osmesa_renderbuffer(struct gl_context *ctx, GLenum format, GLenum type)
{
const GLuint name = 0;
struct swrast_renderbuffer *srb = CALLOC_STRUCT(swrast_renderbuffer);
if (srb) {
_mesa_init_renderbuffer(&srb->Base, name);
srb->Base.ClassID = OSMESA_RENDERBUFFER_CLASS;
srb->Base.Delete = osmesa_delete_renderbuffer;
srb->Base.AllocStorage = osmesa_renderbuffer_storage;
srb->Base.InternalFormat = GL_RGBA;
srb->Base._BaseFormat = GL_RGBA;
return srb;
}
return NULL;
}
static void
osmesa_MapRenderbuffer(struct gl_context *ctx,
struct gl_renderbuffer *rb,
GLuint x, GLuint y, GLuint w, GLuint h,
GLbitfield mode,
GLubyte **mapOut, GLint *rowStrideOut,
bool flip_y)
{
const OSMesaContext osmesa = OSMESA_CONTEXT(ctx);
if (rb->ClassID == OSMESA_RENDERBUFFER_CLASS) {
/* this is an OSMesa renderbuffer which wraps user memory */
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
const GLuint bpp = _mesa_get_format_bytes(rb->Format);
GLint rowStride; /* in bytes */
if (osmesa->userRowLength)
rowStride = osmesa->userRowLength * bpp;
else
rowStride = rb->Width * bpp;
if (!osmesa->yup) {
/* Y=0 is top line of window */
y = rb->Height - y - 1;
*rowStrideOut = -rowStride;
}
else {
*rowStrideOut = rowStride;
}
*mapOut = (GLubyte *) srb->Buffer + y * rowStride + x * bpp;
}
else {
_swrast_map_soft_renderbuffer(ctx, rb, x, y, w, h, mode,
mapOut, rowStrideOut, flip_y);
}
}
static void
osmesa_UnmapRenderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
{
if (rb->ClassID == OSMESA_RENDERBUFFER_CLASS) {
/* no-op */
}
else {
_swrast_unmap_soft_renderbuffer(ctx, 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 )
{
int attribs[100], n = 0;
attribs[n++] = OSMESA_FORMAT;
attribs[n++] = format;
attribs[n++] = OSMESA_DEPTH_BITS;
attribs[n++] = depthBits;
attribs[n++] = OSMESA_STENCIL_BITS;
attribs[n++] = stencilBits;
attribs[n++] = OSMESA_ACCUM_BITS;
attribs[n++] = accumBits;
attribs[n++] = 0;
return OSMesaCreateContextAttribs(attribs, sharelist);
}
/**
* New in Mesa 11.2
*
* Create context with attribute list.
*/
GLAPI OSMesaContext GLAPIENTRY
OSMesaCreateContextAttribs(const int *attribList, OSMesaContext sharelist)
{
OSMesaContext osmesa;
struct dd_function_table functions;
GLint rind, gind, bind, aind;
GLint redBits = 0, greenBits = 0, blueBits = 0, alphaBits =0;
GLenum format = OSMESA_RGBA;
GLint depthBits = 0, stencilBits = 0, accumBits = 0;
int profile = OSMESA_COMPAT_PROFILE, version_major = 1, version_minor = 0;
gl_api api_profile = API_OPENGL_COMPAT;
int i;
for (i = 0; attribList[i]; i += 2) {
switch (attribList[i]) {
case OSMESA_FORMAT:
format = attribList[i+1];
switch (format) {
case OSMESA_COLOR_INDEX:
case OSMESA_RGBA:
case OSMESA_BGRA:
case OSMESA_ARGB:
case OSMESA_RGB:
case OSMESA_BGR:
case OSMESA_RGB_565:
/* legal */
break;
default:
return NULL;
}
break;
case OSMESA_DEPTH_BITS:
depthBits = attribList[i+1];
if (depthBits < 0)
return NULL;
break;
case OSMESA_STENCIL_BITS:
stencilBits = attribList[i+1];
if (stencilBits < 0)
return NULL;
break;
case OSMESA_ACCUM_BITS:
accumBits = attribList[i+1];
if (accumBits < 0)
return NULL;
break;
case OSMESA_PROFILE:
profile = attribList[i+1];
if (profile == OSMESA_COMPAT_PROFILE)
api_profile = API_OPENGL_COMPAT;
else if (profile == OSMESA_CORE_PROFILE)
api_profile = API_OPENGL_CORE;
else
return NULL;
break;
case OSMESA_CONTEXT_MAJOR_VERSION:
version_major = attribList[i+1];
if (version_major < 1)
return NULL;
break;
case OSMESA_CONTEXT_MINOR_VERSION:
version_minor = attribList[i+1];
if (version_minor < 0)
return NULL;
break;
case 0:
/* end of list */
break;
default:
fprintf(stderr, "Bad attribute in OSMesaCreateContextAttribs()\n");
return NULL;
}
}
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);
_tnl_init_driver_draw_function(&functions);
/* override with our functions */
functions.GetString = get_string;
functions.UpdateState = osmesa_update_state_wrapper;
if (!_mesa_initialize_context(&osmesa->mesa,
api_profile,
osmesa->gl_visual,
sharelist ? &sharelist->mesa
: (struct gl_context *) NULL,
&functions)) {
_mesa_destroy_visual( osmesa->gl_visual );
free(osmesa);
return NULL;
}
_mesa_enable_sw_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().
*/
_swrast_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. */
{
struct gl_context *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;
ctx->Driver.MapRenderbuffer = osmesa_MapRenderbuffer;
ctx->Driver.UnmapRenderbuffer = osmesa_UnmapRenderbuffer;
ctx->Driver.GenerateMipmap = _mesa_generate_mipmap;
/* 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;
_mesa_override_extensions(ctx);
_mesa_compute_version(ctx);
if (ctx->Version < version_major * 10 + version_minor) {
_mesa_destroy_visual(osmesa->gl_visual);
_mesa_free_context_data(ctx);
free(osmesa);
return NULL;
}
/* Exec table initialization requires the version to be computed */
_mesa_initialize_dispatch_tables(ctx);
_mesa_initialize_vbo_vtxfmt(ctx);
}
}
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->srb)
_mesa_reference_renderbuffer((struct gl_renderbuffer **) &osmesa->srb, 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).
*
* If both the context and the buffer are null, the current context will be
* unbound.
*
* 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) {
return _mesa_make_current(NULL, NULL, NULL);
}
if (!osmesa || !buffer ||
width < 1 || height < 1 ||
width > SWRAST_MAX_WIDTH || height > SWRAST_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 );
/* 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_attach_and_reference_rb() function will create a "wrapper"
* renderbuffer that converts rendering from CHAN_BITS to the
* user-requested channel size.
*/
if (!osmesa->srb) {
osmesa->srb = new_osmesa_renderbuffer(&osmesa->mesa, osmesa->format, type);
_mesa_remove_renderbuffer(osmesa->gl_buffer, BUFFER_FRONT_LEFT);
_mesa_attach_and_reference_rb(osmesa->gl_buffer, BUFFER_FRONT_LEFT,
&osmesa->srb->Base);
assert(osmesa->srb->Base.RefCount == 2);
}
osmesa->DataType = type;
/* Set renderbuffer fields. Set width/height = 0 to force
* osmesa_renderbuffer_storage() being called by _mesa_resize_framebuffer()
*/
osmesa->srb->Buffer = buffer;
osmesa->srb->Base.Width = osmesa->srb->Base.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);
_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_attach_and_reference_rb(osmesa->gl_buffer, BUFFER_FRONT_LEFT,
&osmesa->srb->Base);
/* this updates the visual's red/green/blue/alphaBits fields */
_mesa_update_framebuffer_visual(&osmesa->mesa, 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 )
{
struct gl_context *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 */
*value = osmesa->DataType;
return;
case OSMESA_ROW_LENGTH:
*value = osmesa->userRowLength;
return;
case OSMESA_Y_UP:
*value = osmesa->yup;
return;
case OSMESA_MAX_WIDTH:
*value = SWRAST_MAX_WIDTH;
return;
case OSMESA_MAX_HEIGHT:
*value = SWRAST_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 swrast_renderbuffer *srb = NULL;
if (c->gl_buffer)
srb = swrast_renderbuffer(c->gl_buffer->
Attachment[BUFFER_DEPTH].Renderbuffer);
if (!srb || !srb->Buffer) {
*width = 0;
*height = 0;
*bytesPerValue = 0;
*buffer = 0;
return GL_FALSE;
}
else {
*width = srb->Base.Width;
*height = srb->Base.Height;
if (c->gl_visual->depthBits <= 16)
*bytesPerValue = sizeof(GLushort);
else
*bytesPerValue = sizeof(GLuint);
*buffer = (void *) srb->Buffer;
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->srb && osmesa->srb->Buffer) {
*width = osmesa->srb->Base.Width;
*height = osmesa->srb->Base.Height;
*format = osmesa->format;
*buffer = (void *) osmesa->srb->Buffer;
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 },
{ "OSMesaCreateContextAttribs", (OSMESAproc) OSMesaCreateContextAttribs },
{ "OSMesaDestroyContext", (OSMESAproc) OSMesaDestroyContext },
{ "OSMesaMakeCurrent", (OSMESAproc) OSMesaMakeCurrent },
{ "OSMesaGetCurrentContext", (OSMESAproc) OSMesaGetCurrentContext },
{ "OSMesaPixelStore", (OSMESAproc) OSMesaPixelStore },
{ "OSMesaGetIntegerv", (OSMESAproc) OSMesaGetIntegerv },
{ "OSMesaGetDepthBuffer", (OSMESAproc) OSMesaGetDepthBuffer },
{ "OSMesaGetColorBuffer", (OSMESAproc) OSMesaGetColorBuffer },
{ "OSMesaGetProcAddress", (OSMESAproc) OSMesaGetProcAddress },
{ "OSMesaColorClamp", (OSMESAproc) OSMesaColorClamp },
{ "OSMesaPostprocess", (OSMESAproc) OSMesaPostprocess },
{ 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;
}
}
GLAPI void GLAPIENTRY
OSMesaPostprocess(OSMesaContext osmesa, const char *filter,
unsigned enable_value)
{
fprintf(stderr,
"OSMesaPostProcess() is only available with gallium drivers\n");
}
/**
* When GLX_INDIRECT_RENDERING is defined, some symbols are missing in
* libglapi.a. We need to define them here.
*/
#ifdef GLX_INDIRECT_RENDERING
#define GL_GLEXT_PROTOTYPES
#include "GL/gl.h"
#include "glapi/glapi.h"
#include "glapitable.h"
#if defined(USE_MGL_NAMESPACE)
#define NAME(func) mgl##func
#else
#define NAME(func) gl##func
#endif
#define DISPATCH(FUNC, ARGS, MESSAGE) \
GET_DISPATCH()->FUNC ARGS
#define RETURN_DISPATCH(FUNC, ARGS, MESSAGE) \
return GET_DISPATCH()->FUNC ARGS
/* skip normal ones */
#define _GLAPI_SKIP_NORMAL_ENTRY_POINTS
#include "glapitemp.h"
#endif /* GLX_INDIRECT_RENDERING */