diff options
author | marha <marha@users.sourceforge.net> | 2011-03-01 07:17:23 +0000 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2011-03-01 07:17:23 +0000 |
commit | a18769801e521ccb5a409c377ac0a6a1141f5776 (patch) | |
tree | cfc3429a80c2f996cb5592512acdebe7719d608c /mesalib/src/mesa/main | |
parent | feee2b5ceb37101bd1c4162e49805e6ad63e28ae (diff) | |
download | vcxsrv-a18769801e521ccb5a409c377ac0a6a1141f5776.tar.gz vcxsrv-a18769801e521ccb5a409c377ac0a6a1141f5776.tar.bz2 vcxsrv-a18769801e521ccb5a409c377ac0a6a1141f5776.zip |
pixman mesa git update 1 Mar 2011
Diffstat (limited to 'mesalib/src/mesa/main')
24 files changed, 20037 insertions, 20469 deletions
diff --git a/mesalib/src/mesa/main/attrib.c b/mesalib/src/mesa/main/attrib.c index f97ec08e5..ae7f633b8 100644 --- a/mesalib/src/mesa/main/attrib.c +++ b/mesalib/src/mesa/main/attrib.c @@ -1,1566 +1,1555 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.6
- *
- * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- * Copyright (C) 2009 VMware, Inc. 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.
- */
-
-#include "glheader.h"
-#include "imports.h"
-#include "accum.h"
-#include "arrayobj.h"
-#include "attrib.h"
-#include "blend.h"
-#include "buffers.h"
-#include "bufferobj.h"
-#include "clear.h"
-#include "colormac.h"
-#include "context.h"
-#include "depth.h"
-#include "enable.h"
-#include "enums.h"
-#include "fog.h"
-#include "hint.h"
-#include "light.h"
-#include "lines.h"
-#include "macros.h"
-#include "matrix.h"
-#include "mfeatures.h"
-#include "multisample.h"
-#include "points.h"
-#include "polygon.h"
-#include "scissor.h"
-#include "stencil.h"
-#include "texenv.h"
-#include "texgen.h"
-#include "texobj.h"
-#include "texparam.h"
-#include "texstate.h"
-#include "varray.h"
-#include "viewport.h"
-#include "mtypes.h"
-#include "main/dispatch.h"
-
-
-/**
- * glEnable()/glDisable() attribute group (GL_ENABLE_BIT).
- */
-struct gl_enable_attrib
-{
- GLboolean AlphaTest;
- GLboolean AutoNormal;
- GLboolean Blend;
- GLbitfield ClipPlanes;
- GLboolean ColorMaterial;
- GLboolean CullFace;
- GLboolean DepthClamp;
- GLboolean DepthTest;
- GLboolean Dither;
- GLboolean Fog;
- GLboolean Light[MAX_LIGHTS];
- GLboolean Lighting;
- GLboolean LineSmooth;
- GLboolean LineStipple;
- GLboolean IndexLogicOp;
- GLboolean ColorLogicOp;
-
- GLboolean Map1Color4;
- GLboolean Map1Index;
- GLboolean Map1Normal;
- GLboolean Map1TextureCoord1;
- GLboolean Map1TextureCoord2;
- GLboolean Map1TextureCoord3;
- GLboolean Map1TextureCoord4;
- GLboolean Map1Vertex3;
- GLboolean Map1Vertex4;
- GLboolean Map1Attrib[16]; /* GL_NV_vertex_program */
- GLboolean Map2Color4;
- GLboolean Map2Index;
- GLboolean Map2Normal;
- GLboolean Map2TextureCoord1;
- GLboolean Map2TextureCoord2;
- GLboolean Map2TextureCoord3;
- GLboolean Map2TextureCoord4;
- GLboolean Map2Vertex3;
- GLboolean Map2Vertex4;
- GLboolean Map2Attrib[16]; /* GL_NV_vertex_program */
-
- GLboolean Normalize;
- GLboolean PixelTexture;
- GLboolean PointSmooth;
- GLboolean PolygonOffsetPoint;
- GLboolean PolygonOffsetLine;
- GLboolean PolygonOffsetFill;
- GLboolean PolygonSmooth;
- GLboolean PolygonStipple;
- GLboolean RescaleNormals;
- GLboolean Scissor;
- GLboolean Stencil;
- GLboolean StencilTwoSide; /* GL_EXT_stencil_two_side */
- GLboolean MultisampleEnabled; /* GL_ARB_multisample */
- GLboolean SampleAlphaToCoverage; /* GL_ARB_multisample */
- GLboolean SampleAlphaToOne; /* GL_ARB_multisample */
- GLboolean SampleCoverage; /* GL_ARB_multisample */
- GLboolean SampleCoverageInvert; /* GL_ARB_multisample */
- GLboolean RasterPositionUnclipped; /* GL_IBM_rasterpos_clip */
-
- GLbitfield Texture[MAX_TEXTURE_UNITS];
- GLbitfield TexGen[MAX_TEXTURE_UNITS];
-
- /* SGI_texture_color_table */
- GLboolean TextureColorTable[MAX_TEXTURE_UNITS];
-
- /* GL_ARB_vertex_program / GL_NV_vertex_program */
- GLboolean VertexProgram;
- GLboolean VertexProgramPointSize;
- GLboolean VertexProgramTwoSide;
-
- /* GL_ARB_point_sprite / GL_NV_point_sprite */
- GLboolean PointSprite;
- GLboolean FragmentShaderATI;
-};
-
-
-/**
- * Node for the attribute stack.
- */
-struct gl_attrib_node
-{
- GLbitfield kind;
- void *data;
- struct gl_attrib_node *next;
-};
-
-
-
-/**
- * Special struct for saving/restoring texture state (GL_TEXTURE_BIT)
- */
-struct texture_state
-{
- struct gl_texture_attrib Texture; /**< The usual context state */
-
- /** to save per texture object state (wrap modes, filters, etc): */
- struct gl_texture_object SavedObj[MAX_TEXTURE_UNITS][NUM_TEXTURE_TARGETS];
-
- /**
- * To save references to texture objects (so they don't get accidentally
- * deleted while saved in the attribute stack).
- */
- struct gl_texture_object *SavedTexRef[MAX_TEXTURE_UNITS][NUM_TEXTURE_TARGETS];
-};
-
-
-#if FEATURE_attrib_stack
-
-
-/**
- * Allocate new attribute node of given type/kind. Attach payload data.
- * Insert it into the linked list named by 'head'.
- */
-static void
-save_attrib_data(struct gl_attrib_node **head,
- GLbitfield kind, void *payload)
-{
- struct gl_attrib_node *n = MALLOC_STRUCT(gl_attrib_node);
- if (n) {
- n->kind = kind;
- n->data = payload;
- /* insert at head */
- n->next = *head;
- *head = n;
- }
- else {
- /* out of memory! */
- }
-}
-
-
-void GLAPIENTRY
-_mesa_PushAttrib(GLbitfield mask)
-{
- struct gl_attrib_node *head;
-
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx, "glPushAttrib %x\n", (int) mask);
-
- if (ctx->AttribStackDepth >= MAX_ATTRIB_STACK_DEPTH) {
- _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushAttrib" );
- return;
- }
-
- /* Build linked list of attribute nodes which save all attribute */
- /* groups specified by the mask. */
- head = NULL;
-
- if (mask & GL_ACCUM_BUFFER_BIT) {
- struct gl_accum_attrib *attr;
- attr = MALLOC_STRUCT( gl_accum_attrib );
- memcpy( attr, &ctx->Accum, sizeof(struct gl_accum_attrib) );
- save_attrib_data(&head, GL_ACCUM_BUFFER_BIT, attr);
- }
-
- if (mask & GL_COLOR_BUFFER_BIT) {
- GLuint i;
- struct gl_colorbuffer_attrib *attr;
- attr = MALLOC_STRUCT( gl_colorbuffer_attrib );
- memcpy( attr, &ctx->Color, sizeof(struct gl_colorbuffer_attrib) );
- /* push the Draw FBO's DrawBuffer[] state, not ctx->Color.DrawBuffer[] */
- for (i = 0; i < ctx->Const.MaxDrawBuffers; i ++)
- attr->DrawBuffer[i] = ctx->DrawBuffer->ColorDrawBuffer[i];
- save_attrib_data(&head, GL_COLOR_BUFFER_BIT, attr);
- }
-
- if (mask & GL_CURRENT_BIT) {
- struct gl_current_attrib *attr;
- FLUSH_CURRENT( ctx, 0 );
- attr = MALLOC_STRUCT( gl_current_attrib );
- memcpy( attr, &ctx->Current, sizeof(struct gl_current_attrib) );
- save_attrib_data(&head, GL_CURRENT_BIT, attr);
- }
-
- if (mask & GL_DEPTH_BUFFER_BIT) {
- struct gl_depthbuffer_attrib *attr;
- attr = MALLOC_STRUCT( gl_depthbuffer_attrib );
- memcpy( attr, &ctx->Depth, sizeof(struct gl_depthbuffer_attrib) );
- save_attrib_data(&head, GL_DEPTH_BUFFER_BIT, attr);
- }
-
- if (mask & GL_ENABLE_BIT) {
- struct gl_enable_attrib *attr;
- GLuint i;
- attr = MALLOC_STRUCT( gl_enable_attrib );
- /* Copy enable flags from all other attributes into the enable struct. */
- attr->AlphaTest = ctx->Color.AlphaEnabled;
- attr->AutoNormal = ctx->Eval.AutoNormal;
- attr->Blend = ctx->Color.BlendEnabled;
- attr->ClipPlanes = ctx->Transform.ClipPlanesEnabled;
- attr->ColorMaterial = ctx->Light.ColorMaterialEnabled;
- attr->CullFace = ctx->Polygon.CullFlag;
- attr->DepthClamp = ctx->Transform.DepthClamp;
- attr->DepthTest = ctx->Depth.Test;
- attr->Dither = ctx->Color.DitherFlag;
- attr->Fog = ctx->Fog.Enabled;
- for (i = 0; i < ctx->Const.MaxLights; i++) {
- attr->Light[i] = ctx->Light.Light[i].Enabled;
- }
- attr->Lighting = ctx->Light.Enabled;
- attr->LineSmooth = ctx->Line.SmoothFlag;
- attr->LineStipple = ctx->Line.StippleFlag;
- attr->IndexLogicOp = ctx->Color.IndexLogicOpEnabled;
- attr->ColorLogicOp = ctx->Color.ColorLogicOpEnabled;
- attr->Map1Color4 = ctx->Eval.Map1Color4;
- attr->Map1Index = ctx->Eval.Map1Index;
- attr->Map1Normal = ctx->Eval.Map1Normal;
- attr->Map1TextureCoord1 = ctx->Eval.Map1TextureCoord1;
- attr->Map1TextureCoord2 = ctx->Eval.Map1TextureCoord2;
- attr->Map1TextureCoord3 = ctx->Eval.Map1TextureCoord3;
- attr->Map1TextureCoord4 = ctx->Eval.Map1TextureCoord4;
- attr->Map1Vertex3 = ctx->Eval.Map1Vertex3;
- attr->Map1Vertex4 = ctx->Eval.Map1Vertex4;
- memcpy(attr->Map1Attrib, ctx->Eval.Map1Attrib, sizeof(ctx->Eval.Map1Attrib));
- attr->Map2Color4 = ctx->Eval.Map2Color4;
- attr->Map2Index = ctx->Eval.Map2Index;
- attr->Map2Normal = ctx->Eval.Map2Normal;
- attr->Map2TextureCoord1 = ctx->Eval.Map2TextureCoord1;
- attr->Map2TextureCoord2 = ctx->Eval.Map2TextureCoord2;
- attr->Map2TextureCoord3 = ctx->Eval.Map2TextureCoord3;
- attr->Map2TextureCoord4 = ctx->Eval.Map2TextureCoord4;
- attr->Map2Vertex3 = ctx->Eval.Map2Vertex3;
- attr->Map2Vertex4 = ctx->Eval.Map2Vertex4;
- memcpy(attr->Map2Attrib, ctx->Eval.Map2Attrib, sizeof(ctx->Eval.Map2Attrib));
- attr->Normalize = ctx->Transform.Normalize;
- attr->RasterPositionUnclipped = ctx->Transform.RasterPositionUnclipped;
- attr->PointSmooth = ctx->Point.SmoothFlag;
- attr->PointSprite = ctx->Point.PointSprite;
- attr->PolygonOffsetPoint = ctx->Polygon.OffsetPoint;
- attr->PolygonOffsetLine = ctx->Polygon.OffsetLine;
- attr->PolygonOffsetFill = ctx->Polygon.OffsetFill;
- attr->PolygonSmooth = ctx->Polygon.SmoothFlag;
- attr->PolygonStipple = ctx->Polygon.StippleFlag;
- attr->RescaleNormals = ctx->Transform.RescaleNormals;
- attr->Scissor = ctx->Scissor.Enabled;
- attr->Stencil = ctx->Stencil.Enabled;
- attr->StencilTwoSide = ctx->Stencil.TestTwoSide;
- attr->MultisampleEnabled = ctx->Multisample.Enabled;
- attr->SampleAlphaToCoverage = ctx->Multisample.SampleAlphaToCoverage;
- attr->SampleAlphaToOne = ctx->Multisample.SampleAlphaToOne;
- attr->SampleCoverage = ctx->Multisample.SampleCoverage;
- attr->SampleCoverageInvert = ctx->Multisample.SampleCoverageInvert;
- for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
- attr->Texture[i] = ctx->Texture.Unit[i].Enabled;
- attr->TexGen[i] = ctx->Texture.Unit[i].TexGenEnabled;
- attr->TextureColorTable[i] = ctx->Texture.Unit[i].ColorTableEnabled;
- }
- /* GL_NV_vertex_program */
- attr->VertexProgram = ctx->VertexProgram.Enabled;
- attr->VertexProgramPointSize = ctx->VertexProgram.PointSizeEnabled;
- attr->VertexProgramTwoSide = ctx->VertexProgram.TwoSideEnabled;
- save_attrib_data(&head, GL_ENABLE_BIT, attr);
- }
-
- if (mask & GL_EVAL_BIT) {
- struct gl_eval_attrib *attr;
- attr = MALLOC_STRUCT( gl_eval_attrib );
- memcpy( attr, &ctx->Eval, sizeof(struct gl_eval_attrib) );
- save_attrib_data(&head, GL_EVAL_BIT, attr);
- }
-
- if (mask & GL_FOG_BIT) {
- struct gl_fog_attrib *attr;
- attr = MALLOC_STRUCT( gl_fog_attrib );
- memcpy( attr, &ctx->Fog, sizeof(struct gl_fog_attrib) );
- save_attrib_data(&head, GL_FOG_BIT, attr);
- }
-
- if (mask & GL_HINT_BIT) {
- struct gl_hint_attrib *attr;
- attr = MALLOC_STRUCT( gl_hint_attrib );
- memcpy( attr, &ctx->Hint, sizeof(struct gl_hint_attrib) );
- save_attrib_data(&head, GL_HINT_BIT, attr);
- }
-
- if (mask & GL_LIGHTING_BIT) {
- struct gl_light_attrib *attr;
- FLUSH_CURRENT(ctx, 0); /* flush material changes */
- attr = MALLOC_STRUCT( gl_light_attrib );
- memcpy( attr, &ctx->Light, sizeof(struct gl_light_attrib) );
- save_attrib_data(&head, GL_LIGHTING_BIT, attr);
- }
-
- if (mask & GL_LINE_BIT) {
- struct gl_line_attrib *attr;
- attr = MALLOC_STRUCT( gl_line_attrib );
- memcpy( attr, &ctx->Line, sizeof(struct gl_line_attrib) );
- save_attrib_data(&head, GL_LINE_BIT, attr);
- }
-
- if (mask & GL_LIST_BIT) {
- struct gl_list_attrib *attr;
- attr = MALLOC_STRUCT( gl_list_attrib );
- memcpy( attr, &ctx->List, sizeof(struct gl_list_attrib) );
- save_attrib_data(&head, GL_LIST_BIT, attr);
- }
-
- if (mask & GL_PIXEL_MODE_BIT) {
- struct gl_pixel_attrib *attr;
- attr = MALLOC_STRUCT( gl_pixel_attrib );
- memcpy( attr, &ctx->Pixel, sizeof(struct gl_pixel_attrib) );
- /* push the Read FBO's ReadBuffer state, not ctx->Pixel.ReadBuffer */
- attr->ReadBuffer = ctx->ReadBuffer->ColorReadBuffer;
- save_attrib_data(&head, GL_PIXEL_MODE_BIT, attr);
- }
-
- if (mask & GL_POINT_BIT) {
- struct gl_point_attrib *attr;
- attr = MALLOC_STRUCT( gl_point_attrib );
- memcpy( attr, &ctx->Point, sizeof(struct gl_point_attrib) );
- save_attrib_data(&head, GL_POINT_BIT, attr);
- }
-
- if (mask & GL_POLYGON_BIT) {
- struct gl_polygon_attrib *attr;
- attr = MALLOC_STRUCT( gl_polygon_attrib );
- memcpy( attr, &ctx->Polygon, sizeof(struct gl_polygon_attrib) );
- save_attrib_data(&head, GL_POLYGON_BIT, attr);
- }
-
- if (mask & GL_POLYGON_STIPPLE_BIT) {
- GLuint *stipple;
- stipple = (GLuint *) MALLOC( 32*sizeof(GLuint) );
- memcpy( stipple, ctx->PolygonStipple, 32*sizeof(GLuint) );
- save_attrib_data(&head, GL_POLYGON_STIPPLE_BIT, stipple);
- }
-
- if (mask & GL_SCISSOR_BIT) {
- struct gl_scissor_attrib *attr;
- attr = MALLOC_STRUCT( gl_scissor_attrib );
- memcpy( attr, &ctx->Scissor, sizeof(struct gl_scissor_attrib) );
- save_attrib_data(&head, GL_SCISSOR_BIT, attr);
- }
-
- if (mask & GL_STENCIL_BUFFER_BIT) {
- struct gl_stencil_attrib *attr;
- attr = MALLOC_STRUCT( gl_stencil_attrib );
- memcpy( attr, &ctx->Stencil, sizeof(struct gl_stencil_attrib) );
- save_attrib_data(&head, GL_STENCIL_BUFFER_BIT, attr);
- }
-
- if (mask & GL_TEXTURE_BIT) {
- struct texture_state *texstate = CALLOC_STRUCT(texture_state);
- GLuint u, tex;
-
- if (!texstate) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glPushAttrib(GL_TEXTURE_BIT)");
- goto end;
- }
-
- _mesa_lock_context_textures(ctx);
-
- /* copy/save the bulk of texture state here */
- memcpy(&texstate->Texture, &ctx->Texture, sizeof(ctx->Texture));
-
- /* Save references to the currently bound texture objects so they don't
- * accidentally get deleted while referenced in the attribute stack.
- */
- for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
- for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) {
- _mesa_reference_texobj(&texstate->SavedTexRef[u][tex],
- ctx->Texture.Unit[u].CurrentTex[tex]);
- }
- }
-
- /* copy state/contents of the currently bound texture objects */
- for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
- for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) {
- _mesa_copy_texture_object(&texstate->SavedObj[u][tex],
- ctx->Texture.Unit[u].CurrentTex[tex]);
- }
- }
-
- _mesa_unlock_context_textures(ctx);
-
- save_attrib_data(&head, GL_TEXTURE_BIT, texstate);
- }
-
- if (mask & GL_TRANSFORM_BIT) {
- struct gl_transform_attrib *attr;
- attr = MALLOC_STRUCT( gl_transform_attrib );
- memcpy( attr, &ctx->Transform, sizeof(struct gl_transform_attrib) );
- save_attrib_data(&head, GL_TRANSFORM_BIT, attr);
- }
-
- if (mask & GL_VIEWPORT_BIT) {
- struct gl_viewport_attrib *attr;
- attr = MALLOC_STRUCT( gl_viewport_attrib );
- memcpy( attr, &ctx->Viewport, sizeof(struct gl_viewport_attrib) );
- save_attrib_data(&head, GL_VIEWPORT_BIT, attr);
- }
-
- /* GL_ARB_multisample */
- if (mask & GL_MULTISAMPLE_BIT_ARB) {
- struct gl_multisample_attrib *attr;
- attr = MALLOC_STRUCT( gl_multisample_attrib );
- memcpy( attr, &ctx->Multisample, sizeof(struct gl_multisample_attrib) );
- save_attrib_data(&head, GL_MULTISAMPLE_BIT_ARB, attr);
- }
-
-end:
- ctx->AttribStack[ctx->AttribStackDepth] = head;
- ctx->AttribStackDepth++;
-}
-
-
-
-static void
-pop_enable_group(struct gl_context *ctx, const struct gl_enable_attrib *enable)
-{
- const GLuint curTexUnitSave = ctx->Texture.CurrentUnit;
- GLuint i;
-
-#define TEST_AND_UPDATE(VALUE, NEWVALUE, ENUM) \
- if ((VALUE) != (NEWVALUE)) { \
- _mesa_set_enable( ctx, ENUM, (NEWVALUE) ); \
- }
-
- TEST_AND_UPDATE(ctx->Color.AlphaEnabled, enable->AlphaTest, GL_ALPHA_TEST);
- if (ctx->Color.BlendEnabled != enable->Blend) {
- if (ctx->Extensions.EXT_draw_buffers2) {
- GLuint i;
- for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
- _mesa_set_enablei(ctx, GL_BLEND, i, (enable->Blend >> i) & 1);
- }
- }
- else {
- _mesa_set_enable(ctx, GL_BLEND, (enable->Blend & 1));
- }
- }
-
- for (i=0;i<MAX_CLIP_PLANES;i++) {
- const GLuint mask = 1 << i;
- if ((ctx->Transform.ClipPlanesEnabled & mask) != (enable->ClipPlanes & mask))
- _mesa_set_enable(ctx, (GLenum) (GL_CLIP_PLANE0 + i),
- (GLboolean) ((enable->ClipPlanes & mask) ? GL_TRUE : GL_FALSE));
- }
-
- TEST_AND_UPDATE(ctx->Light.ColorMaterialEnabled, enable->ColorMaterial,
- GL_COLOR_MATERIAL);
- TEST_AND_UPDATE(ctx->Polygon.CullFlag, enable->CullFace, GL_CULL_FACE);
- TEST_AND_UPDATE(ctx->Transform.DepthClamp, enable->DepthClamp,
- GL_DEPTH_CLAMP);
- TEST_AND_UPDATE(ctx->Depth.Test, enable->DepthTest, GL_DEPTH_TEST);
- TEST_AND_UPDATE(ctx->Color.DitherFlag, enable->Dither, GL_DITHER);
- TEST_AND_UPDATE(ctx->Fog.Enabled, enable->Fog, GL_FOG);
- TEST_AND_UPDATE(ctx->Light.Enabled, enable->Lighting, GL_LIGHTING);
- TEST_AND_UPDATE(ctx->Line.SmoothFlag, enable->LineSmooth, GL_LINE_SMOOTH);
- TEST_AND_UPDATE(ctx->Line.StippleFlag, enable->LineStipple,
- GL_LINE_STIPPLE);
- TEST_AND_UPDATE(ctx->Color.IndexLogicOpEnabled, enable->IndexLogicOp,
- GL_INDEX_LOGIC_OP);
- TEST_AND_UPDATE(ctx->Color.ColorLogicOpEnabled, enable->ColorLogicOp,
- GL_COLOR_LOGIC_OP);
-
- TEST_AND_UPDATE(ctx->Eval.Map1Color4, enable->Map1Color4, GL_MAP1_COLOR_4);
- TEST_AND_UPDATE(ctx->Eval.Map1Index, enable->Map1Index, GL_MAP1_INDEX);
- TEST_AND_UPDATE(ctx->Eval.Map1Normal, enable->Map1Normal, GL_MAP1_NORMAL);
- TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord1, enable->Map1TextureCoord1,
- GL_MAP1_TEXTURE_COORD_1);
- TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord2, enable->Map1TextureCoord2,
- GL_MAP1_TEXTURE_COORD_2);
- TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord3, enable->Map1TextureCoord3,
- GL_MAP1_TEXTURE_COORD_3);
- TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord4, enable->Map1TextureCoord4,
- GL_MAP1_TEXTURE_COORD_4);
- TEST_AND_UPDATE(ctx->Eval.Map1Vertex3, enable->Map1Vertex3,
- GL_MAP1_VERTEX_3);
- TEST_AND_UPDATE(ctx->Eval.Map1Vertex4, enable->Map1Vertex4,
- GL_MAP1_VERTEX_4);
- for (i = 0; i < 16; i++) {
- TEST_AND_UPDATE(ctx->Eval.Map1Attrib[i], enable->Map1Attrib[i],
- GL_MAP1_VERTEX_ATTRIB0_4_NV + i);
- }
-
- TEST_AND_UPDATE(ctx->Eval.Map2Color4, enable->Map2Color4, GL_MAP2_COLOR_4);
- TEST_AND_UPDATE(ctx->Eval.Map2Index, enable->Map2Index, GL_MAP2_INDEX);
- TEST_AND_UPDATE(ctx->Eval.Map2Normal, enable->Map2Normal, GL_MAP2_NORMAL);
- TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord1, enable->Map2TextureCoord1,
- GL_MAP2_TEXTURE_COORD_1);
- TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord2, enable->Map2TextureCoord2,
- GL_MAP2_TEXTURE_COORD_2);
- TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord3, enable->Map2TextureCoord3,
- GL_MAP2_TEXTURE_COORD_3);
- TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord4, enable->Map2TextureCoord4,
- GL_MAP2_TEXTURE_COORD_4);
- TEST_AND_UPDATE(ctx->Eval.Map2Vertex3, enable->Map2Vertex3,
- GL_MAP2_VERTEX_3);
- TEST_AND_UPDATE(ctx->Eval.Map2Vertex4, enable->Map2Vertex4,
- GL_MAP2_VERTEX_4);
- for (i = 0; i < 16; i++) {
- TEST_AND_UPDATE(ctx->Eval.Map2Attrib[i], enable->Map2Attrib[i],
- GL_MAP2_VERTEX_ATTRIB0_4_NV + i);
- }
-
- TEST_AND_UPDATE(ctx->Eval.AutoNormal, enable->AutoNormal, GL_AUTO_NORMAL);
- TEST_AND_UPDATE(ctx->Transform.Normalize, enable->Normalize, GL_NORMALIZE);
- TEST_AND_UPDATE(ctx->Transform.RescaleNormals, enable->RescaleNormals,
- GL_RESCALE_NORMAL_EXT);
- TEST_AND_UPDATE(ctx->Transform.RasterPositionUnclipped,
- enable->RasterPositionUnclipped,
- GL_RASTER_POSITION_UNCLIPPED_IBM);
- TEST_AND_UPDATE(ctx->Point.SmoothFlag, enable->PointSmooth,
- GL_POINT_SMOOTH);
- if (ctx->Extensions.NV_point_sprite || ctx->Extensions.ARB_point_sprite) {
- TEST_AND_UPDATE(ctx->Point.PointSprite, enable->PointSprite,
- GL_POINT_SPRITE_NV);
- }
- TEST_AND_UPDATE(ctx->Polygon.OffsetPoint, enable->PolygonOffsetPoint,
- GL_POLYGON_OFFSET_POINT);
- TEST_AND_UPDATE(ctx->Polygon.OffsetLine, enable->PolygonOffsetLine,
- GL_POLYGON_OFFSET_LINE);
- TEST_AND_UPDATE(ctx->Polygon.OffsetFill, enable->PolygonOffsetFill,
- GL_POLYGON_OFFSET_FILL);
- TEST_AND_UPDATE(ctx->Polygon.SmoothFlag, enable->PolygonSmooth,
- GL_POLYGON_SMOOTH);
- TEST_AND_UPDATE(ctx->Polygon.StippleFlag, enable->PolygonStipple,
- GL_POLYGON_STIPPLE);
- TEST_AND_UPDATE(ctx->Scissor.Enabled, enable->Scissor, GL_SCISSOR_TEST);
- TEST_AND_UPDATE(ctx->Stencil.Enabled, enable->Stencil, GL_STENCIL_TEST);
- if (ctx->Extensions.EXT_stencil_two_side) {
- TEST_AND_UPDATE(ctx->Stencil.TestTwoSide, enable->StencilTwoSide, GL_STENCIL_TEST_TWO_SIDE_EXT);
- }
- TEST_AND_UPDATE(ctx->Multisample.Enabled, enable->MultisampleEnabled,
- GL_MULTISAMPLE_ARB);
- TEST_AND_UPDATE(ctx->Multisample.SampleAlphaToCoverage,
- enable->SampleAlphaToCoverage,
- GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
- TEST_AND_UPDATE(ctx->Multisample.SampleAlphaToOne,
- enable->SampleAlphaToOne,
- GL_SAMPLE_ALPHA_TO_ONE_ARB);
- TEST_AND_UPDATE(ctx->Multisample.SampleCoverage,
- enable->SampleCoverage,
- GL_SAMPLE_COVERAGE_ARB);
- TEST_AND_UPDATE(ctx->Multisample.SampleCoverageInvert,
- enable->SampleCoverageInvert,
- GL_SAMPLE_COVERAGE_INVERT_ARB);
- /* GL_ARB_vertex_program, GL_NV_vertex_program */
- TEST_AND_UPDATE(ctx->VertexProgram.Enabled,
- enable->VertexProgram,
- GL_VERTEX_PROGRAM_ARB);
- TEST_AND_UPDATE(ctx->VertexProgram.PointSizeEnabled,
- enable->VertexProgramPointSize,
- GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
- TEST_AND_UPDATE(ctx->VertexProgram.TwoSideEnabled,
- enable->VertexProgramTwoSide,
- GL_VERTEX_PROGRAM_TWO_SIDE_ARB);
-
-#undef TEST_AND_UPDATE
-
- /* texture unit enables */
- for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
- const GLbitfield enabled = enable->Texture[i];
- const GLbitfield genEnabled = enable->TexGen[i];
-
- if (ctx->Texture.Unit[i].Enabled != enabled) {
- _mesa_ActiveTextureARB(GL_TEXTURE0 + i);
-
- _mesa_set_enable(ctx, GL_TEXTURE_1D,
- (enabled & TEXTURE_1D_BIT) ? GL_TRUE : GL_FALSE);
- _mesa_set_enable(ctx, GL_TEXTURE_2D,
- (enabled & TEXTURE_2D_BIT) ? GL_TRUE : GL_FALSE);
- _mesa_set_enable(ctx, GL_TEXTURE_3D,
- (enabled & TEXTURE_3D_BIT) ? GL_TRUE : GL_FALSE);
- if (ctx->Extensions.NV_texture_rectangle) {
- _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE_ARB,
- (enabled & TEXTURE_RECT_BIT) ? GL_TRUE : GL_FALSE);
- }
- if (ctx->Extensions.ARB_texture_cube_map) {
- _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP,
- (enabled & TEXTURE_CUBE_BIT) ? GL_TRUE : GL_FALSE);
- }
- if (ctx->Extensions.MESA_texture_array) {
- _mesa_set_enable(ctx, GL_TEXTURE_1D_ARRAY_EXT,
- (enabled & TEXTURE_1D_ARRAY_BIT) ? GL_TRUE : GL_FALSE);
- _mesa_set_enable(ctx, GL_TEXTURE_2D_ARRAY_EXT,
- (enabled & TEXTURE_2D_ARRAY_BIT) ? GL_TRUE : GL_FALSE);
- }
- }
-
- if (ctx->Texture.Unit[i].TexGenEnabled != genEnabled) {
- _mesa_ActiveTextureARB(GL_TEXTURE0 + i);
- _mesa_set_enable(ctx, GL_TEXTURE_GEN_S,
- (genEnabled & S_BIT) ? GL_TRUE : GL_FALSE);
- _mesa_set_enable(ctx, GL_TEXTURE_GEN_T,
- (genEnabled & T_BIT) ? GL_TRUE : GL_FALSE);
- _mesa_set_enable(ctx, GL_TEXTURE_GEN_R,
- (genEnabled & R_BIT) ? GL_TRUE : GL_FALSE);
- _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q,
- (genEnabled & Q_BIT) ? GL_TRUE : GL_FALSE);
- }
-
- /* GL_SGI_texture_color_table */
- ctx->Texture.Unit[i].ColorTableEnabled = enable->TextureColorTable[i];
- }
-
- _mesa_ActiveTextureARB(GL_TEXTURE0 + curTexUnitSave);
-}
-
-
-/**
- * Pop/restore texture attribute/group state.
- */
-static void
-pop_texture_group(struct gl_context *ctx, struct texture_state *texstate)
-{
- GLuint u;
-
- _mesa_lock_context_textures(ctx);
-
- for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
- const struct gl_texture_unit *unit = &texstate->Texture.Unit[u];
- GLuint tgt;
-
- _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + u);
- _mesa_set_enable(ctx, GL_TEXTURE_1D,
- (unit->Enabled & TEXTURE_1D_BIT) ? GL_TRUE : GL_FALSE);
- _mesa_set_enable(ctx, GL_TEXTURE_2D,
- (unit->Enabled & TEXTURE_2D_BIT) ? GL_TRUE : GL_FALSE);
- _mesa_set_enable(ctx, GL_TEXTURE_3D,
- (unit->Enabled & TEXTURE_3D_BIT) ? GL_TRUE : GL_FALSE);
- if (ctx->Extensions.ARB_texture_cube_map) {
- _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP_ARB,
- (unit->Enabled & TEXTURE_CUBE_BIT) ? GL_TRUE : GL_FALSE);
- }
- if (ctx->Extensions.NV_texture_rectangle) {
- _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE_NV,
- (unit->Enabled & TEXTURE_RECT_BIT) ? GL_TRUE : GL_FALSE);
- }
- if (ctx->Extensions.MESA_texture_array) {
- _mesa_set_enable(ctx, GL_TEXTURE_1D_ARRAY_EXT,
- (unit->Enabled & TEXTURE_1D_ARRAY_BIT) ? GL_TRUE : GL_FALSE);
- _mesa_set_enable(ctx, GL_TEXTURE_2D_ARRAY_EXT,
- (unit->Enabled & TEXTURE_2D_ARRAY_BIT) ? GL_TRUE : GL_FALSE);
- }
-
- if (ctx->Extensions.SGI_texture_color_table) {
- _mesa_set_enable(ctx, GL_TEXTURE_COLOR_TABLE_SGI,
- unit->ColorTableEnabled);
- }
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->EnvMode);
- _mesa_TexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, unit->EnvColor);
- _mesa_TexGeni(GL_S, GL_TEXTURE_GEN_MODE, unit->GenS.Mode);
- _mesa_TexGeni(GL_T, GL_TEXTURE_GEN_MODE, unit->GenT.Mode);
- _mesa_TexGeni(GL_R, GL_TEXTURE_GEN_MODE, unit->GenR.Mode);
- _mesa_TexGeni(GL_Q, GL_TEXTURE_GEN_MODE, unit->GenQ.Mode);
- _mesa_TexGenfv(GL_S, GL_OBJECT_PLANE, unit->GenS.ObjectPlane);
- _mesa_TexGenfv(GL_T, GL_OBJECT_PLANE, unit->GenT.ObjectPlane);
- _mesa_TexGenfv(GL_R, GL_OBJECT_PLANE, unit->GenR.ObjectPlane);
- _mesa_TexGenfv(GL_Q, GL_OBJECT_PLANE, unit->GenQ.ObjectPlane);
- /* Eye plane done differently to avoid re-transformation */
- {
- struct gl_texture_unit *destUnit = &ctx->Texture.Unit[u];
- COPY_4FV(destUnit->GenS.EyePlane, unit->GenS.EyePlane);
- COPY_4FV(destUnit->GenT.EyePlane, unit->GenT.EyePlane);
- COPY_4FV(destUnit->GenR.EyePlane, unit->GenR.EyePlane);
- COPY_4FV(destUnit->GenQ.EyePlane, unit->GenQ.EyePlane);
- if (ctx->Driver.TexGen) {
- ctx->Driver.TexGen(ctx, GL_S, GL_EYE_PLANE, unit->GenS.EyePlane);
- ctx->Driver.TexGen(ctx, GL_T, GL_EYE_PLANE, unit->GenT.EyePlane);
- ctx->Driver.TexGen(ctx, GL_R, GL_EYE_PLANE, unit->GenR.EyePlane);
- ctx->Driver.TexGen(ctx, GL_Q, GL_EYE_PLANE, unit->GenQ.EyePlane);
- }
- }
- _mesa_set_enable(ctx, GL_TEXTURE_GEN_S,
- ((unit->TexGenEnabled & S_BIT) ? GL_TRUE : GL_FALSE));
- _mesa_set_enable(ctx, GL_TEXTURE_GEN_T,
- ((unit->TexGenEnabled & T_BIT) ? GL_TRUE : GL_FALSE));
- _mesa_set_enable(ctx, GL_TEXTURE_GEN_R,
- ((unit->TexGenEnabled & R_BIT) ? GL_TRUE : GL_FALSE));
- _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q,
- ((unit->TexGenEnabled & Q_BIT) ? GL_TRUE : GL_FALSE));
- if (ctx->Extensions.EXT_texture_lod_bias) {
- _mesa_TexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
- GL_TEXTURE_LOD_BIAS_EXT, unit->LodBias);
- }
- if (ctx->Extensions.EXT_texture_env_combine ||
- ctx->Extensions.ARB_texture_env_combine) {
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB,
- unit->Combine.ModeRGB);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA,
- unit->Combine.ModeA);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB,
- unit->Combine.SourceRGB[0]);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB,
- unit->Combine.SourceRGB[1]);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB,
- unit->Combine.SourceRGB[2]);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA,
- unit->Combine.SourceA[0]);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA,
- unit->Combine.SourceA[1]);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA,
- unit->Combine.SourceA[2]);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB,
- unit->Combine.OperandRGB[0]);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB,
- unit->Combine.OperandRGB[1]);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB,
- unit->Combine.OperandRGB[2]);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA,
- unit->Combine.OperandA[0]);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA,
- unit->Combine.OperandA[1]);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA,
- unit->Combine.OperandA[2]);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE,
- 1 << unit->Combine.ScaleShiftRGB);
- _mesa_TexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE,
- 1 << unit->Combine.ScaleShiftA);
- }
-
- /* Restore texture object state for each target */
- for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) {
- const struct gl_texture_object *obj = NULL;
- GLenum target;
-
- obj = &texstate->SavedObj[u][tgt];
-
- /* don't restore state for unsupported targets to prevent
- * raising GL errors.
- */
- if (obj->Target == GL_TEXTURE_CUBE_MAP_ARB &&
- !ctx->Extensions.ARB_texture_cube_map) {
- continue;
- }
- else if (obj->Target == GL_TEXTURE_RECTANGLE_NV &&
- !ctx->Extensions.NV_texture_rectangle) {
- continue;
- }
- else if ((obj->Target == GL_TEXTURE_1D_ARRAY_EXT ||
- obj->Target == GL_TEXTURE_2D_ARRAY_EXT) &&
- !ctx->Extensions.MESA_texture_array) {
- continue;
- }
-
- target = obj->Target;
-
- _mesa_BindTexture(target, obj->Name);
-
- _mesa_TexParameterfv(target, GL_TEXTURE_BORDER_COLOR, obj->BorderColor.f);
- _mesa_TexParameterf(target, GL_TEXTURE_PRIORITY, obj->Priority);
- _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, obj->WrapS);
- _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, obj->WrapT);
- _mesa_TexParameteri(target, GL_TEXTURE_WRAP_R, obj->WrapR);
- _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, obj->MinFilter);
- _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, obj->MagFilter);
- _mesa_TexParameterf(target, GL_TEXTURE_MIN_LOD, obj->MinLod);
- _mesa_TexParameterf(target, GL_TEXTURE_MAX_LOD, obj->MaxLod);
- _mesa_TexParameterf(target, GL_TEXTURE_LOD_BIAS, obj->LodBias);
- _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, obj->BaseLevel);
- if (target != GL_TEXTURE_RECTANGLE_ARB)
- _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, obj->MaxLevel);
- if (ctx->Extensions.EXT_texture_filter_anisotropic) {
- _mesa_TexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT,
- obj->MaxAnisotropy);
- }
- if (ctx->Extensions.ARB_shadow_ambient) {
- _mesa_TexParameterf(target, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB,
- obj->CompareFailValue);
- }
- }
-
- /* remove saved references to the texture objects */
- for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) {
- _mesa_reference_texobj(&texstate->SavedTexRef[u][tgt], NULL);
- }
- }
-
- _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + texstate->Texture.CurrentUnit);
-
- _mesa_unlock_context_textures(ctx);
-}
-
-
-/*
- * This function is kind of long just because we have to call a lot
- * of device driver functions to update device driver state.
- *
- * XXX As it is now, most of the pop-code calls immediate-mode Mesa functions
- * in order to restore GL state. This isn't terribly efficient but it
- * ensures that dirty flags and any derived state gets updated correctly.
- * We could at least check if the value to restore equals the current value
- * and then skip the Mesa call.
- */
-void GLAPIENTRY
-_mesa_PopAttrib(void)
-{
- struct gl_attrib_node *attr, *next;
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (ctx->AttribStackDepth == 0) {
- _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopAttrib" );
- return;
- }
-
- ctx->AttribStackDepth--;
- attr = ctx->AttribStack[ctx->AttribStackDepth];
-
- while (attr) {
-
- if (MESA_VERBOSE & VERBOSE_API) {
- _mesa_debug(ctx, "glPopAttrib %s\n",
- _mesa_lookup_enum_by_nr(attr->kind));
- }
-
- switch (attr->kind) {
- case GL_ACCUM_BUFFER_BIT:
- {
- const struct gl_accum_attrib *accum;
- accum = (const struct gl_accum_attrib *) attr->data;
- _mesa_ClearAccum(accum->ClearColor[0],
- accum->ClearColor[1],
- accum->ClearColor[2],
- accum->ClearColor[3]);
- }
- break;
- case GL_COLOR_BUFFER_BIT:
- {
- const struct gl_colorbuffer_attrib *color;
-
- color = (const struct gl_colorbuffer_attrib *) attr->data;
- _mesa_ClearIndex((GLfloat) color->ClearIndex);
- _mesa_ClearColor(color->ClearColor[0],
- color->ClearColor[1],
- color->ClearColor[2],
- color->ClearColor[3]);
- _mesa_IndexMask(color->IndexMask);
- if (!ctx->Extensions.EXT_draw_buffers2) {
- _mesa_ColorMask((GLboolean) (color->ColorMask[0][0] != 0),
- (GLboolean) (color->ColorMask[0][1] != 0),
- (GLboolean) (color->ColorMask[0][2] != 0),
- (GLboolean) (color->ColorMask[0][3] != 0));
- }
- else {
- GLuint i;
- for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
- _mesa_ColorMaskIndexed(i,
- (GLboolean) (color->ColorMask[i][0] != 0),
- (GLboolean) (color->ColorMask[i][1] != 0),
- (GLboolean) (color->ColorMask[i][2] != 0),
- (GLboolean) (color->ColorMask[i][3] != 0));
- }
- }
- {
- /* Need to determine if more than one color output is
- * specified. If so, call glDrawBuffersARB, else call
- * glDrawBuffer(). This is a subtle, but essential point
- * since GL_FRONT (for example) is illegal for the former
- * function, but legal for the later.
- */
- GLboolean multipleBuffers = GL_FALSE;
- GLuint i;
-
- for (i = 1; i < ctx->Const.MaxDrawBuffers; i++) {
- if (color->DrawBuffer[i] != GL_NONE) {
- multipleBuffers = GL_TRUE;
- break;
- }
- }
- /* Call the API_level functions, not _mesa_drawbuffers()
- * since we need to do error checking on the pop'd
- * GL_DRAW_BUFFER.
- * Ex: if GL_FRONT were pushed, but we're popping with a
- * user FBO bound, GL_FRONT will be illegal and we'll need
- * to record that error. Per OpenGL ARB decision.
- */
- if (multipleBuffers)
- _mesa_DrawBuffersARB(ctx->Const.MaxDrawBuffers,
- color->DrawBuffer);
- else
- _mesa_DrawBuffer(color->DrawBuffer[0]);
- }
- _mesa_set_enable(ctx, GL_ALPHA_TEST, color->AlphaEnabled);
- _mesa_AlphaFunc(color->AlphaFunc, color->AlphaRef);
- if (ctx->Color.BlendEnabled != color->BlendEnabled) {
- if (ctx->Extensions.EXT_draw_buffers2) {
- GLuint i;
- for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
- _mesa_set_enablei(ctx, GL_BLEND, i,
- (color->BlendEnabled >> i) & 1);
- }
- }
- else {
- _mesa_set_enable(ctx, GL_BLEND, (color->BlendEnabled & 1));
- }
- }
- if (ctx->Color._BlendFuncPerBuffer ||
- ctx->Color._BlendEquationPerBuffer) {
- /* set blend per buffer */
- GLuint buf;
- for (buf = 0; buf < ctx->Const.MaxDrawBuffers; buf++) {
- _mesa_BlendFuncSeparatei(buf, color->Blend[buf].SrcRGB,
- color->Blend[buf].DstRGB,
- color->Blend[buf].SrcA,
- color->Blend[buf].DstA);
- _mesa_BlendEquationSeparatei(buf,
- color->Blend[buf].EquationRGB,
- color->Blend[buf].EquationA);
- }
- }
- else {
- /* set same blend modes for all buffers */
- _mesa_BlendFuncSeparateEXT(color->Blend[0].SrcRGB,
- color->Blend[0].DstRGB,
- color->Blend[0].SrcA,
- color->Blend[0].DstA);
- /* This special case is because glBlendEquationSeparateEXT
- * cannot take GL_LOGIC_OP as a parameter.
- */
- if (color->Blend[0].EquationRGB ==
- color->Blend[0].EquationA) {
- _mesa_BlendEquation(color->Blend[0].EquationRGB);
- }
- else {
- _mesa_BlendEquationSeparateEXT(
- color->Blend[0].EquationRGB,
- color->Blend[0].EquationA);
- }
- }
- _mesa_BlendColor(color->BlendColor[0],
- color->BlendColor[1],
- color->BlendColor[2],
- color->BlendColor[3]);
- _mesa_LogicOp(color->LogicOp);
- _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP,
- color->ColorLogicOpEnabled);
- _mesa_set_enable(ctx, GL_INDEX_LOGIC_OP,
- color->IndexLogicOpEnabled);
- _mesa_set_enable(ctx, GL_DITHER, color->DitherFlag);
- }
- break;
- case GL_CURRENT_BIT:
- FLUSH_CURRENT( ctx, 0 );
- memcpy( &ctx->Current, attr->data,
- sizeof(struct gl_current_attrib) );
- break;
- case GL_DEPTH_BUFFER_BIT:
- {
- const struct gl_depthbuffer_attrib *depth;
- depth = (const struct gl_depthbuffer_attrib *) attr->data;
- _mesa_DepthFunc(depth->Func);
- _mesa_ClearDepth(depth->Clear);
- _mesa_set_enable(ctx, GL_DEPTH_TEST, depth->Test);
- _mesa_DepthMask(depth->Mask);
- }
- break;
- case GL_ENABLE_BIT:
- {
- const struct gl_enable_attrib *enable;
- enable = (const struct gl_enable_attrib *) attr->data;
- pop_enable_group(ctx, enable);
- ctx->NewState |= _NEW_ALL;
- }
- break;
- case GL_EVAL_BIT:
- memcpy( &ctx->Eval, attr->data, sizeof(struct gl_eval_attrib) );
- ctx->NewState |= _NEW_EVAL;
- break;
- case GL_FOG_BIT:
- {
- const struct gl_fog_attrib *fog;
- fog = (const struct gl_fog_attrib *) attr->data;
- _mesa_set_enable(ctx, GL_FOG, fog->Enabled);
- _mesa_Fogfv(GL_FOG_COLOR, fog->Color);
- _mesa_Fogf(GL_FOG_DENSITY, fog->Density);
- _mesa_Fogf(GL_FOG_START, fog->Start);
- _mesa_Fogf(GL_FOG_END, fog->End);
- _mesa_Fogf(GL_FOG_INDEX, fog->Index);
- _mesa_Fogi(GL_FOG_MODE, fog->Mode);
- }
- break;
- case GL_HINT_BIT:
- {
- const struct gl_hint_attrib *hint;
- hint = (const struct gl_hint_attrib *) attr->data;
- _mesa_Hint(GL_PERSPECTIVE_CORRECTION_HINT,
- hint->PerspectiveCorrection );
- _mesa_Hint(GL_POINT_SMOOTH_HINT, hint->PointSmooth);
- _mesa_Hint(GL_LINE_SMOOTH_HINT, hint->LineSmooth);
- _mesa_Hint(GL_POLYGON_SMOOTH_HINT, hint->PolygonSmooth);
- _mesa_Hint(GL_FOG_HINT, hint->Fog);
- _mesa_Hint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT,
- hint->ClipVolumeClipping);
- _mesa_Hint(GL_TEXTURE_COMPRESSION_HINT_ARB,
- hint->TextureCompression);
- }
- break;
- case GL_LIGHTING_BIT:
- {
- GLuint i;
- const struct gl_light_attrib *light;
- light = (const struct gl_light_attrib *) attr->data;
- /* lighting enable */
- _mesa_set_enable(ctx, GL_LIGHTING, light->Enabled);
- /* per-light state */
- if (_math_matrix_is_dirty(ctx->ModelviewMatrixStack.Top))
- _math_matrix_analyse( ctx->ModelviewMatrixStack.Top );
-
- for (i = 0; i < ctx->Const.MaxLights; i++) {
- const struct gl_light *l = &light->Light[i];
- _mesa_set_enable(ctx, GL_LIGHT0 + i, l->Enabled);
- _mesa_light(ctx, i, GL_AMBIENT, l->Ambient);
- _mesa_light(ctx, i, GL_DIFFUSE, l->Diffuse);
- _mesa_light(ctx, i, GL_SPECULAR, l->Specular );
- _mesa_light(ctx, i, GL_POSITION, l->EyePosition);
- _mesa_light(ctx, i, GL_SPOT_DIRECTION, l->SpotDirection);
- {
- GLfloat p[4] = { 0 };
- p[0] = l->SpotExponent;
- _mesa_light(ctx, i, GL_SPOT_EXPONENT, p);
- }
- {
- GLfloat p[4] = { 0 };
- p[0] = l->SpotCutoff;
- _mesa_light(ctx, i, GL_SPOT_CUTOFF, p);
- }
- {
- GLfloat p[4] = { 0 };
- p[0] = l->ConstantAttenuation;
- _mesa_light(ctx, i, GL_CONSTANT_ATTENUATION, p);
- }
- {
- GLfloat p[4] = { 0 };
- p[0] = l->LinearAttenuation;
- _mesa_light(ctx, i, GL_LINEAR_ATTENUATION, p);
- }
- {
- GLfloat p[4] = { 0 };
- p[0] = l->QuadraticAttenuation;
- _mesa_light(ctx, i, GL_QUADRATIC_ATTENUATION, p);
- }
- }
- /* light model */
- _mesa_LightModelfv(GL_LIGHT_MODEL_AMBIENT,
- light->Model.Ambient);
- _mesa_LightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER,
- (GLfloat) light->Model.LocalViewer);
- _mesa_LightModelf(GL_LIGHT_MODEL_TWO_SIDE,
- (GLfloat) light->Model.TwoSide);
- _mesa_LightModelf(GL_LIGHT_MODEL_COLOR_CONTROL,
- (GLfloat) light->Model.ColorControl);
- /* shade model */
- _mesa_ShadeModel(light->ShadeModel);
- /* color material */
- _mesa_ColorMaterial(light->ColorMaterialFace,
- light->ColorMaterialMode);
- _mesa_set_enable(ctx, GL_COLOR_MATERIAL,
- light->ColorMaterialEnabled);
- /* materials */
- memcpy(&ctx->Light.Material, &light->Material,
- sizeof(struct gl_material));
- }
- break;
- case GL_LINE_BIT:
- {
- const struct gl_line_attrib *line;
- line = (const struct gl_line_attrib *) attr->data;
- _mesa_set_enable(ctx, GL_LINE_SMOOTH, line->SmoothFlag);
- _mesa_set_enable(ctx, GL_LINE_STIPPLE, line->StippleFlag);
- _mesa_LineStipple(line->StippleFactor, line->StipplePattern);
- _mesa_LineWidth(line->Width);
- }
- break;
- case GL_LIST_BIT:
- memcpy( &ctx->List, attr->data, sizeof(struct gl_list_attrib) );
- break;
- case GL_PIXEL_MODE_BIT:
- memcpy( &ctx->Pixel, attr->data, sizeof(struct gl_pixel_attrib) );
- /* XXX what other pixel state needs to be set by function calls? */
- _mesa_ReadBuffer(ctx->Pixel.ReadBuffer);
- ctx->NewState |= _NEW_PIXEL;
- break;
- case GL_POINT_BIT:
- {
- const struct gl_point_attrib *point;
- point = (const struct gl_point_attrib *) attr->data;
- _mesa_PointSize(point->Size);
- _mesa_set_enable(ctx, GL_POINT_SMOOTH, point->SmoothFlag);
- if (ctx->Extensions.EXT_point_parameters) {
- _mesa_PointParameterfv(GL_DISTANCE_ATTENUATION_EXT,
- point->Params);
- _mesa_PointParameterf(GL_POINT_SIZE_MIN_EXT,
- point->MinSize);
- _mesa_PointParameterf(GL_POINT_SIZE_MAX_EXT,
- point->MaxSize);
- _mesa_PointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_EXT,
- point->Threshold);
- }
- if (ctx->Extensions.NV_point_sprite
- || ctx->Extensions.ARB_point_sprite) {
- GLuint u;
- for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
- _mesa_TexEnvi(GL_POINT_SPRITE_NV, GL_COORD_REPLACE_NV,
- (GLint) point->CoordReplace[u]);
- }
- _mesa_set_enable(ctx, GL_POINT_SPRITE_NV,point->PointSprite);
- if (ctx->Extensions.NV_point_sprite)
- _mesa_PointParameteri(GL_POINT_SPRITE_R_MODE_NV,
- ctx->Point.SpriteRMode);
- _mesa_PointParameterf(GL_POINT_SPRITE_COORD_ORIGIN,
- (GLfloat)ctx->Point.SpriteOrigin);
- }
- }
- break;
- case GL_POLYGON_BIT:
- {
- const struct gl_polygon_attrib *polygon;
- polygon = (const struct gl_polygon_attrib *) attr->data;
- _mesa_CullFace(polygon->CullFaceMode);
- _mesa_FrontFace(polygon->FrontFace);
- _mesa_PolygonMode(GL_FRONT, polygon->FrontMode);
- _mesa_PolygonMode(GL_BACK, polygon->BackMode);
- _mesa_PolygonOffset(polygon->OffsetFactor,
- polygon->OffsetUnits);
- _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, polygon->SmoothFlag);
- _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, polygon->StippleFlag);
- _mesa_set_enable(ctx, GL_CULL_FACE, polygon->CullFlag);
- _mesa_set_enable(ctx, GL_POLYGON_OFFSET_POINT,
- polygon->OffsetPoint);
- _mesa_set_enable(ctx, GL_POLYGON_OFFSET_LINE,
- polygon->OffsetLine);
- _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL,
- polygon->OffsetFill);
- }
- break;
- case GL_POLYGON_STIPPLE_BIT:
- memcpy( ctx->PolygonStipple, attr->data, 32*sizeof(GLuint) );
- ctx->NewState |= _NEW_POLYGONSTIPPLE;
- if (ctx->Driver.PolygonStipple)
- ctx->Driver.PolygonStipple( ctx, (const GLubyte *) attr->data );
- break;
- case GL_SCISSOR_BIT:
- {
- const struct gl_scissor_attrib *scissor;
- scissor = (const struct gl_scissor_attrib *) attr->data;
- _mesa_Scissor(scissor->X, scissor->Y,
- scissor->Width, scissor->Height);
- _mesa_set_enable(ctx, GL_SCISSOR_TEST, scissor->Enabled);
- }
- break;
- case GL_STENCIL_BUFFER_BIT:
- {
- const struct gl_stencil_attrib *stencil;
- stencil = (const struct gl_stencil_attrib *) attr->data;
- _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled);
- _mesa_ClearStencil(stencil->Clear);
- if (ctx->Extensions.EXT_stencil_two_side) {
- _mesa_set_enable(ctx, GL_STENCIL_TEST_TWO_SIDE_EXT,
- stencil->TestTwoSide);
- _mesa_ActiveStencilFaceEXT(stencil->ActiveFace
- ? GL_BACK : GL_FRONT);
- }
- /* front state */
- _mesa_StencilFuncSeparate(GL_FRONT,
- stencil->Function[0],
- stencil->Ref[0],
- stencil->ValueMask[0]);
- _mesa_StencilMaskSeparate(GL_FRONT, stencil->WriteMask[0]);
- _mesa_StencilOpSeparate(GL_FRONT, stencil->FailFunc[0],
- stencil->ZFailFunc[0],
- stencil->ZPassFunc[0]);
- /* back state */
- _mesa_StencilFuncSeparate(GL_BACK,
- stencil->Function[1],
- stencil->Ref[1],
- stencil->ValueMask[1]);
- _mesa_StencilMaskSeparate(GL_BACK, stencil->WriteMask[1]);
- _mesa_StencilOpSeparate(GL_BACK, stencil->FailFunc[1],
- stencil->ZFailFunc[1],
- stencil->ZPassFunc[1]);
- }
- break;
- case GL_TRANSFORM_BIT:
- {
- GLuint i;
- const struct gl_transform_attrib *xform;
- xform = (const struct gl_transform_attrib *) attr->data;
- _mesa_MatrixMode(xform->MatrixMode);
- if (_math_matrix_is_dirty(ctx->ProjectionMatrixStack.Top))
- _math_matrix_analyse( ctx->ProjectionMatrixStack.Top );
-
- /* restore clip planes */
- for (i = 0; i < MAX_CLIP_PLANES; i++) {
- const GLuint mask = 1 << i;
- const GLfloat *eyePlane = xform->EyeUserPlane[i];
- COPY_4V(ctx->Transform.EyeUserPlane[i], eyePlane);
- if (xform->ClipPlanesEnabled & mask) {
- _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_TRUE);
- }
- else {
- _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_FALSE);
- }
- if (ctx->Driver.ClipPlane)
- ctx->Driver.ClipPlane( ctx, GL_CLIP_PLANE0 + i, eyePlane );
- }
-
- /* normalize/rescale */
- if (xform->Normalize != ctx->Transform.Normalize)
- _mesa_set_enable(ctx, GL_NORMALIZE,ctx->Transform.Normalize);
- if (xform->RescaleNormals != ctx->Transform.RescaleNormals)
- _mesa_set_enable(ctx, GL_RESCALE_NORMAL_EXT,
- ctx->Transform.RescaleNormals);
- if (xform->DepthClamp != ctx->Transform.DepthClamp)
- _mesa_set_enable(ctx, GL_DEPTH_CLAMP,
- ctx->Transform.DepthClamp);
- }
- break;
- case GL_TEXTURE_BIT:
- /* Take care of texture object reference counters */
- {
- struct texture_state *texstate
- = (struct texture_state *) attr->data;
- pop_texture_group(ctx, texstate);
- ctx->NewState |= _NEW_TEXTURE;
- }
- break;
- case GL_VIEWPORT_BIT:
- {
- const struct gl_viewport_attrib *vp;
- vp = (const struct gl_viewport_attrib *) attr->data;
- _mesa_Viewport(vp->X, vp->Y, vp->Width, vp->Height);
- _mesa_DepthRange(vp->Near, vp->Far);
- }
- break;
- case GL_MULTISAMPLE_BIT_ARB:
- {
- const struct gl_multisample_attrib *ms;
- ms = (const struct gl_multisample_attrib *) attr->data;
- _mesa_SampleCoverageARB(ms->SampleCoverageValue,
- ms->SampleCoverageInvert);
- }
- break;
-
- default:
- _mesa_problem( ctx, "Bad attrib flag in PopAttrib");
- break;
- }
-
- next = attr->next;
- FREE( attr->data );
- FREE( attr );
- attr = next;
- }
-}
-
-
-/**
- * Helper for incrementing/decrementing vertex buffer object reference
- * counts when pushing/popping the GL_CLIENT_VERTEX_ARRAY_BIT attribute group.
- */
-static void
-adjust_buffer_object_ref_counts(struct gl_array_object *arrayObj, GLint step)
-{
- GLuint i;
-
- arrayObj->Vertex.BufferObj->RefCount += step;
- arrayObj->Weight.BufferObj->RefCount += step;
- arrayObj->Normal.BufferObj->RefCount += step;
- arrayObj->Color.BufferObj->RefCount += step;
- arrayObj->SecondaryColor.BufferObj->RefCount += step;
- arrayObj->FogCoord.BufferObj->RefCount += step;
- arrayObj->Index.BufferObj->RefCount += step;
- arrayObj->EdgeFlag.BufferObj->RefCount += step;
- for (i = 0; i < Elements(arrayObj->TexCoord); i++)
- arrayObj->TexCoord[i].BufferObj->RefCount += step;
- for (i = 0; i < Elements(arrayObj->VertexAttrib); i++)
- arrayObj->VertexAttrib[i].BufferObj->RefCount += step;
-}
-
-
-/**
- * Copy gl_pixelstore_attrib from src to dst, updating buffer
- * object refcounts.
- */
-static void
-copy_pixelstore(struct gl_context *ctx,
- struct gl_pixelstore_attrib *dst,
- const struct gl_pixelstore_attrib *src)
-{
- dst->Alignment = src->Alignment;
- dst->RowLength = src->RowLength;
- dst->SkipPixels = src->SkipPixels;
- dst->SkipRows = src->SkipRows;
- dst->ImageHeight = src->ImageHeight;
- dst->SkipImages = src->SkipImages;
- dst->SwapBytes = src->SwapBytes;
- dst->LsbFirst = src->LsbFirst;
- dst->ClientStorage = src->ClientStorage;
- dst->Invert = src->Invert;
- _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj);
-}
-
-
-#define GL_CLIENT_PACK_BIT (1<<20)
-#define GL_CLIENT_UNPACK_BIT (1<<21)
-
-
-void GLAPIENTRY
-_mesa_PushClientAttrib(GLbitfield mask)
-{
- struct gl_attrib_node *head;
-
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (ctx->ClientAttribStackDepth >= MAX_CLIENT_ATTRIB_STACK_DEPTH) {
- _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushClientAttrib" );
- return;
- }
-
- /* Build linked list of attribute nodes which save all attribute
- * groups specified by the mask.
- */
- head = NULL;
-
- if (mask & GL_CLIENT_PIXEL_STORE_BIT) {
- struct gl_pixelstore_attrib *attr;
- /* packing attribs */
- attr = CALLOC_STRUCT( gl_pixelstore_attrib );
- copy_pixelstore(ctx, attr, &ctx->Pack);
- save_attrib_data(&head, GL_CLIENT_PACK_BIT, attr);
- /* unpacking attribs */
- attr = CALLOC_STRUCT( gl_pixelstore_attrib );
- copy_pixelstore(ctx, attr, &ctx->Unpack);
- save_attrib_data(&head, GL_CLIENT_UNPACK_BIT, attr);
- }
-
- if (mask & GL_CLIENT_VERTEX_ARRAY_BIT) {
- struct gl_array_attrib *attr;
- struct gl_array_object *obj;
-
- attr = MALLOC_STRUCT( gl_array_attrib );
- obj = MALLOC_STRUCT( gl_array_object );
-
-#if FEATURE_ARB_vertex_buffer_object
- /* increment ref counts since we're copying pointers to these objects */
- ctx->Array.ArrayBufferObj->RefCount++;
- ctx->Array.ElementArrayBufferObj->RefCount++;
-#endif
-
- memcpy( attr, &ctx->Array, sizeof(struct gl_array_attrib) );
- memcpy( obj, ctx->Array.ArrayObj, sizeof(struct gl_array_object) );
-
- attr->ArrayObj = obj;
-
- save_attrib_data(&head, GL_CLIENT_VERTEX_ARRAY_BIT, attr);
-
- /* bump reference counts on buffer objects */
- adjust_buffer_object_ref_counts(ctx->Array.ArrayObj, 1);
- }
-
- ctx->ClientAttribStack[ctx->ClientAttribStackDepth] = head;
- ctx->ClientAttribStackDepth++;
-}
-
-
-
-
-void GLAPIENTRY
-_mesa_PopClientAttrib(void)
-{
- struct gl_attrib_node *node, *next;
-
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (ctx->ClientAttribStackDepth == 0) {
- _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopClientAttrib" );
- return;
- }
-
- ctx->ClientAttribStackDepth--;
- node = ctx->ClientAttribStack[ctx->ClientAttribStackDepth];
-
- while (node) {
- switch (node->kind) {
- case GL_CLIENT_PACK_BIT:
- {
- struct gl_pixelstore_attrib *store =
- (struct gl_pixelstore_attrib *) node->data;
- copy_pixelstore(ctx, &ctx->Pack, store);
- _mesa_reference_buffer_object(ctx, &store->BufferObj, NULL);
- }
- ctx->NewState |= _NEW_PACKUNPACK;
- break;
- case GL_CLIENT_UNPACK_BIT:
- {
- struct gl_pixelstore_attrib *store =
- (struct gl_pixelstore_attrib *) node->data;
- copy_pixelstore(ctx, &ctx->Unpack, store);
- _mesa_reference_buffer_object(ctx, &store->BufferObj, NULL);
- }
- ctx->NewState |= _NEW_PACKUNPACK;
- break;
- case GL_CLIENT_VERTEX_ARRAY_BIT: {
- struct gl_array_attrib * data =
- (struct gl_array_attrib *) node->data;
-
- adjust_buffer_object_ref_counts(ctx->Array.ArrayObj, -1);
-
- ctx->Array.ActiveTexture = data->ActiveTexture;
- if (data->LockCount != 0)
- _mesa_LockArraysEXT(data->LockFirst, data->LockCount);
- else if (ctx->Array.LockCount)
- _mesa_UnlockArraysEXT();
-
- _mesa_BindVertexArrayAPPLE( data->ArrayObj->Name );
-
-#if FEATURE_ARB_vertex_buffer_object
- _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB,
- data->ArrayBufferObj->Name);
- _mesa_BindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
- data->ElementArrayBufferObj->Name);
-#endif
-
- memcpy( ctx->Array.ArrayObj, data->ArrayObj,
- sizeof( struct gl_array_object ) );
-
- FREE( data->ArrayObj );
-
- /* FIXME: Should some bits in ctx->Array->NewState also be set
- * FIXME: here? It seems like it should be set to inclusive-or
- * FIXME: of the old ArrayObj->_Enabled and the new _Enabled.
- */
-
- ctx->NewState |= _NEW_ARRAY;
- break;
- }
- default:
- _mesa_problem( ctx, "Bad attrib flag in PopClientAttrib");
- break;
- }
-
- next = node->next;
- FREE( node->data );
- FREE( node );
- node = next;
- }
-}
-
-
-void
-_mesa_init_attrib_dispatch(struct _glapi_table *disp)
-{
- SET_PopAttrib(disp, _mesa_PopAttrib);
- SET_PushAttrib(disp, _mesa_PushAttrib);
- SET_PopClientAttrib(disp, _mesa_PopClientAttrib);
- SET_PushClientAttrib(disp, _mesa_PushClientAttrib);
-}
-
-
-#endif /* FEATURE_attrib_stack */
-
-
-/**
- * Free any attribute state data that might be attached to the context.
- */
-void
-_mesa_free_attrib_data(struct gl_context *ctx)
-{
- while (ctx->AttribStackDepth > 0) {
- struct gl_attrib_node *attr, *next;
-
- ctx->AttribStackDepth--;
- attr = ctx->AttribStack[ctx->AttribStackDepth];
-
- while (attr) {
- if (attr->kind == GL_TEXTURE_BIT) {
- struct texture_state *texstate = (struct texture_state*)attr->data;
- GLuint u, tgt;
- /* clear references to the saved texture objects */
- for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
- for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) {
- _mesa_reference_texobj(&texstate->SavedTexRef[u][tgt], NULL);
- }
- }
- }
- else {
- /* any other chunks of state that requires special handling? */
- }
-
- next = attr->next;
- free(attr->data);
- free(attr);
- attr = next;
- }
- }
-}
-
-
-void _mesa_init_attrib( struct gl_context *ctx )
-{
- /* Renderer and client attribute stacks */
- ctx->AttribStackDepth = 0;
- ctx->ClientAttribStackDepth = 0;
-}
+/* + * Mesa 3-D graphics library + * Version: 7.6 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. 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. + */ + +#include "glheader.h" +#include "imports.h" +#include "accum.h" +#include "arrayobj.h" +#include "attrib.h" +#include "blend.h" +#include "buffers.h" +#include "bufferobj.h" +#include "clear.h" +#include "colormac.h" +#include "context.h" +#include "depth.h" +#include "enable.h" +#include "enums.h" +#include "fog.h" +#include "hint.h" +#include "light.h" +#include "lines.h" +#include "macros.h" +#include "matrix.h" +#include "mfeatures.h" +#include "multisample.h" +#include "points.h" +#include "polygon.h" +#include "scissor.h" +#include "stencil.h" +#include "texenv.h" +#include "texgen.h" +#include "texobj.h" +#include "texparam.h" +#include "texstate.h" +#include "varray.h" +#include "viewport.h" +#include "mtypes.h" +#include "main/dispatch.h" + + +/** + * glEnable()/glDisable() attribute group (GL_ENABLE_BIT). + */ +struct gl_enable_attrib +{ + GLboolean AlphaTest; + GLboolean AutoNormal; + GLboolean Blend; + GLbitfield ClipPlanes; + GLboolean ColorMaterial; + GLboolean CullFace; + GLboolean DepthClamp; + GLboolean DepthTest; + GLboolean Dither; + GLboolean Fog; + GLboolean Light[MAX_LIGHTS]; + GLboolean Lighting; + GLboolean LineSmooth; + GLboolean LineStipple; + GLboolean IndexLogicOp; + GLboolean ColorLogicOp; + + GLboolean Map1Color4; + GLboolean Map1Index; + GLboolean Map1Normal; + GLboolean Map1TextureCoord1; + GLboolean Map1TextureCoord2; + GLboolean Map1TextureCoord3; + GLboolean Map1TextureCoord4; + GLboolean Map1Vertex3; + GLboolean Map1Vertex4; + GLboolean Map1Attrib[16]; /* GL_NV_vertex_program */ + GLboolean Map2Color4; + GLboolean Map2Index; + GLboolean Map2Normal; + GLboolean Map2TextureCoord1; + GLboolean Map2TextureCoord2; + GLboolean Map2TextureCoord3; + GLboolean Map2TextureCoord4; + GLboolean Map2Vertex3; + GLboolean Map2Vertex4; + GLboolean Map2Attrib[16]; /* GL_NV_vertex_program */ + + GLboolean Normalize; + GLboolean PixelTexture; + GLboolean PointSmooth; + GLboolean PolygonOffsetPoint; + GLboolean PolygonOffsetLine; + GLboolean PolygonOffsetFill; + GLboolean PolygonSmooth; + GLboolean PolygonStipple; + GLboolean RescaleNormals; + GLboolean Scissor; + GLboolean Stencil; + GLboolean StencilTwoSide; /* GL_EXT_stencil_two_side */ + GLboolean MultisampleEnabled; /* GL_ARB_multisample */ + GLboolean SampleAlphaToCoverage; /* GL_ARB_multisample */ + GLboolean SampleAlphaToOne; /* GL_ARB_multisample */ + GLboolean SampleCoverage; /* GL_ARB_multisample */ + GLboolean SampleCoverageInvert; /* GL_ARB_multisample */ + GLboolean RasterPositionUnclipped; /* GL_IBM_rasterpos_clip */ + + GLbitfield Texture[MAX_TEXTURE_UNITS]; + GLbitfield TexGen[MAX_TEXTURE_UNITS]; + + /* GL_ARB_vertex_program / GL_NV_vertex_program */ + GLboolean VertexProgram; + GLboolean VertexProgramPointSize; + GLboolean VertexProgramTwoSide; + + /* GL_ARB_point_sprite / GL_NV_point_sprite */ + GLboolean PointSprite; + GLboolean FragmentShaderATI; +}; + + +/** + * Node for the attribute stack. + */ +struct gl_attrib_node +{ + GLbitfield kind; + void *data; + struct gl_attrib_node *next; +}; + + + +/** + * Special struct for saving/restoring texture state (GL_TEXTURE_BIT) + */ +struct texture_state +{ + struct gl_texture_attrib Texture; /**< The usual context state */ + + /** to save per texture object state (wrap modes, filters, etc): */ + struct gl_texture_object SavedObj[MAX_TEXTURE_UNITS][NUM_TEXTURE_TARGETS]; + + /** + * To save references to texture objects (so they don't get accidentally + * deleted while saved in the attribute stack). + */ + struct gl_texture_object *SavedTexRef[MAX_TEXTURE_UNITS][NUM_TEXTURE_TARGETS]; +}; + + +#if FEATURE_attrib_stack + + +/** + * Allocate new attribute node of given type/kind. Attach payload data. + * Insert it into the linked list named by 'head'. + */ +static void +save_attrib_data(struct gl_attrib_node **head, + GLbitfield kind, void *payload) +{ + struct gl_attrib_node *n = MALLOC_STRUCT(gl_attrib_node); + if (n) { + n->kind = kind; + n->data = payload; + /* insert at head */ + n->next = *head; + *head = n; + } + else { + /* out of memory! */ + } +} + + +void GLAPIENTRY +_mesa_PushAttrib(GLbitfield mask) +{ + struct gl_attrib_node *head; + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glPushAttrib %x\n", (int) mask); + + if (ctx->AttribStackDepth >= MAX_ATTRIB_STACK_DEPTH) { + _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushAttrib" ); + return; + } + + /* Build linked list of attribute nodes which save all attribute */ + /* groups specified by the mask. */ + head = NULL; + + if (mask & GL_ACCUM_BUFFER_BIT) { + struct gl_accum_attrib *attr; + attr = MALLOC_STRUCT( gl_accum_attrib ); + memcpy( attr, &ctx->Accum, sizeof(struct gl_accum_attrib) ); + save_attrib_data(&head, GL_ACCUM_BUFFER_BIT, attr); + } + + if (mask & GL_COLOR_BUFFER_BIT) { + GLuint i; + struct gl_colorbuffer_attrib *attr; + attr = MALLOC_STRUCT( gl_colorbuffer_attrib ); + memcpy( attr, &ctx->Color, sizeof(struct gl_colorbuffer_attrib) ); + /* push the Draw FBO's DrawBuffer[] state, not ctx->Color.DrawBuffer[] */ + for (i = 0; i < ctx->Const.MaxDrawBuffers; i ++) + attr->DrawBuffer[i] = ctx->DrawBuffer->ColorDrawBuffer[i]; + save_attrib_data(&head, GL_COLOR_BUFFER_BIT, attr); + } + + if (mask & GL_CURRENT_BIT) { + struct gl_current_attrib *attr; + FLUSH_CURRENT( ctx, 0 ); + attr = MALLOC_STRUCT( gl_current_attrib ); + memcpy( attr, &ctx->Current, sizeof(struct gl_current_attrib) ); + save_attrib_data(&head, GL_CURRENT_BIT, attr); + } + + if (mask & GL_DEPTH_BUFFER_BIT) { + struct gl_depthbuffer_attrib *attr; + attr = MALLOC_STRUCT( gl_depthbuffer_attrib ); + memcpy( attr, &ctx->Depth, sizeof(struct gl_depthbuffer_attrib) ); + save_attrib_data(&head, GL_DEPTH_BUFFER_BIT, attr); + } + + if (mask & GL_ENABLE_BIT) { + struct gl_enable_attrib *attr; + GLuint i; + attr = MALLOC_STRUCT( gl_enable_attrib ); + /* Copy enable flags from all other attributes into the enable struct. */ + attr->AlphaTest = ctx->Color.AlphaEnabled; + attr->AutoNormal = ctx->Eval.AutoNormal; + attr->Blend = ctx->Color.BlendEnabled; + attr->ClipPlanes = ctx->Transform.ClipPlanesEnabled; + attr->ColorMaterial = ctx->Light.ColorMaterialEnabled; + attr->CullFace = ctx->Polygon.CullFlag; + attr->DepthClamp = ctx->Transform.DepthClamp; + attr->DepthTest = ctx->Depth.Test; + attr->Dither = ctx->Color.DitherFlag; + attr->Fog = ctx->Fog.Enabled; + for (i = 0; i < ctx->Const.MaxLights; i++) { + attr->Light[i] = ctx->Light.Light[i].Enabled; + } + attr->Lighting = ctx->Light.Enabled; + attr->LineSmooth = ctx->Line.SmoothFlag; + attr->LineStipple = ctx->Line.StippleFlag; + attr->IndexLogicOp = ctx->Color.IndexLogicOpEnabled; + attr->ColorLogicOp = ctx->Color.ColorLogicOpEnabled; + attr->Map1Color4 = ctx->Eval.Map1Color4; + attr->Map1Index = ctx->Eval.Map1Index; + attr->Map1Normal = ctx->Eval.Map1Normal; + attr->Map1TextureCoord1 = ctx->Eval.Map1TextureCoord1; + attr->Map1TextureCoord2 = ctx->Eval.Map1TextureCoord2; + attr->Map1TextureCoord3 = ctx->Eval.Map1TextureCoord3; + attr->Map1TextureCoord4 = ctx->Eval.Map1TextureCoord4; + attr->Map1Vertex3 = ctx->Eval.Map1Vertex3; + attr->Map1Vertex4 = ctx->Eval.Map1Vertex4; + memcpy(attr->Map1Attrib, ctx->Eval.Map1Attrib, sizeof(ctx->Eval.Map1Attrib)); + attr->Map2Color4 = ctx->Eval.Map2Color4; + attr->Map2Index = ctx->Eval.Map2Index; + attr->Map2Normal = ctx->Eval.Map2Normal; + attr->Map2TextureCoord1 = ctx->Eval.Map2TextureCoord1; + attr->Map2TextureCoord2 = ctx->Eval.Map2TextureCoord2; + attr->Map2TextureCoord3 = ctx->Eval.Map2TextureCoord3; + attr->Map2TextureCoord4 = ctx->Eval.Map2TextureCoord4; + attr->Map2Vertex3 = ctx->Eval.Map2Vertex3; + attr->Map2Vertex4 = ctx->Eval.Map2Vertex4; + memcpy(attr->Map2Attrib, ctx->Eval.Map2Attrib, sizeof(ctx->Eval.Map2Attrib)); + attr->Normalize = ctx->Transform.Normalize; + attr->RasterPositionUnclipped = ctx->Transform.RasterPositionUnclipped; + attr->PointSmooth = ctx->Point.SmoothFlag; + attr->PointSprite = ctx->Point.PointSprite; + attr->PolygonOffsetPoint = ctx->Polygon.OffsetPoint; + attr->PolygonOffsetLine = ctx->Polygon.OffsetLine; + attr->PolygonOffsetFill = ctx->Polygon.OffsetFill; + attr->PolygonSmooth = ctx->Polygon.SmoothFlag; + attr->PolygonStipple = ctx->Polygon.StippleFlag; + attr->RescaleNormals = ctx->Transform.RescaleNormals; + attr->Scissor = ctx->Scissor.Enabled; + attr->Stencil = ctx->Stencil.Enabled; + attr->StencilTwoSide = ctx->Stencil.TestTwoSide; + attr->MultisampleEnabled = ctx->Multisample.Enabled; + attr->SampleAlphaToCoverage = ctx->Multisample.SampleAlphaToCoverage; + attr->SampleAlphaToOne = ctx->Multisample.SampleAlphaToOne; + attr->SampleCoverage = ctx->Multisample.SampleCoverage; + attr->SampleCoverageInvert = ctx->Multisample.SampleCoverageInvert; + for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { + attr->Texture[i] = ctx->Texture.Unit[i].Enabled; + attr->TexGen[i] = ctx->Texture.Unit[i].TexGenEnabled; + } + /* GL_NV_vertex_program */ + attr->VertexProgram = ctx->VertexProgram.Enabled; + attr->VertexProgramPointSize = ctx->VertexProgram.PointSizeEnabled; + attr->VertexProgramTwoSide = ctx->VertexProgram.TwoSideEnabled; + save_attrib_data(&head, GL_ENABLE_BIT, attr); + } + + if (mask & GL_EVAL_BIT) { + struct gl_eval_attrib *attr; + attr = MALLOC_STRUCT( gl_eval_attrib ); + memcpy( attr, &ctx->Eval, sizeof(struct gl_eval_attrib) ); + save_attrib_data(&head, GL_EVAL_BIT, attr); + } + + if (mask & GL_FOG_BIT) { + struct gl_fog_attrib *attr; + attr = MALLOC_STRUCT( gl_fog_attrib ); + memcpy( attr, &ctx->Fog, sizeof(struct gl_fog_attrib) ); + save_attrib_data(&head, GL_FOG_BIT, attr); + } + + if (mask & GL_HINT_BIT) { + struct gl_hint_attrib *attr; + attr = MALLOC_STRUCT( gl_hint_attrib ); + memcpy( attr, &ctx->Hint, sizeof(struct gl_hint_attrib) ); + save_attrib_data(&head, GL_HINT_BIT, attr); + } + + if (mask & GL_LIGHTING_BIT) { + struct gl_light_attrib *attr; + FLUSH_CURRENT(ctx, 0); /* flush material changes */ + attr = MALLOC_STRUCT( gl_light_attrib ); + memcpy( attr, &ctx->Light, sizeof(struct gl_light_attrib) ); + save_attrib_data(&head, GL_LIGHTING_BIT, attr); + } + + if (mask & GL_LINE_BIT) { + struct gl_line_attrib *attr; + attr = MALLOC_STRUCT( gl_line_attrib ); + memcpy( attr, &ctx->Line, sizeof(struct gl_line_attrib) ); + save_attrib_data(&head, GL_LINE_BIT, attr); + } + + if (mask & GL_LIST_BIT) { + struct gl_list_attrib *attr; + attr = MALLOC_STRUCT( gl_list_attrib ); + memcpy( attr, &ctx->List, sizeof(struct gl_list_attrib) ); + save_attrib_data(&head, GL_LIST_BIT, attr); + } + + if (mask & GL_PIXEL_MODE_BIT) { + struct gl_pixel_attrib *attr; + attr = MALLOC_STRUCT( gl_pixel_attrib ); + memcpy( attr, &ctx->Pixel, sizeof(struct gl_pixel_attrib) ); + /* push the Read FBO's ReadBuffer state, not ctx->Pixel.ReadBuffer */ + attr->ReadBuffer = ctx->ReadBuffer->ColorReadBuffer; + save_attrib_data(&head, GL_PIXEL_MODE_BIT, attr); + } + + if (mask & GL_POINT_BIT) { + struct gl_point_attrib *attr; + attr = MALLOC_STRUCT( gl_point_attrib ); + memcpy( attr, &ctx->Point, sizeof(struct gl_point_attrib) ); + save_attrib_data(&head, GL_POINT_BIT, attr); + } + + if (mask & GL_POLYGON_BIT) { + struct gl_polygon_attrib *attr; + attr = MALLOC_STRUCT( gl_polygon_attrib ); + memcpy( attr, &ctx->Polygon, sizeof(struct gl_polygon_attrib) ); + save_attrib_data(&head, GL_POLYGON_BIT, attr); + } + + if (mask & GL_POLYGON_STIPPLE_BIT) { + GLuint *stipple; + stipple = (GLuint *) MALLOC( 32*sizeof(GLuint) ); + memcpy( stipple, ctx->PolygonStipple, 32*sizeof(GLuint) ); + save_attrib_data(&head, GL_POLYGON_STIPPLE_BIT, stipple); + } + + if (mask & GL_SCISSOR_BIT) { + struct gl_scissor_attrib *attr; + attr = MALLOC_STRUCT( gl_scissor_attrib ); + memcpy( attr, &ctx->Scissor, sizeof(struct gl_scissor_attrib) ); + save_attrib_data(&head, GL_SCISSOR_BIT, attr); + } + + if (mask & GL_STENCIL_BUFFER_BIT) { + struct gl_stencil_attrib *attr; + attr = MALLOC_STRUCT( gl_stencil_attrib ); + memcpy( attr, &ctx->Stencil, sizeof(struct gl_stencil_attrib) ); + save_attrib_data(&head, GL_STENCIL_BUFFER_BIT, attr); + } + + if (mask & GL_TEXTURE_BIT) { + struct texture_state *texstate = CALLOC_STRUCT(texture_state); + GLuint u, tex; + + if (!texstate) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glPushAttrib(GL_TEXTURE_BIT)"); + goto end; + } + + _mesa_lock_context_textures(ctx); + + /* copy/save the bulk of texture state here */ + memcpy(&texstate->Texture, &ctx->Texture, sizeof(ctx->Texture)); + + /* Save references to the currently bound texture objects so they don't + * accidentally get deleted while referenced in the attribute stack. + */ + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { + _mesa_reference_texobj(&texstate->SavedTexRef[u][tex], + ctx->Texture.Unit[u].CurrentTex[tex]); + } + } + + /* copy state/contents of the currently bound texture objects */ + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { + _mesa_copy_texture_object(&texstate->SavedObj[u][tex], + ctx->Texture.Unit[u].CurrentTex[tex]); + } + } + + _mesa_unlock_context_textures(ctx); + + save_attrib_data(&head, GL_TEXTURE_BIT, texstate); + } + + if (mask & GL_TRANSFORM_BIT) { + struct gl_transform_attrib *attr; + attr = MALLOC_STRUCT( gl_transform_attrib ); + memcpy( attr, &ctx->Transform, sizeof(struct gl_transform_attrib) ); + save_attrib_data(&head, GL_TRANSFORM_BIT, attr); + } + + if (mask & GL_VIEWPORT_BIT) { + struct gl_viewport_attrib *attr; + attr = MALLOC_STRUCT( gl_viewport_attrib ); + memcpy( attr, &ctx->Viewport, sizeof(struct gl_viewport_attrib) ); + save_attrib_data(&head, GL_VIEWPORT_BIT, attr); + } + + /* GL_ARB_multisample */ + if (mask & GL_MULTISAMPLE_BIT_ARB) { + struct gl_multisample_attrib *attr; + attr = MALLOC_STRUCT( gl_multisample_attrib ); + memcpy( attr, &ctx->Multisample, sizeof(struct gl_multisample_attrib) ); + save_attrib_data(&head, GL_MULTISAMPLE_BIT_ARB, attr); + } + +end: + ctx->AttribStack[ctx->AttribStackDepth] = head; + ctx->AttribStackDepth++; +} + + + +static void +pop_enable_group(struct gl_context *ctx, const struct gl_enable_attrib *enable) +{ + const GLuint curTexUnitSave = ctx->Texture.CurrentUnit; + GLuint i; + +#define TEST_AND_UPDATE(VALUE, NEWVALUE, ENUM) \ + if ((VALUE) != (NEWVALUE)) { \ + _mesa_set_enable( ctx, ENUM, (NEWVALUE) ); \ + } + + TEST_AND_UPDATE(ctx->Color.AlphaEnabled, enable->AlphaTest, GL_ALPHA_TEST); + if (ctx->Color.BlendEnabled != enable->Blend) { + if (ctx->Extensions.EXT_draw_buffers2) { + GLuint i; + for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { + _mesa_set_enablei(ctx, GL_BLEND, i, (enable->Blend >> i) & 1); + } + } + else { + _mesa_set_enable(ctx, GL_BLEND, (enable->Blend & 1)); + } + } + + for (i=0;i<MAX_CLIP_PLANES;i++) { + const GLuint mask = 1 << i; + if ((ctx->Transform.ClipPlanesEnabled & mask) != (enable->ClipPlanes & mask)) + _mesa_set_enable(ctx, (GLenum) (GL_CLIP_PLANE0 + i), + (GLboolean) ((enable->ClipPlanes & mask) ? GL_TRUE : GL_FALSE)); + } + + TEST_AND_UPDATE(ctx->Light.ColorMaterialEnabled, enable->ColorMaterial, + GL_COLOR_MATERIAL); + TEST_AND_UPDATE(ctx->Polygon.CullFlag, enable->CullFace, GL_CULL_FACE); + TEST_AND_UPDATE(ctx->Transform.DepthClamp, enable->DepthClamp, + GL_DEPTH_CLAMP); + TEST_AND_UPDATE(ctx->Depth.Test, enable->DepthTest, GL_DEPTH_TEST); + TEST_AND_UPDATE(ctx->Color.DitherFlag, enable->Dither, GL_DITHER); + TEST_AND_UPDATE(ctx->Fog.Enabled, enable->Fog, GL_FOG); + TEST_AND_UPDATE(ctx->Light.Enabled, enable->Lighting, GL_LIGHTING); + TEST_AND_UPDATE(ctx->Line.SmoothFlag, enable->LineSmooth, GL_LINE_SMOOTH); + TEST_AND_UPDATE(ctx->Line.StippleFlag, enable->LineStipple, + GL_LINE_STIPPLE); + TEST_AND_UPDATE(ctx->Color.IndexLogicOpEnabled, enable->IndexLogicOp, + GL_INDEX_LOGIC_OP); + TEST_AND_UPDATE(ctx->Color.ColorLogicOpEnabled, enable->ColorLogicOp, + GL_COLOR_LOGIC_OP); + + TEST_AND_UPDATE(ctx->Eval.Map1Color4, enable->Map1Color4, GL_MAP1_COLOR_4); + TEST_AND_UPDATE(ctx->Eval.Map1Index, enable->Map1Index, GL_MAP1_INDEX); + TEST_AND_UPDATE(ctx->Eval.Map1Normal, enable->Map1Normal, GL_MAP1_NORMAL); + TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord1, enable->Map1TextureCoord1, + GL_MAP1_TEXTURE_COORD_1); + TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord2, enable->Map1TextureCoord2, + GL_MAP1_TEXTURE_COORD_2); + TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord3, enable->Map1TextureCoord3, + GL_MAP1_TEXTURE_COORD_3); + TEST_AND_UPDATE(ctx->Eval.Map1TextureCoord4, enable->Map1TextureCoord4, + GL_MAP1_TEXTURE_COORD_4); + TEST_AND_UPDATE(ctx->Eval.Map1Vertex3, enable->Map1Vertex3, + GL_MAP1_VERTEX_3); + TEST_AND_UPDATE(ctx->Eval.Map1Vertex4, enable->Map1Vertex4, + GL_MAP1_VERTEX_4); + for (i = 0; i < 16; i++) { + TEST_AND_UPDATE(ctx->Eval.Map1Attrib[i], enable->Map1Attrib[i], + GL_MAP1_VERTEX_ATTRIB0_4_NV + i); + } + + TEST_AND_UPDATE(ctx->Eval.Map2Color4, enable->Map2Color4, GL_MAP2_COLOR_4); + TEST_AND_UPDATE(ctx->Eval.Map2Index, enable->Map2Index, GL_MAP2_INDEX); + TEST_AND_UPDATE(ctx->Eval.Map2Normal, enable->Map2Normal, GL_MAP2_NORMAL); + TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord1, enable->Map2TextureCoord1, + GL_MAP2_TEXTURE_COORD_1); + TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord2, enable->Map2TextureCoord2, + GL_MAP2_TEXTURE_COORD_2); + TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord3, enable->Map2TextureCoord3, + GL_MAP2_TEXTURE_COORD_3); + TEST_AND_UPDATE(ctx->Eval.Map2TextureCoord4, enable->Map2TextureCoord4, + GL_MAP2_TEXTURE_COORD_4); + TEST_AND_UPDATE(ctx->Eval.Map2Vertex3, enable->Map2Vertex3, + GL_MAP2_VERTEX_3); + TEST_AND_UPDATE(ctx->Eval.Map2Vertex4, enable->Map2Vertex4, + GL_MAP2_VERTEX_4); + for (i = 0; i < 16; i++) { + TEST_AND_UPDATE(ctx->Eval.Map2Attrib[i], enable->Map2Attrib[i], + GL_MAP2_VERTEX_ATTRIB0_4_NV + i); + } + + TEST_AND_UPDATE(ctx->Eval.AutoNormal, enable->AutoNormal, GL_AUTO_NORMAL); + TEST_AND_UPDATE(ctx->Transform.Normalize, enable->Normalize, GL_NORMALIZE); + TEST_AND_UPDATE(ctx->Transform.RescaleNormals, enable->RescaleNormals, + GL_RESCALE_NORMAL_EXT); + TEST_AND_UPDATE(ctx->Transform.RasterPositionUnclipped, + enable->RasterPositionUnclipped, + GL_RASTER_POSITION_UNCLIPPED_IBM); + TEST_AND_UPDATE(ctx->Point.SmoothFlag, enable->PointSmooth, + GL_POINT_SMOOTH); + if (ctx->Extensions.NV_point_sprite || ctx->Extensions.ARB_point_sprite) { + TEST_AND_UPDATE(ctx->Point.PointSprite, enable->PointSprite, + GL_POINT_SPRITE_NV); + } + TEST_AND_UPDATE(ctx->Polygon.OffsetPoint, enable->PolygonOffsetPoint, + GL_POLYGON_OFFSET_POINT); + TEST_AND_UPDATE(ctx->Polygon.OffsetLine, enable->PolygonOffsetLine, + GL_POLYGON_OFFSET_LINE); + TEST_AND_UPDATE(ctx->Polygon.OffsetFill, enable->PolygonOffsetFill, + GL_POLYGON_OFFSET_FILL); + TEST_AND_UPDATE(ctx->Polygon.SmoothFlag, enable->PolygonSmooth, + GL_POLYGON_SMOOTH); + TEST_AND_UPDATE(ctx->Polygon.StippleFlag, enable->PolygonStipple, + GL_POLYGON_STIPPLE); + TEST_AND_UPDATE(ctx->Scissor.Enabled, enable->Scissor, GL_SCISSOR_TEST); + TEST_AND_UPDATE(ctx->Stencil.Enabled, enable->Stencil, GL_STENCIL_TEST); + if (ctx->Extensions.EXT_stencil_two_side) { + TEST_AND_UPDATE(ctx->Stencil.TestTwoSide, enable->StencilTwoSide, GL_STENCIL_TEST_TWO_SIDE_EXT); + } + TEST_AND_UPDATE(ctx->Multisample.Enabled, enable->MultisampleEnabled, + GL_MULTISAMPLE_ARB); + TEST_AND_UPDATE(ctx->Multisample.SampleAlphaToCoverage, + enable->SampleAlphaToCoverage, + GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); + TEST_AND_UPDATE(ctx->Multisample.SampleAlphaToOne, + enable->SampleAlphaToOne, + GL_SAMPLE_ALPHA_TO_ONE_ARB); + TEST_AND_UPDATE(ctx->Multisample.SampleCoverage, + enable->SampleCoverage, + GL_SAMPLE_COVERAGE_ARB); + TEST_AND_UPDATE(ctx->Multisample.SampleCoverageInvert, + enable->SampleCoverageInvert, + GL_SAMPLE_COVERAGE_INVERT_ARB); + /* GL_ARB_vertex_program, GL_NV_vertex_program */ + TEST_AND_UPDATE(ctx->VertexProgram.Enabled, + enable->VertexProgram, + GL_VERTEX_PROGRAM_ARB); + TEST_AND_UPDATE(ctx->VertexProgram.PointSizeEnabled, + enable->VertexProgramPointSize, + GL_VERTEX_PROGRAM_POINT_SIZE_ARB); + TEST_AND_UPDATE(ctx->VertexProgram.TwoSideEnabled, + enable->VertexProgramTwoSide, + GL_VERTEX_PROGRAM_TWO_SIDE_ARB); + +#undef TEST_AND_UPDATE + + /* texture unit enables */ + for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { + const GLbitfield enabled = enable->Texture[i]; + const GLbitfield genEnabled = enable->TexGen[i]; + + if (ctx->Texture.Unit[i].Enabled != enabled) { + _mesa_ActiveTextureARB(GL_TEXTURE0 + i); + + _mesa_set_enable(ctx, GL_TEXTURE_1D, + (enabled & TEXTURE_1D_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_2D, + (enabled & TEXTURE_2D_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_3D, + (enabled & TEXTURE_3D_BIT) ? GL_TRUE : GL_FALSE); + if (ctx->Extensions.NV_texture_rectangle) { + _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE_ARB, + (enabled & TEXTURE_RECT_BIT) ? GL_TRUE : GL_FALSE); + } + if (ctx->Extensions.ARB_texture_cube_map) { + _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, + (enabled & TEXTURE_CUBE_BIT) ? GL_TRUE : GL_FALSE); + } + if (ctx->Extensions.MESA_texture_array) { + _mesa_set_enable(ctx, GL_TEXTURE_1D_ARRAY_EXT, + (enabled & TEXTURE_1D_ARRAY_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_2D_ARRAY_EXT, + (enabled & TEXTURE_2D_ARRAY_BIT) ? GL_TRUE : GL_FALSE); + } + } + + if (ctx->Texture.Unit[i].TexGenEnabled != genEnabled) { + _mesa_ActiveTextureARB(GL_TEXTURE0 + i); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, + (genEnabled & S_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, + (genEnabled & T_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, + (genEnabled & R_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, + (genEnabled & Q_BIT) ? GL_TRUE : GL_FALSE); + } + } + + _mesa_ActiveTextureARB(GL_TEXTURE0 + curTexUnitSave); +} + + +/** + * Pop/restore texture attribute/group state. + */ +static void +pop_texture_group(struct gl_context *ctx, struct texture_state *texstate) +{ + GLuint u; + + _mesa_lock_context_textures(ctx); + + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + const struct gl_texture_unit *unit = &texstate->Texture.Unit[u]; + GLuint tgt; + + _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + u); + _mesa_set_enable(ctx, GL_TEXTURE_1D, + (unit->Enabled & TEXTURE_1D_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_2D, + (unit->Enabled & TEXTURE_2D_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_3D, + (unit->Enabled & TEXTURE_3D_BIT) ? GL_TRUE : GL_FALSE); + if (ctx->Extensions.ARB_texture_cube_map) { + _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP_ARB, + (unit->Enabled & TEXTURE_CUBE_BIT) ? GL_TRUE : GL_FALSE); + } + if (ctx->Extensions.NV_texture_rectangle) { + _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE_NV, + (unit->Enabled & TEXTURE_RECT_BIT) ? GL_TRUE : GL_FALSE); + } + if (ctx->Extensions.MESA_texture_array) { + _mesa_set_enable(ctx, GL_TEXTURE_1D_ARRAY_EXT, + (unit->Enabled & TEXTURE_1D_ARRAY_BIT) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_2D_ARRAY_EXT, + (unit->Enabled & TEXTURE_2D_ARRAY_BIT) ? GL_TRUE : GL_FALSE); + } + + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->EnvMode); + _mesa_TexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, unit->EnvColor); + _mesa_TexGeni(GL_S, GL_TEXTURE_GEN_MODE, unit->GenS.Mode); + _mesa_TexGeni(GL_T, GL_TEXTURE_GEN_MODE, unit->GenT.Mode); + _mesa_TexGeni(GL_R, GL_TEXTURE_GEN_MODE, unit->GenR.Mode); + _mesa_TexGeni(GL_Q, GL_TEXTURE_GEN_MODE, unit->GenQ.Mode); + _mesa_TexGenfv(GL_S, GL_OBJECT_PLANE, unit->GenS.ObjectPlane); + _mesa_TexGenfv(GL_T, GL_OBJECT_PLANE, unit->GenT.ObjectPlane); + _mesa_TexGenfv(GL_R, GL_OBJECT_PLANE, unit->GenR.ObjectPlane); + _mesa_TexGenfv(GL_Q, GL_OBJECT_PLANE, unit->GenQ.ObjectPlane); + /* Eye plane done differently to avoid re-transformation */ + { + struct gl_texture_unit *destUnit = &ctx->Texture.Unit[u]; + COPY_4FV(destUnit->GenS.EyePlane, unit->GenS.EyePlane); + COPY_4FV(destUnit->GenT.EyePlane, unit->GenT.EyePlane); + COPY_4FV(destUnit->GenR.EyePlane, unit->GenR.EyePlane); + COPY_4FV(destUnit->GenQ.EyePlane, unit->GenQ.EyePlane); + if (ctx->Driver.TexGen) { + ctx->Driver.TexGen(ctx, GL_S, GL_EYE_PLANE, unit->GenS.EyePlane); + ctx->Driver.TexGen(ctx, GL_T, GL_EYE_PLANE, unit->GenT.EyePlane); + ctx->Driver.TexGen(ctx, GL_R, GL_EYE_PLANE, unit->GenR.EyePlane); + ctx->Driver.TexGen(ctx, GL_Q, GL_EYE_PLANE, unit->GenQ.EyePlane); + } + } + _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, + ((unit->TexGenEnabled & S_BIT) ? GL_TRUE : GL_FALSE)); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, + ((unit->TexGenEnabled & T_BIT) ? GL_TRUE : GL_FALSE)); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, + ((unit->TexGenEnabled & R_BIT) ? GL_TRUE : GL_FALSE)); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, + ((unit->TexGenEnabled & Q_BIT) ? GL_TRUE : GL_FALSE)); + if (ctx->Extensions.EXT_texture_lod_bias) { + _mesa_TexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, + GL_TEXTURE_LOD_BIAS_EXT, unit->LodBias); + } + if (ctx->Extensions.EXT_texture_env_combine || + ctx->Extensions.ARB_texture_env_combine) { + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, + unit->Combine.ModeRGB); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, + unit->Combine.ModeA); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, + unit->Combine.SourceRGB[0]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, + unit->Combine.SourceRGB[1]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, + unit->Combine.SourceRGB[2]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, + unit->Combine.SourceA[0]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, + unit->Combine.SourceA[1]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, + unit->Combine.SourceA[2]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, + unit->Combine.OperandRGB[0]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, + unit->Combine.OperandRGB[1]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, + unit->Combine.OperandRGB[2]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, + unit->Combine.OperandA[0]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, + unit->Combine.OperandA[1]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, + unit->Combine.OperandA[2]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, + 1 << unit->Combine.ScaleShiftRGB); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, + 1 << unit->Combine.ScaleShiftA); + } + + /* Restore texture object state for each target */ + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + const struct gl_texture_object *obj = NULL; + GLenum target; + + obj = &texstate->SavedObj[u][tgt]; + + /* don't restore state for unsupported targets to prevent + * raising GL errors. + */ + if (obj->Target == GL_TEXTURE_CUBE_MAP_ARB && + !ctx->Extensions.ARB_texture_cube_map) { + continue; + } + else if (obj->Target == GL_TEXTURE_RECTANGLE_NV && + !ctx->Extensions.NV_texture_rectangle) { + continue; + } + else if ((obj->Target == GL_TEXTURE_1D_ARRAY_EXT || + obj->Target == GL_TEXTURE_2D_ARRAY_EXT) && + !ctx->Extensions.MESA_texture_array) { + continue; + } + + target = obj->Target; + + _mesa_BindTexture(target, obj->Name); + + _mesa_TexParameterfv(target, GL_TEXTURE_BORDER_COLOR, obj->BorderColor.f); + _mesa_TexParameterf(target, GL_TEXTURE_PRIORITY, obj->Priority); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, obj->WrapS); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, obj->WrapT); + _mesa_TexParameteri(target, GL_TEXTURE_WRAP_R, obj->WrapR); + _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, obj->MinFilter); + _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, obj->MagFilter); + _mesa_TexParameterf(target, GL_TEXTURE_MIN_LOD, obj->MinLod); + _mesa_TexParameterf(target, GL_TEXTURE_MAX_LOD, obj->MaxLod); + _mesa_TexParameterf(target, GL_TEXTURE_LOD_BIAS, obj->LodBias); + _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, obj->BaseLevel); + if (target != GL_TEXTURE_RECTANGLE_ARB) + _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, obj->MaxLevel); + if (ctx->Extensions.EXT_texture_filter_anisotropic) { + _mesa_TexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, + obj->MaxAnisotropy); + } + if (ctx->Extensions.ARB_shadow_ambient) { + _mesa_TexParameterf(target, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, + obj->CompareFailValue); + } + } + + /* remove saved references to the texture objects */ + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + _mesa_reference_texobj(&texstate->SavedTexRef[u][tgt], NULL); + } + } + + _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + texstate->Texture.CurrentUnit); + + _mesa_unlock_context_textures(ctx); +} + + +/* + * This function is kind of long just because we have to call a lot + * of device driver functions to update device driver state. + * + * XXX As it is now, most of the pop-code calls immediate-mode Mesa functions + * in order to restore GL state. This isn't terribly efficient but it + * ensures that dirty flags and any derived state gets updated correctly. + * We could at least check if the value to restore equals the current value + * and then skip the Mesa call. + */ +void GLAPIENTRY +_mesa_PopAttrib(void) +{ + struct gl_attrib_node *attr, *next; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (ctx->AttribStackDepth == 0) { + _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopAttrib" ); + return; + } + + ctx->AttribStackDepth--; + attr = ctx->AttribStack[ctx->AttribStackDepth]; + + while (attr) { + + if (MESA_VERBOSE & VERBOSE_API) { + _mesa_debug(ctx, "glPopAttrib %s\n", + _mesa_lookup_enum_by_nr(attr->kind)); + } + + switch (attr->kind) { + case GL_ACCUM_BUFFER_BIT: + { + const struct gl_accum_attrib *accum; + accum = (const struct gl_accum_attrib *) attr->data; + _mesa_ClearAccum(accum->ClearColor[0], + accum->ClearColor[1], + accum->ClearColor[2], + accum->ClearColor[3]); + } + break; + case GL_COLOR_BUFFER_BIT: + { + const struct gl_colorbuffer_attrib *color; + + color = (const struct gl_colorbuffer_attrib *) attr->data; + _mesa_ClearIndex((GLfloat) color->ClearIndex); + _mesa_ClearColor(color->ClearColor[0], + color->ClearColor[1], + color->ClearColor[2], + color->ClearColor[3]); + _mesa_IndexMask(color->IndexMask); + if (!ctx->Extensions.EXT_draw_buffers2) { + _mesa_ColorMask((GLboolean) (color->ColorMask[0][0] != 0), + (GLboolean) (color->ColorMask[0][1] != 0), + (GLboolean) (color->ColorMask[0][2] != 0), + (GLboolean) (color->ColorMask[0][3] != 0)); + } + else { + GLuint i; + for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { + _mesa_ColorMaskIndexed(i, + (GLboolean) (color->ColorMask[i][0] != 0), + (GLboolean) (color->ColorMask[i][1] != 0), + (GLboolean) (color->ColorMask[i][2] != 0), + (GLboolean) (color->ColorMask[i][3] != 0)); + } + } + { + /* Need to determine if more than one color output is + * specified. If so, call glDrawBuffersARB, else call + * glDrawBuffer(). This is a subtle, but essential point + * since GL_FRONT (for example) is illegal for the former + * function, but legal for the later. + */ + GLboolean multipleBuffers = GL_FALSE; + GLuint i; + + for (i = 1; i < ctx->Const.MaxDrawBuffers; i++) { + if (color->DrawBuffer[i] != GL_NONE) { + multipleBuffers = GL_TRUE; + break; + } + } + /* Call the API_level functions, not _mesa_drawbuffers() + * since we need to do error checking on the pop'd + * GL_DRAW_BUFFER. + * Ex: if GL_FRONT were pushed, but we're popping with a + * user FBO bound, GL_FRONT will be illegal and we'll need + * to record that error. Per OpenGL ARB decision. + */ + if (multipleBuffers) + _mesa_DrawBuffersARB(ctx->Const.MaxDrawBuffers, + color->DrawBuffer); + else + _mesa_DrawBuffer(color->DrawBuffer[0]); + } + _mesa_set_enable(ctx, GL_ALPHA_TEST, color->AlphaEnabled); + _mesa_AlphaFunc(color->AlphaFunc, color->AlphaRef); + if (ctx->Color.BlendEnabled != color->BlendEnabled) { + if (ctx->Extensions.EXT_draw_buffers2) { + GLuint i; + for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { + _mesa_set_enablei(ctx, GL_BLEND, i, + (color->BlendEnabled >> i) & 1); + } + } + else { + _mesa_set_enable(ctx, GL_BLEND, (color->BlendEnabled & 1)); + } + } + if (ctx->Color._BlendFuncPerBuffer || + ctx->Color._BlendEquationPerBuffer) { + /* set blend per buffer */ + GLuint buf; + for (buf = 0; buf < ctx->Const.MaxDrawBuffers; buf++) { + _mesa_BlendFuncSeparatei(buf, color->Blend[buf].SrcRGB, + color->Blend[buf].DstRGB, + color->Blend[buf].SrcA, + color->Blend[buf].DstA); + _mesa_BlendEquationSeparatei(buf, + color->Blend[buf].EquationRGB, + color->Blend[buf].EquationA); + } + } + else { + /* set same blend modes for all buffers */ + _mesa_BlendFuncSeparateEXT(color->Blend[0].SrcRGB, + color->Blend[0].DstRGB, + color->Blend[0].SrcA, + color->Blend[0].DstA); + /* This special case is because glBlendEquationSeparateEXT + * cannot take GL_LOGIC_OP as a parameter. + */ + if (color->Blend[0].EquationRGB == + color->Blend[0].EquationA) { + _mesa_BlendEquation(color->Blend[0].EquationRGB); + } + else { + _mesa_BlendEquationSeparateEXT( + color->Blend[0].EquationRGB, + color->Blend[0].EquationA); + } + } + _mesa_BlendColor(color->BlendColor[0], + color->BlendColor[1], + color->BlendColor[2], + color->BlendColor[3]); + _mesa_LogicOp(color->LogicOp); + _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, + color->ColorLogicOpEnabled); + _mesa_set_enable(ctx, GL_INDEX_LOGIC_OP, + color->IndexLogicOpEnabled); + _mesa_set_enable(ctx, GL_DITHER, color->DitherFlag); + } + break; + case GL_CURRENT_BIT: + FLUSH_CURRENT( ctx, 0 ); + memcpy( &ctx->Current, attr->data, + sizeof(struct gl_current_attrib) ); + break; + case GL_DEPTH_BUFFER_BIT: + { + const struct gl_depthbuffer_attrib *depth; + depth = (const struct gl_depthbuffer_attrib *) attr->data; + _mesa_DepthFunc(depth->Func); + _mesa_ClearDepth(depth->Clear); + _mesa_set_enable(ctx, GL_DEPTH_TEST, depth->Test); + _mesa_DepthMask(depth->Mask); + } + break; + case GL_ENABLE_BIT: + { + const struct gl_enable_attrib *enable; + enable = (const struct gl_enable_attrib *) attr->data; + pop_enable_group(ctx, enable); + ctx->NewState |= _NEW_ALL; + } + break; + case GL_EVAL_BIT: + memcpy( &ctx->Eval, attr->data, sizeof(struct gl_eval_attrib) ); + ctx->NewState |= _NEW_EVAL; + break; + case GL_FOG_BIT: + { + const struct gl_fog_attrib *fog; + fog = (const struct gl_fog_attrib *) attr->data; + _mesa_set_enable(ctx, GL_FOG, fog->Enabled); + _mesa_Fogfv(GL_FOG_COLOR, fog->Color); + _mesa_Fogf(GL_FOG_DENSITY, fog->Density); + _mesa_Fogf(GL_FOG_START, fog->Start); + _mesa_Fogf(GL_FOG_END, fog->End); + _mesa_Fogf(GL_FOG_INDEX, fog->Index); + _mesa_Fogi(GL_FOG_MODE, fog->Mode); + } + break; + case GL_HINT_BIT: + { + const struct gl_hint_attrib *hint; + hint = (const struct gl_hint_attrib *) attr->data; + _mesa_Hint(GL_PERSPECTIVE_CORRECTION_HINT, + hint->PerspectiveCorrection ); + _mesa_Hint(GL_POINT_SMOOTH_HINT, hint->PointSmooth); + _mesa_Hint(GL_LINE_SMOOTH_HINT, hint->LineSmooth); + _mesa_Hint(GL_POLYGON_SMOOTH_HINT, hint->PolygonSmooth); + _mesa_Hint(GL_FOG_HINT, hint->Fog); + _mesa_Hint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, + hint->ClipVolumeClipping); + _mesa_Hint(GL_TEXTURE_COMPRESSION_HINT_ARB, + hint->TextureCompression); + } + break; + case GL_LIGHTING_BIT: + { + GLuint i; + const struct gl_light_attrib *light; + light = (const struct gl_light_attrib *) attr->data; + /* lighting enable */ + _mesa_set_enable(ctx, GL_LIGHTING, light->Enabled); + /* per-light state */ + if (_math_matrix_is_dirty(ctx->ModelviewMatrixStack.Top)) + _math_matrix_analyse( ctx->ModelviewMatrixStack.Top ); + + for (i = 0; i < ctx->Const.MaxLights; i++) { + const struct gl_light *l = &light->Light[i]; + _mesa_set_enable(ctx, GL_LIGHT0 + i, l->Enabled); + _mesa_light(ctx, i, GL_AMBIENT, l->Ambient); + _mesa_light(ctx, i, GL_DIFFUSE, l->Diffuse); + _mesa_light(ctx, i, GL_SPECULAR, l->Specular ); + _mesa_light(ctx, i, GL_POSITION, l->EyePosition); + _mesa_light(ctx, i, GL_SPOT_DIRECTION, l->SpotDirection); + { + GLfloat p[4] = { 0 }; + p[0] = l->SpotExponent; + _mesa_light(ctx, i, GL_SPOT_EXPONENT, p); + } + { + GLfloat p[4] = { 0 }; + p[0] = l->SpotCutoff; + _mesa_light(ctx, i, GL_SPOT_CUTOFF, p); + } + { + GLfloat p[4] = { 0 }; + p[0] = l->ConstantAttenuation; + _mesa_light(ctx, i, GL_CONSTANT_ATTENUATION, p); + } + { + GLfloat p[4] = { 0 }; + p[0] = l->LinearAttenuation; + _mesa_light(ctx, i, GL_LINEAR_ATTENUATION, p); + } + { + GLfloat p[4] = { 0 }; + p[0] = l->QuadraticAttenuation; + _mesa_light(ctx, i, GL_QUADRATIC_ATTENUATION, p); + } + } + /* light model */ + _mesa_LightModelfv(GL_LIGHT_MODEL_AMBIENT, + light->Model.Ambient); + _mesa_LightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, + (GLfloat) light->Model.LocalViewer); + _mesa_LightModelf(GL_LIGHT_MODEL_TWO_SIDE, + (GLfloat) light->Model.TwoSide); + _mesa_LightModelf(GL_LIGHT_MODEL_COLOR_CONTROL, + (GLfloat) light->Model.ColorControl); + /* shade model */ + _mesa_ShadeModel(light->ShadeModel); + /* color material */ + _mesa_ColorMaterial(light->ColorMaterialFace, + light->ColorMaterialMode); + _mesa_set_enable(ctx, GL_COLOR_MATERIAL, + light->ColorMaterialEnabled); + /* materials */ + memcpy(&ctx->Light.Material, &light->Material, + sizeof(struct gl_material)); + } + break; + case GL_LINE_BIT: + { + const struct gl_line_attrib *line; + line = (const struct gl_line_attrib *) attr->data; + _mesa_set_enable(ctx, GL_LINE_SMOOTH, line->SmoothFlag); + _mesa_set_enable(ctx, GL_LINE_STIPPLE, line->StippleFlag); + _mesa_LineStipple(line->StippleFactor, line->StipplePattern); + _mesa_LineWidth(line->Width); + } + break; + case GL_LIST_BIT: + memcpy( &ctx->List, attr->data, sizeof(struct gl_list_attrib) ); + break; + case GL_PIXEL_MODE_BIT: + memcpy( &ctx->Pixel, attr->data, sizeof(struct gl_pixel_attrib) ); + /* XXX what other pixel state needs to be set by function calls? */ + _mesa_ReadBuffer(ctx->Pixel.ReadBuffer); + ctx->NewState |= _NEW_PIXEL; + break; + case GL_POINT_BIT: + { + const struct gl_point_attrib *point; + point = (const struct gl_point_attrib *) attr->data; + _mesa_PointSize(point->Size); + _mesa_set_enable(ctx, GL_POINT_SMOOTH, point->SmoothFlag); + if (ctx->Extensions.EXT_point_parameters) { + _mesa_PointParameterfv(GL_DISTANCE_ATTENUATION_EXT, + point->Params); + _mesa_PointParameterf(GL_POINT_SIZE_MIN_EXT, + point->MinSize); + _mesa_PointParameterf(GL_POINT_SIZE_MAX_EXT, + point->MaxSize); + _mesa_PointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_EXT, + point->Threshold); + } + if (ctx->Extensions.NV_point_sprite + || ctx->Extensions.ARB_point_sprite) { + GLuint u; + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + _mesa_TexEnvi(GL_POINT_SPRITE_NV, GL_COORD_REPLACE_NV, + (GLint) point->CoordReplace[u]); + } + _mesa_set_enable(ctx, GL_POINT_SPRITE_NV,point->PointSprite); + if (ctx->Extensions.NV_point_sprite) + _mesa_PointParameteri(GL_POINT_SPRITE_R_MODE_NV, + ctx->Point.SpriteRMode); + _mesa_PointParameterf(GL_POINT_SPRITE_COORD_ORIGIN, + (GLfloat)ctx->Point.SpriteOrigin); + } + } + break; + case GL_POLYGON_BIT: + { + const struct gl_polygon_attrib *polygon; + polygon = (const struct gl_polygon_attrib *) attr->data; + _mesa_CullFace(polygon->CullFaceMode); + _mesa_FrontFace(polygon->FrontFace); + _mesa_PolygonMode(GL_FRONT, polygon->FrontMode); + _mesa_PolygonMode(GL_BACK, polygon->BackMode); + _mesa_PolygonOffset(polygon->OffsetFactor, + polygon->OffsetUnits); + _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, polygon->SmoothFlag); + _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, polygon->StippleFlag); + _mesa_set_enable(ctx, GL_CULL_FACE, polygon->CullFlag); + _mesa_set_enable(ctx, GL_POLYGON_OFFSET_POINT, + polygon->OffsetPoint); + _mesa_set_enable(ctx, GL_POLYGON_OFFSET_LINE, + polygon->OffsetLine); + _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, + polygon->OffsetFill); + } + break; + case GL_POLYGON_STIPPLE_BIT: + memcpy( ctx->PolygonStipple, attr->data, 32*sizeof(GLuint) ); + ctx->NewState |= _NEW_POLYGONSTIPPLE; + if (ctx->Driver.PolygonStipple) + ctx->Driver.PolygonStipple( ctx, (const GLubyte *) attr->data ); + break; + case GL_SCISSOR_BIT: + { + const struct gl_scissor_attrib *scissor; + scissor = (const struct gl_scissor_attrib *) attr->data; + _mesa_Scissor(scissor->X, scissor->Y, + scissor->Width, scissor->Height); + _mesa_set_enable(ctx, GL_SCISSOR_TEST, scissor->Enabled); + } + break; + case GL_STENCIL_BUFFER_BIT: + { + const struct gl_stencil_attrib *stencil; + stencil = (const struct gl_stencil_attrib *) attr->data; + _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled); + _mesa_ClearStencil(stencil->Clear); + if (ctx->Extensions.EXT_stencil_two_side) { + _mesa_set_enable(ctx, GL_STENCIL_TEST_TWO_SIDE_EXT, + stencil->TestTwoSide); + _mesa_ActiveStencilFaceEXT(stencil->ActiveFace + ? GL_BACK : GL_FRONT); + } + /* front state */ + _mesa_StencilFuncSeparate(GL_FRONT, + stencil->Function[0], + stencil->Ref[0], + stencil->ValueMask[0]); + _mesa_StencilMaskSeparate(GL_FRONT, stencil->WriteMask[0]); + _mesa_StencilOpSeparate(GL_FRONT, stencil->FailFunc[0], + stencil->ZFailFunc[0], + stencil->ZPassFunc[0]); + /* back state */ + _mesa_StencilFuncSeparate(GL_BACK, + stencil->Function[1], + stencil->Ref[1], + stencil->ValueMask[1]); + _mesa_StencilMaskSeparate(GL_BACK, stencil->WriteMask[1]); + _mesa_StencilOpSeparate(GL_BACK, stencil->FailFunc[1], + stencil->ZFailFunc[1], + stencil->ZPassFunc[1]); + } + break; + case GL_TRANSFORM_BIT: + { + GLuint i; + const struct gl_transform_attrib *xform; + xform = (const struct gl_transform_attrib *) attr->data; + _mesa_MatrixMode(xform->MatrixMode); + if (_math_matrix_is_dirty(ctx->ProjectionMatrixStack.Top)) + _math_matrix_analyse( ctx->ProjectionMatrixStack.Top ); + + /* restore clip planes */ + for (i = 0; i < MAX_CLIP_PLANES; i++) { + const GLuint mask = 1 << i; + const GLfloat *eyePlane = xform->EyeUserPlane[i]; + COPY_4V(ctx->Transform.EyeUserPlane[i], eyePlane); + if (xform->ClipPlanesEnabled & mask) { + _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_TRUE); + } + else { + _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_FALSE); + } + if (ctx->Driver.ClipPlane) + ctx->Driver.ClipPlane( ctx, GL_CLIP_PLANE0 + i, eyePlane ); + } + + /* normalize/rescale */ + if (xform->Normalize != ctx->Transform.Normalize) + _mesa_set_enable(ctx, GL_NORMALIZE,ctx->Transform.Normalize); + if (xform->RescaleNormals != ctx->Transform.RescaleNormals) + _mesa_set_enable(ctx, GL_RESCALE_NORMAL_EXT, + ctx->Transform.RescaleNormals); + if (xform->DepthClamp != ctx->Transform.DepthClamp) + _mesa_set_enable(ctx, GL_DEPTH_CLAMP, + ctx->Transform.DepthClamp); + } + break; + case GL_TEXTURE_BIT: + /* Take care of texture object reference counters */ + { + struct texture_state *texstate + = (struct texture_state *) attr->data; + pop_texture_group(ctx, texstate); + ctx->NewState |= _NEW_TEXTURE; + } + break; + case GL_VIEWPORT_BIT: + { + const struct gl_viewport_attrib *vp; + vp = (const struct gl_viewport_attrib *) attr->data; + _mesa_Viewport(vp->X, vp->Y, vp->Width, vp->Height); + _mesa_DepthRange(vp->Near, vp->Far); + } + break; + case GL_MULTISAMPLE_BIT_ARB: + { + const struct gl_multisample_attrib *ms; + ms = (const struct gl_multisample_attrib *) attr->data; + _mesa_SampleCoverageARB(ms->SampleCoverageValue, + ms->SampleCoverageInvert); + } + break; + + default: + _mesa_problem( ctx, "Bad attrib flag in PopAttrib"); + break; + } + + next = attr->next; + FREE( attr->data ); + FREE( attr ); + attr = next; + } +} + + +/** + * Helper for incrementing/decrementing vertex buffer object reference + * counts when pushing/popping the GL_CLIENT_VERTEX_ARRAY_BIT attribute group. + */ +static void +adjust_buffer_object_ref_counts(struct gl_array_object *arrayObj, GLint step) +{ + GLuint i; + + arrayObj->Vertex.BufferObj->RefCount += step; + arrayObj->Weight.BufferObj->RefCount += step; + arrayObj->Normal.BufferObj->RefCount += step; + arrayObj->Color.BufferObj->RefCount += step; + arrayObj->SecondaryColor.BufferObj->RefCount += step; + arrayObj->FogCoord.BufferObj->RefCount += step; + arrayObj->Index.BufferObj->RefCount += step; + arrayObj->EdgeFlag.BufferObj->RefCount += step; + for (i = 0; i < Elements(arrayObj->TexCoord); i++) + arrayObj->TexCoord[i].BufferObj->RefCount += step; + for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) + arrayObj->VertexAttrib[i].BufferObj->RefCount += step; +} + + +/** + * Copy gl_pixelstore_attrib from src to dst, updating buffer + * object refcounts. + */ +static void +copy_pixelstore(struct gl_context *ctx, + struct gl_pixelstore_attrib *dst, + const struct gl_pixelstore_attrib *src) +{ + dst->Alignment = src->Alignment; + dst->RowLength = src->RowLength; + dst->SkipPixels = src->SkipPixels; + dst->SkipRows = src->SkipRows; + dst->ImageHeight = src->ImageHeight; + dst->SkipImages = src->SkipImages; + dst->SwapBytes = src->SwapBytes; + dst->LsbFirst = src->LsbFirst; + dst->ClientStorage = src->ClientStorage; + dst->Invert = src->Invert; + _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj); +} + + +#define GL_CLIENT_PACK_BIT (1<<20) +#define GL_CLIENT_UNPACK_BIT (1<<21) + + +void GLAPIENTRY +_mesa_PushClientAttrib(GLbitfield mask) +{ + struct gl_attrib_node *head; + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (ctx->ClientAttribStackDepth >= MAX_CLIENT_ATTRIB_STACK_DEPTH) { + _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushClientAttrib" ); + return; + } + + /* Build linked list of attribute nodes which save all attribute + * groups specified by the mask. + */ + head = NULL; + + if (mask & GL_CLIENT_PIXEL_STORE_BIT) { + struct gl_pixelstore_attrib *attr; + /* packing attribs */ + attr = CALLOC_STRUCT( gl_pixelstore_attrib ); + copy_pixelstore(ctx, attr, &ctx->Pack); + save_attrib_data(&head, GL_CLIENT_PACK_BIT, attr); + /* unpacking attribs */ + attr = CALLOC_STRUCT( gl_pixelstore_attrib ); + copy_pixelstore(ctx, attr, &ctx->Unpack); + save_attrib_data(&head, GL_CLIENT_UNPACK_BIT, attr); + } + + if (mask & GL_CLIENT_VERTEX_ARRAY_BIT) { + struct gl_array_attrib *attr; + struct gl_array_object *obj; + + attr = MALLOC_STRUCT( gl_array_attrib ); + obj = MALLOC_STRUCT( gl_array_object ); + +#if FEATURE_ARB_vertex_buffer_object + /* increment ref counts since we're copying pointers to these objects */ + ctx->Array.ArrayBufferObj->RefCount++; + ctx->Array.ElementArrayBufferObj->RefCount++; +#endif + + memcpy( attr, &ctx->Array, sizeof(struct gl_array_attrib) ); + memcpy( obj, ctx->Array.ArrayObj, sizeof(struct gl_array_object) ); + + attr->ArrayObj = obj; + + save_attrib_data(&head, GL_CLIENT_VERTEX_ARRAY_BIT, attr); + + /* bump reference counts on buffer objects */ + adjust_buffer_object_ref_counts(ctx->Array.ArrayObj, 1); + } + + ctx->ClientAttribStack[ctx->ClientAttribStackDepth] = head; + ctx->ClientAttribStackDepth++; +} + + + + +void GLAPIENTRY +_mesa_PopClientAttrib(void) +{ + struct gl_attrib_node *node, *next; + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (ctx->ClientAttribStackDepth == 0) { + _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopClientAttrib" ); + return; + } + + ctx->ClientAttribStackDepth--; + node = ctx->ClientAttribStack[ctx->ClientAttribStackDepth]; + + while (node) { + switch (node->kind) { + case GL_CLIENT_PACK_BIT: + { + struct gl_pixelstore_attrib *store = + (struct gl_pixelstore_attrib *) node->data; + copy_pixelstore(ctx, &ctx->Pack, store); + _mesa_reference_buffer_object(ctx, &store->BufferObj, NULL); + } + ctx->NewState |= _NEW_PACKUNPACK; + break; + case GL_CLIENT_UNPACK_BIT: + { + struct gl_pixelstore_attrib *store = + (struct gl_pixelstore_attrib *) node->data; + copy_pixelstore(ctx, &ctx->Unpack, store); + _mesa_reference_buffer_object(ctx, &store->BufferObj, NULL); + } + ctx->NewState |= _NEW_PACKUNPACK; + break; + case GL_CLIENT_VERTEX_ARRAY_BIT: { + struct gl_array_attrib * data = + (struct gl_array_attrib *) node->data; + + adjust_buffer_object_ref_counts(ctx->Array.ArrayObj, -1); + + ctx->Array.ActiveTexture = data->ActiveTexture; + if (data->LockCount != 0) + _mesa_LockArraysEXT(data->LockFirst, data->LockCount); + else if (ctx->Array.LockCount) + _mesa_UnlockArraysEXT(); + + _mesa_BindVertexArrayAPPLE( data->ArrayObj->Name ); + +#if FEATURE_ARB_vertex_buffer_object + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, + data->ArrayBufferObj->Name); + _mesa_BindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, + data->ElementArrayBufferObj->Name); +#endif + + memcpy( ctx->Array.ArrayObj, data->ArrayObj, + sizeof( struct gl_array_object ) ); + + FREE( data->ArrayObj ); + + /* FIXME: Should some bits in ctx->Array->NewState also be set + * FIXME: here? It seems like it should be set to inclusive-or + * FIXME: of the old ArrayObj->_Enabled and the new _Enabled. + */ + + ctx->NewState |= _NEW_ARRAY; + break; + } + default: + _mesa_problem( ctx, "Bad attrib flag in PopClientAttrib"); + break; + } + + next = node->next; + FREE( node->data ); + FREE( node ); + node = next; + } +} + + +void +_mesa_init_attrib_dispatch(struct _glapi_table *disp) +{ + SET_PopAttrib(disp, _mesa_PopAttrib); + SET_PushAttrib(disp, _mesa_PushAttrib); + SET_PopClientAttrib(disp, _mesa_PopClientAttrib); + SET_PushClientAttrib(disp, _mesa_PushClientAttrib); +} + + +#endif /* FEATURE_attrib_stack */ + + +/** + * Free any attribute state data that might be attached to the context. + */ +void +_mesa_free_attrib_data(struct gl_context *ctx) +{ + while (ctx->AttribStackDepth > 0) { + struct gl_attrib_node *attr, *next; + + ctx->AttribStackDepth--; + attr = ctx->AttribStack[ctx->AttribStackDepth]; + + while (attr) { + if (attr->kind == GL_TEXTURE_BIT) { + struct texture_state *texstate = (struct texture_state*)attr->data; + GLuint u, tgt; + /* clear references to the saved texture objects */ + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + _mesa_reference_texobj(&texstate->SavedTexRef[u][tgt], NULL); + } + } + } + else { + /* any other chunks of state that requires special handling? */ + } + + next = attr->next; + free(attr->data); + free(attr); + attr = next; + } + } +} + + +void _mesa_init_attrib( struct gl_context *ctx ) +{ + /* Renderer and client attribute stacks */ + ctx->AttribStackDepth = 0; + ctx->ClientAttribStackDepth = 0; +} diff --git a/mesalib/src/mesa/main/bufferobj.c b/mesalib/src/mesa/main/bufferobj.c index 75afae0ad..35d92616f 100644 --- a/mesalib/src/mesa/main/bufferobj.c +++ b/mesalib/src/mesa/main/bufferobj.c @@ -658,248 +658,6 @@ _mesa_update_default_objects_buffer_objects(struct gl_context *ctx) } -/** - * When we're about to read pixel data out of a PBO (via glDrawPixels, - * glTexImage, etc) or write data into a PBO (via glReadPixels, - * glGetTexImage, etc) we call this function to check that we're not - * going to read out of bounds. - * - * XXX This would also be a convenient time to check that the PBO isn't - * currently mapped. Whoever calls this function should check for that. - * Remember, we can't use a PBO when it's mapped! - * - * If we're not using a PBO, this is a no-op. - * - * \param width width of image to read/write - * \param height height of image to read/write - * \param depth depth of image to read/write - * \param format format of image to read/write - * \param type datatype of image to read/write - * \param ptr the user-provided pointer/offset - * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would - * go out of bounds. - */ -GLboolean -_mesa_validate_pbo_access(GLuint dimensions, - const struct gl_pixelstore_attrib *pack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *ptr) -{ - GLvoid *start, *end; - const GLubyte *sizeAddr; /* buffer size, cast to a pointer */ - - if (!_mesa_is_bufferobj(pack->BufferObj)) - return GL_TRUE; /* no PBO, OK */ - - if (pack->BufferObj->Size == 0) - /* no buffer! */ - return GL_FALSE; - - /* get address of first pixel we'll read */ - start = _mesa_image_address(dimensions, pack, ptr, width, height, - format, type, 0, 0, 0); - - /* get address just past the last pixel we'll read */ - end = _mesa_image_address(dimensions, pack, ptr, width, height, - format, type, depth-1, height-1, width); - - - sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size; - - if ((const GLubyte *) start > sizeAddr) { - /* This will catch negative values / wrap-around */ - return GL_FALSE; - } - if ((const GLubyte *) end > sizeAddr) { - /* Image read goes beyond end of buffer */ - return GL_FALSE; - } - - /* OK! */ - return GL_TRUE; -} - - -/** - * For commands that read from a PBO (glDrawPixels, glTexImage, - * glPolygonStipple, etc), if we're reading from a PBO, map it read-only - * and return the pointer into the PBO. If we're not reading from a - * PBO, return \p src as-is. - * If non-null return, must call _mesa_unmap_pbo_source() when done. - * - * \return NULL if error, else pointer to start of data - */ -const GLvoid * -_mesa_map_pbo_source(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack, - const GLvoid *src) -{ - const GLubyte *buf; - - if (_mesa_is_bufferobj(unpack->BufferObj)) { - /* unpack from PBO */ - buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - GL_READ_ONLY_ARB, - unpack->BufferObj); - if (!buf) - return NULL; - - buf = ADD_POINTERS(buf, src); - } - else { - /* unpack from normal memory */ - buf = src; - } - - return buf; -} - - -/** - * Combine PBO-read validation and mapping. - * If any GL errors are detected, they'll be recorded and NULL returned. - * \sa _mesa_validate_pbo_access - * \sa _mesa_map_pbo_source - * A call to this function should have a matching call to - * _mesa_unmap_pbo_source(). - */ -const GLvoid * -_mesa_map_validate_pbo_source(struct gl_context *ctx, - GLuint dimensions, - const struct gl_pixelstore_attrib *unpack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *ptr, - const char *where) -{ - ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); - - if (!_mesa_is_bufferobj(unpack->BufferObj)) { - /* non-PBO access: no validation to be done */ - return ptr; - } - - if (!_mesa_validate_pbo_access(dimensions, unpack, - width, height, depth, format, type, ptr)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(out of bounds PBO access)", where); - return NULL; - } - - if (_mesa_bufferobj_mapped(unpack->BufferObj)) { - /* buffer is already mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); - return NULL; - } - - ptr = _mesa_map_pbo_source(ctx, unpack, ptr); - return ptr; -} - - -/** - * Counterpart to _mesa_map_pbo_source() - */ -void -_mesa_unmap_pbo_source(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack) -{ - ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */ - if (_mesa_is_bufferobj(unpack->BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - unpack->BufferObj); - } -} - - -/** - * For commands that write to a PBO (glReadPixels, glGetColorTable, etc), - * if we're writing to a PBO, map it write-only and return the pointer - * into the PBO. If we're not writing to a PBO, return \p dst as-is. - * If non-null return, must call _mesa_unmap_pbo_dest() when done. - * - * \return NULL if error, else pointer to start of data - */ -void * -_mesa_map_pbo_dest(struct gl_context *ctx, - const struct gl_pixelstore_attrib *pack, - GLvoid *dest) -{ - void *buf; - - if (_mesa_is_bufferobj(pack->BufferObj)) { - /* pack into PBO */ - buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, - GL_WRITE_ONLY_ARB, - pack->BufferObj); - if (!buf) - return NULL; - - buf = ADD_POINTERS(buf, dest); - } - else { - /* pack to normal memory */ - buf = dest; - } - - return buf; -} - - -/** - * Combine PBO-write validation and mapping. - * If any GL errors are detected, they'll be recorded and NULL returned. - * \sa _mesa_validate_pbo_access - * \sa _mesa_map_pbo_dest - * A call to this function should have a matching call to - * _mesa_unmap_pbo_dest(). - */ -GLvoid * -_mesa_map_validate_pbo_dest(struct gl_context *ctx, - GLuint dimensions, - const struct gl_pixelstore_attrib *unpack, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, GLvoid *ptr, - const char *where) -{ - ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); - - if (!_mesa_is_bufferobj(unpack->BufferObj)) { - /* non-PBO access: no validation to be done */ - return ptr; - } - - if (!_mesa_validate_pbo_access(dimensions, unpack, - width, height, depth, format, type, ptr)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(out of bounds PBO access)", where); - return NULL; - } - - if (_mesa_bufferobj_mapped(unpack->BufferObj)) { - /* buffer is already mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); - return NULL; - } - - ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); - return ptr; -} - - -/** - * Counterpart to _mesa_map_pbo_dest() - */ -void -_mesa_unmap_pbo_dest(struct gl_context *ctx, - const struct gl_pixelstore_attrib *pack) -{ - ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */ - if (_mesa_is_bufferobj(pack->BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj); - } -} - - /** * Return the gl_buffer_object for the given ID. diff --git a/mesalib/src/mesa/main/bufferobj.h b/mesalib/src/mesa/main/bufferobj.h index cf43ad9a2..91fa073b6 100644 --- a/mesalib/src/mesa/main/bufferobj.h +++ b/mesalib/src/mesa/main/bufferobj.h @@ -1,190 +1,149 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.6
- *
- * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- * Copyright (C) 2009 VMware, Inc. 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.
- */
-
-
-
-#ifndef BUFFEROBJ_H
-#define BUFFEROBJ_H
-
-
-#include "mfeatures.h"
-#include "mtypes.h"
-
-
-/*
- * Internal functions
- */
-
-
-/** Is the given buffer object currently mapped? */
-static INLINE GLboolean
-_mesa_bufferobj_mapped(const struct gl_buffer_object *obj)
-{
- return obj->Pointer != NULL;
-}
-
-/**
- * Is the given buffer object a user-created buffer object?
- * Mesa uses default buffer objects in several places. Default buffers
- * always have Name==0. User created buffers have Name!=0.
- */
-static INLINE GLboolean
-_mesa_is_bufferobj(const struct gl_buffer_object *obj)
-{
- return obj->Name != 0;
-}
-
-
-extern void
-_mesa_init_buffer_objects( struct gl_context *ctx );
-
-extern void
-_mesa_free_buffer_objects( struct gl_context *ctx );
-
-extern void
-_mesa_update_default_objects_buffer_objects(struct gl_context *ctx);
-
-
-extern struct gl_buffer_object *
-_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer);
-
-extern void
-_mesa_initialize_buffer_object( struct gl_buffer_object *obj,
- GLuint name, GLenum target );
-
-extern void
-_mesa_reference_buffer_object(struct gl_context *ctx,
- struct gl_buffer_object **ptr,
- struct gl_buffer_object *bufObj);
-
-extern GLboolean
-_mesa_validate_pbo_access(GLuint dimensions,
- const struct gl_pixelstore_attrib *pack,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLenum type, const GLvoid *ptr);
-
-extern const GLvoid *
-_mesa_map_pbo_source(struct gl_context *ctx,
- const struct gl_pixelstore_attrib *unpack,
- const GLvoid *src);
-
-extern const GLvoid *
-_mesa_map_validate_pbo_source(struct gl_context *ctx,
- GLuint dimensions,
- const struct gl_pixelstore_attrib *unpack,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLenum type, const GLvoid *ptr,
- const char *where);
-
-extern void
-_mesa_unmap_pbo_source(struct gl_context *ctx,
- const struct gl_pixelstore_attrib *unpack);
-
-extern void *
-_mesa_map_pbo_dest(struct gl_context *ctx,
- const struct gl_pixelstore_attrib *pack,
- GLvoid *dest);
-
-extern GLvoid *
-_mesa_map_validate_pbo_dest(struct gl_context *ctx,
- GLuint dimensions,
- const struct gl_pixelstore_attrib *unpack,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLenum type, GLvoid *ptr,
- const char *where);
-
-extern void
-_mesa_unmap_pbo_dest(struct gl_context *ctx,
- const struct gl_pixelstore_attrib *pack);
-
-
-extern void
-_mesa_init_buffer_object_functions(struct dd_function_table *driver);
-
-
-/*
- * API functions
- */
-
-extern void GLAPIENTRY
-_mesa_BindBufferARB(GLenum target, GLuint buffer);
-
-extern void GLAPIENTRY
-_mesa_DeleteBuffersARB(GLsizei n, const GLuint * buffer);
-
-extern void GLAPIENTRY
-_mesa_GenBuffersARB(GLsizei n, GLuint * buffer);
-
-extern GLboolean GLAPIENTRY
-_mesa_IsBufferARB(GLuint buffer);
-
-extern void GLAPIENTRY
-_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage);
-
-extern void GLAPIENTRY
-_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data);
-
-extern void GLAPIENTRY
-_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, void * data);
-
-extern void * GLAPIENTRY
-_mesa_MapBufferARB(GLenum target, GLenum access);
-
-extern GLboolean GLAPIENTRY
-_mesa_UnmapBufferARB(GLenum target);
-
-extern void GLAPIENTRY
-_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params);
-
-extern void GLAPIENTRY
-_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params);
-
-extern void GLAPIENTRY
-_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params);
-
-extern void GLAPIENTRY
-_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
- GLintptr readOffset, GLintptr writeOffset,
- GLsizeiptr size);
-
-extern void * GLAPIENTRY
-_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
- GLbitfield access);
-
-extern void GLAPIENTRY
-_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
-
-#if FEATURE_APPLE_object_purgeable
-extern GLenum GLAPIENTRY
-_mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option);
-
-extern GLenum GLAPIENTRY
-_mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option);
-
-extern void GLAPIENTRY
-_mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname, GLint* params);
-#endif
-
-#endif
+/* + * Mesa 3-D graphics library + * Version: 7.6 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. 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. + */ + + + +#ifndef BUFFEROBJ_H +#define BUFFEROBJ_H + + +#include "mfeatures.h" +#include "mtypes.h" + + +/* + * Internal functions + */ + + +/** Is the given buffer object currently mapped? */ +static INLINE GLboolean +_mesa_bufferobj_mapped(const struct gl_buffer_object *obj) +{ + return obj->Pointer != NULL; +} + +/** + * Is the given buffer object a user-created buffer object? + * Mesa uses default buffer objects in several places. Default buffers + * always have Name==0. User created buffers have Name!=0. + */ +static INLINE GLboolean +_mesa_is_bufferobj(const struct gl_buffer_object *obj) +{ + return obj->Name != 0; +} + + +extern void +_mesa_init_buffer_objects( struct gl_context *ctx ); + +extern void +_mesa_free_buffer_objects( struct gl_context *ctx ); + +extern void +_mesa_update_default_objects_buffer_objects(struct gl_context *ctx); + + +extern struct gl_buffer_object * +_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer); + +extern void +_mesa_initialize_buffer_object( struct gl_buffer_object *obj, + GLuint name, GLenum target ); + +extern void +_mesa_reference_buffer_object(struct gl_context *ctx, + struct gl_buffer_object **ptr, + struct gl_buffer_object *bufObj); + +extern void +_mesa_init_buffer_object_functions(struct dd_function_table *driver); + + +/* + * API functions + */ + +extern void GLAPIENTRY +_mesa_BindBufferARB(GLenum target, GLuint buffer); + +extern void GLAPIENTRY +_mesa_DeleteBuffersARB(GLsizei n, const GLuint * buffer); + +extern void GLAPIENTRY +_mesa_GenBuffersARB(GLsizei n, GLuint * buffer); + +extern GLboolean GLAPIENTRY +_mesa_IsBufferARB(GLuint buffer); + +extern void GLAPIENTRY +_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage); + +extern void GLAPIENTRY +_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data); + +extern void GLAPIENTRY +_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, void * data); + +extern void * GLAPIENTRY +_mesa_MapBufferARB(GLenum target, GLenum access); + +extern GLboolean GLAPIENTRY +_mesa_UnmapBufferARB(GLenum target); + +extern void GLAPIENTRY +_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params); + +extern void GLAPIENTRY +_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params); + +extern void GLAPIENTRY +_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params); + +extern void GLAPIENTRY +_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size); + +extern void * GLAPIENTRY +_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, + GLbitfield access); + +extern void GLAPIENTRY +_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length); + +#if FEATURE_APPLE_object_purgeable +extern GLenum GLAPIENTRY +_mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option); + +extern GLenum GLAPIENTRY +_mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option); + +extern void GLAPIENTRY +_mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname, GLint* params); +#endif + +#endif diff --git a/mesalib/src/mesa/main/colortab.c b/mesalib/src/mesa/main/colortab.c index 9c23e253b..d0c865735 100644 --- a/mesalib/src/mesa/main/colortab.c +++ b/mesalib/src/mesa/main/colortab.c @@ -1,934 +1,821 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.1
- *
- * 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.
- */
-
-
-#include "glheader.h"
-#include "bufferobj.h"
-#include "colortab.h"
-#include "context.h"
-#include "image.h"
-#include "macros.h"
-#include "mfeatures.h"
-#include "mtypes.h"
-#include "pack.h"
-#include "state.h"
-#include "teximage.h"
-#include "texstate.h"
-#include "main/dispatch.h"
-
-
-#if FEATURE_colortable
-
-
-/**
- * Given an internalFormat token passed to glColorTable,
- * return the corresponding base format.
- * Return -1 if invalid token.
- */
-static GLint
-base_colortab_format( GLenum format )
-{
- switch (format) {
- case GL_ALPHA:
- case GL_ALPHA4:
- case GL_ALPHA8:
- case GL_ALPHA12:
- case GL_ALPHA16:
- return GL_ALPHA;
- case GL_LUMINANCE:
- case GL_LUMINANCE4:
- case GL_LUMINANCE8:
- case GL_LUMINANCE12:
- case GL_LUMINANCE16:
- return GL_LUMINANCE;
- case GL_LUMINANCE_ALPHA:
- case GL_LUMINANCE4_ALPHA4:
- case GL_LUMINANCE6_ALPHA2:
- case GL_LUMINANCE8_ALPHA8:
- case GL_LUMINANCE12_ALPHA4:
- case GL_LUMINANCE12_ALPHA12:
- case GL_LUMINANCE16_ALPHA16:
- return GL_LUMINANCE_ALPHA;
- case GL_INTENSITY:
- case GL_INTENSITY4:
- case GL_INTENSITY8:
- case GL_INTENSITY12:
- case GL_INTENSITY16:
- return GL_INTENSITY;
- case GL_RGB:
- case GL_R3_G3_B2:
- case GL_RGB4:
- case GL_RGB5:
- case GL_RGB8:
- case GL_RGB10:
- case GL_RGB12:
- case GL_RGB16:
- return GL_RGB;
- case GL_RGBA:
- case GL_RGBA2:
- case GL_RGBA4:
- case GL_RGB5_A1:
- case GL_RGBA8:
- case GL_RGB10_A2:
- case GL_RGBA12:
- case GL_RGBA16:
- return GL_RGBA;
- default:
- return -1; /* error */
- }
-}
-
-
-
-/**
- * Examine table's format and set the component sizes accordingly.
- */
-static void
-set_component_sizes( struct gl_color_table *table )
-{
- /* assuming the ubyte table */
- const GLubyte sz = 8;
-
- switch (table->_BaseFormat) {
- case GL_ALPHA:
- table->RedSize = 0;
- table->GreenSize = 0;
- table->BlueSize = 0;
- table->AlphaSize = sz;
- table->IntensitySize = 0;
- table->LuminanceSize = 0;
- break;
- case GL_LUMINANCE:
- table->RedSize = 0;
- table->GreenSize = 0;
- table->BlueSize = 0;
- table->AlphaSize = 0;
- table->IntensitySize = 0;
- table->LuminanceSize = sz;
- break;
- case GL_LUMINANCE_ALPHA:
- table->RedSize = 0;
- table->GreenSize = 0;
- table->BlueSize = 0;
- table->AlphaSize = sz;
- table->IntensitySize = 0;
- table->LuminanceSize = sz;
- break;
- case GL_INTENSITY:
- table->RedSize = 0;
- table->GreenSize = 0;
- table->BlueSize = 0;
- table->AlphaSize = 0;
- table->IntensitySize = sz;
- table->LuminanceSize = 0;
- break;
- case GL_RGB:
- table->RedSize = sz;
- table->GreenSize = sz;
- table->BlueSize = sz;
- table->AlphaSize = 0;
- table->IntensitySize = 0;
- table->LuminanceSize = 0;
- break;
- case GL_RGBA:
- table->RedSize = sz;
- table->GreenSize = sz;
- table->BlueSize = sz;
- table->AlphaSize = sz;
- table->IntensitySize = 0;
- table->LuminanceSize = 0;
- break;
- default:
- _mesa_problem(NULL, "unexpected format in set_component_sizes");
- }
-}
-
-
-
-/**
- * Update/replace all or part of a color table. Helper function
- * used by _mesa_ColorTable() and _mesa_ColorSubTable().
- * The table->Table buffer should already be allocated.
- * \param start first entry to update
- * \param count number of entries to update
- * \param format format of user-provided table data
- * \param type datatype of user-provided table data
- * \param data user-provided table data
- * \param [rgba]Scale - RGBA scale factors
- * \param [rgba]Bias - RGBA bias factors
- */
-static void
-store_colortable_entries(struct gl_context *ctx, struct gl_color_table *table,
- GLsizei start, GLsizei count,
- GLenum format, GLenum type, const GLvoid *data,
- GLfloat rScale, GLfloat rBias,
- GLfloat gScale, GLfloat gBias,
- GLfloat bScale, GLfloat bBias,
- GLfloat aScale, GLfloat aBias)
-{
- data = _mesa_map_validate_pbo_source(ctx,
- 1, &ctx->Unpack, count, 1, 1,
- format, type, data,
- "glColor[Sub]Table");
- if (!data)
- return;
-
- {
- /* convert user-provided data to GLfloat values */
- GLfloat tempTab[MAX_COLOR_TABLE_SIZE * 4];
- GLfloat *tableF;
- GLint i;
-
- _mesa_unpack_color_span_float(ctx,
- count, /* number of pixels */
- table->_BaseFormat, /* dest format */
- tempTab, /* dest address */
- format, type, /* src format/type */
- data, /* src data */
- &ctx->Unpack,
- IMAGE_CLAMP_BIT); /* transfer ops */
-
- /* the destination */
- tableF = table->TableF;
-
- /* Apply scale & bias & clamp now */
- switch (table->_BaseFormat) {
- case GL_INTENSITY:
- for (i = 0; i < count; i++) {
- GLuint j = start + i;
- tableF[j] = CLAMP(tempTab[i] * rScale + rBias, 0.0F, 1.0F);
- }
- break;
- case GL_LUMINANCE:
- for (i = 0; i < count; i++) {
- GLuint j = start + i;
- tableF[j] = CLAMP(tempTab[i] * rScale + rBias, 0.0F, 1.0F);
- }
- break;
- case GL_ALPHA:
- for (i = 0; i < count; i++) {
- GLuint j = start + i;
- tableF[j] = CLAMP(tempTab[i] * aScale + aBias, 0.0F, 1.0F);
- }
- break;
- case GL_LUMINANCE_ALPHA:
- for (i = 0; i < count; i++) {
- GLuint j = start + i;
- tableF[j*2+0] = CLAMP(tempTab[i*2+0] * rScale + rBias, 0.0F, 1.0F);
- tableF[j*2+1] = CLAMP(tempTab[i*2+1] * aScale + aBias, 0.0F, 1.0F);
- }
- break;
- case GL_RGB:
- for (i = 0; i < count; i++) {
- GLuint j = start + i;
- tableF[j*3+0] = CLAMP(tempTab[i*3+0] * rScale + rBias, 0.0F, 1.0F);
- tableF[j*3+1] = CLAMP(tempTab[i*3+1] * gScale + gBias, 0.0F, 1.0F);
- tableF[j*3+2] = CLAMP(tempTab[i*3+2] * bScale + bBias, 0.0F, 1.0F);
- }
- break;
- case GL_RGBA:
- for (i = 0; i < count; i++) {
- GLuint j = start + i;
- tableF[j*4+0] = CLAMP(tempTab[i*4+0] * rScale + rBias, 0.0F, 1.0F);
- tableF[j*4+1] = CLAMP(tempTab[i*4+1] * gScale + gBias, 0.0F, 1.0F);
- tableF[j*4+2] = CLAMP(tempTab[i*4+2] * bScale + bBias, 0.0F, 1.0F);
- tableF[j*4+3] = CLAMP(tempTab[i*4+3] * aScale + aBias, 0.0F, 1.0F);
- }
- break;
- default:
- _mesa_problem(ctx, "Bad format in store_colortable_entries");
- return;
- }
- }
-
- /* update the ubyte table */
- {
- const GLint comps = _mesa_components_in_format(table->_BaseFormat);
- const GLfloat *tableF = table->TableF + start * comps;
- GLubyte *tableUB = table->TableUB + start * comps;
- GLint i;
- for (i = 0; i < count * comps; i++) {
- CLAMPED_FLOAT_TO_UBYTE(tableUB[i], tableF[i]);
- }
- }
-
- _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
-}
-
-
-
-void GLAPIENTRY
-_mesa_ColorTable( GLenum target, GLenum internalFormat,
- GLsizei width, GLenum format, GLenum type,
- const GLvoid *data )
-{
- static const GLfloat one[4] = { 1.0, 1.0, 1.0, 1.0 };
- static const GLfloat zero[4] = { 0.0, 0.0, 0.0, 0.0 };
- GET_CURRENT_CONTEXT(ctx);
- struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
- struct gl_texture_object *texObj = NULL;
- struct gl_color_table *table = NULL;
- GLboolean proxy = GL_FALSE;
- GLint baseFormat;
- const GLfloat *scale = one, *bias = zero;
- GLint comps;
-
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */
-
- switch (target) {
- case GL_SHARED_TEXTURE_PALETTE_EXT:
- table = &ctx->Texture.Palette;
- break;
- case GL_TEXTURE_COLOR_TABLE_SGI:
- if (!ctx->Extensions.SGI_texture_color_table) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(target)");
- return;
- }
- table = &(texUnit->ColorTable);
- scale = ctx->Pixel.TextureColorTableScale;
- bias = ctx->Pixel.TextureColorTableBias;
- break;
- case GL_PROXY_TEXTURE_COLOR_TABLE_SGI:
- if (!ctx->Extensions.SGI_texture_color_table) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(target)");
- return;
- }
- table = &(texUnit->ProxyColorTable);
- proxy = GL_TRUE;
- break;
- default:
- /* try texture targets */
- {
- struct gl_texture_object *texobj
- = _mesa_select_tex_object(ctx, texUnit, target);
- if (texobj) {
- table = &texobj->Palette;
- proxy = _mesa_is_proxy_texture(target);
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(target)");
- return;
- }
- }
- }
-
- assert(table);
-
- if (!_mesa_is_legal_format_and_type(ctx, format, type) ||
- format == GL_INTENSITY) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glColorTable(format or type)");
- return;
- }
-
- baseFormat = base_colortab_format(internalFormat);
- if (baseFormat < 0) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(internalFormat)");
- return;
- }
-
- if (width < 0 || (width != 0 && !_mesa_is_pow_two(width))) {
- /* error */
- if (proxy) {
- table->Size = 0;
- table->InternalFormat = (GLenum) 0;
- table->_BaseFormat = (GLenum) 0;
- }
- else {
- _mesa_error(ctx, GL_INVALID_VALUE, "glColorTable(width=%d)", width);
- }
- return;
- }
-
- if (width > (GLsizei) ctx->Const.MaxColorTableSize) {
- if (proxy) {
- table->Size = 0;
- table->InternalFormat = (GLenum) 0;
- table->_BaseFormat = (GLenum) 0;
- }
- else {
- _mesa_error(ctx, GL_TABLE_TOO_LARGE, "glColorTable(width)");
- }
- return;
- }
-
- table->Size = width;
- table->InternalFormat = internalFormat;
- table->_BaseFormat = (GLenum) baseFormat;
-
- comps = _mesa_components_in_format(table->_BaseFormat);
- assert(comps > 0); /* error should have been caught sooner */
-
- if (!proxy) {
- _mesa_free_colortable_data(table);
-
- if (width > 0) {
- table->TableF = (GLfloat *) malloc(comps * width * sizeof(GLfloat));
- table->TableUB = (GLubyte *) malloc(comps * width * sizeof(GLubyte));
-
- if (!table->TableF || !table->TableUB) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glColorTable");
- return;
- }
-
- store_colortable_entries(ctx, table,
- 0, width, /* start, count */
- format, type, data,
- scale[0], bias[0],
- scale[1], bias[1],
- scale[2], bias[2],
- scale[3], bias[3]);
- }
- } /* proxy */
-
- /* do this after the table's Type and Format are set */
- set_component_sizes(table);
-
- if (texObj || target == GL_SHARED_TEXTURE_PALETTE_EXT) {
- /* texture object palette, texObj==NULL means the shared palette */
- if (ctx->Driver.UpdateTexturePalette) {
- (*ctx->Driver.UpdateTexturePalette)( ctx, texObj );
- }
- }
-
- ctx->NewState |= _NEW_PIXEL;
-}
-
-
-
-void GLAPIENTRY
-_mesa_ColorSubTable( GLenum target, GLsizei start,
- GLsizei count, GLenum format, GLenum type,
- const GLvoid *data )
-{
- static const GLfloat one[4] = { 1.0, 1.0, 1.0, 1.0 };
- static const GLfloat zero[4] = { 0.0, 0.0, 0.0, 0.0 };
- GET_CURRENT_CONTEXT(ctx);
- struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
- struct gl_texture_object *texObj = NULL;
- struct gl_color_table *table = NULL;
- const GLfloat *scale = one, *bias = zero;
-
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- switch (target) {
- case GL_SHARED_TEXTURE_PALETTE_EXT:
- table = &ctx->Texture.Palette;
- break;
- case GL_TEXTURE_COLOR_TABLE_SGI:
- if (!ctx->Extensions.SGI_texture_color_table) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glColorSubTable(target)");
- return;
- }
- table = &(texUnit->ColorTable);
- scale = ctx->Pixel.TextureColorTableScale;
- bias = ctx->Pixel.TextureColorTableBias;
- break;
- default:
- /* try texture targets */
- texObj = _mesa_select_tex_object(ctx, texUnit, target);
- if (texObj && !_mesa_is_proxy_texture(target)) {
- table = &texObj->Palette;
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM, "glColorSubTable(target)");
- return;
- }
- }
-
- assert(table);
-
- if (!_mesa_is_legal_format_and_type(ctx, format, type) ||
- format == GL_INTENSITY) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glColorSubTable(format or type)");
- return;
- }
-
- if (count < 1) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glColorSubTable(count)");
- return;
- }
-
- /* error should have been caught sooner */
- assert(_mesa_components_in_format(table->_BaseFormat) > 0);
-
- if (start + count > (GLint) table->Size) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glColorSubTable(count)");
- return;
- }
-
- if (!table->TableF || !table->TableUB) {
- /* a GL_OUT_OF_MEMORY error would have been recorded previously */
- return;
- }
-
- store_colortable_entries(ctx, table, start, count,
- format, type, data,
- scale[0], bias[0],
- scale[1], bias[1],
- scale[2], bias[2],
- scale[3], bias[3]);
-
- if (texObj || target == GL_SHARED_TEXTURE_PALETTE_EXT) {
- /* per-texture object palette */
- if (ctx->Driver.UpdateTexturePalette) {
- (*ctx->Driver.UpdateTexturePalette)( ctx, texObj );
- }
- }
-
- ctx->NewState |= _NEW_PIXEL;
-}
-
-
-
-static void GLAPIENTRY
-_mesa_CopyColorTable(GLenum target, GLenum internalformat,
- GLint x, GLint y, GLsizei width)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (!ctx->ReadBuffer->_ColorReadBuffer) {
- return; /* no readbuffer - OK */
- }
-
- ctx->Driver.CopyColorTable( ctx, target, internalformat, x, y, width );
-}
-
-
-
-static void GLAPIENTRY
-_mesa_CopyColorSubTable(GLenum target, GLsizei start,
- GLint x, GLint y, GLsizei width)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (!ctx->ReadBuffer->_ColorReadBuffer) {
- return; /* no readbuffer - OK */
- }
-
- ctx->Driver.CopyColorSubTable( ctx, target, start, x, y, width );
-}
-
-
-
-static void GLAPIENTRY
-_mesa_GetColorTable( GLenum target, GLenum format,
- GLenum type, GLvoid *data )
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
- struct gl_color_table *table = NULL;
- GLfloat rgba[MAX_COLOR_TABLE_SIZE][4];
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (ctx->NewState) {
- _mesa_update_state(ctx);
- }
-
- switch (target) {
- case GL_SHARED_TEXTURE_PALETTE_EXT:
- table = &ctx->Texture.Palette;
- break;
- case GL_TEXTURE_COLOR_TABLE_SGI:
- if (!ctx->Extensions.SGI_texture_color_table) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTable(target)");
- return;
- }
- table = &(texUnit->ColorTable);
- break;
- default:
- /* try texture targets */
- {
- struct gl_texture_object *texobj
- = _mesa_select_tex_object(ctx, texUnit, target);
- if (texobj && !_mesa_is_proxy_texture(target)) {
- table = &texobj->Palette;
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTable(target)");
- return;
- }
- }
- }
-
- ASSERT(table);
-
- if (table->Size <= 0) {
- return;
- }
-
- switch (table->_BaseFormat) {
- case GL_ALPHA:
- {
- GLuint i;
- for (i = 0; i < table->Size; i++) {
- rgba[i][RCOMP] = 0;
- rgba[i][GCOMP] = 0;
- rgba[i][BCOMP] = 0;
- rgba[i][ACOMP] = table->TableF[i];
- }
- }
- break;
- case GL_LUMINANCE:
- {
- GLuint i;
- for (i = 0; i < table->Size; i++) {
- rgba[i][RCOMP] =
- rgba[i][GCOMP] =
- rgba[i][BCOMP] = table->TableF[i];
- rgba[i][ACOMP] = 1.0F;
- }
- }
- break;
- case GL_LUMINANCE_ALPHA:
- {
- GLuint i;
- for (i = 0; i < table->Size; i++) {
- rgba[i][RCOMP] =
- rgba[i][GCOMP] =
- rgba[i][BCOMP] = table->TableF[i*2+0];
- rgba[i][ACOMP] = table->TableF[i*2+1];
- }
- }
- break;
- case GL_INTENSITY:
- {
- GLuint i;
- for (i = 0; i < table->Size; i++) {
- rgba[i][RCOMP] =
- rgba[i][GCOMP] =
- rgba[i][BCOMP] =
- rgba[i][ACOMP] = table->TableF[i];
- }
- }
- break;
- case GL_RGB:
- {
- GLuint i;
- for (i = 0; i < table->Size; i++) {
- rgba[i][RCOMP] = table->TableF[i*3+0];
- rgba[i][GCOMP] = table->TableF[i*3+1];
- rgba[i][BCOMP] = table->TableF[i*3+2];
- rgba[i][ACOMP] = 1.0F;
- }
- }
- break;
- case GL_RGBA:
- memcpy(rgba, table->TableF, 4 * table->Size * sizeof(GLfloat));
- break;
- default:
- _mesa_problem(ctx, "bad table format in glGetColorTable");
- return;
- }
-
- data = _mesa_map_validate_pbo_dest(ctx,
- 1, &ctx->Pack, table->Size, 1, 1,
- format, type, data,
- "glGetColorTable");
- if (!data)
- return;
-
- _mesa_pack_rgba_span_float(ctx, table->Size, rgba,
- format, type, data, &ctx->Pack, 0x0);
-
- _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
-}
-
-
-
-static void GLAPIENTRY
-_mesa_ColorTableParameterfv(GLenum target, GLenum pname, const GLfloat *params)
-{
- GLfloat *scale, *bias;
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- switch (target) {
- case GL_TEXTURE_COLOR_TABLE_SGI:
- scale = ctx->Pixel.TextureColorTableScale;
- bias = ctx->Pixel.TextureColorTableBias;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glColorTableParameter(target)");
- return;
- }
-
- if (pname == GL_COLOR_TABLE_SCALE_SGI) {
- COPY_4V(scale, params);
- }
- else if (pname == GL_COLOR_TABLE_BIAS_SGI) {
- COPY_4V(bias, params);
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM, "glColorTableParameterfv(pname)");
- return;
- }
-
- ctx->NewState |= _NEW_PIXEL;
-}
-
-
-
-static void GLAPIENTRY
-_mesa_ColorTableParameteriv(GLenum target, GLenum pname, const GLint *params)
-{
- GLfloat fparams[4];
- if (pname == GL_TEXTURE_COLOR_TABLE_SGI) {
- /* four values */
- fparams[0] = (GLfloat) params[0];
- fparams[1] = (GLfloat) params[1];
- fparams[2] = (GLfloat) params[2];
- fparams[3] = (GLfloat) params[3];
- }
- else {
- /* one values */
- fparams[0] = (GLfloat) params[0];
- }
- _mesa_ColorTableParameterfv(target, pname, fparams);
-}
-
-
-
-static void GLAPIENTRY
-_mesa_GetColorTableParameterfv( GLenum target, GLenum pname, GLfloat *params )
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
- struct gl_color_table *table = NULL;
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- switch (target) {
- case GL_SHARED_TEXTURE_PALETTE_EXT:
- table = &ctx->Texture.Palette;
- break;
- case GL_TEXTURE_COLOR_TABLE_SGI:
- if (!ctx->Extensions.SGI_texture_color_table) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameter(target)");
- return;
- }
- table = &(texUnit->ColorTable);
- if (pname == GL_COLOR_TABLE_SCALE_SGI) {
- COPY_4V(params, ctx->Pixel.TextureColorTableScale);
- return;
- }
- else if (pname == GL_COLOR_TABLE_BIAS_SGI) {
- COPY_4V(params, ctx->Pixel.TextureColorTableBias);
- return;
- }
- break;
- case GL_PROXY_TEXTURE_COLOR_TABLE_SGI:
- if (!ctx->Extensions.SGI_texture_color_table) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameter(target)");
- return;
- }
- table = &(texUnit->ProxyColorTable);
- break;
- default:
- /* try texture targets */
- {
- struct gl_texture_object *texobj
- = _mesa_select_tex_object(ctx, texUnit, target);
- if (texobj) {
- table = &texobj->Palette;
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetColorTableParameterfv(target)");
- return;
- }
- }
- }
-
- assert(table);
-
- switch (pname) {
- case GL_COLOR_TABLE_FORMAT:
- *params = (GLfloat) table->InternalFormat;
- break;
- case GL_COLOR_TABLE_WIDTH:
- *params = (GLfloat) table->Size;
- break;
- case GL_COLOR_TABLE_RED_SIZE:
- *params = (GLfloat) table->RedSize;
- break;
- case GL_COLOR_TABLE_GREEN_SIZE:
- *params = (GLfloat) table->GreenSize;
- break;
- case GL_COLOR_TABLE_BLUE_SIZE:
- *params = (GLfloat) table->BlueSize;
- break;
- case GL_COLOR_TABLE_ALPHA_SIZE:
- *params = (GLfloat) table->AlphaSize;
- break;
- case GL_COLOR_TABLE_LUMINANCE_SIZE:
- *params = (GLfloat) table->LuminanceSize;
- break;
- case GL_COLOR_TABLE_INTENSITY_SIZE:
- *params = (GLfloat) table->IntensitySize;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameterfv(pname)" );
- return;
- }
-}
-
-
-
-static void GLAPIENTRY
-_mesa_GetColorTableParameteriv( GLenum target, GLenum pname, GLint *params )
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
- struct gl_color_table *table = NULL;
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- switch (target) {
- case GL_SHARED_TEXTURE_PALETTE_EXT:
- table = &ctx->Texture.Palette;
- break;
- case GL_TEXTURE_COLOR_TABLE_SGI:
- if (!ctx->Extensions.SGI_texture_color_table) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameter(target)");
- return;
- }
- table = &(texUnit->ColorTable);
- if (pname == GL_COLOR_TABLE_SCALE_SGI) {
- params[0] = (GLint) ctx->Pixel.TextureColorTableScale[0];
- params[1] = (GLint) ctx->Pixel.TextureColorTableScale[1];
- params[2] = (GLint) ctx->Pixel.TextureColorTableScale[2];
- params[3] = (GLint) ctx->Pixel.TextureColorTableScale[3];
- return;
- }
- else if (pname == GL_COLOR_TABLE_BIAS_SGI) {
- params[0] = (GLint) ctx->Pixel.TextureColorTableBias[0];
- params[1] = (GLint) ctx->Pixel.TextureColorTableBias[1];
- params[2] = (GLint) ctx->Pixel.TextureColorTableBias[2];
- params[3] = (GLint) ctx->Pixel.TextureColorTableBias[3];
- return;
- }
- break;
- case GL_PROXY_TEXTURE_COLOR_TABLE_SGI:
- if (!ctx->Extensions.SGI_texture_color_table) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameter(target)");
- return;
- }
- table = &(texUnit->ProxyColorTable);
- break;
- default:
- /* Try texture targets */
- {
- struct gl_texture_object *texobj
- = _mesa_select_tex_object(ctx, texUnit, target);
- if (texobj) {
- table = &texobj->Palette;
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetColorTableParameteriv(target)");
- return;
- }
- }
- }
-
- assert(table);
-
- switch (pname) {
- case GL_COLOR_TABLE_FORMAT:
- *params = table->InternalFormat;
- break;
- case GL_COLOR_TABLE_WIDTH:
- *params = table->Size;
- break;
- case GL_COLOR_TABLE_RED_SIZE:
- *params = table->RedSize;
- break;
- case GL_COLOR_TABLE_GREEN_SIZE:
- *params = table->GreenSize;
- break;
- case GL_COLOR_TABLE_BLUE_SIZE:
- *params = table->BlueSize;
- break;
- case GL_COLOR_TABLE_ALPHA_SIZE:
- *params = table->AlphaSize;
- break;
- case GL_COLOR_TABLE_LUMINANCE_SIZE:
- *params = table->LuminanceSize;
- break;
- case GL_COLOR_TABLE_INTENSITY_SIZE:
- *params = table->IntensitySize;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameteriv(pname)" );
- return;
- }
-}
-
-
-void
-_mesa_init_colortable_dispatch(struct _glapi_table *disp)
-{
- SET_ColorSubTable(disp, _mesa_ColorSubTable);
- SET_ColorTable(disp, _mesa_ColorTable);
- SET_ColorTableParameterfv(disp, _mesa_ColorTableParameterfv);
- SET_ColorTableParameteriv(disp, _mesa_ColorTableParameteriv);
- SET_CopyColorSubTable(disp, _mesa_CopyColorSubTable);
- SET_CopyColorTable(disp, _mesa_CopyColorTable);
- SET_GetColorTable(disp, _mesa_GetColorTable);
- SET_GetColorTableParameterfv(disp, _mesa_GetColorTableParameterfv);
- SET_GetColorTableParameteriv(disp, _mesa_GetColorTableParameteriv);
-}
-
-
-#endif /* FEATURE_colortable */
-
-
-/**********************************************************************/
-/***** Initialization *****/
-/**********************************************************************/
-
-
-void
-_mesa_init_colortable( struct gl_color_table *p )
-{
- p->TableF = NULL;
- p->TableUB = NULL;
- p->Size = 0;
- p->InternalFormat = GL_RGBA;
-}
-
-
-
-void
-_mesa_free_colortable_data( struct gl_color_table *p )
-{
- if (p->TableF) {
- free(p->TableF);
- p->TableF = NULL;
- }
- if (p->TableUB) {
- free(p->TableUB);
- p->TableUB = NULL;
- }
-}
+/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * 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. + */ + + +#include "glheader.h" +#include "bufferobj.h" +#include "colortab.h" +#include "context.h" +#include "image.h" +#include "macros.h" +#include "mfeatures.h" +#include "mtypes.h" +#include "pack.h" +#include "pbo.h" +#include "state.h" +#include "teximage.h" +#include "texstate.h" +#include "main/dispatch.h" + + +#if FEATURE_colortable + + +/** + * Given an internalFormat token passed to glColorTable, + * return the corresponding base format. + * Return -1 if invalid token. + */ +static GLint +base_colortab_format( GLenum format ) +{ + switch (format) { + case GL_ALPHA: + case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + return GL_ALPHA; + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE4_ALPHA4: + case GL_LUMINANCE6_ALPHA2: + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE12_ALPHA4: + case GL_LUMINANCE12_ALPHA12: + case GL_LUMINANCE16_ALPHA16: + return GL_LUMINANCE_ALPHA; + case GL_INTENSITY: + case GL_INTENSITY4: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + return GL_INTENSITY; + case GL_RGB: + case GL_R3_G3_B2: + case GL_RGB4: + case GL_RGB5: + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + return GL_RGB; + case GL_RGBA: + case GL_RGBA2: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: + return GL_RGBA; + default: + return -1; /* error */ + } +} + + + +/** + * Examine table's format and set the component sizes accordingly. + */ +static void +set_component_sizes( struct gl_color_table *table ) +{ + /* assuming the ubyte table */ + const GLubyte sz = 8; + + switch (table->_BaseFormat) { + case GL_ALPHA: + table->RedSize = 0; + table->GreenSize = 0; + table->BlueSize = 0; + table->AlphaSize = sz; + table->IntensitySize = 0; + table->LuminanceSize = 0; + break; + case GL_LUMINANCE: + table->RedSize = 0; + table->GreenSize = 0; + table->BlueSize = 0; + table->AlphaSize = 0; + table->IntensitySize = 0; + table->LuminanceSize = sz; + break; + case GL_LUMINANCE_ALPHA: + table->RedSize = 0; + table->GreenSize = 0; + table->BlueSize = 0; + table->AlphaSize = sz; + table->IntensitySize = 0; + table->LuminanceSize = sz; + break; + case GL_INTENSITY: + table->RedSize = 0; + table->GreenSize = 0; + table->BlueSize = 0; + table->AlphaSize = 0; + table->IntensitySize = sz; + table->LuminanceSize = 0; + break; + case GL_RGB: + table->RedSize = sz; + table->GreenSize = sz; + table->BlueSize = sz; + table->AlphaSize = 0; + table->IntensitySize = 0; + table->LuminanceSize = 0; + break; + case GL_RGBA: + table->RedSize = sz; + table->GreenSize = sz; + table->BlueSize = sz; + table->AlphaSize = sz; + table->IntensitySize = 0; + table->LuminanceSize = 0; + break; + default: + _mesa_problem(NULL, "unexpected format in set_component_sizes"); + } +} + + + +/** + * Update/replace all or part of a color table. Helper function + * used by _mesa_ColorTable() and _mesa_ColorSubTable(). + * The table->Table buffer should already be allocated. + * \param start first entry to update + * \param count number of entries to update + * \param format format of user-provided table data + * \param type datatype of user-provided table data + * \param data user-provided table data + * \param [rgba]Scale - RGBA scale factors + * \param [rgba]Bias - RGBA bias factors + */ +static void +store_colortable_entries(struct gl_context *ctx, struct gl_color_table *table, + GLsizei start, GLsizei count, + GLenum format, GLenum type, const GLvoid *data, + GLfloat rScale, GLfloat rBias, + GLfloat gScale, GLfloat gBias, + GLfloat bScale, GLfloat bBias, + GLfloat aScale, GLfloat aBias) +{ + data = _mesa_map_validate_pbo_source(ctx, + 1, &ctx->Unpack, count, 1, 1, + format, type, data, + "glColor[Sub]Table"); + if (!data) + return; + + { + /* convert user-provided data to GLfloat values */ + GLfloat tempTab[MAX_COLOR_TABLE_SIZE * 4]; + GLfloat *tableF; + GLint i; + + _mesa_unpack_color_span_float(ctx, + count, /* number of pixels */ + table->_BaseFormat, /* dest format */ + tempTab, /* dest address */ + format, type, /* src format/type */ + data, /* src data */ + &ctx->Unpack, + IMAGE_CLAMP_BIT); /* transfer ops */ + + /* the destination */ + tableF = table->TableF; + + /* Apply scale & bias & clamp now */ + switch (table->_BaseFormat) { + case GL_INTENSITY: + for (i = 0; i < count; i++) { + GLuint j = start + i; + tableF[j] = CLAMP(tempTab[i] * rScale + rBias, 0.0F, 1.0F); + } + break; + case GL_LUMINANCE: + for (i = 0; i < count; i++) { + GLuint j = start + i; + tableF[j] = CLAMP(tempTab[i] * rScale + rBias, 0.0F, 1.0F); + } + break; + case GL_ALPHA: + for (i = 0; i < count; i++) { + GLuint j = start + i; + tableF[j] = CLAMP(tempTab[i] * aScale + aBias, 0.0F, 1.0F); + } + break; + case GL_LUMINANCE_ALPHA: + for (i = 0; i < count; i++) { + GLuint j = start + i; + tableF[j*2+0] = CLAMP(tempTab[i*2+0] * rScale + rBias, 0.0F, 1.0F); + tableF[j*2+1] = CLAMP(tempTab[i*2+1] * aScale + aBias, 0.0F, 1.0F); + } + break; + case GL_RGB: + for (i = 0; i < count; i++) { + GLuint j = start + i; + tableF[j*3+0] = CLAMP(tempTab[i*3+0] * rScale + rBias, 0.0F, 1.0F); + tableF[j*3+1] = CLAMP(tempTab[i*3+1] * gScale + gBias, 0.0F, 1.0F); + tableF[j*3+2] = CLAMP(tempTab[i*3+2] * bScale + bBias, 0.0F, 1.0F); + } + break; + case GL_RGBA: + for (i = 0; i < count; i++) { + GLuint j = start + i; + tableF[j*4+0] = CLAMP(tempTab[i*4+0] * rScale + rBias, 0.0F, 1.0F); + tableF[j*4+1] = CLAMP(tempTab[i*4+1] * gScale + gBias, 0.0F, 1.0F); + tableF[j*4+2] = CLAMP(tempTab[i*4+2] * bScale + bBias, 0.0F, 1.0F); + tableF[j*4+3] = CLAMP(tempTab[i*4+3] * aScale + aBias, 0.0F, 1.0F); + } + break; + default: + _mesa_problem(ctx, "Bad format in store_colortable_entries"); + return; + } + } + + /* update the ubyte table */ + { + const GLint comps = _mesa_components_in_format(table->_BaseFormat); + const GLfloat *tableF = table->TableF + start * comps; + GLubyte *tableUB = table->TableUB + start * comps; + GLint i; + for (i = 0; i < count * comps; i++) { + CLAMPED_FLOAT_TO_UBYTE(tableUB[i], tableF[i]); + } + } + + _mesa_unmap_pbo_source(ctx, &ctx->Unpack); +} + + + +void GLAPIENTRY +_mesa_ColorTable( GLenum target, GLenum internalFormat, + GLsizei width, GLenum format, GLenum type, + const GLvoid *data ) +{ + static const GLfloat one[4] = { 1.0, 1.0, 1.0, 1.0 }; + static const GLfloat zero[4] = { 0.0, 0.0, 0.0, 0.0 }; + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + struct gl_texture_object *texObj = NULL; + struct gl_color_table *table = NULL; + GLboolean proxy = GL_FALSE; + GLint baseFormat; + const GLfloat *scale = one, *bias = zero; + GLint comps; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */ + + switch (target) { + case GL_SHARED_TEXTURE_PALETTE_EXT: + table = &ctx->Texture.Palette; + break; + default: + /* try texture targets */ + { + struct gl_texture_object *texobj + = _mesa_select_tex_object(ctx, texUnit, target); + if (texobj) { + table = &texobj->Palette; + proxy = _mesa_is_proxy_texture(target); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(target)"); + return; + } + } + } + + assert(table); + + if (!_mesa_is_legal_format_and_type(ctx, format, type) || + format == GL_INTENSITY) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glColorTable(format or type)"); + return; + } + + baseFormat = base_colortab_format(internalFormat); + if (baseFormat < 0) { + _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(internalFormat)"); + return; + } + + if (width < 0 || (width != 0 && !_mesa_is_pow_two(width))) { + /* error */ + if (proxy) { + table->Size = 0; + table->InternalFormat = (GLenum) 0; + table->_BaseFormat = (GLenum) 0; + } + else { + _mesa_error(ctx, GL_INVALID_VALUE, "glColorTable(width=%d)", width); + } + return; + } + + if (width > (GLsizei) ctx->Const.MaxColorTableSize) { + if (proxy) { + table->Size = 0; + table->InternalFormat = (GLenum) 0; + table->_BaseFormat = (GLenum) 0; + } + else { + _mesa_error(ctx, GL_TABLE_TOO_LARGE, "glColorTable(width)"); + } + return; + } + + table->Size = width; + table->InternalFormat = internalFormat; + table->_BaseFormat = (GLenum) baseFormat; + + comps = _mesa_components_in_format(table->_BaseFormat); + assert(comps > 0); /* error should have been caught sooner */ + + if (!proxy) { + _mesa_free_colortable_data(table); + + if (width > 0) { + table->TableF = (GLfloat *) malloc(comps * width * sizeof(GLfloat)); + table->TableUB = (GLubyte *) malloc(comps * width * sizeof(GLubyte)); + + if (!table->TableF || !table->TableUB) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glColorTable"); + return; + } + + store_colortable_entries(ctx, table, + 0, width, /* start, count */ + format, type, data, + scale[0], bias[0], + scale[1], bias[1], + scale[2], bias[2], + scale[3], bias[3]); + } + } /* proxy */ + + /* do this after the table's Type and Format are set */ + set_component_sizes(table); + + if (texObj || target == GL_SHARED_TEXTURE_PALETTE_EXT) { + /* texture object palette, texObj==NULL means the shared palette */ + if (ctx->Driver.UpdateTexturePalette) { + (*ctx->Driver.UpdateTexturePalette)( ctx, texObj ); + } + } + + ctx->NewState |= _NEW_PIXEL; +} + + + +void GLAPIENTRY +_mesa_ColorSubTable( GLenum target, GLsizei start, + GLsizei count, GLenum format, GLenum type, + const GLvoid *data ) +{ + static const GLfloat one[4] = { 1.0, 1.0, 1.0, 1.0 }; + static const GLfloat zero[4] = { 0.0, 0.0, 0.0, 0.0 }; + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + struct gl_texture_object *texObj = NULL; + struct gl_color_table *table = NULL; + const GLfloat *scale = one, *bias = zero; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + switch (target) { + case GL_SHARED_TEXTURE_PALETTE_EXT: + table = &ctx->Texture.Palette; + break; + default: + /* try texture targets */ + texObj = _mesa_select_tex_object(ctx, texUnit, target); + if (texObj && !_mesa_is_proxy_texture(target)) { + table = &texObj->Palette; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glColorSubTable(target)"); + return; + } + } + + assert(table); + + if (!_mesa_is_legal_format_and_type(ctx, format, type) || + format == GL_INTENSITY) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glColorSubTable(format or type)"); + return; + } + + if (count < 1) { + _mesa_error(ctx, GL_INVALID_VALUE, "glColorSubTable(count)"); + return; + } + + /* error should have been caught sooner */ + assert(_mesa_components_in_format(table->_BaseFormat) > 0); + + if (start + count > (GLint) table->Size) { + _mesa_error(ctx, GL_INVALID_VALUE, "glColorSubTable(count)"); + return; + } + + if (!table->TableF || !table->TableUB) { + /* a GL_OUT_OF_MEMORY error would have been recorded previously */ + return; + } + + store_colortable_entries(ctx, table, start, count, + format, type, data, + scale[0], bias[0], + scale[1], bias[1], + scale[2], bias[2], + scale[3], bias[3]); + + if (texObj || target == GL_SHARED_TEXTURE_PALETTE_EXT) { + /* per-texture object palette */ + if (ctx->Driver.UpdateTexturePalette) { + (*ctx->Driver.UpdateTexturePalette)( ctx, texObj ); + } + } + + ctx->NewState |= _NEW_PIXEL; +} + + + +static void GLAPIENTRY +_mesa_CopyColorTable(GLenum target, GLenum internalformat, + GLint x, GLint y, GLsizei width) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (!ctx->ReadBuffer->_ColorReadBuffer) { + return; /* no readbuffer - OK */ + } + + ctx->Driver.CopyColorTable( ctx, target, internalformat, x, y, width ); +} + + + +static void GLAPIENTRY +_mesa_CopyColorSubTable(GLenum target, GLsizei start, + GLint x, GLint y, GLsizei width) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (!ctx->ReadBuffer->_ColorReadBuffer) { + return; /* no readbuffer - OK */ + } + + ctx->Driver.CopyColorSubTable( ctx, target, start, x, y, width ); +} + + + +static void GLAPIENTRY +_mesa_GetColorTable( GLenum target, GLenum format, + GLenum type, GLvoid *data ) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + struct gl_color_table *table = NULL; + GLfloat rgba[MAX_COLOR_TABLE_SIZE][4]; + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (ctx->NewState) { + _mesa_update_state(ctx); + } + + switch (target) { + case GL_SHARED_TEXTURE_PALETTE_EXT: + table = &ctx->Texture.Palette; + break; + default: + /* try texture targets */ + { + struct gl_texture_object *texobj + = _mesa_select_tex_object(ctx, texUnit, target); + if (texobj && !_mesa_is_proxy_texture(target)) { + table = &texobj->Palette; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTable(target)"); + return; + } + } + } + + ASSERT(table); + + if (table->Size <= 0) { + return; + } + + switch (table->_BaseFormat) { + case GL_ALPHA: + { + GLuint i; + for (i = 0; i < table->Size; i++) { + rgba[i][RCOMP] = 0; + rgba[i][GCOMP] = 0; + rgba[i][BCOMP] = 0; + rgba[i][ACOMP] = table->TableF[i]; + } + } + break; + case GL_LUMINANCE: + { + GLuint i; + for (i = 0; i < table->Size; i++) { + rgba[i][RCOMP] = + rgba[i][GCOMP] = + rgba[i][BCOMP] = table->TableF[i]; + rgba[i][ACOMP] = 1.0F; + } + } + break; + case GL_LUMINANCE_ALPHA: + { + GLuint i; + for (i = 0; i < table->Size; i++) { + rgba[i][RCOMP] = + rgba[i][GCOMP] = + rgba[i][BCOMP] = table->TableF[i*2+0]; + rgba[i][ACOMP] = table->TableF[i*2+1]; + } + } + break; + case GL_INTENSITY: + { + GLuint i; + for (i = 0; i < table->Size; i++) { + rgba[i][RCOMP] = + rgba[i][GCOMP] = + rgba[i][BCOMP] = + rgba[i][ACOMP] = table->TableF[i]; + } + } + break; + case GL_RGB: + { + GLuint i; + for (i = 0; i < table->Size; i++) { + rgba[i][RCOMP] = table->TableF[i*3+0]; + rgba[i][GCOMP] = table->TableF[i*3+1]; + rgba[i][BCOMP] = table->TableF[i*3+2]; + rgba[i][ACOMP] = 1.0F; + } + } + break; + case GL_RGBA: + memcpy(rgba, table->TableF, 4 * table->Size * sizeof(GLfloat)); + break; + default: + _mesa_problem(ctx, "bad table format in glGetColorTable"); + return; + } + + data = _mesa_map_validate_pbo_dest(ctx, + 1, &ctx->Pack, table->Size, 1, 1, + format, type, data, + "glGetColorTable"); + if (!data) + return; + + _mesa_pack_rgba_span_float(ctx, table->Size, rgba, + format, type, data, &ctx->Pack, 0x0); + + _mesa_unmap_pbo_dest(ctx, &ctx->Pack); +} + + + +static void GLAPIENTRY +_mesa_ColorTableParameterfv(GLenum target, GLenum pname, const GLfloat *params) +{ + /* no extensions use this function */ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + _mesa_error(ctx, GL_INVALID_ENUM, "glColorTableParameterfv(target)"); +} + + + +static void GLAPIENTRY +_mesa_ColorTableParameteriv(GLenum target, GLenum pname, const GLint *params) +{ + /* no extensions use this function */ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + _mesa_error(ctx, GL_INVALID_ENUM, "glColorTableParameteriv(target)"); +} + + + +static void GLAPIENTRY +_mesa_GetColorTableParameterfv( GLenum target, GLenum pname, GLfloat *params ) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + struct gl_color_table *table = NULL; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + switch (target) { + case GL_SHARED_TEXTURE_PALETTE_EXT: + table = &ctx->Texture.Palette; + break; + default: + /* try texture targets */ + { + struct gl_texture_object *texobj + = _mesa_select_tex_object(ctx, texUnit, target); + if (texobj) { + table = &texobj->Palette; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetColorTableParameterfv(target)"); + return; + } + } + } + + assert(table); + + switch (pname) { + case GL_COLOR_TABLE_FORMAT: + *params = (GLfloat) table->InternalFormat; + break; + case GL_COLOR_TABLE_WIDTH: + *params = (GLfloat) table->Size; + break; + case GL_COLOR_TABLE_RED_SIZE: + *params = (GLfloat) table->RedSize; + break; + case GL_COLOR_TABLE_GREEN_SIZE: + *params = (GLfloat) table->GreenSize; + break; + case GL_COLOR_TABLE_BLUE_SIZE: + *params = (GLfloat) table->BlueSize; + break; + case GL_COLOR_TABLE_ALPHA_SIZE: + *params = (GLfloat) table->AlphaSize; + break; + case GL_COLOR_TABLE_LUMINANCE_SIZE: + *params = (GLfloat) table->LuminanceSize; + break; + case GL_COLOR_TABLE_INTENSITY_SIZE: + *params = (GLfloat) table->IntensitySize; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameterfv(pname)" ); + return; + } +} + + + +static void GLAPIENTRY +_mesa_GetColorTableParameteriv( GLenum target, GLenum pname, GLint *params ) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + struct gl_color_table *table = NULL; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + switch (target) { + case GL_SHARED_TEXTURE_PALETTE_EXT: + table = &ctx->Texture.Palette; + break; + default: + /* Try texture targets */ + { + struct gl_texture_object *texobj + = _mesa_select_tex_object(ctx, texUnit, target); + if (texobj) { + table = &texobj->Palette; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetColorTableParameteriv(target)"); + return; + } + } + } + + assert(table); + + switch (pname) { + case GL_COLOR_TABLE_FORMAT: + *params = table->InternalFormat; + break; + case GL_COLOR_TABLE_WIDTH: + *params = table->Size; + break; + case GL_COLOR_TABLE_RED_SIZE: + *params = table->RedSize; + break; + case GL_COLOR_TABLE_GREEN_SIZE: + *params = table->GreenSize; + break; + case GL_COLOR_TABLE_BLUE_SIZE: + *params = table->BlueSize; + break; + case GL_COLOR_TABLE_ALPHA_SIZE: + *params = table->AlphaSize; + break; + case GL_COLOR_TABLE_LUMINANCE_SIZE: + *params = table->LuminanceSize; + break; + case GL_COLOR_TABLE_INTENSITY_SIZE: + *params = table->IntensitySize; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameteriv(pname)" ); + return; + } +} + + +void +_mesa_init_colortable_dispatch(struct _glapi_table *disp) +{ + SET_ColorSubTable(disp, _mesa_ColorSubTable); + SET_ColorTable(disp, _mesa_ColorTable); + SET_ColorTableParameterfv(disp, _mesa_ColorTableParameterfv); + SET_ColorTableParameteriv(disp, _mesa_ColorTableParameteriv); + SET_CopyColorSubTable(disp, _mesa_CopyColorSubTable); + SET_CopyColorTable(disp, _mesa_CopyColorTable); + SET_GetColorTable(disp, _mesa_GetColorTable); + SET_GetColorTableParameterfv(disp, _mesa_GetColorTableParameterfv); + SET_GetColorTableParameteriv(disp, _mesa_GetColorTableParameteriv); +} + + +#endif /* FEATURE_colortable */ + + +/**********************************************************************/ +/***** Initialization *****/ +/**********************************************************************/ + + +void +_mesa_init_colortable( struct gl_color_table *p ) +{ + p->TableF = NULL; + p->TableUB = NULL; + p->Size = 0; + p->InternalFormat = GL_RGBA; +} + + + +void +_mesa_free_colortable_data( struct gl_color_table *p ) +{ + if (p->TableF) { + free(p->TableF); + p->TableF = NULL; + } + if (p->TableUB) { + free(p->TableUB); + p->TableUB = NULL; + } +} diff --git a/mesalib/src/mesa/main/dlist.c b/mesalib/src/mesa/main/dlist.c index 8e904c778..4e463dd06 100644 --- a/mesalib/src/mesa/main/dlist.c +++ b/mesalib/src/mesa/main/dlist.c @@ -54,6 +54,7 @@ #include "light.h" #include "macros.h" #include "pack.h" +#include "pbo.h" #include "queryobj.h" #include "teximage.h" #include "mtypes.h" diff --git a/mesalib/src/mesa/main/drawpix.c b/mesalib/src/mesa/main/drawpix.c index 554d7a84a..98e82ef85 100644 --- a/mesalib/src/mesa/main/drawpix.c +++ b/mesalib/src/mesa/main/drawpix.c @@ -1,303 +1,304 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.1
- *
- * Copyright (C) 1999-2008 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.
- */
-
-#include "glheader.h"
-#include "imports.h"
-#include "bufferobj.h"
-#include "context.h"
-#include "drawpix.h"
-#include "enums.h"
-#include "feedback.h"
-#include "framebuffer.h"
-#include "mfeatures.h"
-#include "readpix.h"
-#include "state.h"
-#include "dispatch.h"
-
-
-#if FEATURE_drawpix
-
-
-/*
- * Execute glDrawPixels
- */
-static void GLAPIENTRY
-_mesa_DrawPixels( GLsizei width, GLsizei height,
- GLenum format, GLenum type, const GLvoid *pixels )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx, "glDrawPixels(%d, %d, %s, %s, %p) // to %s at %d, %d\n",
- width, height,
- _mesa_lookup_enum_by_nr(format),
- _mesa_lookup_enum_by_nr(type),
- pixels,
- _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]),
- IROUND(ctx->Current.RasterPos[0]),
- IROUND(ctx->Current.RasterPos[1]));
-
-
- if (width < 0 || height < 0) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" );
- return;
- }
-
- /* We're not using the current vertex program, and the driver may install
- * its own. Note: this may dirty some state.
- */
- _mesa_set_vp_override(ctx, GL_TRUE);
-
- /* Note: this call does state validation */
- if (!_mesa_valid_to_render(ctx, "glDrawPixels")) {
- goto end; /* the error code was recorded */
- }
-
- if (_mesa_error_check_format_type(ctx, format, type, GL_TRUE)) {
- goto end; /* the error code was recorded */
- }
-
- if (!ctx->Current.RasterPosValid) {
- goto end; /* no-op, not an error */
- }
-
- if (ctx->RenderMode == GL_RENDER) {
- if (width > 0 && height > 0) {
- /* Round, to satisfy conformance tests (matches SGI's OpenGL) */
- GLint x = IROUND(ctx->Current.RasterPos[0]);
- GLint y = IROUND(ctx->Current.RasterPos[1]);
-
- if (ctx->Unpack.BufferObj->Name) {
- /* unpack from PBO */
- if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1,
- format, type, pixels)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glDrawPixels(invalid PBO access)");
- goto end;
- }
- if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) {
- /* buffer is mapped - that's an error */
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glDrawPixels(PBO is mapped)");
- goto end;
- }
- }
-
- ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type,
- &ctx->Unpack, pixels);
- }
- }
- else if (ctx->RenderMode == GL_FEEDBACK) {
- /* Feedback the current raster pos info */
- FLUSH_CURRENT( ctx, 0 );
- _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
- _mesa_feedback_vertex( ctx,
- ctx->Current.RasterPos,
- ctx->Current.RasterColor,
- ctx->Current.RasterTexCoords[0] );
- }
- else {
- ASSERT(ctx->RenderMode == GL_SELECT);
- /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */
- }
-
-end:
- _mesa_set_vp_override(ctx, GL_FALSE);
-}
-
-
-static void GLAPIENTRY
-_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height,
- GLenum type )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- _mesa_finish(ctx);
-
- if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx,
- "glCopyPixels(%d, %d, %d, %d, %s) // from %s to %s at %d, %d\n",
- srcx, srcy, width, height,
- _mesa_lookup_enum_by_nr(type),
- _mesa_lookup_enum_by_nr(ctx->ReadBuffer->ColorReadBuffer),
- _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]),
- IROUND(ctx->Current.RasterPos[0]),
- IROUND(ctx->Current.RasterPos[1]));
-
- if (width < 0 || height < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)");
- return;
- }
-
- /* Note: more detailed 'type' checking is done by the
- * _mesa_source/dest_buffer_exists() calls below. That's where we
- * check if the stencil buffer exists, etc.
- */
- if (type != GL_COLOR &&
- type != GL_DEPTH &&
- type != GL_STENCIL &&
- type != GL_DEPTH_STENCIL) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)",
- _mesa_lookup_enum_by_nr(type));
- return;
- }
-
- /* We're not using the current vertex program, and the driver may install
- * it's own. Note: this may dirty some state.
- */
- _mesa_set_vp_override(ctx, GL_TRUE);
-
- /* Note: this call does state validation */
- if (!_mesa_valid_to_render(ctx, "glCopyPixels")) {
- goto end; /* the error code was recorded */
- }
-
- /* Check read buffer's status (draw buffer was already checked) */
- if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
- "glCopyPixels(incomplete framebuffer)" );
- goto end;
- }
-
- if (!_mesa_source_buffer_exists(ctx, type) ||
- !_mesa_dest_buffer_exists(ctx, type)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glCopyPixels(missing source or dest buffer)");
- goto end;
- }
-
- if (!ctx->Current.RasterPosValid || width ==0 || height == 0) {
- goto end; /* no-op, not an error */
- }
-
- if (ctx->RenderMode == GL_RENDER) {
- /* Round to satisfy conformance tests (matches SGI's OpenGL) */
- if (width > 0 && height > 0) {
- GLint destx = IROUND(ctx->Current.RasterPos[0]);
- GLint desty = IROUND(ctx->Current.RasterPos[1]);
- ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty,
- type );
- }
- }
- else if (ctx->RenderMode == GL_FEEDBACK) {
- FLUSH_CURRENT( ctx, 0 );
- _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN );
- _mesa_feedback_vertex( ctx,
- ctx->Current.RasterPos,
- ctx->Current.RasterColor,
- ctx->Current.RasterTexCoords[0] );
- }
- else {
- ASSERT(ctx->RenderMode == GL_SELECT);
- /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */
- }
-
-end:
- _mesa_set_vp_override(ctx, GL_FALSE);
-}
-
-
-static void GLAPIENTRY
-_mesa_Bitmap( GLsizei width, GLsizei height,
- GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove,
- const GLubyte *bitmap )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (width < 0 || height < 0) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" );
- return;
- }
-
- if (!ctx->Current.RasterPosValid) {
- return; /* do nothing */
- }
-
- /* Note: this call does state validation */
- if (!_mesa_valid_to_render(ctx, "glBitmap")) {
- /* the error code was recorded */
- return;
- }
-
- if (ctx->RenderMode == GL_RENDER) {
- /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */
- if (width > 0 && height > 0) {
- const GLfloat epsilon = 0.0001F;
- GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig);
- GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig);
-
- if (ctx->Unpack.BufferObj->Name) {
- /* unpack from PBO */
- if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1,
- GL_COLOR_INDEX, GL_BITMAP,
- (GLvoid *) bitmap)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBitmap(invalid PBO access)");
- return;
- }
- if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) {
- /* buffer is mapped - that's an error */
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBitmap(PBO is mapped)");
- return;
- }
- }
-
- ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap );
- }
- }
-#if _HAVE_FULL_GL
- else if (ctx->RenderMode == GL_FEEDBACK) {
- FLUSH_CURRENT(ctx, 0);
- _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN );
- _mesa_feedback_vertex( ctx,
- ctx->Current.RasterPos,
- ctx->Current.RasterColor,
- ctx->Current.RasterTexCoords[0] );
- }
- else {
- ASSERT(ctx->RenderMode == GL_SELECT);
- /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */
- }
-#endif
-
- /* update raster position */
- ctx->Current.RasterPos[0] += xmove;
- ctx->Current.RasterPos[1] += ymove;
-}
-
-
-void
-_mesa_init_drawpix_dispatch(struct _glapi_table *disp)
-{
- SET_Bitmap(disp, _mesa_Bitmap);
- SET_CopyPixels(disp, _mesa_CopyPixels);
- SET_DrawPixels(disp, _mesa_DrawPixels);
-}
-
-
-#endif /* FEATURE_drawpix */
+/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2008 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. + */ + +#include "glheader.h" +#include "imports.h" +#include "bufferobj.h" +#include "context.h" +#include "drawpix.h" +#include "enums.h" +#include "feedback.h" +#include "framebuffer.h" +#include "mfeatures.h" +#include "pbo.h" +#include "readpix.h" +#include "state.h" +#include "dispatch.h" + + +#if FEATURE_drawpix + + +/* + * Execute glDrawPixels + */ +static void GLAPIENTRY +_mesa_DrawPixels( GLsizei width, GLsizei height, + GLenum format, GLenum type, const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glDrawPixels(%d, %d, %s, %s, %p) // to %s at %d, %d\n", + width, height, + _mesa_lookup_enum_by_nr(format), + _mesa_lookup_enum_by_nr(type), + pixels, + _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]), + IROUND(ctx->Current.RasterPos[0]), + IROUND(ctx->Current.RasterPos[1])); + + + if (width < 0 || height < 0) { + _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" ); + return; + } + + /* We're not using the current vertex program, and the driver may install + * its own. Note: this may dirty some state. + */ + _mesa_set_vp_override(ctx, GL_TRUE); + + /* Note: this call does state validation */ + if (!_mesa_valid_to_render(ctx, "glDrawPixels")) { + goto end; /* the error code was recorded */ + } + + if (_mesa_error_check_format_type(ctx, format, type, GL_TRUE)) { + goto end; /* the error code was recorded */ + } + + if (!ctx->Current.RasterPosValid) { + goto end; /* no-op, not an error */ + } + + if (ctx->RenderMode == GL_RENDER) { + if (width > 0 && height > 0) { + /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ + GLint x = IROUND(ctx->Current.RasterPos[0]); + GLint y = IROUND(ctx->Current.RasterPos[1]); + + if (ctx->Unpack.BufferObj->Name) { + /* unpack from PBO */ + if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, + format, type, pixels)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDrawPixels(invalid PBO access)"); + goto end; + } + if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) { + /* buffer is mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDrawPixels(PBO is mapped)"); + goto end; + } + } + + ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, + &ctx->Unpack, pixels); + } + } + else if (ctx->RenderMode == GL_FEEDBACK) { + /* Feedback the current raster pos info */ + FLUSH_CURRENT( ctx, 0 ); + _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); + _mesa_feedback_vertex( ctx, + ctx->Current.RasterPos, + ctx->Current.RasterColor, + ctx->Current.RasterTexCoords[0] ); + } + else { + ASSERT(ctx->RenderMode == GL_SELECT); + /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ + } + +end: + _mesa_set_vp_override(ctx, GL_FALSE); +} + + +static void GLAPIENTRY +_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, + GLenum type ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + _mesa_finish(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, + "glCopyPixels(%d, %d, %d, %d, %s) // from %s to %s at %d, %d\n", + srcx, srcy, width, height, + _mesa_lookup_enum_by_nr(type), + _mesa_lookup_enum_by_nr(ctx->ReadBuffer->ColorReadBuffer), + _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]), + IROUND(ctx->Current.RasterPos[0]), + IROUND(ctx->Current.RasterPos[1])); + + if (width < 0 || height < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); + return; + } + + /* Note: more detailed 'type' checking is done by the + * _mesa_source/dest_buffer_exists() calls below. That's where we + * check if the stencil buffer exists, etc. + */ + if (type != GL_COLOR && + type != GL_DEPTH && + type != GL_STENCIL && + type != GL_DEPTH_STENCIL) { + _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)", + _mesa_lookup_enum_by_nr(type)); + return; + } + + /* We're not using the current vertex program, and the driver may install + * it's own. Note: this may dirty some state. + */ + _mesa_set_vp_override(ctx, GL_TRUE); + + /* Note: this call does state validation */ + if (!_mesa_valid_to_render(ctx, "glCopyPixels")) { + goto end; /* the error code was recorded */ + } + + /* Check read buffer's status (draw buffer was already checked) */ + if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "glCopyPixels(incomplete framebuffer)" ); + goto end; + } + + if (!_mesa_source_buffer_exists(ctx, type) || + !_mesa_dest_buffer_exists(ctx, type)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyPixels(missing source or dest buffer)"); + goto end; + } + + if (!ctx->Current.RasterPosValid || width ==0 || height == 0) { + goto end; /* no-op, not an error */ + } + + if (ctx->RenderMode == GL_RENDER) { + /* Round to satisfy conformance tests (matches SGI's OpenGL) */ + if (width > 0 && height > 0) { + GLint destx = IROUND(ctx->Current.RasterPos[0]); + GLint desty = IROUND(ctx->Current.RasterPos[1]); + ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, + type ); + } + } + else if (ctx->RenderMode == GL_FEEDBACK) { + FLUSH_CURRENT( ctx, 0 ); + _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); + _mesa_feedback_vertex( ctx, + ctx->Current.RasterPos, + ctx->Current.RasterColor, + ctx->Current.RasterTexCoords[0] ); + } + else { + ASSERT(ctx->RenderMode == GL_SELECT); + /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ + } + +end: + _mesa_set_vp_override(ctx, GL_FALSE); +} + + +static void GLAPIENTRY +_mesa_Bitmap( GLsizei width, GLsizei height, + GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, + const GLubyte *bitmap ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (width < 0 || height < 0) { + _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); + return; + } + + if (!ctx->Current.RasterPosValid) { + return; /* do nothing */ + } + + /* Note: this call does state validation */ + if (!_mesa_valid_to_render(ctx, "glBitmap")) { + /* the error code was recorded */ + return; + } + + if (ctx->RenderMode == GL_RENDER) { + /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ + if (width > 0 && height > 0) { + const GLfloat epsilon = 0.0001F; + GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig); + GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig); + + if (ctx->Unpack.BufferObj->Name) { + /* unpack from PBO */ + if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, + GL_COLOR_INDEX, GL_BITMAP, + (GLvoid *) bitmap)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBitmap(invalid PBO access)"); + return; + } + if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) { + /* buffer is mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBitmap(PBO is mapped)"); + return; + } + } + + ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); + } + } +#if _HAVE_FULL_GL + else if (ctx->RenderMode == GL_FEEDBACK) { + FLUSH_CURRENT(ctx, 0); + _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); + _mesa_feedback_vertex( ctx, + ctx->Current.RasterPos, + ctx->Current.RasterColor, + ctx->Current.RasterTexCoords[0] ); + } + else { + ASSERT(ctx->RenderMode == GL_SELECT); + /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ + } +#endif + + /* update raster position */ + ctx->Current.RasterPos[0] += xmove; + ctx->Current.RasterPos[1] += ymove; +} + + +void +_mesa_init_drawpix_dispatch(struct _glapi_table *disp) +{ + SET_Bitmap(disp, _mesa_Bitmap); + SET_CopyPixels(disp, _mesa_CopyPixels); + SET_DrawPixels(disp, _mesa_DrawPixels); +} + + +#endif /* FEATURE_drawpix */ diff --git a/mesalib/src/mesa/main/enable.c b/mesalib/src/mesa/main/enable.c index 231278bee..f24709241 100644 --- a/mesalib/src/mesa/main/enable.c +++ b/mesalib/src/mesa/main/enable.c @@ -1,1501 +1,1487 @@ -/**
- * \file enable.c
- * Enable/disable/query GL capabilities.
- */
-
-/*
- * Mesa 3-D graphics library
- * Version: 7.0.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.
- */
-
-
-#include "glheader.h"
-#include "context.h"
-#include "enable.h"
-#include "light.h"
-#include "simple_list.h"
-#include "mfeatures.h"
-#include "mtypes.h"
-#include "enums.h"
-#include "api_arrayelt.h"
-#include "texstate.h"
-
-
-
-#define CHECK_EXTENSION(EXTNAME, CAP) \
- if (!ctx->Extensions.EXTNAME) { \
- goto invalid_enum_error; \
- }
-
-
-/**
- * Helper to enable/disable client-side state.
- */
-static void
-client_state(struct gl_context *ctx, GLenum cap, GLboolean state)
-{
- struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
- GLuint flag;
- GLboolean *var;
-
- switch (cap) {
- case GL_VERTEX_ARRAY:
- var = &arrayObj->Vertex.Enabled;
- flag = _NEW_ARRAY_VERTEX;
- break;
- case GL_NORMAL_ARRAY:
- var = &arrayObj->Normal.Enabled;
- flag = _NEW_ARRAY_NORMAL;
- break;
- case GL_COLOR_ARRAY:
- var = &arrayObj->Color.Enabled;
- flag = _NEW_ARRAY_COLOR0;
- break;
- case GL_INDEX_ARRAY:
- var = &arrayObj->Index.Enabled;
- flag = _NEW_ARRAY_INDEX;
- break;
- case GL_TEXTURE_COORD_ARRAY:
- var = &arrayObj->TexCoord[ctx->Array.ActiveTexture].Enabled;
- flag = _NEW_ARRAY_TEXCOORD(ctx->Array.ActiveTexture);
- break;
- case GL_EDGE_FLAG_ARRAY:
- var = &arrayObj->EdgeFlag.Enabled;
- flag = _NEW_ARRAY_EDGEFLAG;
- break;
- case GL_FOG_COORDINATE_ARRAY_EXT:
- var = &arrayObj->FogCoord.Enabled;
- flag = _NEW_ARRAY_FOGCOORD;
- break;
- case GL_SECONDARY_COLOR_ARRAY_EXT:
- var = &arrayObj->SecondaryColor.Enabled;
- flag = _NEW_ARRAY_COLOR1;
- break;
-
-#if FEATURE_point_size_array
- case GL_POINT_SIZE_ARRAY_OES:
- var = &arrayObj->PointSize.Enabled;
- flag = _NEW_ARRAY_POINT_SIZE;
- break;
-#endif
-
-#if FEATURE_NV_vertex_program
- case GL_VERTEX_ATTRIB_ARRAY0_NV:
- case GL_VERTEX_ATTRIB_ARRAY1_NV:
- case GL_VERTEX_ATTRIB_ARRAY2_NV:
- case GL_VERTEX_ATTRIB_ARRAY3_NV:
- case GL_VERTEX_ATTRIB_ARRAY4_NV:
- case GL_VERTEX_ATTRIB_ARRAY5_NV:
- case GL_VERTEX_ATTRIB_ARRAY6_NV:
- case GL_VERTEX_ATTRIB_ARRAY7_NV:
- case GL_VERTEX_ATTRIB_ARRAY8_NV:
- case GL_VERTEX_ATTRIB_ARRAY9_NV:
- case GL_VERTEX_ATTRIB_ARRAY10_NV:
- case GL_VERTEX_ATTRIB_ARRAY11_NV:
- case GL_VERTEX_ATTRIB_ARRAY12_NV:
- case GL_VERTEX_ATTRIB_ARRAY13_NV:
- case GL_VERTEX_ATTRIB_ARRAY14_NV:
- case GL_VERTEX_ATTRIB_ARRAY15_NV:
- CHECK_EXTENSION(NV_vertex_program, cap);
- {
- GLint n = (GLint) cap - GL_VERTEX_ATTRIB_ARRAY0_NV;
- ASSERT(n < Elements(ctx->Array.ArrayObj->VertexAttrib));
- var = &arrayObj->VertexAttrib[n].Enabled;
- flag = _NEW_ARRAY_ATTRIB(n);
- }
- break;
-#endif /* FEATURE_NV_vertex_program */
-
- /* GL_NV_primitive_restart */
- case GL_PRIMITIVE_RESTART_NV:
- if (!ctx->Extensions.NV_primitive_restart) {
- goto invalid_enum_error;
- }
- var = &ctx->Array.PrimitiveRestart;
- flag = 0;
- break;
-
- default:
- goto invalid_enum_error;
- }
-
- if (*var == state)
- return;
-
- FLUSH_VERTICES(ctx, _NEW_ARRAY);
- ctx->Array.NewState |= flag;
-
- _ae_invalidate_state(ctx, _NEW_ARRAY);
-
- *var = state;
-
- if (state)
- ctx->Array.ArrayObj->_Enabled |= flag;
- else
- ctx->Array.ArrayObj->_Enabled &= ~flag;
-
- if (ctx->Driver.Enable) {
- ctx->Driver.Enable( ctx, cap, state );
- }
-
- return;
-
-invalid_enum_error:
- _mesa_error(ctx, GL_INVALID_ENUM, "gl%sClientState(0x%x)",
- state ? "Enable" : "Disable", cap);
-}
-
-
-/**
- * Enable GL capability.
- * \param cap state to enable/disable.
- *
- * Get's the current context, assures that we're outside glBegin()/glEnd() and
- * calls client_state().
- */
-void GLAPIENTRY
-_mesa_EnableClientState( GLenum cap )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- client_state( ctx, cap, GL_TRUE );
-}
-
-
-/**
- * Disable GL capability.
- * \param cap state to enable/disable.
- *
- * Get's the current context, assures that we're outside glBegin()/glEnd() and
- * calls client_state().
- */
-void GLAPIENTRY
-_mesa_DisableClientState( GLenum cap )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- client_state( ctx, cap, GL_FALSE );
-}
-
-
-#undef CHECK_EXTENSION
-#define CHECK_EXTENSION(EXTNAME, CAP) \
- if (!ctx->Extensions.EXTNAME) { \
- goto invalid_enum_error; \
- }
-
-#define CHECK_EXTENSION2(EXT1, EXT2, CAP) \
- if (!ctx->Extensions.EXT1 && !ctx->Extensions.EXT2) { \
- goto invalid_enum_error; \
- }
-
-
-
-/**
- * Return pointer to current texture unit for setting/getting coordinate
- * state.
- * Note that we'll set GL_INVALID_OPERATION if the active texture unit is
- * higher than the number of supported coordinate units. And we'll return NULL.
- */
-static struct gl_texture_unit *
-get_texcoord_unit(struct gl_context *ctx)
-{
- if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glEnable/Disable(texcoord unit)");
- return NULL;
- }
- else {
- return &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
- }
-}
-
-
-/**
- * Helper function to enable or disable a texture target.
- * \param bit one of the TEXTURE_x_BIT values
- * \return GL_TRUE if state is changing or GL_FALSE if no change
- */
-static GLboolean
-enable_texture(struct gl_context *ctx, GLboolean state, GLbitfield texBit)
-{
- struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
- const GLbitfield newenabled = state
- ? (texUnit->Enabled | texBit) : (texUnit->Enabled & ~texBit);
-
- if (texUnit->Enabled == newenabled)
- return GL_FALSE;
-
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
- texUnit->Enabled = newenabled;
- return GL_TRUE;
-}
-
-
-/**
- * Helper function to enable or disable state.
- *
- * \param ctx GL context.
- * \param cap the state to enable/disable
- * \param state whether to enable or disable the specified capability.
- *
- * Updates the current context and flushes the vertices as needed. For
- * capabilities associated with extensions it verifies that those extensions
- * are effectivly present before updating. Notifies the driver via
- * dd_function_table::Enable.
- */
-void
-_mesa_set_enable(struct gl_context *ctx, GLenum cap, GLboolean state)
-{
- if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx, "%s %s (newstate is %x)\n",
- state ? "glEnable" : "glDisable",
- _mesa_lookup_enum_by_nr(cap),
- ctx->NewState);
-
- switch (cap) {
- case GL_ALPHA_TEST:
- if (ctx->Color.AlphaEnabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_COLOR);
- ctx->Color.AlphaEnabled = state;
- break;
- case GL_AUTO_NORMAL:
- if (ctx->Eval.AutoNormal == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.AutoNormal = state;
- break;
- case GL_BLEND:
- {
- GLbitfield newEnabled = state * ((1 << ctx->Const.MaxDrawBuffers) - 1);
- if (newEnabled != ctx->Color.BlendEnabled) {
- FLUSH_VERTICES(ctx, _NEW_COLOR);
- ctx->Color.BlendEnabled = newEnabled;
- }
- }
- break;
-#if FEATURE_userclip
- case GL_CLIP_PLANE0:
- case GL_CLIP_PLANE1:
- case GL_CLIP_PLANE2:
- case GL_CLIP_PLANE3:
- case GL_CLIP_PLANE4:
- case GL_CLIP_PLANE5:
- {
- const GLuint p = cap - GL_CLIP_PLANE0;
-
- if ((ctx->Transform.ClipPlanesEnabled & (1 << p)) == ((GLuint) state << p))
- return;
-
- FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
-
- if (state) {
- ctx->Transform.ClipPlanesEnabled |= (1 << p);
-
- if (_math_matrix_is_dirty(ctx->ProjectionMatrixStack.Top))
- _math_matrix_analyse( ctx->ProjectionMatrixStack.Top );
-
- /* This derived state also calculated in clip.c and
- * from _mesa_update_state() on changes to EyeUserPlane
- * and ctx->ProjectionMatrix respectively.
- */
- _mesa_transform_vector( ctx->Transform._ClipUserPlane[p],
- ctx->Transform.EyeUserPlane[p],
- ctx->ProjectionMatrixStack.Top->inv );
- }
- else {
- ctx->Transform.ClipPlanesEnabled &= ~(1 << p);
- }
- }
- break;
-#endif
- case GL_COLOR_MATERIAL:
- if (ctx->Light.ColorMaterialEnabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_LIGHT);
- FLUSH_CURRENT(ctx, 0);
- ctx->Light.ColorMaterialEnabled = state;
- if (state) {
- _mesa_update_color_material( ctx,
- ctx->Current.Attrib[VERT_ATTRIB_COLOR0] );
- }
- break;
- case GL_CULL_FACE:
- if (ctx->Polygon.CullFlag == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_POLYGON);
- ctx->Polygon.CullFlag = state;
- break;
- case GL_DEPTH_TEST:
- if (ctx->Depth.Test == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_DEPTH);
- ctx->Depth.Test = state;
- break;
- case GL_DITHER:
- if (ctx->Color.DitherFlag == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_COLOR);
- ctx->Color.DitherFlag = state;
- break;
- case GL_FOG:
- if (ctx->Fog.Enabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_FOG);
- ctx->Fog.Enabled = state;
- break;
- case GL_LIGHT0:
- case GL_LIGHT1:
- case GL_LIGHT2:
- case GL_LIGHT3:
- case GL_LIGHT4:
- case GL_LIGHT5:
- case GL_LIGHT6:
- case GL_LIGHT7:
- if (ctx->Light.Light[cap-GL_LIGHT0].Enabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_LIGHT);
- ctx->Light.Light[cap-GL_LIGHT0].Enabled = state;
- if (state) {
- insert_at_tail(&ctx->Light.EnabledList,
- &ctx->Light.Light[cap-GL_LIGHT0]);
- }
- else {
- remove_from_list(&ctx->Light.Light[cap-GL_LIGHT0]);
- }
- break;
- case GL_LIGHTING:
- if (ctx->Light.Enabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_LIGHT);
- ctx->Light.Enabled = state;
- if (ctx->Light.Enabled && ctx->Light.Model.TwoSide)
- ctx->_TriangleCaps |= DD_TRI_LIGHT_TWOSIDE;
- else
- ctx->_TriangleCaps &= ~DD_TRI_LIGHT_TWOSIDE;
- break;
- case GL_LINE_SMOOTH:
- if (ctx->Line.SmoothFlag == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_LINE);
- ctx->Line.SmoothFlag = state;
- ctx->_TriangleCaps ^= DD_LINE_SMOOTH;
- break;
- case GL_LINE_STIPPLE:
- if (ctx->Line.StippleFlag == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_LINE);
- ctx->Line.StippleFlag = state;
- ctx->_TriangleCaps ^= DD_LINE_STIPPLE;
- break;
- case GL_INDEX_LOGIC_OP:
- if (ctx->Color.IndexLogicOpEnabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_COLOR);
- ctx->Color.IndexLogicOpEnabled = state;
- break;
- case GL_COLOR_LOGIC_OP:
- if (ctx->Color.ColorLogicOpEnabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_COLOR);
- ctx->Color.ColorLogicOpEnabled = state;
- break;
- case GL_MAP1_COLOR_4:
- if (ctx->Eval.Map1Color4 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map1Color4 = state;
- break;
- case GL_MAP1_INDEX:
- if (ctx->Eval.Map1Index == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map1Index = state;
- break;
- case GL_MAP1_NORMAL:
- if (ctx->Eval.Map1Normal == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map1Normal = state;
- break;
- case GL_MAP1_TEXTURE_COORD_1:
- if (ctx->Eval.Map1TextureCoord1 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map1TextureCoord1 = state;
- break;
- case GL_MAP1_TEXTURE_COORD_2:
- if (ctx->Eval.Map1TextureCoord2 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map1TextureCoord2 = state;
- break;
- case GL_MAP1_TEXTURE_COORD_3:
- if (ctx->Eval.Map1TextureCoord3 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map1TextureCoord3 = state;
- break;
- case GL_MAP1_TEXTURE_COORD_4:
- if (ctx->Eval.Map1TextureCoord4 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map1TextureCoord4 = state;
- break;
- case GL_MAP1_VERTEX_3:
- if (ctx->Eval.Map1Vertex3 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map1Vertex3 = state;
- break;
- case GL_MAP1_VERTEX_4:
- if (ctx->Eval.Map1Vertex4 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map1Vertex4 = state;
- break;
- case GL_MAP2_COLOR_4:
- if (ctx->Eval.Map2Color4 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map2Color4 = state;
- break;
- case GL_MAP2_INDEX:
- if (ctx->Eval.Map2Index == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map2Index = state;
- break;
- case GL_MAP2_NORMAL:
- if (ctx->Eval.Map2Normal == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map2Normal = state;
- break;
- case GL_MAP2_TEXTURE_COORD_1:
- if (ctx->Eval.Map2TextureCoord1 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map2TextureCoord1 = state;
- break;
- case GL_MAP2_TEXTURE_COORD_2:
- if (ctx->Eval.Map2TextureCoord2 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map2TextureCoord2 = state;
- break;
- case GL_MAP2_TEXTURE_COORD_3:
- if (ctx->Eval.Map2TextureCoord3 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map2TextureCoord3 = state;
- break;
- case GL_MAP2_TEXTURE_COORD_4:
- if (ctx->Eval.Map2TextureCoord4 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map2TextureCoord4 = state;
- break;
- case GL_MAP2_VERTEX_3:
- if (ctx->Eval.Map2Vertex3 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map2Vertex3 = state;
- break;
- case GL_MAP2_VERTEX_4:
- if (ctx->Eval.Map2Vertex4 == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map2Vertex4 = state;
- break;
- case GL_NORMALIZE:
- if (ctx->Transform.Normalize == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
- ctx->Transform.Normalize = state;
- break;
- case GL_POINT_SMOOTH:
- if (ctx->Point.SmoothFlag == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_POINT);
- ctx->Point.SmoothFlag = state;
- ctx->_TriangleCaps ^= DD_POINT_SMOOTH;
- break;
- case GL_POLYGON_SMOOTH:
- if (ctx->Polygon.SmoothFlag == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_POLYGON);
- ctx->Polygon.SmoothFlag = state;
- ctx->_TriangleCaps ^= DD_TRI_SMOOTH;
- break;
- case GL_POLYGON_STIPPLE:
- if (ctx->Polygon.StippleFlag == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_POLYGON);
- ctx->Polygon.StippleFlag = state;
- ctx->_TriangleCaps ^= DD_TRI_STIPPLE;
- break;
- case GL_POLYGON_OFFSET_POINT:
- if (ctx->Polygon.OffsetPoint == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_POLYGON);
- ctx->Polygon.OffsetPoint = state;
- break;
- case GL_POLYGON_OFFSET_LINE:
- if (ctx->Polygon.OffsetLine == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_POLYGON);
- ctx->Polygon.OffsetLine = state;
- break;
- case GL_POLYGON_OFFSET_FILL:
- /*case GL_POLYGON_OFFSET_EXT:*/
- if (ctx->Polygon.OffsetFill == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_POLYGON);
- ctx->Polygon.OffsetFill = state;
- break;
- case GL_RESCALE_NORMAL_EXT:
- if (ctx->Transform.RescaleNormals == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
- ctx->Transform.RescaleNormals = state;
- break;
- case GL_SCISSOR_TEST:
- if (ctx->Scissor.Enabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_SCISSOR);
- ctx->Scissor.Enabled = state;
- break;
- case GL_SHARED_TEXTURE_PALETTE_EXT:
- if (ctx->Texture.SharedPalette == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
- ctx->Texture.SharedPalette = state;
- break;
- case GL_STENCIL_TEST:
- if (ctx->Stencil.Enabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_STENCIL);
- ctx->Stencil.Enabled = state;
- break;
- case GL_TEXTURE_1D:
- if (!enable_texture(ctx, state, TEXTURE_1D_BIT)) {
- return;
- }
- break;
- case GL_TEXTURE_2D:
- if (!enable_texture(ctx, state, TEXTURE_2D_BIT)) {
- return;
- }
- break;
- case GL_TEXTURE_3D:
- if (!enable_texture(ctx, state, TEXTURE_3D_BIT)) {
- return;
- }
- break;
- case GL_TEXTURE_GEN_Q:
- {
- struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
- if (texUnit) {
- GLuint newenabled = texUnit->TexGenEnabled & ~Q_BIT;
- if (state)
- newenabled |= Q_BIT;
- if (texUnit->TexGenEnabled == newenabled)
- return;
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
- texUnit->TexGenEnabled = newenabled;
- }
- }
- break;
- case GL_TEXTURE_GEN_R:
- {
- struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
- if (texUnit) {
- GLuint newenabled = texUnit->TexGenEnabled & ~R_BIT;
- if (state)
- newenabled |= R_BIT;
- if (texUnit->TexGenEnabled == newenabled)
- return;
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
- texUnit->TexGenEnabled = newenabled;
- }
- }
- break;
- case GL_TEXTURE_GEN_S:
- {
- struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
- if (texUnit) {
- GLuint newenabled = texUnit->TexGenEnabled & ~S_BIT;
- if (state)
- newenabled |= S_BIT;
- if (texUnit->TexGenEnabled == newenabled)
- return;
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
- texUnit->TexGenEnabled = newenabled;
- }
- }
- break;
- case GL_TEXTURE_GEN_T:
- {
- struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
- if (texUnit) {
- GLuint newenabled = texUnit->TexGenEnabled & ~T_BIT;
- if (state)
- newenabled |= T_BIT;
- if (texUnit->TexGenEnabled == newenabled)
- return;
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
- texUnit->TexGenEnabled = newenabled;
- }
- }
- break;
-
-#if FEATURE_ES1
- case GL_TEXTURE_GEN_STR_OES:
- /* disable S, T, and R at the same time */
- {
- struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
- if (texUnit) {
- GLuint newenabled =
- texUnit->TexGenEnabled & ~STR_BITS;
- if (state)
- newenabled |= STR_BITS;
- if (texUnit->TexGenEnabled == newenabled)
- return;
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
- texUnit->TexGenEnabled = newenabled;
- }
- }
- break;
-#endif
-
- /*
- * CLIENT STATE!!!
- */
- case GL_VERTEX_ARRAY:
- case GL_NORMAL_ARRAY:
- case GL_COLOR_ARRAY:
- case GL_INDEX_ARRAY:
- case GL_TEXTURE_COORD_ARRAY:
- case GL_EDGE_FLAG_ARRAY:
- case GL_FOG_COORDINATE_ARRAY_EXT:
- case GL_SECONDARY_COLOR_ARRAY_EXT:
- case GL_POINT_SIZE_ARRAY_OES:
- client_state( ctx, cap, state );
- return;
-
- /* GL_SGI_texture_color_table */
- case GL_TEXTURE_COLOR_TABLE_SGI:
- CHECK_EXTENSION(SGI_texture_color_table, cap);
- if (ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
- ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled = state;
- break;
-
- /* GL_ARB_texture_cube_map */
- case GL_TEXTURE_CUBE_MAP_ARB:
- CHECK_EXTENSION(ARB_texture_cube_map, cap);
- if (!enable_texture(ctx, state, TEXTURE_CUBE_BIT)) {
- return;
- }
- break;
-
- /* GL_EXT_secondary_color */
- case GL_COLOR_SUM_EXT:
- CHECK_EXTENSION2(EXT_secondary_color, ARB_vertex_program, cap);
- if (ctx->Fog.ColorSumEnabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_FOG);
- ctx->Fog.ColorSumEnabled = state;
- break;
-
- /* GL_ARB_multisample */
- case GL_MULTISAMPLE_ARB:
- if (ctx->Multisample.Enabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
- ctx->Multisample.Enabled = state;
- break;
- case GL_SAMPLE_ALPHA_TO_COVERAGE_ARB:
- if (ctx->Multisample.SampleAlphaToCoverage == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
- ctx->Multisample.SampleAlphaToCoverage = state;
- break;
- case GL_SAMPLE_ALPHA_TO_ONE_ARB:
- if (ctx->Multisample.SampleAlphaToOne == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
- ctx->Multisample.SampleAlphaToOne = state;
- break;
- case GL_SAMPLE_COVERAGE_ARB:
- if (ctx->Multisample.SampleCoverage == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
- ctx->Multisample.SampleCoverage = state;
- break;
- case GL_SAMPLE_COVERAGE_INVERT_ARB:
- if (ctx->Multisample.SampleCoverageInvert == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE);
- ctx->Multisample.SampleCoverageInvert = state;
- break;
-
- /* GL_IBM_rasterpos_clip */
- case GL_RASTER_POSITION_UNCLIPPED_IBM:
- CHECK_EXTENSION(IBM_rasterpos_clip, cap);
- if (ctx->Transform.RasterPositionUnclipped == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
- ctx->Transform.RasterPositionUnclipped = state;
- break;
-
- /* GL_NV_point_sprite */
- case GL_POINT_SPRITE_NV:
- CHECK_EXTENSION2(NV_point_sprite, ARB_point_sprite, cap);
- if (ctx->Point.PointSprite == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_POINT);
- ctx->Point.PointSprite = state;
- break;
-
-#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
- case GL_VERTEX_PROGRAM_ARB:
- CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap);
- if (ctx->VertexProgram.Enabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_PROGRAM);
- ctx->VertexProgram.Enabled = state;
- break;
- case GL_VERTEX_PROGRAM_POINT_SIZE_ARB:
- CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap);
- if (ctx->VertexProgram.PointSizeEnabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_PROGRAM);
- ctx->VertexProgram.PointSizeEnabled = state;
- break;
- case GL_VERTEX_PROGRAM_TWO_SIDE_ARB:
- CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap);
- if (ctx->VertexProgram.TwoSideEnabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_PROGRAM);
- ctx->VertexProgram.TwoSideEnabled = state;
- break;
-#endif
-#if FEATURE_NV_vertex_program
- case GL_MAP1_VERTEX_ATTRIB0_4_NV:
- case GL_MAP1_VERTEX_ATTRIB1_4_NV:
- case GL_MAP1_VERTEX_ATTRIB2_4_NV:
- case GL_MAP1_VERTEX_ATTRIB3_4_NV:
- case GL_MAP1_VERTEX_ATTRIB4_4_NV:
- case GL_MAP1_VERTEX_ATTRIB5_4_NV:
- case GL_MAP1_VERTEX_ATTRIB6_4_NV:
- case GL_MAP1_VERTEX_ATTRIB7_4_NV:
- case GL_MAP1_VERTEX_ATTRIB8_4_NV:
- case GL_MAP1_VERTEX_ATTRIB9_4_NV:
- case GL_MAP1_VERTEX_ATTRIB10_4_NV:
- case GL_MAP1_VERTEX_ATTRIB11_4_NV:
- case GL_MAP1_VERTEX_ATTRIB12_4_NV:
- case GL_MAP1_VERTEX_ATTRIB13_4_NV:
- case GL_MAP1_VERTEX_ATTRIB14_4_NV:
- case GL_MAP1_VERTEX_ATTRIB15_4_NV:
- CHECK_EXTENSION(NV_vertex_program, cap);
- {
- const GLuint map = (GLuint) (cap - GL_MAP1_VERTEX_ATTRIB0_4_NV);
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map1Attrib[map] = state;
- }
- break;
- case GL_MAP2_VERTEX_ATTRIB0_4_NV:
- case GL_MAP2_VERTEX_ATTRIB1_4_NV:
- case GL_MAP2_VERTEX_ATTRIB2_4_NV:
- case GL_MAP2_VERTEX_ATTRIB3_4_NV:
- case GL_MAP2_VERTEX_ATTRIB4_4_NV:
- case GL_MAP2_VERTEX_ATTRIB5_4_NV:
- case GL_MAP2_VERTEX_ATTRIB6_4_NV:
- case GL_MAP2_VERTEX_ATTRIB7_4_NV:
- case GL_MAP2_VERTEX_ATTRIB8_4_NV:
- case GL_MAP2_VERTEX_ATTRIB9_4_NV:
- case GL_MAP2_VERTEX_ATTRIB10_4_NV:
- case GL_MAP2_VERTEX_ATTRIB11_4_NV:
- case GL_MAP2_VERTEX_ATTRIB12_4_NV:
- case GL_MAP2_VERTEX_ATTRIB13_4_NV:
- case GL_MAP2_VERTEX_ATTRIB14_4_NV:
- case GL_MAP2_VERTEX_ATTRIB15_4_NV:
- CHECK_EXTENSION(NV_vertex_program, cap);
- {
- const GLuint map = (GLuint) (cap - GL_MAP2_VERTEX_ATTRIB0_4_NV);
- FLUSH_VERTICES(ctx, _NEW_EVAL);
- ctx->Eval.Map2Attrib[map] = state;
- }
- break;
-#endif /* FEATURE_NV_vertex_program */
-
-#if FEATURE_NV_fragment_program
- case GL_FRAGMENT_PROGRAM_NV:
- CHECK_EXTENSION(NV_fragment_program, cap);
- if (ctx->FragmentProgram.Enabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_PROGRAM);
- ctx->FragmentProgram.Enabled = state;
- break;
-#endif /* FEATURE_NV_fragment_program */
-
- /* GL_NV_texture_rectangle */
- case GL_TEXTURE_RECTANGLE_NV:
- CHECK_EXTENSION(NV_texture_rectangle, cap);
- if (!enable_texture(ctx, state, TEXTURE_RECT_BIT)) {
- return;
- }
- break;
-
- /* GL_EXT_stencil_two_side */
- case GL_STENCIL_TEST_TWO_SIDE_EXT:
- CHECK_EXTENSION(EXT_stencil_two_side, cap);
- if (ctx->Stencil.TestTwoSide == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_STENCIL);
- ctx->Stencil.TestTwoSide = state;
- if (state) {
- ctx->Stencil._BackFace = 2;
- ctx->_TriangleCaps |= DD_TRI_TWOSTENCIL;
- } else {
- ctx->Stencil._BackFace = 1;
- ctx->_TriangleCaps &= ~DD_TRI_TWOSTENCIL;
- }
- break;
-
-#if FEATURE_ARB_fragment_program
- case GL_FRAGMENT_PROGRAM_ARB:
- CHECK_EXTENSION(ARB_fragment_program, cap);
- if (ctx->FragmentProgram.Enabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_PROGRAM);
- ctx->FragmentProgram.Enabled = state;
- break;
-#endif /* FEATURE_ARB_fragment_program */
-
- /* GL_EXT_depth_bounds_test */
- case GL_DEPTH_BOUNDS_TEST_EXT:
- CHECK_EXTENSION(EXT_depth_bounds_test, cap);
- if (ctx->Depth.BoundsTest == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_DEPTH);
- ctx->Depth.BoundsTest = state;
- break;
-
- case GL_DEPTH_CLAMP:
- if (ctx->Transform.DepthClamp == state)
- return;
- CHECK_EXTENSION(ARB_depth_clamp, cap);
- FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
- ctx->Transform.DepthClamp = state;
- break;
-
-#if FEATURE_ATI_fragment_shader
- case GL_FRAGMENT_SHADER_ATI:
- CHECK_EXTENSION(ATI_fragment_shader, cap);
- if (ctx->ATIFragmentShader.Enabled == state)
- return;
- FLUSH_VERTICES(ctx, _NEW_PROGRAM);
- ctx->ATIFragmentShader.Enabled = state;
- break;
-#endif
-
- /* GL_MESA_texture_array */
- case GL_TEXTURE_1D_ARRAY_EXT:
- CHECK_EXTENSION(MESA_texture_array, cap);
- if (!enable_texture(ctx, state, TEXTURE_1D_ARRAY_BIT)) {
- return;
- }
- break;
-
- case GL_TEXTURE_2D_ARRAY_EXT:
- CHECK_EXTENSION(MESA_texture_array, cap);
- if (!enable_texture(ctx, state, TEXTURE_2D_ARRAY_BIT)) {
- return;
- }
- break;
-
- case GL_TEXTURE_CUBE_MAP_SEAMLESS:
- CHECK_EXTENSION(ARB_seamless_cube_map, cap);
- ctx->Texture.CubeMapSeamless = state;
- break;
-
-#if FEATURE_EXT_transform_feedback
- case GL_RASTERIZER_DISCARD:
- CHECK_EXTENSION(EXT_transform_feedback, cap);
- if (ctx->TransformFeedback.RasterDiscard != state) {
- ctx->TransformFeedback.RasterDiscard = state;
- FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
- }
- break;
-#endif
-
- /* GL 3.1 primitive restart. Note: this enum is different from
- * GL_PRIMITIVE_RESTART_NV (which is client state).
- */
- case GL_PRIMITIVE_RESTART:
- if (ctx->VersionMajor * 10 + ctx->VersionMinor < 31) {
- goto invalid_enum_error;
- }
- if (ctx->Array.PrimitiveRestart != state) {
- FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
- ctx->Array.PrimitiveRestart = state;
- }
- break;
-
- /* GL3.0 - GL_framebuffer_sRGB */
- case GL_FRAMEBUFFER_SRGB_EXT:
- CHECK_EXTENSION(EXT_framebuffer_sRGB, cap);
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
- ctx->Color.sRGBEnabled = state;
- break;
-
- default:
- goto invalid_enum_error;
- }
-
- if (ctx->Driver.Enable) {
- ctx->Driver.Enable( ctx, cap, state );
- }
-
- return;
-
-invalid_enum_error:
- _mesa_error(ctx, GL_INVALID_ENUM, "gl%s(0x%x)",
- state ? "Enable" : "Disable", cap);
-}
-
-
-/**
- * Enable GL capability. Called by glEnable()
- * \param cap state to enable.
- */
-void GLAPIENTRY
-_mesa_Enable( GLenum cap )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- _mesa_set_enable( ctx, cap, GL_TRUE );
-}
-
-
-/**
- * Disable GL capability. Called by glDisable()
- * \param cap state to disable.
- */
-void GLAPIENTRY
-_mesa_Disable( GLenum cap )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- _mesa_set_enable( ctx, cap, GL_FALSE );
-}
-
-
-
-/**
- * Enable/disable an indexed state var.
- */
-void
-_mesa_set_enablei(struct gl_context *ctx, GLenum cap, GLuint index, GLboolean state)
-{
- ASSERT(state == 0 || state == 1);
- switch (cap) {
- case GL_BLEND:
- if (!ctx->Extensions.EXT_draw_buffers2) {
- goto invalid_enum_error;
- }
- if (index >= ctx->Const.MaxDrawBuffers) {
- _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%u)",
- state ? "glEnableIndexed" : "glDisableIndexed", index);
- return;
- }
- if (((ctx->Color.BlendEnabled >> index) & 1) != state) {
- FLUSH_VERTICES(ctx, _NEW_COLOR);
- if (state)
- ctx->Color.BlendEnabled |= (1 << index);
- else
- ctx->Color.BlendEnabled &= ~(1 << index);
- }
- break;
- default:
- goto invalid_enum_error;
- }
- return;
-
-invalid_enum_error:
- _mesa_error(ctx, GL_INVALID_ENUM, "%s(cap=%s)",
- state ? "glEnablei" : "glDisablei",
- _mesa_lookup_enum_by_nr(cap));
-}
-
-
-void GLAPIENTRY
-_mesa_DisableIndexed( GLenum cap, GLuint index )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- _mesa_set_enablei(ctx, cap, index, GL_FALSE);
-}
-
-
-void GLAPIENTRY
-_mesa_EnableIndexed( GLenum cap, GLuint index )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- _mesa_set_enablei(ctx, cap, index, GL_TRUE);
-}
-
-
-GLboolean GLAPIENTRY
-_mesa_IsEnabledIndexed( GLenum cap, GLuint index )
-{
- GET_CURRENT_CONTEXT(ctx);
- switch (cap) {
- case GL_BLEND:
- if (index >= ctx->Const.MaxDrawBuffers) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glIsEnabledIndexed(index=%u)",
- index);
- return GL_FALSE;
- }
- return (ctx->Color.BlendEnabled >> index) & 1;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabledIndexed(cap=%s)",
- _mesa_lookup_enum_by_nr(cap));
- return GL_FALSE;
- }
-}
-
-
-
-
-#undef CHECK_EXTENSION
-#define CHECK_EXTENSION(EXTNAME) \
- if (!ctx->Extensions.EXTNAME) { \
- goto invalid_enum_error; \
- }
-
-#undef CHECK_EXTENSION2
-#define CHECK_EXTENSION2(EXT1, EXT2) \
- if (!ctx->Extensions.EXT1 && !ctx->Extensions.EXT2) { \
- goto invalid_enum_error; \
- }
-
-
-/**
- * Helper function to determine whether a texture target is enabled.
- */
-static GLboolean
-is_texture_enabled(struct gl_context *ctx, GLbitfield bit)
-{
- const struct gl_texture_unit *const texUnit =
- &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
- return (texUnit->Enabled & bit) ? GL_TRUE : GL_FALSE;
-}
-
-
-/**
- * Return simple enable/disable state.
- *
- * \param cap state variable to query.
- *
- * Returns the state of the specified capability from the current GL context.
- * For the capabilities associated with extensions verifies that those
- * extensions are effectively present before reporting.
- */
-GLboolean GLAPIENTRY
-_mesa_IsEnabled( GLenum cap )
-{
- GET_CURRENT_CONTEXT(ctx);
- switch (cap) {
- case GL_ALPHA_TEST:
- return ctx->Color.AlphaEnabled;
- case GL_AUTO_NORMAL:
- return ctx->Eval.AutoNormal;
- case GL_BLEND:
- return ctx->Color.BlendEnabled & 1; /* return state for buffer[0] */
- case GL_CLIP_PLANE0:
- case GL_CLIP_PLANE1:
- case GL_CLIP_PLANE2:
- case GL_CLIP_PLANE3:
- case GL_CLIP_PLANE4:
- case GL_CLIP_PLANE5:
- return (ctx->Transform.ClipPlanesEnabled >> (cap - GL_CLIP_PLANE0)) & 1;
- case GL_COLOR_MATERIAL:
- return ctx->Light.ColorMaterialEnabled;
- case GL_CULL_FACE:
- return ctx->Polygon.CullFlag;
- case GL_DEPTH_TEST:
- return ctx->Depth.Test;
- case GL_DITHER:
- return ctx->Color.DitherFlag;
- case GL_FOG:
- return ctx->Fog.Enabled;
- case GL_LIGHTING:
- return ctx->Light.Enabled;
- case GL_LIGHT0:
- case GL_LIGHT1:
- case GL_LIGHT2:
- case GL_LIGHT3:
- case GL_LIGHT4:
- case GL_LIGHT5:
- case GL_LIGHT6:
- case GL_LIGHT7:
- return ctx->Light.Light[cap-GL_LIGHT0].Enabled;
- case GL_LINE_SMOOTH:
- return ctx->Line.SmoothFlag;
- case GL_LINE_STIPPLE:
- return ctx->Line.StippleFlag;
- case GL_INDEX_LOGIC_OP:
- return ctx->Color.IndexLogicOpEnabled;
- case GL_COLOR_LOGIC_OP:
- return ctx->Color.ColorLogicOpEnabled;
- case GL_MAP1_COLOR_4:
- return ctx->Eval.Map1Color4;
- case GL_MAP1_INDEX:
- return ctx->Eval.Map1Index;
- case GL_MAP1_NORMAL:
- return ctx->Eval.Map1Normal;
- case GL_MAP1_TEXTURE_COORD_1:
- return ctx->Eval.Map1TextureCoord1;
- case GL_MAP1_TEXTURE_COORD_2:
- return ctx->Eval.Map1TextureCoord2;
- case GL_MAP1_TEXTURE_COORD_3:
- return ctx->Eval.Map1TextureCoord3;
- case GL_MAP1_TEXTURE_COORD_4:
- return ctx->Eval.Map1TextureCoord4;
- case GL_MAP1_VERTEX_3:
- return ctx->Eval.Map1Vertex3;
- case GL_MAP1_VERTEX_4:
- return ctx->Eval.Map1Vertex4;
- case GL_MAP2_COLOR_4:
- return ctx->Eval.Map2Color4;
- case GL_MAP2_INDEX:
- return ctx->Eval.Map2Index;
- case GL_MAP2_NORMAL:
- return ctx->Eval.Map2Normal;
- case GL_MAP2_TEXTURE_COORD_1:
- return ctx->Eval.Map2TextureCoord1;
- case GL_MAP2_TEXTURE_COORD_2:
- return ctx->Eval.Map2TextureCoord2;
- case GL_MAP2_TEXTURE_COORD_3:
- return ctx->Eval.Map2TextureCoord3;
- case GL_MAP2_TEXTURE_COORD_4:
- return ctx->Eval.Map2TextureCoord4;
- case GL_MAP2_VERTEX_3:
- return ctx->Eval.Map2Vertex3;
- case GL_MAP2_VERTEX_4:
- return ctx->Eval.Map2Vertex4;
- case GL_NORMALIZE:
- return ctx->Transform.Normalize;
- case GL_POINT_SMOOTH:
- return ctx->Point.SmoothFlag;
- case GL_POLYGON_SMOOTH:
- return ctx->Polygon.SmoothFlag;
- case GL_POLYGON_STIPPLE:
- return ctx->Polygon.StippleFlag;
- case GL_POLYGON_OFFSET_POINT:
- return ctx->Polygon.OffsetPoint;
- case GL_POLYGON_OFFSET_LINE:
- return ctx->Polygon.OffsetLine;
- case GL_POLYGON_OFFSET_FILL:
- /*case GL_POLYGON_OFFSET_EXT:*/
- return ctx->Polygon.OffsetFill;
- case GL_RESCALE_NORMAL_EXT:
- return ctx->Transform.RescaleNormals;
- case GL_SCISSOR_TEST:
- return ctx->Scissor.Enabled;
- case GL_SHARED_TEXTURE_PALETTE_EXT:
- return ctx->Texture.SharedPalette;
- case GL_STENCIL_TEST:
- return ctx->Stencil.Enabled;
- case GL_TEXTURE_1D:
- return is_texture_enabled(ctx, TEXTURE_1D_BIT);
- case GL_TEXTURE_2D:
- return is_texture_enabled(ctx, TEXTURE_2D_BIT);
- case GL_TEXTURE_3D:
- return is_texture_enabled(ctx, TEXTURE_3D_BIT);
- case GL_TEXTURE_GEN_Q:
- {
- const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
- if (texUnit) {
- return (texUnit->TexGenEnabled & Q_BIT) ? GL_TRUE : GL_FALSE;
- }
- }
- return GL_FALSE;
- case GL_TEXTURE_GEN_R:
- {
- const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
- if (texUnit) {
- return (texUnit->TexGenEnabled & R_BIT) ? GL_TRUE : GL_FALSE;
- }
- }
- return GL_FALSE;
- case GL_TEXTURE_GEN_S:
- {
- const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
- if (texUnit) {
- return (texUnit->TexGenEnabled & S_BIT) ? GL_TRUE : GL_FALSE;
- }
- }
- return GL_FALSE;
- case GL_TEXTURE_GEN_T:
- {
- const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
- if (texUnit) {
- return (texUnit->TexGenEnabled & T_BIT) ? GL_TRUE : GL_FALSE;
- }
- }
- return GL_FALSE;
-#if FEATURE_ES1
- case GL_TEXTURE_GEN_STR_OES:
- {
- const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx);
- if (texUnit) {
- return (texUnit->TexGenEnabled & STR_BITS) == STR_BITS ? GL_TRUE : GL_FALSE;
- }
- }
-#endif
-
- /*
- * CLIENT STATE!!!
- */
- case GL_VERTEX_ARRAY:
- return (ctx->Array.ArrayObj->Vertex.Enabled != 0);
- case GL_NORMAL_ARRAY:
- return (ctx->Array.ArrayObj->Normal.Enabled != 0);
- case GL_COLOR_ARRAY:
- return (ctx->Array.ArrayObj->Color.Enabled != 0);
- case GL_INDEX_ARRAY:
- return (ctx->Array.ArrayObj->Index.Enabled != 0);
- case GL_TEXTURE_COORD_ARRAY:
- return (ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture].Enabled != 0);
- case GL_EDGE_FLAG_ARRAY:
- return (ctx->Array.ArrayObj->EdgeFlag.Enabled != 0);
- case GL_FOG_COORDINATE_ARRAY_EXT:
- CHECK_EXTENSION(EXT_fog_coord);
- return (ctx->Array.ArrayObj->FogCoord.Enabled != 0);
- case GL_SECONDARY_COLOR_ARRAY_EXT:
- CHECK_EXTENSION(EXT_secondary_color);
- return (ctx->Array.ArrayObj->SecondaryColor.Enabled != 0);
-#if FEATURE_point_size_array
- case GL_POINT_SIZE_ARRAY_OES:
- return (ctx->Array.ArrayObj->PointSize.Enabled != 0);
-#endif
-
- /* GL_SGI_texture_color_table */
- case GL_TEXTURE_COLOR_TABLE_SGI:
- CHECK_EXTENSION(SGI_texture_color_table);
- return ctx->Texture.Unit[ctx->Texture.CurrentUnit].ColorTableEnabled;
-
- /* GL_ARB_texture_cube_map */
- case GL_TEXTURE_CUBE_MAP_ARB:
- CHECK_EXTENSION(ARB_texture_cube_map);
- return is_texture_enabled(ctx, TEXTURE_CUBE_BIT);
-
- /* GL_EXT_secondary_color */
- case GL_COLOR_SUM_EXT:
- CHECK_EXTENSION2(EXT_secondary_color, ARB_vertex_program);
- return ctx->Fog.ColorSumEnabled;
-
- /* GL_ARB_multisample */
- case GL_MULTISAMPLE_ARB:
- return ctx->Multisample.Enabled;
- case GL_SAMPLE_ALPHA_TO_COVERAGE_ARB:
- return ctx->Multisample.SampleAlphaToCoverage;
- case GL_SAMPLE_ALPHA_TO_ONE_ARB:
- return ctx->Multisample.SampleAlphaToOne;
- case GL_SAMPLE_COVERAGE_ARB:
- return ctx->Multisample.SampleCoverage;
- case GL_SAMPLE_COVERAGE_INVERT_ARB:
- return ctx->Multisample.SampleCoverageInvert;
-
- /* GL_IBM_rasterpos_clip */
- case GL_RASTER_POSITION_UNCLIPPED_IBM:
- CHECK_EXTENSION(IBM_rasterpos_clip);
- return ctx->Transform.RasterPositionUnclipped;
-
- /* GL_NV_point_sprite */
- case GL_POINT_SPRITE_NV:
- CHECK_EXTENSION2(NV_point_sprite, ARB_point_sprite)
- return ctx->Point.PointSprite;
-
-#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
- case GL_VERTEX_PROGRAM_ARB:
- CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program);
- return ctx->VertexProgram.Enabled;
- case GL_VERTEX_PROGRAM_POINT_SIZE_ARB:
- CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program);
- return ctx->VertexProgram.PointSizeEnabled;
- case GL_VERTEX_PROGRAM_TWO_SIDE_ARB:
- CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program);
- return ctx->VertexProgram.TwoSideEnabled;
-#endif
-#if FEATURE_NV_vertex_program
- case GL_VERTEX_ATTRIB_ARRAY0_NV:
- case GL_VERTEX_ATTRIB_ARRAY1_NV:
- case GL_VERTEX_ATTRIB_ARRAY2_NV:
- case GL_VERTEX_ATTRIB_ARRAY3_NV:
- case GL_VERTEX_ATTRIB_ARRAY4_NV:
- case GL_VERTEX_ATTRIB_ARRAY5_NV:
- case GL_VERTEX_ATTRIB_ARRAY6_NV:
- case GL_VERTEX_ATTRIB_ARRAY7_NV:
- case GL_VERTEX_ATTRIB_ARRAY8_NV:
- case GL_VERTEX_ATTRIB_ARRAY9_NV:
- case GL_VERTEX_ATTRIB_ARRAY10_NV:
- case GL_VERTEX_ATTRIB_ARRAY11_NV:
- case GL_VERTEX_ATTRIB_ARRAY12_NV:
- case GL_VERTEX_ATTRIB_ARRAY13_NV:
- case GL_VERTEX_ATTRIB_ARRAY14_NV:
- case GL_VERTEX_ATTRIB_ARRAY15_NV:
- CHECK_EXTENSION(NV_vertex_program);
- {
- GLint n = (GLint) cap - GL_VERTEX_ATTRIB_ARRAY0_NV;
- ASSERT(n < Elements(ctx->Array.ArrayObj->VertexAttrib));
- return (ctx->Array.ArrayObj->VertexAttrib[n].Enabled != 0);
- }
- case GL_MAP1_VERTEX_ATTRIB0_4_NV:
- case GL_MAP1_VERTEX_ATTRIB1_4_NV:
- case GL_MAP1_VERTEX_ATTRIB2_4_NV:
- case GL_MAP1_VERTEX_ATTRIB3_4_NV:
- case GL_MAP1_VERTEX_ATTRIB4_4_NV:
- case GL_MAP1_VERTEX_ATTRIB5_4_NV:
- case GL_MAP1_VERTEX_ATTRIB6_4_NV:
- case GL_MAP1_VERTEX_ATTRIB7_4_NV:
- case GL_MAP1_VERTEX_ATTRIB8_4_NV:
- case GL_MAP1_VERTEX_ATTRIB9_4_NV:
- case GL_MAP1_VERTEX_ATTRIB10_4_NV:
- case GL_MAP1_VERTEX_ATTRIB11_4_NV:
- case GL_MAP1_VERTEX_ATTRIB12_4_NV:
- case GL_MAP1_VERTEX_ATTRIB13_4_NV:
- case GL_MAP1_VERTEX_ATTRIB14_4_NV:
- case GL_MAP1_VERTEX_ATTRIB15_4_NV:
- CHECK_EXTENSION(NV_vertex_program);
- {
- const GLuint map = (GLuint) (cap - GL_MAP1_VERTEX_ATTRIB0_4_NV);
- return ctx->Eval.Map1Attrib[map];
- }
- case GL_MAP2_VERTEX_ATTRIB0_4_NV:
- case GL_MAP2_VERTEX_ATTRIB1_4_NV:
- case GL_MAP2_VERTEX_ATTRIB2_4_NV:
- case GL_MAP2_VERTEX_ATTRIB3_4_NV:
- case GL_MAP2_VERTEX_ATTRIB4_4_NV:
- case GL_MAP2_VERTEX_ATTRIB5_4_NV:
- case GL_MAP2_VERTEX_ATTRIB6_4_NV:
- case GL_MAP2_VERTEX_ATTRIB7_4_NV:
- case GL_MAP2_VERTEX_ATTRIB8_4_NV:
- case GL_MAP2_VERTEX_ATTRIB9_4_NV:
- case GL_MAP2_VERTEX_ATTRIB10_4_NV:
- case GL_MAP2_VERTEX_ATTRIB11_4_NV:
- case GL_MAP2_VERTEX_ATTRIB12_4_NV:
- case GL_MAP2_VERTEX_ATTRIB13_4_NV:
- case GL_MAP2_VERTEX_ATTRIB14_4_NV:
- case GL_MAP2_VERTEX_ATTRIB15_4_NV:
- CHECK_EXTENSION(NV_vertex_program);
- {
- const GLuint map = (GLuint) (cap - GL_MAP2_VERTEX_ATTRIB0_4_NV);
- return ctx->Eval.Map2Attrib[map];
- }
-#endif /* FEATURE_NV_vertex_program */
-
-#if FEATURE_NV_fragment_program
- case GL_FRAGMENT_PROGRAM_NV:
- CHECK_EXTENSION(NV_fragment_program);
- return ctx->FragmentProgram.Enabled;
-#endif /* FEATURE_NV_fragment_program */
-
- /* GL_NV_texture_rectangle */
- case GL_TEXTURE_RECTANGLE_NV:
- CHECK_EXTENSION(NV_texture_rectangle);
- return is_texture_enabled(ctx, TEXTURE_RECT_BIT);
-
- /* GL_EXT_stencil_two_side */
- case GL_STENCIL_TEST_TWO_SIDE_EXT:
- CHECK_EXTENSION(EXT_stencil_two_side);
- return ctx->Stencil.TestTwoSide;
-
-#if FEATURE_ARB_fragment_program
- case GL_FRAGMENT_PROGRAM_ARB:
- return ctx->FragmentProgram.Enabled;
-#endif /* FEATURE_ARB_fragment_program */
-
- /* GL_EXT_depth_bounds_test */
- case GL_DEPTH_BOUNDS_TEST_EXT:
- CHECK_EXTENSION(EXT_depth_bounds_test);
- return ctx->Depth.BoundsTest;
-
- /* GL_ARB_depth_clamp */
- case GL_DEPTH_CLAMP:
- CHECK_EXTENSION(ARB_depth_clamp);
- return ctx->Transform.DepthClamp;
-
-#if FEATURE_ATI_fragment_shader
- case GL_FRAGMENT_SHADER_ATI:
- CHECK_EXTENSION(ATI_fragment_shader);
- return ctx->ATIFragmentShader.Enabled;
-#endif /* FEATURE_ATI_fragment_shader */
-
- case GL_TEXTURE_CUBE_MAP_SEAMLESS:
- CHECK_EXTENSION(ARB_seamless_cube_map);
- return ctx->Texture.CubeMapSeamless;
-
-#if FEATURE_EXT_transform_feedback
- case GL_RASTERIZER_DISCARD:
- CHECK_EXTENSION(EXT_transform_feedback);
- return ctx->TransformFeedback.RasterDiscard;
-#endif
-
- /* GL_NV_primitive_restart */
- case GL_PRIMITIVE_RESTART_NV:
- if (!ctx->Extensions.NV_primitive_restart) {
- goto invalid_enum_error;
- }
- return ctx->Array.PrimitiveRestart;
-
- /* GL 3.1 primitive restart */
- case GL_PRIMITIVE_RESTART:
- if (ctx->VersionMajor * 10 + ctx->VersionMinor < 31) {
- goto invalid_enum_error;
- }
- return ctx->Array.PrimitiveRestart;
-
- /* GL3.0 - GL_framebuffer_sRGB */
- case GL_FRAMEBUFFER_SRGB_EXT:
- CHECK_EXTENSION(EXT_framebuffer_sRGB);
- return ctx->Color.sRGBEnabled;
-
- default:
- goto invalid_enum_error;
- }
-
- return GL_FALSE;
-
-invalid_enum_error:
- _mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabled(0x%x)", (int) cap);
- return GL_FALSE;
-}
+/** + * \file enable.c + * Enable/disable/query GL capabilities. + */ + +/* + * Mesa 3-D graphics library + * Version: 7.0.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. + */ + + +#include "glheader.h" +#include "context.h" +#include "enable.h" +#include "light.h" +#include "simple_list.h" +#include "mfeatures.h" +#include "mtypes.h" +#include "enums.h" +#include "api_arrayelt.h" +#include "texstate.h" + + + +#define CHECK_EXTENSION(EXTNAME, CAP) \ + if (!ctx->Extensions.EXTNAME) { \ + goto invalid_enum_error; \ + } + + +/** + * Helper to enable/disable client-side state. + */ +static void +client_state(struct gl_context *ctx, GLenum cap, GLboolean state) +{ + struct gl_array_object *arrayObj = ctx->Array.ArrayObj; + GLuint flag; + GLboolean *var; + + switch (cap) { + case GL_VERTEX_ARRAY: + var = &arrayObj->Vertex.Enabled; + flag = _NEW_ARRAY_VERTEX; + break; + case GL_NORMAL_ARRAY: + var = &arrayObj->Normal.Enabled; + flag = _NEW_ARRAY_NORMAL; + break; + case GL_COLOR_ARRAY: + var = &arrayObj->Color.Enabled; + flag = _NEW_ARRAY_COLOR0; + break; + case GL_INDEX_ARRAY: + var = &arrayObj->Index.Enabled; + flag = _NEW_ARRAY_INDEX; + break; + case GL_TEXTURE_COORD_ARRAY: + var = &arrayObj->TexCoord[ctx->Array.ActiveTexture].Enabled; + flag = _NEW_ARRAY_TEXCOORD(ctx->Array.ActiveTexture); + break; + case GL_EDGE_FLAG_ARRAY: + var = &arrayObj->EdgeFlag.Enabled; + flag = _NEW_ARRAY_EDGEFLAG; + break; + case GL_FOG_COORDINATE_ARRAY_EXT: + var = &arrayObj->FogCoord.Enabled; + flag = _NEW_ARRAY_FOGCOORD; + break; + case GL_SECONDARY_COLOR_ARRAY_EXT: + var = &arrayObj->SecondaryColor.Enabled; + flag = _NEW_ARRAY_COLOR1; + break; + +#if FEATURE_point_size_array + case GL_POINT_SIZE_ARRAY_OES: + var = &arrayObj->PointSize.Enabled; + flag = _NEW_ARRAY_POINT_SIZE; + break; +#endif + +#if FEATURE_NV_vertex_program + case GL_VERTEX_ATTRIB_ARRAY0_NV: + case GL_VERTEX_ATTRIB_ARRAY1_NV: + case GL_VERTEX_ATTRIB_ARRAY2_NV: + case GL_VERTEX_ATTRIB_ARRAY3_NV: + case GL_VERTEX_ATTRIB_ARRAY4_NV: + case GL_VERTEX_ATTRIB_ARRAY5_NV: + case GL_VERTEX_ATTRIB_ARRAY6_NV: + case GL_VERTEX_ATTRIB_ARRAY7_NV: + case GL_VERTEX_ATTRIB_ARRAY8_NV: + case GL_VERTEX_ATTRIB_ARRAY9_NV: + case GL_VERTEX_ATTRIB_ARRAY10_NV: + case GL_VERTEX_ATTRIB_ARRAY11_NV: + case GL_VERTEX_ATTRIB_ARRAY12_NV: + case GL_VERTEX_ATTRIB_ARRAY13_NV: + case GL_VERTEX_ATTRIB_ARRAY14_NV: + case GL_VERTEX_ATTRIB_ARRAY15_NV: + CHECK_EXTENSION(NV_vertex_program, cap); + { + GLint n = (GLint) cap - GL_VERTEX_ATTRIB_ARRAY0_NV; + ASSERT(n < Elements(ctx->Array.ArrayObj->VertexAttrib)); + var = &arrayObj->VertexAttrib[n].Enabled; + flag = _NEW_ARRAY_ATTRIB(n); + } + break; +#endif /* FEATURE_NV_vertex_program */ + + /* GL_NV_primitive_restart */ + case GL_PRIMITIVE_RESTART_NV: + if (!ctx->Extensions.NV_primitive_restart) { + goto invalid_enum_error; + } + var = &ctx->Array.PrimitiveRestart; + flag = 0; + break; + + default: + goto invalid_enum_error; + } + + if (*var == state) + return; + + FLUSH_VERTICES(ctx, _NEW_ARRAY); + ctx->Array.NewState |= flag; + + _ae_invalidate_state(ctx, _NEW_ARRAY); + + *var = state; + + if (state) + ctx->Array.ArrayObj->_Enabled |= flag; + else + ctx->Array.ArrayObj->_Enabled &= ~flag; + + if (ctx->Driver.Enable) { + ctx->Driver.Enable( ctx, cap, state ); + } + + return; + +invalid_enum_error: + _mesa_error(ctx, GL_INVALID_ENUM, "gl%sClientState(0x%x)", + state ? "Enable" : "Disable", cap); +} + + +/** + * Enable GL capability. + * \param cap state to enable/disable. + * + * Get's the current context, assures that we're outside glBegin()/glEnd() and + * calls client_state(). + */ +void GLAPIENTRY +_mesa_EnableClientState( GLenum cap ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + client_state( ctx, cap, GL_TRUE ); +} + + +/** + * Disable GL capability. + * \param cap state to enable/disable. + * + * Get's the current context, assures that we're outside glBegin()/glEnd() and + * calls client_state(). + */ +void GLAPIENTRY +_mesa_DisableClientState( GLenum cap ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + client_state( ctx, cap, GL_FALSE ); +} + + +#undef CHECK_EXTENSION +#define CHECK_EXTENSION(EXTNAME, CAP) \ + if (!ctx->Extensions.EXTNAME) { \ + goto invalid_enum_error; \ + } + +#define CHECK_EXTENSION2(EXT1, EXT2, CAP) \ + if (!ctx->Extensions.EXT1 && !ctx->Extensions.EXT2) { \ + goto invalid_enum_error; \ + } + + + +/** + * Return pointer to current texture unit for setting/getting coordinate + * state. + * Note that we'll set GL_INVALID_OPERATION if the active texture unit is + * higher than the number of supported coordinate units. And we'll return NULL. + */ +static struct gl_texture_unit * +get_texcoord_unit(struct gl_context *ctx) +{ + if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glEnable/Disable(texcoord unit)"); + return NULL; + } + else { + return &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + } +} + + +/** + * Helper function to enable or disable a texture target. + * \param bit one of the TEXTURE_x_BIT values + * \return GL_TRUE if state is changing or GL_FALSE if no change + */ +static GLboolean +enable_texture(struct gl_context *ctx, GLboolean state, GLbitfield texBit) +{ + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + const GLbitfield newenabled = state + ? (texUnit->Enabled | texBit) : (texUnit->Enabled & ~texBit); + + if (texUnit->Enabled == newenabled) + return GL_FALSE; + + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + texUnit->Enabled = newenabled; + return GL_TRUE; +} + + +/** + * Helper function to enable or disable state. + * + * \param ctx GL context. + * \param cap the state to enable/disable + * \param state whether to enable or disable the specified capability. + * + * Updates the current context and flushes the vertices as needed. For + * capabilities associated with extensions it verifies that those extensions + * are effectivly present before updating. Notifies the driver via + * dd_function_table::Enable. + */ +void +_mesa_set_enable(struct gl_context *ctx, GLenum cap, GLboolean state) +{ + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "%s %s (newstate is %x)\n", + state ? "glEnable" : "glDisable", + _mesa_lookup_enum_by_nr(cap), + ctx->NewState); + + switch (cap) { + case GL_ALPHA_TEST: + if (ctx->Color.AlphaEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.AlphaEnabled = state; + break; + case GL_AUTO_NORMAL: + if (ctx->Eval.AutoNormal == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.AutoNormal = state; + break; + case GL_BLEND: + { + GLbitfield newEnabled = state * ((1 << ctx->Const.MaxDrawBuffers) - 1); + if (newEnabled != ctx->Color.BlendEnabled) { + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.BlendEnabled = newEnabled; + } + } + break; +#if FEATURE_userclip + case GL_CLIP_PLANE0: + case GL_CLIP_PLANE1: + case GL_CLIP_PLANE2: + case GL_CLIP_PLANE3: + case GL_CLIP_PLANE4: + case GL_CLIP_PLANE5: + { + const GLuint p = cap - GL_CLIP_PLANE0; + + if ((ctx->Transform.ClipPlanesEnabled & (1 << p)) == ((GLuint) state << p)) + return; + + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + + if (state) { + ctx->Transform.ClipPlanesEnabled |= (1 << p); + + if (_math_matrix_is_dirty(ctx->ProjectionMatrixStack.Top)) + _math_matrix_analyse( ctx->ProjectionMatrixStack.Top ); + + /* This derived state also calculated in clip.c and + * from _mesa_update_state() on changes to EyeUserPlane + * and ctx->ProjectionMatrix respectively. + */ + _mesa_transform_vector( ctx->Transform._ClipUserPlane[p], + ctx->Transform.EyeUserPlane[p], + ctx->ProjectionMatrixStack.Top->inv ); + } + else { + ctx->Transform.ClipPlanesEnabled &= ~(1 << p); + } + } + break; +#endif + case GL_COLOR_MATERIAL: + if (ctx->Light.ColorMaterialEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_LIGHT); + FLUSH_CURRENT(ctx, 0); + ctx->Light.ColorMaterialEnabled = state; + if (state) { + _mesa_update_color_material( ctx, + ctx->Current.Attrib[VERT_ATTRIB_COLOR0] ); + } + break; + case GL_CULL_FACE: + if (ctx->Polygon.CullFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.CullFlag = state; + break; + case GL_DEPTH_TEST: + if (ctx->Depth.Test == state) + return; + FLUSH_VERTICES(ctx, _NEW_DEPTH); + ctx->Depth.Test = state; + break; + case GL_DITHER: + if (ctx->Color.DitherFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.DitherFlag = state; + break; + case GL_FOG: + if (ctx->Fog.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_FOG); + ctx->Fog.Enabled = state; + break; + case GL_LIGHT0: + case GL_LIGHT1: + case GL_LIGHT2: + case GL_LIGHT3: + case GL_LIGHT4: + case GL_LIGHT5: + case GL_LIGHT6: + case GL_LIGHT7: + if (ctx->Light.Light[cap-GL_LIGHT0].Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_LIGHT); + ctx->Light.Light[cap-GL_LIGHT0].Enabled = state; + if (state) { + insert_at_tail(&ctx->Light.EnabledList, + &ctx->Light.Light[cap-GL_LIGHT0]); + } + else { + remove_from_list(&ctx->Light.Light[cap-GL_LIGHT0]); + } + break; + case GL_LIGHTING: + if (ctx->Light.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_LIGHT); + ctx->Light.Enabled = state; + if (ctx->Light.Enabled && ctx->Light.Model.TwoSide) + ctx->_TriangleCaps |= DD_TRI_LIGHT_TWOSIDE; + else + ctx->_TriangleCaps &= ~DD_TRI_LIGHT_TWOSIDE; + break; + case GL_LINE_SMOOTH: + if (ctx->Line.SmoothFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_LINE); + ctx->Line.SmoothFlag = state; + ctx->_TriangleCaps ^= DD_LINE_SMOOTH; + break; + case GL_LINE_STIPPLE: + if (ctx->Line.StippleFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_LINE); + ctx->Line.StippleFlag = state; + ctx->_TriangleCaps ^= DD_LINE_STIPPLE; + break; + case GL_INDEX_LOGIC_OP: + if (ctx->Color.IndexLogicOpEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.IndexLogicOpEnabled = state; + break; + case GL_COLOR_LOGIC_OP: + if (ctx->Color.ColorLogicOpEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.ColorLogicOpEnabled = state; + break; + case GL_MAP1_COLOR_4: + if (ctx->Eval.Map1Color4 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1Color4 = state; + break; + case GL_MAP1_INDEX: + if (ctx->Eval.Map1Index == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1Index = state; + break; + case GL_MAP1_NORMAL: + if (ctx->Eval.Map1Normal == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1Normal = state; + break; + case GL_MAP1_TEXTURE_COORD_1: + if (ctx->Eval.Map1TextureCoord1 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1TextureCoord1 = state; + break; + case GL_MAP1_TEXTURE_COORD_2: + if (ctx->Eval.Map1TextureCoord2 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1TextureCoord2 = state; + break; + case GL_MAP1_TEXTURE_COORD_3: + if (ctx->Eval.Map1TextureCoord3 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1TextureCoord3 = state; + break; + case GL_MAP1_TEXTURE_COORD_4: + if (ctx->Eval.Map1TextureCoord4 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1TextureCoord4 = state; + break; + case GL_MAP1_VERTEX_3: + if (ctx->Eval.Map1Vertex3 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1Vertex3 = state; + break; + case GL_MAP1_VERTEX_4: + if (ctx->Eval.Map1Vertex4 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1Vertex4 = state; + break; + case GL_MAP2_COLOR_4: + if (ctx->Eval.Map2Color4 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2Color4 = state; + break; + case GL_MAP2_INDEX: + if (ctx->Eval.Map2Index == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2Index = state; + break; + case GL_MAP2_NORMAL: + if (ctx->Eval.Map2Normal == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2Normal = state; + break; + case GL_MAP2_TEXTURE_COORD_1: + if (ctx->Eval.Map2TextureCoord1 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2TextureCoord1 = state; + break; + case GL_MAP2_TEXTURE_COORD_2: + if (ctx->Eval.Map2TextureCoord2 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2TextureCoord2 = state; + break; + case GL_MAP2_TEXTURE_COORD_3: + if (ctx->Eval.Map2TextureCoord3 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2TextureCoord3 = state; + break; + case GL_MAP2_TEXTURE_COORD_4: + if (ctx->Eval.Map2TextureCoord4 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2TextureCoord4 = state; + break; + case GL_MAP2_VERTEX_3: + if (ctx->Eval.Map2Vertex3 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2Vertex3 = state; + break; + case GL_MAP2_VERTEX_4: + if (ctx->Eval.Map2Vertex4 == state) + return; + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2Vertex4 = state; + break; + case GL_NORMALIZE: + if (ctx->Transform.Normalize == state) + return; + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + ctx->Transform.Normalize = state; + break; + case GL_POINT_SMOOTH: + if (ctx->Point.SmoothFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_POINT); + ctx->Point.SmoothFlag = state; + ctx->_TriangleCaps ^= DD_POINT_SMOOTH; + break; + case GL_POLYGON_SMOOTH: + if (ctx->Polygon.SmoothFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.SmoothFlag = state; + ctx->_TriangleCaps ^= DD_TRI_SMOOTH; + break; + case GL_POLYGON_STIPPLE: + if (ctx->Polygon.StippleFlag == state) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.StippleFlag = state; + ctx->_TriangleCaps ^= DD_TRI_STIPPLE; + break; + case GL_POLYGON_OFFSET_POINT: + if (ctx->Polygon.OffsetPoint == state) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.OffsetPoint = state; + break; + case GL_POLYGON_OFFSET_LINE: + if (ctx->Polygon.OffsetLine == state) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.OffsetLine = state; + break; + case GL_POLYGON_OFFSET_FILL: + /*case GL_POLYGON_OFFSET_EXT:*/ + if (ctx->Polygon.OffsetFill == state) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.OffsetFill = state; + break; + case GL_RESCALE_NORMAL_EXT: + if (ctx->Transform.RescaleNormals == state) + return; + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + ctx->Transform.RescaleNormals = state; + break; + case GL_SCISSOR_TEST: + if (ctx->Scissor.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_SCISSOR); + ctx->Scissor.Enabled = state; + break; + case GL_SHARED_TEXTURE_PALETTE_EXT: + if (ctx->Texture.SharedPalette == state) + return; + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + ctx->Texture.SharedPalette = state; + break; + case GL_STENCIL_TEST: + if (ctx->Stencil.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.Enabled = state; + break; + case GL_TEXTURE_1D: + if (!enable_texture(ctx, state, TEXTURE_1D_BIT)) { + return; + } + break; + case GL_TEXTURE_2D: + if (!enable_texture(ctx, state, TEXTURE_2D_BIT)) { + return; + } + break; + case GL_TEXTURE_3D: + if (!enable_texture(ctx, state, TEXTURE_3D_BIT)) { + return; + } + break; + case GL_TEXTURE_GEN_Q: + { + struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + GLuint newenabled = texUnit->TexGenEnabled & ~Q_BIT; + if (state) + newenabled |= Q_BIT; + if (texUnit->TexGenEnabled == newenabled) + return; + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + texUnit->TexGenEnabled = newenabled; + } + } + break; + case GL_TEXTURE_GEN_R: + { + struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + GLuint newenabled = texUnit->TexGenEnabled & ~R_BIT; + if (state) + newenabled |= R_BIT; + if (texUnit->TexGenEnabled == newenabled) + return; + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + texUnit->TexGenEnabled = newenabled; + } + } + break; + case GL_TEXTURE_GEN_S: + { + struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + GLuint newenabled = texUnit->TexGenEnabled & ~S_BIT; + if (state) + newenabled |= S_BIT; + if (texUnit->TexGenEnabled == newenabled) + return; + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + texUnit->TexGenEnabled = newenabled; + } + } + break; + case GL_TEXTURE_GEN_T: + { + struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + GLuint newenabled = texUnit->TexGenEnabled & ~T_BIT; + if (state) + newenabled |= T_BIT; + if (texUnit->TexGenEnabled == newenabled) + return; + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + texUnit->TexGenEnabled = newenabled; + } + } + break; + +#if FEATURE_ES1 + case GL_TEXTURE_GEN_STR_OES: + /* disable S, T, and R at the same time */ + { + struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + GLuint newenabled = + texUnit->TexGenEnabled & ~STR_BITS; + if (state) + newenabled |= STR_BITS; + if (texUnit->TexGenEnabled == newenabled) + return; + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + texUnit->TexGenEnabled = newenabled; + } + } + break; +#endif + + /* + * CLIENT STATE!!! + */ + case GL_VERTEX_ARRAY: + case GL_NORMAL_ARRAY: + case GL_COLOR_ARRAY: + case GL_INDEX_ARRAY: + case GL_TEXTURE_COORD_ARRAY: + case GL_EDGE_FLAG_ARRAY: + case GL_FOG_COORDINATE_ARRAY_EXT: + case GL_SECONDARY_COLOR_ARRAY_EXT: + case GL_POINT_SIZE_ARRAY_OES: + client_state( ctx, cap, state ); + return; + + /* GL_ARB_texture_cube_map */ + case GL_TEXTURE_CUBE_MAP_ARB: + CHECK_EXTENSION(ARB_texture_cube_map, cap); + if (!enable_texture(ctx, state, TEXTURE_CUBE_BIT)) { + return; + } + break; + + /* GL_EXT_secondary_color */ + case GL_COLOR_SUM_EXT: + CHECK_EXTENSION2(EXT_secondary_color, ARB_vertex_program, cap); + if (ctx->Fog.ColorSumEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_FOG); + ctx->Fog.ColorSumEnabled = state; + break; + + /* GL_ARB_multisample */ + case GL_MULTISAMPLE_ARB: + if (ctx->Multisample.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); + ctx->Multisample.Enabled = state; + break; + case GL_SAMPLE_ALPHA_TO_COVERAGE_ARB: + if (ctx->Multisample.SampleAlphaToCoverage == state) + return; + FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); + ctx->Multisample.SampleAlphaToCoverage = state; + break; + case GL_SAMPLE_ALPHA_TO_ONE_ARB: + if (ctx->Multisample.SampleAlphaToOne == state) + return; + FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); + ctx->Multisample.SampleAlphaToOne = state; + break; + case GL_SAMPLE_COVERAGE_ARB: + if (ctx->Multisample.SampleCoverage == state) + return; + FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); + ctx->Multisample.SampleCoverage = state; + break; + case GL_SAMPLE_COVERAGE_INVERT_ARB: + if (ctx->Multisample.SampleCoverageInvert == state) + return; + FLUSH_VERTICES(ctx, _NEW_MULTISAMPLE); + ctx->Multisample.SampleCoverageInvert = state; + break; + + /* GL_IBM_rasterpos_clip */ + case GL_RASTER_POSITION_UNCLIPPED_IBM: + CHECK_EXTENSION(IBM_rasterpos_clip, cap); + if (ctx->Transform.RasterPositionUnclipped == state) + return; + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + ctx->Transform.RasterPositionUnclipped = state; + break; + + /* GL_NV_point_sprite */ + case GL_POINT_SPRITE_NV: + CHECK_EXTENSION2(NV_point_sprite, ARB_point_sprite, cap); + if (ctx->Point.PointSprite == state) + return; + FLUSH_VERTICES(ctx, _NEW_POINT); + ctx->Point.PointSprite = state; + break; + +#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program + case GL_VERTEX_PROGRAM_ARB: + CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap); + if (ctx->VertexProgram.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + ctx->VertexProgram.Enabled = state; + break; + case GL_VERTEX_PROGRAM_POINT_SIZE_ARB: + CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap); + if (ctx->VertexProgram.PointSizeEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + ctx->VertexProgram.PointSizeEnabled = state; + break; + case GL_VERTEX_PROGRAM_TWO_SIDE_ARB: + CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program, cap); + if (ctx->VertexProgram.TwoSideEnabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + ctx->VertexProgram.TwoSideEnabled = state; + break; +#endif +#if FEATURE_NV_vertex_program + case GL_MAP1_VERTEX_ATTRIB0_4_NV: + case GL_MAP1_VERTEX_ATTRIB1_4_NV: + case GL_MAP1_VERTEX_ATTRIB2_4_NV: + case GL_MAP1_VERTEX_ATTRIB3_4_NV: + case GL_MAP1_VERTEX_ATTRIB4_4_NV: + case GL_MAP1_VERTEX_ATTRIB5_4_NV: + case GL_MAP1_VERTEX_ATTRIB6_4_NV: + case GL_MAP1_VERTEX_ATTRIB7_4_NV: + case GL_MAP1_VERTEX_ATTRIB8_4_NV: + case GL_MAP1_VERTEX_ATTRIB9_4_NV: + case GL_MAP1_VERTEX_ATTRIB10_4_NV: + case GL_MAP1_VERTEX_ATTRIB11_4_NV: + case GL_MAP1_VERTEX_ATTRIB12_4_NV: + case GL_MAP1_VERTEX_ATTRIB13_4_NV: + case GL_MAP1_VERTEX_ATTRIB14_4_NV: + case GL_MAP1_VERTEX_ATTRIB15_4_NV: + CHECK_EXTENSION(NV_vertex_program, cap); + { + const GLuint map = (GLuint) (cap - GL_MAP1_VERTEX_ATTRIB0_4_NV); + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map1Attrib[map] = state; + } + break; + case GL_MAP2_VERTEX_ATTRIB0_4_NV: + case GL_MAP2_VERTEX_ATTRIB1_4_NV: + case GL_MAP2_VERTEX_ATTRIB2_4_NV: + case GL_MAP2_VERTEX_ATTRIB3_4_NV: + case GL_MAP2_VERTEX_ATTRIB4_4_NV: + case GL_MAP2_VERTEX_ATTRIB5_4_NV: + case GL_MAP2_VERTEX_ATTRIB6_4_NV: + case GL_MAP2_VERTEX_ATTRIB7_4_NV: + case GL_MAP2_VERTEX_ATTRIB8_4_NV: + case GL_MAP2_VERTEX_ATTRIB9_4_NV: + case GL_MAP2_VERTEX_ATTRIB10_4_NV: + case GL_MAP2_VERTEX_ATTRIB11_4_NV: + case GL_MAP2_VERTEX_ATTRIB12_4_NV: + case GL_MAP2_VERTEX_ATTRIB13_4_NV: + case GL_MAP2_VERTEX_ATTRIB14_4_NV: + case GL_MAP2_VERTEX_ATTRIB15_4_NV: + CHECK_EXTENSION(NV_vertex_program, cap); + { + const GLuint map = (GLuint) (cap - GL_MAP2_VERTEX_ATTRIB0_4_NV); + FLUSH_VERTICES(ctx, _NEW_EVAL); + ctx->Eval.Map2Attrib[map] = state; + } + break; +#endif /* FEATURE_NV_vertex_program */ + +#if FEATURE_NV_fragment_program + case GL_FRAGMENT_PROGRAM_NV: + CHECK_EXTENSION(NV_fragment_program, cap); + if (ctx->FragmentProgram.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + ctx->FragmentProgram.Enabled = state; + break; +#endif /* FEATURE_NV_fragment_program */ + + /* GL_NV_texture_rectangle */ + case GL_TEXTURE_RECTANGLE_NV: + CHECK_EXTENSION(NV_texture_rectangle, cap); + if (!enable_texture(ctx, state, TEXTURE_RECT_BIT)) { + return; + } + break; + + /* GL_EXT_stencil_two_side */ + case GL_STENCIL_TEST_TWO_SIDE_EXT: + CHECK_EXTENSION(EXT_stencil_two_side, cap); + if (ctx->Stencil.TestTwoSide == state) + return; + FLUSH_VERTICES(ctx, _NEW_STENCIL); + ctx->Stencil.TestTwoSide = state; + if (state) { + ctx->Stencil._BackFace = 2; + ctx->_TriangleCaps |= DD_TRI_TWOSTENCIL; + } else { + ctx->Stencil._BackFace = 1; + ctx->_TriangleCaps &= ~DD_TRI_TWOSTENCIL; + } + break; + +#if FEATURE_ARB_fragment_program + case GL_FRAGMENT_PROGRAM_ARB: + CHECK_EXTENSION(ARB_fragment_program, cap); + if (ctx->FragmentProgram.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + ctx->FragmentProgram.Enabled = state; + break; +#endif /* FEATURE_ARB_fragment_program */ + + /* GL_EXT_depth_bounds_test */ + case GL_DEPTH_BOUNDS_TEST_EXT: + CHECK_EXTENSION(EXT_depth_bounds_test, cap); + if (ctx->Depth.BoundsTest == state) + return; + FLUSH_VERTICES(ctx, _NEW_DEPTH); + ctx->Depth.BoundsTest = state; + break; + + case GL_DEPTH_CLAMP: + if (ctx->Transform.DepthClamp == state) + return; + CHECK_EXTENSION(ARB_depth_clamp, cap); + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + ctx->Transform.DepthClamp = state; + break; + +#if FEATURE_ATI_fragment_shader + case GL_FRAGMENT_SHADER_ATI: + CHECK_EXTENSION(ATI_fragment_shader, cap); + if (ctx->ATIFragmentShader.Enabled == state) + return; + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + ctx->ATIFragmentShader.Enabled = state; + break; +#endif + + /* GL_MESA_texture_array */ + case GL_TEXTURE_1D_ARRAY_EXT: + CHECK_EXTENSION(MESA_texture_array, cap); + if (!enable_texture(ctx, state, TEXTURE_1D_ARRAY_BIT)) { + return; + } + break; + + case GL_TEXTURE_2D_ARRAY_EXT: + CHECK_EXTENSION(MESA_texture_array, cap); + if (!enable_texture(ctx, state, TEXTURE_2D_ARRAY_BIT)) { + return; + } + break; + + case GL_TEXTURE_CUBE_MAP_SEAMLESS: + CHECK_EXTENSION(ARB_seamless_cube_map, cap); + ctx->Texture.CubeMapSeamless = state; + break; + +#if FEATURE_EXT_transform_feedback + case GL_RASTERIZER_DISCARD: + CHECK_EXTENSION(EXT_transform_feedback, cap); + if (ctx->TransformFeedback.RasterDiscard != state) { + ctx->TransformFeedback.RasterDiscard = state; + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + } + break; +#endif + + /* GL 3.1 primitive restart. Note: this enum is different from + * GL_PRIMITIVE_RESTART_NV (which is client state). + */ + case GL_PRIMITIVE_RESTART: + if (ctx->VersionMajor * 10 + ctx->VersionMinor < 31) { + goto invalid_enum_error; + } + if (ctx->Array.PrimitiveRestart != state) { + FLUSH_VERTICES(ctx, _NEW_TRANSFORM); + ctx->Array.PrimitiveRestart = state; + } + break; + + /* GL3.0 - GL_framebuffer_sRGB */ + case GL_FRAMEBUFFER_SRGB_EXT: + CHECK_EXTENSION(EXT_framebuffer_sRGB, cap); + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + ctx->Color.sRGBEnabled = state; + break; + + default: + goto invalid_enum_error; + } + + if (ctx->Driver.Enable) { + ctx->Driver.Enable( ctx, cap, state ); + } + + return; + +invalid_enum_error: + _mesa_error(ctx, GL_INVALID_ENUM, "gl%s(0x%x)", + state ? "Enable" : "Disable", cap); +} + + +/** + * Enable GL capability. Called by glEnable() + * \param cap state to enable. + */ +void GLAPIENTRY +_mesa_Enable( GLenum cap ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + _mesa_set_enable( ctx, cap, GL_TRUE ); +} + + +/** + * Disable GL capability. Called by glDisable() + * \param cap state to disable. + */ +void GLAPIENTRY +_mesa_Disable( GLenum cap ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + _mesa_set_enable( ctx, cap, GL_FALSE ); +} + + + +/** + * Enable/disable an indexed state var. + */ +void +_mesa_set_enablei(struct gl_context *ctx, GLenum cap, GLuint index, GLboolean state) +{ + ASSERT(state == 0 || state == 1); + switch (cap) { + case GL_BLEND: + if (!ctx->Extensions.EXT_draw_buffers2) { + goto invalid_enum_error; + } + if (index >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%u)", + state ? "glEnableIndexed" : "glDisableIndexed", index); + return; + } + if (((ctx->Color.BlendEnabled >> index) & 1) != state) { + FLUSH_VERTICES(ctx, _NEW_COLOR); + if (state) + ctx->Color.BlendEnabled |= (1 << index); + else + ctx->Color.BlendEnabled &= ~(1 << index); + } + break; + default: + goto invalid_enum_error; + } + return; + +invalid_enum_error: + _mesa_error(ctx, GL_INVALID_ENUM, "%s(cap=%s)", + state ? "glEnablei" : "glDisablei", + _mesa_lookup_enum_by_nr(cap)); +} + + +void GLAPIENTRY +_mesa_DisableIndexed( GLenum cap, GLuint index ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + _mesa_set_enablei(ctx, cap, index, GL_FALSE); +} + + +void GLAPIENTRY +_mesa_EnableIndexed( GLenum cap, GLuint index ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + _mesa_set_enablei(ctx, cap, index, GL_TRUE); +} + + +GLboolean GLAPIENTRY +_mesa_IsEnabledIndexed( GLenum cap, GLuint index ) +{ + GET_CURRENT_CONTEXT(ctx); + switch (cap) { + case GL_BLEND: + if (index >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "glIsEnabledIndexed(index=%u)", + index); + return GL_FALSE; + } + return (ctx->Color.BlendEnabled >> index) & 1; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabledIndexed(cap=%s)", + _mesa_lookup_enum_by_nr(cap)); + return GL_FALSE; + } +} + + + + +#undef CHECK_EXTENSION +#define CHECK_EXTENSION(EXTNAME) \ + if (!ctx->Extensions.EXTNAME) { \ + goto invalid_enum_error; \ + } + +#undef CHECK_EXTENSION2 +#define CHECK_EXTENSION2(EXT1, EXT2) \ + if (!ctx->Extensions.EXT1 && !ctx->Extensions.EXT2) { \ + goto invalid_enum_error; \ + } + + +/** + * Helper function to determine whether a texture target is enabled. + */ +static GLboolean +is_texture_enabled(struct gl_context *ctx, GLbitfield bit) +{ + const struct gl_texture_unit *const texUnit = + &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + return (texUnit->Enabled & bit) ? GL_TRUE : GL_FALSE; +} + + +/** + * Return simple enable/disable state. + * + * \param cap state variable to query. + * + * Returns the state of the specified capability from the current GL context. + * For the capabilities associated with extensions verifies that those + * extensions are effectively present before reporting. + */ +GLboolean GLAPIENTRY +_mesa_IsEnabled( GLenum cap ) +{ + GET_CURRENT_CONTEXT(ctx); + switch (cap) { + case GL_ALPHA_TEST: + return ctx->Color.AlphaEnabled; + case GL_AUTO_NORMAL: + return ctx->Eval.AutoNormal; + case GL_BLEND: + return ctx->Color.BlendEnabled & 1; /* return state for buffer[0] */ + case GL_CLIP_PLANE0: + case GL_CLIP_PLANE1: + case GL_CLIP_PLANE2: + case GL_CLIP_PLANE3: + case GL_CLIP_PLANE4: + case GL_CLIP_PLANE5: + return (ctx->Transform.ClipPlanesEnabled >> (cap - GL_CLIP_PLANE0)) & 1; + case GL_COLOR_MATERIAL: + return ctx->Light.ColorMaterialEnabled; + case GL_CULL_FACE: + return ctx->Polygon.CullFlag; + case GL_DEPTH_TEST: + return ctx->Depth.Test; + case GL_DITHER: + return ctx->Color.DitherFlag; + case GL_FOG: + return ctx->Fog.Enabled; + case GL_LIGHTING: + return ctx->Light.Enabled; + case GL_LIGHT0: + case GL_LIGHT1: + case GL_LIGHT2: + case GL_LIGHT3: + case GL_LIGHT4: + case GL_LIGHT5: + case GL_LIGHT6: + case GL_LIGHT7: + return ctx->Light.Light[cap-GL_LIGHT0].Enabled; + case GL_LINE_SMOOTH: + return ctx->Line.SmoothFlag; + case GL_LINE_STIPPLE: + return ctx->Line.StippleFlag; + case GL_INDEX_LOGIC_OP: + return ctx->Color.IndexLogicOpEnabled; + case GL_COLOR_LOGIC_OP: + return ctx->Color.ColorLogicOpEnabled; + case GL_MAP1_COLOR_4: + return ctx->Eval.Map1Color4; + case GL_MAP1_INDEX: + return ctx->Eval.Map1Index; + case GL_MAP1_NORMAL: + return ctx->Eval.Map1Normal; + case GL_MAP1_TEXTURE_COORD_1: + return ctx->Eval.Map1TextureCoord1; + case GL_MAP1_TEXTURE_COORD_2: + return ctx->Eval.Map1TextureCoord2; + case GL_MAP1_TEXTURE_COORD_3: + return ctx->Eval.Map1TextureCoord3; + case GL_MAP1_TEXTURE_COORD_4: + return ctx->Eval.Map1TextureCoord4; + case GL_MAP1_VERTEX_3: + return ctx->Eval.Map1Vertex3; + case GL_MAP1_VERTEX_4: + return ctx->Eval.Map1Vertex4; + case GL_MAP2_COLOR_4: + return ctx->Eval.Map2Color4; + case GL_MAP2_INDEX: + return ctx->Eval.Map2Index; + case GL_MAP2_NORMAL: + return ctx->Eval.Map2Normal; + case GL_MAP2_TEXTURE_COORD_1: + return ctx->Eval.Map2TextureCoord1; + case GL_MAP2_TEXTURE_COORD_2: + return ctx->Eval.Map2TextureCoord2; + case GL_MAP2_TEXTURE_COORD_3: + return ctx->Eval.Map2TextureCoord3; + case GL_MAP2_TEXTURE_COORD_4: + return ctx->Eval.Map2TextureCoord4; + case GL_MAP2_VERTEX_3: + return ctx->Eval.Map2Vertex3; + case GL_MAP2_VERTEX_4: + return ctx->Eval.Map2Vertex4; + case GL_NORMALIZE: + return ctx->Transform.Normalize; + case GL_POINT_SMOOTH: + return ctx->Point.SmoothFlag; + case GL_POLYGON_SMOOTH: + return ctx->Polygon.SmoothFlag; + case GL_POLYGON_STIPPLE: + return ctx->Polygon.StippleFlag; + case GL_POLYGON_OFFSET_POINT: + return ctx->Polygon.OffsetPoint; + case GL_POLYGON_OFFSET_LINE: + return ctx->Polygon.OffsetLine; + case GL_POLYGON_OFFSET_FILL: + /*case GL_POLYGON_OFFSET_EXT:*/ + return ctx->Polygon.OffsetFill; + case GL_RESCALE_NORMAL_EXT: + return ctx->Transform.RescaleNormals; + case GL_SCISSOR_TEST: + return ctx->Scissor.Enabled; + case GL_SHARED_TEXTURE_PALETTE_EXT: + return ctx->Texture.SharedPalette; + case GL_STENCIL_TEST: + return ctx->Stencil.Enabled; + case GL_TEXTURE_1D: + return is_texture_enabled(ctx, TEXTURE_1D_BIT); + case GL_TEXTURE_2D: + return is_texture_enabled(ctx, TEXTURE_2D_BIT); + case GL_TEXTURE_3D: + return is_texture_enabled(ctx, TEXTURE_3D_BIT); + case GL_TEXTURE_GEN_Q: + { + const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + return (texUnit->TexGenEnabled & Q_BIT) ? GL_TRUE : GL_FALSE; + } + } + return GL_FALSE; + case GL_TEXTURE_GEN_R: + { + const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + return (texUnit->TexGenEnabled & R_BIT) ? GL_TRUE : GL_FALSE; + } + } + return GL_FALSE; + case GL_TEXTURE_GEN_S: + { + const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + return (texUnit->TexGenEnabled & S_BIT) ? GL_TRUE : GL_FALSE; + } + } + return GL_FALSE; + case GL_TEXTURE_GEN_T: + { + const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + return (texUnit->TexGenEnabled & T_BIT) ? GL_TRUE : GL_FALSE; + } + } + return GL_FALSE; +#if FEATURE_ES1 + case GL_TEXTURE_GEN_STR_OES: + { + const struct gl_texture_unit *texUnit = get_texcoord_unit(ctx); + if (texUnit) { + return (texUnit->TexGenEnabled & STR_BITS) == STR_BITS ? GL_TRUE : GL_FALSE; + } + } +#endif + + /* + * CLIENT STATE!!! + */ + case GL_VERTEX_ARRAY: + return (ctx->Array.ArrayObj->Vertex.Enabled != 0); + case GL_NORMAL_ARRAY: + return (ctx->Array.ArrayObj->Normal.Enabled != 0); + case GL_COLOR_ARRAY: + return (ctx->Array.ArrayObj->Color.Enabled != 0); + case GL_INDEX_ARRAY: + return (ctx->Array.ArrayObj->Index.Enabled != 0); + case GL_TEXTURE_COORD_ARRAY: + return (ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture].Enabled != 0); + case GL_EDGE_FLAG_ARRAY: + return (ctx->Array.ArrayObj->EdgeFlag.Enabled != 0); + case GL_FOG_COORDINATE_ARRAY_EXT: + CHECK_EXTENSION(EXT_fog_coord); + return (ctx->Array.ArrayObj->FogCoord.Enabled != 0); + case GL_SECONDARY_COLOR_ARRAY_EXT: + CHECK_EXTENSION(EXT_secondary_color); + return (ctx->Array.ArrayObj->SecondaryColor.Enabled != 0); +#if FEATURE_point_size_array + case GL_POINT_SIZE_ARRAY_OES: + return (ctx->Array.ArrayObj->PointSize.Enabled != 0); +#endif + + /* GL_ARB_texture_cube_map */ + case GL_TEXTURE_CUBE_MAP_ARB: + CHECK_EXTENSION(ARB_texture_cube_map); + return is_texture_enabled(ctx, TEXTURE_CUBE_BIT); + + /* GL_EXT_secondary_color */ + case GL_COLOR_SUM_EXT: + CHECK_EXTENSION2(EXT_secondary_color, ARB_vertex_program); + return ctx->Fog.ColorSumEnabled; + + /* GL_ARB_multisample */ + case GL_MULTISAMPLE_ARB: + return ctx->Multisample.Enabled; + case GL_SAMPLE_ALPHA_TO_COVERAGE_ARB: + return ctx->Multisample.SampleAlphaToCoverage; + case GL_SAMPLE_ALPHA_TO_ONE_ARB: + return ctx->Multisample.SampleAlphaToOne; + case GL_SAMPLE_COVERAGE_ARB: + return ctx->Multisample.SampleCoverage; + case GL_SAMPLE_COVERAGE_INVERT_ARB: + return ctx->Multisample.SampleCoverageInvert; + + /* GL_IBM_rasterpos_clip */ + case GL_RASTER_POSITION_UNCLIPPED_IBM: + CHECK_EXTENSION(IBM_rasterpos_clip); + return ctx->Transform.RasterPositionUnclipped; + + /* GL_NV_point_sprite */ + case GL_POINT_SPRITE_NV: + CHECK_EXTENSION2(NV_point_sprite, ARB_point_sprite) + return ctx->Point.PointSprite; + +#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program + case GL_VERTEX_PROGRAM_ARB: + CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program); + return ctx->VertexProgram.Enabled; + case GL_VERTEX_PROGRAM_POINT_SIZE_ARB: + CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program); + return ctx->VertexProgram.PointSizeEnabled; + case GL_VERTEX_PROGRAM_TWO_SIDE_ARB: + CHECK_EXTENSION2(ARB_vertex_program, NV_vertex_program); + return ctx->VertexProgram.TwoSideEnabled; +#endif +#if FEATURE_NV_vertex_program + case GL_VERTEX_ATTRIB_ARRAY0_NV: + case GL_VERTEX_ATTRIB_ARRAY1_NV: + case GL_VERTEX_ATTRIB_ARRAY2_NV: + case GL_VERTEX_ATTRIB_ARRAY3_NV: + case GL_VERTEX_ATTRIB_ARRAY4_NV: + case GL_VERTEX_ATTRIB_ARRAY5_NV: + case GL_VERTEX_ATTRIB_ARRAY6_NV: + case GL_VERTEX_ATTRIB_ARRAY7_NV: + case GL_VERTEX_ATTRIB_ARRAY8_NV: + case GL_VERTEX_ATTRIB_ARRAY9_NV: + case GL_VERTEX_ATTRIB_ARRAY10_NV: + case GL_VERTEX_ATTRIB_ARRAY11_NV: + case GL_VERTEX_ATTRIB_ARRAY12_NV: + case GL_VERTEX_ATTRIB_ARRAY13_NV: + case GL_VERTEX_ATTRIB_ARRAY14_NV: + case GL_VERTEX_ATTRIB_ARRAY15_NV: + CHECK_EXTENSION(NV_vertex_program); + { + GLint n = (GLint) cap - GL_VERTEX_ATTRIB_ARRAY0_NV; + ASSERT(n < Elements(ctx->Array.ArrayObj->VertexAttrib)); + return (ctx->Array.ArrayObj->VertexAttrib[n].Enabled != 0); + } + case GL_MAP1_VERTEX_ATTRIB0_4_NV: + case GL_MAP1_VERTEX_ATTRIB1_4_NV: + case GL_MAP1_VERTEX_ATTRIB2_4_NV: + case GL_MAP1_VERTEX_ATTRIB3_4_NV: + case GL_MAP1_VERTEX_ATTRIB4_4_NV: + case GL_MAP1_VERTEX_ATTRIB5_4_NV: + case GL_MAP1_VERTEX_ATTRIB6_4_NV: + case GL_MAP1_VERTEX_ATTRIB7_4_NV: + case GL_MAP1_VERTEX_ATTRIB8_4_NV: + case GL_MAP1_VERTEX_ATTRIB9_4_NV: + case GL_MAP1_VERTEX_ATTRIB10_4_NV: + case GL_MAP1_VERTEX_ATTRIB11_4_NV: + case GL_MAP1_VERTEX_ATTRIB12_4_NV: + case GL_MAP1_VERTEX_ATTRIB13_4_NV: + case GL_MAP1_VERTEX_ATTRIB14_4_NV: + case GL_MAP1_VERTEX_ATTRIB15_4_NV: + CHECK_EXTENSION(NV_vertex_program); + { + const GLuint map = (GLuint) (cap - GL_MAP1_VERTEX_ATTRIB0_4_NV); + return ctx->Eval.Map1Attrib[map]; + } + case GL_MAP2_VERTEX_ATTRIB0_4_NV: + case GL_MAP2_VERTEX_ATTRIB1_4_NV: + case GL_MAP2_VERTEX_ATTRIB2_4_NV: + case GL_MAP2_VERTEX_ATTRIB3_4_NV: + case GL_MAP2_VERTEX_ATTRIB4_4_NV: + case GL_MAP2_VERTEX_ATTRIB5_4_NV: + case GL_MAP2_VERTEX_ATTRIB6_4_NV: + case GL_MAP2_VERTEX_ATTRIB7_4_NV: + case GL_MAP2_VERTEX_ATTRIB8_4_NV: + case GL_MAP2_VERTEX_ATTRIB9_4_NV: + case GL_MAP2_VERTEX_ATTRIB10_4_NV: + case GL_MAP2_VERTEX_ATTRIB11_4_NV: + case GL_MAP2_VERTEX_ATTRIB12_4_NV: + case GL_MAP2_VERTEX_ATTRIB13_4_NV: + case GL_MAP2_VERTEX_ATTRIB14_4_NV: + case GL_MAP2_VERTEX_ATTRIB15_4_NV: + CHECK_EXTENSION(NV_vertex_program); + { + const GLuint map = (GLuint) (cap - GL_MAP2_VERTEX_ATTRIB0_4_NV); + return ctx->Eval.Map2Attrib[map]; + } +#endif /* FEATURE_NV_vertex_program */ + +#if FEATURE_NV_fragment_program + case GL_FRAGMENT_PROGRAM_NV: + CHECK_EXTENSION(NV_fragment_program); + return ctx->FragmentProgram.Enabled; +#endif /* FEATURE_NV_fragment_program */ + + /* GL_NV_texture_rectangle */ + case GL_TEXTURE_RECTANGLE_NV: + CHECK_EXTENSION(NV_texture_rectangle); + return is_texture_enabled(ctx, TEXTURE_RECT_BIT); + + /* GL_EXT_stencil_two_side */ + case GL_STENCIL_TEST_TWO_SIDE_EXT: + CHECK_EXTENSION(EXT_stencil_two_side); + return ctx->Stencil.TestTwoSide; + +#if FEATURE_ARB_fragment_program + case GL_FRAGMENT_PROGRAM_ARB: + return ctx->FragmentProgram.Enabled; +#endif /* FEATURE_ARB_fragment_program */ + + /* GL_EXT_depth_bounds_test */ + case GL_DEPTH_BOUNDS_TEST_EXT: + CHECK_EXTENSION(EXT_depth_bounds_test); + return ctx->Depth.BoundsTest; + + /* GL_ARB_depth_clamp */ + case GL_DEPTH_CLAMP: + CHECK_EXTENSION(ARB_depth_clamp); + return ctx->Transform.DepthClamp; + +#if FEATURE_ATI_fragment_shader + case GL_FRAGMENT_SHADER_ATI: + CHECK_EXTENSION(ATI_fragment_shader); + return ctx->ATIFragmentShader.Enabled; +#endif /* FEATURE_ATI_fragment_shader */ + + case GL_TEXTURE_CUBE_MAP_SEAMLESS: + CHECK_EXTENSION(ARB_seamless_cube_map); + return ctx->Texture.CubeMapSeamless; + +#if FEATURE_EXT_transform_feedback + case GL_RASTERIZER_DISCARD: + CHECK_EXTENSION(EXT_transform_feedback); + return ctx->TransformFeedback.RasterDiscard; +#endif + + /* GL_NV_primitive_restart */ + case GL_PRIMITIVE_RESTART_NV: + if (!ctx->Extensions.NV_primitive_restart) { + goto invalid_enum_error; + } + return ctx->Array.PrimitiveRestart; + + /* GL 3.1 primitive restart */ + case GL_PRIMITIVE_RESTART: + if (ctx->VersionMajor * 10 + ctx->VersionMinor < 31) { + goto invalid_enum_error; + } + return ctx->Array.PrimitiveRestart; + + /* GL3.0 - GL_framebuffer_sRGB */ + case GL_FRAMEBUFFER_SRGB_EXT: + CHECK_EXTENSION(EXT_framebuffer_sRGB); + return ctx->Color.sRGBEnabled; + + default: + goto invalid_enum_error; + } + + return GL_FALSE; + +invalid_enum_error: + _mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabled(0x%x)", (int) cap); + return GL_FALSE; +} diff --git a/mesalib/src/mesa/main/extensions.c b/mesalib/src/mesa/main/extensions.c index 310740b0d..3840cdc5d 100644 --- a/mesalib/src/mesa/main/extensions.c +++ b/mesalib/src/mesa/main/extensions.c @@ -241,8 +241,7 @@ static const struct extension extension_table[] = { { "GL_OES_stencil4", o(dummy_false), DISABLE }, { "GL_OES_stencil8", o(EXT_framebuffer_object), ES1 | ES2 }, { "GL_OES_stencil_wrap", o(EXT_stencil_wrap), ES1 }, - /* GL_OES_texture_3D is disabled due to missing GLSL support. */ - { "GL_OES_texture_3D", o(EXT_texture3D), DISABLE }, + { "GL_OES_texture_3D", o(EXT_texture3D), ES2 }, { "GL_OES_texture_cube_map", o(ARB_texture_cube_map), ES1 }, { "GL_OES_texture_env_crossbar", o(ARB_texture_env_crossbar), ES1 }, { "GL_OES_texture_mirrored_repeat", o(ARB_texture_mirrored_repeat), ES1 }, @@ -291,7 +290,6 @@ static const struct extension extension_table[] = { { "GL_SGIS_texture_border_clamp", o(ARB_texture_border_clamp), GL }, { "GL_SGIS_texture_edge_clamp", o(SGIS_texture_edge_clamp), GL }, { "GL_SGIS_texture_lod", o(SGIS_texture_lod), GL }, - { "GL_SGI_texture_color_table", o(SGI_texture_color_table), GL }, { "GL_SUN_multi_draw_arrays", o(EXT_multi_draw_arrays), GL }, { 0, 0, 0 }, @@ -521,7 +519,6 @@ _mesa_enable_sw_extensions(struct gl_context *ctx) #if FEATURE_NV_fragment_program && FEATURE_ARB_fragment_program ctx->Extensions.NV_fragment_program_option = GL_TRUE; #endif - ctx->Extensions.SGI_texture_color_table = GL_TRUE; /*ctx->Extensions.SGIS_generate_mipmap = GL_TRUE;*/ ctx->Extensions.SGIS_texture_edge_clamp = GL_TRUE; #if FEATURE_ARB_vertex_program || FEATURE_ARB_fragment_program diff --git a/mesalib/src/mesa/main/fbobject.c b/mesalib/src/mesa/main/fbobject.c index b2ff4dc29..c242e568d 100644 --- a/mesalib/src/mesa/main/fbobject.c +++ b/mesalib/src/mesa/main/fbobject.c @@ -1,2494 +1,2438 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.1
- *
- * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- * Copyright (C) 1999-2009 VMware, Inc. 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.
- */
-
-
-/*
- * GL_EXT/ARB_framebuffer_object extensions
- *
- * Authors:
- * Brian Paul
- */
-
-
-#include "buffers.h"
-#include "context.h"
-#include "enums.h"
-#include "fbobject.h"
-#include "formats.h"
-#include "framebuffer.h"
-#include "hash.h"
-#include "macros.h"
-#include "mfeatures.h"
-#include "mtypes.h"
-#include "renderbuffer.h"
-#include "state.h"
-#include "teximage.h"
-#include "texobj.h"
-
-
-/** Set this to 1 to help debug FBO incompleteness problems */
-#define DEBUG_FBO 0
-
-/** Set this to 1 to debug/log glBlitFramebuffer() calls */
-#define DEBUG_BLIT 0
-
-
-/**
- * Notes:
- *
- * None of the GL_EXT_framebuffer_object functions are compiled into
- * display lists.
- */
-
-
-
-/*
- * When glGenRender/FramebuffersEXT() is called we insert pointers to
- * these placeholder objects into the hash table.
- * Later, when the object ID is first bound, we replace the placeholder
- * with the real frame/renderbuffer.
- */
-static struct gl_framebuffer DummyFramebuffer;
-static struct gl_renderbuffer DummyRenderbuffer;
-
-/* We bind this framebuffer when applications pass a NULL
- * drawable/surface in make current. */
-static struct gl_framebuffer IncompleteFramebuffer;
-
-
-#define IS_CUBE_FACE(TARGET) \
- ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
- (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
-
-
-static void
-delete_dummy_renderbuffer(struct gl_renderbuffer *rb)
-{
- /* no op */
-}
-
-static void
-delete_dummy_framebuffer(struct gl_framebuffer *fb)
-{
- /* no op */
-}
-
-
-void
-_mesa_init_fbobjects(struct gl_context *ctx)
-{
- _glthread_INIT_MUTEX(DummyFramebuffer.Mutex);
- _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex);
- _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex);
- DummyFramebuffer.Delete = delete_dummy_framebuffer;
- DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
- IncompleteFramebuffer.Delete = delete_dummy_framebuffer;
-}
-
-struct gl_framebuffer *
-_mesa_get_incomplete_framebuffer(void)
-{
- return &IncompleteFramebuffer;
-}
-
-/**
- * Helper routine for getting a gl_renderbuffer.
- */
-struct gl_renderbuffer *
-_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id)
-{
- struct gl_renderbuffer *rb;
-
- if (id == 0)
- return NULL;
-
- rb = (struct gl_renderbuffer *)
- _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
- return rb;
-}
-
-
-/**
- * Helper routine for getting a gl_framebuffer.
- */
-struct gl_framebuffer *
-_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id)
-{
- struct gl_framebuffer *fb;
-
- if (id == 0)
- return NULL;
-
- fb = (struct gl_framebuffer *)
- _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
- return fb;
-}
-
-
-/**
- * Mark the given framebuffer as invalid. This will force the
- * test for framebuffer completeness to be done before the framebuffer
- * is used.
- */
-static void
-invalidate_framebuffer(struct gl_framebuffer *fb)
-{
- fb->_Status = 0; /* "indeterminate" */
-}
-
-
-/**
- * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
- * gl_renderbuffer_attachment object.
- * This function is only used for user-created FB objects, not the
- * default / window-system FB object.
- * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
- * the depth buffer attachment point.
- */
-struct gl_renderbuffer_attachment *
-_mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
- GLenum attachment)
-{
- GLuint i;
-
- assert(fb->Name > 0);
-
- switch (attachment) {
- case GL_COLOR_ATTACHMENT0_EXT:
- case GL_COLOR_ATTACHMENT1_EXT:
- case GL_COLOR_ATTACHMENT2_EXT:
- case GL_COLOR_ATTACHMENT3_EXT:
- case GL_COLOR_ATTACHMENT4_EXT:
- case GL_COLOR_ATTACHMENT5_EXT:
- case GL_COLOR_ATTACHMENT6_EXT:
- case GL_COLOR_ATTACHMENT7_EXT:
- case GL_COLOR_ATTACHMENT8_EXT:
- case GL_COLOR_ATTACHMENT9_EXT:
- case GL_COLOR_ATTACHMENT10_EXT:
- case GL_COLOR_ATTACHMENT11_EXT:
- case GL_COLOR_ATTACHMENT12_EXT:
- case GL_COLOR_ATTACHMENT13_EXT:
- case GL_COLOR_ATTACHMENT14_EXT:
- case GL_COLOR_ATTACHMENT15_EXT:
- i = attachment - GL_COLOR_ATTACHMENT0_EXT;
- if (i >= ctx->Const.MaxColorAttachments) {
- return NULL;
- }
- return &fb->Attachment[BUFFER_COLOR0 + i];
- case GL_DEPTH_STENCIL_ATTACHMENT:
- /* fall-through */
- case GL_DEPTH_BUFFER:
- /* fall-through / new in GL 3.0 */
- case GL_DEPTH_ATTACHMENT_EXT:
- return &fb->Attachment[BUFFER_DEPTH];
- case GL_STENCIL_BUFFER:
- /* fall-through / new in GL 3.0 */
- case GL_STENCIL_ATTACHMENT_EXT:
- return &fb->Attachment[BUFFER_STENCIL];
- default:
- return NULL;
- }
-}
-
-
-/**
- * As above, but only used for getting attachments of the default /
- * window-system framebuffer (not user-created framebuffer objects).
- */
-static struct gl_renderbuffer_attachment *
-_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
- GLenum attachment)
-{
- assert(fb->Name == 0);
-
- switch (attachment) {
- case GL_FRONT_LEFT:
- return &fb->Attachment[BUFFER_FRONT_LEFT];
- case GL_FRONT_RIGHT:
- return &fb->Attachment[BUFFER_FRONT_RIGHT];
- case GL_BACK_LEFT:
- return &fb->Attachment[BUFFER_BACK_LEFT];
- case GL_BACK_RIGHT:
- return &fb->Attachment[BUFFER_BACK_RIGHT];
- case GL_AUX0:
- if (fb->Visual.numAuxBuffers == 1) {
- return &fb->Attachment[BUFFER_AUX0];
- }
- return NULL;
- case GL_DEPTH_BUFFER:
- /* fall-through / new in GL 3.0 */
- case GL_DEPTH_ATTACHMENT_EXT:
- return &fb->Attachment[BUFFER_DEPTH];
- case GL_STENCIL_BUFFER:
- /* fall-through / new in GL 3.0 */
- case GL_STENCIL_ATTACHMENT_EXT:
- return &fb->Attachment[BUFFER_STENCIL];
- default:
- return NULL;
- }
-}
-
-
-
-/**
- * Remove any texture or renderbuffer attached to the given attachment
- * point. Update reference counts, etc.
- */
-void
-_mesa_remove_attachment(struct gl_context *ctx,
- struct gl_renderbuffer_attachment *att)
-{
- if (att->Type == GL_TEXTURE) {
- ASSERT(att->Texture);
- if (ctx->Driver.FinishRenderTexture) {
- /* tell driver that we're done rendering to this texture. */
- ctx->Driver.FinishRenderTexture(ctx, att);
- }
- _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
- ASSERT(!att->Texture);
- }
- if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
- ASSERT(!att->Texture);
- _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
- ASSERT(!att->Renderbuffer);
- }
- att->Type = GL_NONE;
- att->Complete = GL_TRUE;
-}
-
-
-/**
- * Bind a texture object to an attachment point.
- * The previous binding, if any, will be removed first.
- */
-void
-_mesa_set_texture_attachment(struct gl_context *ctx,
- struct gl_framebuffer *fb,
- struct gl_renderbuffer_attachment *att,
- struct gl_texture_object *texObj,
- GLenum texTarget, GLuint level, GLuint zoffset)
-{
- if (att->Texture == texObj) {
- /* re-attaching same texture */
- ASSERT(att->Type == GL_TEXTURE);
- if (ctx->Driver.FinishRenderTexture)
- ctx->Driver.FinishRenderTexture(ctx, att);
- }
- else {
- /* new attachment */
- if (ctx->Driver.FinishRenderTexture && att->Texture)
- ctx->Driver.FinishRenderTexture(ctx, att);
- _mesa_remove_attachment(ctx, att);
- att->Type = GL_TEXTURE;
- assert(!att->Texture);
- _mesa_reference_texobj(&att->Texture, texObj);
- }
-
- /* always update these fields */
- att->TextureLevel = level;
- att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
- att->Zoffset = zoffset;
- att->Complete = GL_FALSE;
-
- if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
- ctx->Driver.RenderTexture(ctx, fb, att);
- }
-
- invalidate_framebuffer(fb);
-}
-
-
-/**
- * Bind a renderbuffer to an attachment point.
- * The previous binding, if any, will be removed first.
- */
-void
-_mesa_set_renderbuffer_attachment(struct gl_context *ctx,
- struct gl_renderbuffer_attachment *att,
- struct gl_renderbuffer *rb)
-{
- /* XXX check if re-doing same attachment, exit early */
- _mesa_remove_attachment(ctx, att);
- att->Type = GL_RENDERBUFFER_EXT;
- att->Texture = NULL; /* just to be safe */
- att->Complete = GL_FALSE;
- _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
-}
-
-
-/**
- * Fallback for ctx->Driver.FramebufferRenderbuffer()
- * Attach a renderbuffer object to a framebuffer object.
- */
-void
-_mesa_framebuffer_renderbuffer(struct gl_context *ctx,
- struct gl_framebuffer *fb,
- GLenum attachment, struct gl_renderbuffer *rb)
-{
- struct gl_renderbuffer_attachment *att;
-
- _glthread_LOCK_MUTEX(fb->Mutex);
-
- att = _mesa_get_attachment(ctx, fb, attachment);
- ASSERT(att);
- if (rb) {
- _mesa_set_renderbuffer_attachment(ctx, att, rb);
- if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
- /* do stencil attachment here (depth already done above) */
- att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
- assert(att);
- _mesa_set_renderbuffer_attachment(ctx, att, rb);
- }
- }
- else {
- _mesa_remove_attachment(ctx, att);
- }
-
- invalidate_framebuffer(fb);
-
- _glthread_UNLOCK_MUTEX(fb->Mutex);
-}
-
-
-/**
- * Fallback for ctx->Driver.ValidateFramebuffer()
- * Check if the renderbuffer's formats are supported by the software
- * renderer.
- * Drivers should probably override this.
- */
-void
-_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
-{
- gl_buffer_index buf;
- for (buf = 0; buf < BUFFER_COUNT; buf++) {
- const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer;
- if (rb) {
- switch (rb->_BaseFormat) {
- case GL_ALPHA:
- case GL_LUMINANCE_ALPHA:
- case GL_LUMINANCE:
- case GL_INTENSITY:
- case GL_RED:
- case GL_RG:
- fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
- return;
- default:
- /* render buffer format is supported by software rendering */
- ;
- }
- }
- }
-}
-
-
-/**
- * For debug only.
- */
-static void
-att_incomplete(const char *msg)
-{
-#if DEBUG_FBO
- _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
-#else
- (void) msg;
-#endif
-}
-
-
-/**
- * For debug only.
- */
-static void
-fbo_incomplete(const char *msg, int index)
-{
-#if DEBUG_FBO
- _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
-#else
- (void) msg;
- (void) index;
-#endif
-}
-
-
-/**
- * Is the given base format a legal format for a color renderbuffer?
- */
-GLboolean
-_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat)
-{
- switch (baseFormat) {
- case GL_RGB:
- case GL_RGBA:
- return GL_TRUE;
- case GL_LUMINANCE:
- case GL_LUMINANCE_ALPHA:
- case GL_INTENSITY:
- case GL_ALPHA:
- return ctx->Extensions.ARB_framebuffer_object;
- case GL_RED:
- case GL_RG:
- return ctx->Extensions.ARB_texture_rg;
- default:
- return GL_FALSE;
- }
-}
-
-
-/**
- * Is the given base format a legal format for a depth/stencil renderbuffer?
- */
-static GLboolean
-is_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat)
-{
- switch (baseFormat) {
- case GL_DEPTH_COMPONENT:
- case GL_DEPTH_STENCIL_EXT:
- return GL_TRUE;
- default:
- return GL_FALSE;
- }
-}
-
-
-/**
- * Test if an attachment point is complete and update its Complete field.
- * \param format if GL_COLOR, this is a color attachment point,
- * if GL_DEPTH, this is a depth component attachment point,
- * if GL_STENCIL, this is a stencil component attachment point.
- */
-static void
-test_attachment_completeness(const struct gl_context *ctx, GLenum format,
- struct gl_renderbuffer_attachment *att)
-{
- assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
-
- /* assume complete */
- att->Complete = GL_TRUE;
-
- /* Look for reasons why the attachment might be incomplete */
- if (att->Type == GL_TEXTURE) {
- const struct gl_texture_object *texObj = att->Texture;
- struct gl_texture_image *texImage;
- GLenum baseFormat;
-
- if (!texObj) {
- att_incomplete("no texobj");
- att->Complete = GL_FALSE;
- return;
- }
-
- texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
- if (!texImage) {
- att_incomplete("no teximage");
- att->Complete = GL_FALSE;
- return;
- }
- if (texImage->Width < 1 || texImage->Height < 1) {
- att_incomplete("teximage width/height=0");
- printf("texobj = %u\n", texObj->Name);
- printf("level = %d\n", att->TextureLevel);
- att->Complete = GL_FALSE;
- return;
- }
- if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
- att_incomplete("bad z offset");
- att->Complete = GL_FALSE;
- return;
- }
-
- baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
-
- if (format == GL_COLOR) {
- if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
- att_incomplete("bad format");
- att->Complete = GL_FALSE;
- return;
- }
- if (_mesa_is_format_compressed(texImage->TexFormat)) {
- att_incomplete("compressed internalformat");
- att->Complete = GL_FALSE;
- return;
- }
- }
- else if (format == GL_DEPTH) {
- if (baseFormat == GL_DEPTH_COMPONENT) {
- /* OK */
- }
- else if (ctx->Extensions.EXT_packed_depth_stencil &&
- ctx->Extensions.ARB_depth_texture &&
- baseFormat == GL_DEPTH_STENCIL_EXT) {
- /* OK */
- }
- else {
- att->Complete = GL_FALSE;
- att_incomplete("bad depth format");
- return;
- }
- }
- else {
- ASSERT(format == GL_STENCIL);
- if (ctx->Extensions.EXT_packed_depth_stencil &&
- ctx->Extensions.ARB_depth_texture &&
- baseFormat == GL_DEPTH_STENCIL_EXT) {
- /* OK */
- }
- else {
- /* no such thing as stencil-only textures */
- att_incomplete("illegal stencil texture");
- att->Complete = GL_FALSE;
- return;
- }
- }
- }
- else if (att->Type == GL_RENDERBUFFER_EXT) {
- const GLenum baseFormat =
- _mesa_get_format_base_format(att->Renderbuffer->Format);
-
- ASSERT(att->Renderbuffer);
- if (!att->Renderbuffer->InternalFormat ||
- att->Renderbuffer->Width < 1 ||
- att->Renderbuffer->Height < 1) {
- att_incomplete("0x0 renderbuffer");
- att->Complete = GL_FALSE;
- return;
- }
- if (format == GL_COLOR) {
- if (!_mesa_is_legal_color_format(ctx, baseFormat)) {
- att_incomplete("bad renderbuffer color format");
- att->Complete = GL_FALSE;
- return;
- }
- }
- else if (format == GL_DEPTH) {
- if (baseFormat == GL_DEPTH_COMPONENT) {
- /* OK */
- }
- else if (ctx->Extensions.EXT_packed_depth_stencil &&
- baseFormat == GL_DEPTH_STENCIL_EXT) {
- /* OK */
- }
- else {
- att_incomplete("bad renderbuffer depth format");
- att->Complete = GL_FALSE;
- return;
- }
- }
- else {
- assert(format == GL_STENCIL);
- if (baseFormat == GL_STENCIL_INDEX) {
- /* OK */
- }
- else if (ctx->Extensions.EXT_packed_depth_stencil &&
- baseFormat == GL_DEPTH_STENCIL_EXT) {
- /* OK */
- }
- else {
- att->Complete = GL_FALSE;
- att_incomplete("bad renderbuffer stencil format");
- return;
- }
- }
- }
- else {
- ASSERT(att->Type == GL_NONE);
- /* complete */
- return;
- }
-}
-
-
-/**
- * Test if the given framebuffer object is complete and update its
- * Status field with the results.
- * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
- * driver to make hardware-specific validation/completeness checks.
- * Also update the framebuffer's Width and Height fields if the
- * framebuffer is complete.
- */
-void
-_mesa_test_framebuffer_completeness(struct gl_context *ctx,
- struct gl_framebuffer *fb)
-{
- GLuint numImages;
- GLenum intFormat = GL_NONE; /* color buffers' internal format */
- GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
- GLint numSamples = -1;
- GLint i;
- GLuint j;
-
- assert(fb->Name != 0);
-
- numImages = 0;
- fb->Width = 0;
- fb->Height = 0;
-
- /* Start at -2 to more easily loop over all attachment points.
- * -2: depth buffer
- * -1: stencil buffer
- * >=0: color buffer
- */
- for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
- struct gl_renderbuffer_attachment *att;
- GLenum f;
- gl_format mesaFormat;
-
- /*
- * XXX for ARB_fbo, only check color buffers that are named by
- * GL_READ_BUFFER and GL_DRAW_BUFFERi.
- */
-
- /* check for attachment completeness
- */
- if (i == -2) {
- att = &fb->Attachment[BUFFER_DEPTH];
- test_attachment_completeness(ctx, GL_DEPTH, att);
- if (!att->Complete) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
- fbo_incomplete("depth attachment incomplete", -1);
- return;
- }
- }
- else if (i == -1) {
- att = &fb->Attachment[BUFFER_STENCIL];
- test_attachment_completeness(ctx, GL_STENCIL, att);
- if (!att->Complete) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
- fbo_incomplete("stencil attachment incomplete", -1);
- return;
- }
- }
- else {
- att = &fb->Attachment[BUFFER_COLOR0 + i];
- test_attachment_completeness(ctx, GL_COLOR, att);
- if (!att->Complete) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
- fbo_incomplete("color attachment incomplete", i);
- return;
- }
- }
-
- /* get width, height, format of the renderbuffer/texture
- */
- if (att->Type == GL_TEXTURE) {
- const struct gl_texture_image *texImg
- = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
- minWidth = MIN2(minWidth, texImg->Width);
- maxWidth = MAX2(maxWidth, texImg->Width);
- minHeight = MIN2(minHeight, texImg->Height);
- maxHeight = MAX2(maxHeight, texImg->Height);
- f = texImg->_BaseFormat;
- mesaFormat = texImg->TexFormat;
- numImages++;
- if (!_mesa_is_legal_color_format(ctx, f) &&
- !is_legal_depth_format(ctx, f)) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
- fbo_incomplete("texture attachment incomplete", -1);
- return;
- }
- }
- else if (att->Type == GL_RENDERBUFFER_EXT) {
- minWidth = MIN2(minWidth, att->Renderbuffer->Width);
- maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
- minHeight = MIN2(minHeight, att->Renderbuffer->Height);
- maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
- f = att->Renderbuffer->InternalFormat;
- mesaFormat = att->Renderbuffer->Format;
- numImages++;
- }
- else {
- assert(att->Type == GL_NONE);
- continue;
- }
-
- if (numSamples < 0) {
- /* first buffer */
- numSamples = att->Renderbuffer->NumSamples;
- }
-
- /* check if integer color */
- fb->_IntegerColor = _mesa_is_format_integer_color(mesaFormat);
-
- /* Error-check width, height, format, samples
- */
- if (numImages == 1) {
- /* save format, num samples */
- if (i >= 0) {
- intFormat = f;
- }
- }
- else {
- if (!ctx->Extensions.ARB_framebuffer_object) {
- /* check that width, height, format are same */
- if (minWidth != maxWidth || minHeight != maxHeight) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
- fbo_incomplete("width or height mismatch", -1);
- return;
- }
- /* check that all color buffer have same format */
- if (intFormat != GL_NONE && f != intFormat) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
- fbo_incomplete("format mismatch", -1);
- return;
- }
- }
- if (att->Renderbuffer &&
- att->Renderbuffer->NumSamples != numSamples) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
- fbo_incomplete("inconsistant number of samples", i);
- return;
- }
-
- }
- }
-
-#if FEATURE_GL
- if (ctx->API == API_OPENGL) {
- /* Check that all DrawBuffers are present */
- for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
- if (fb->ColorDrawBuffer[j] != GL_NONE) {
- const struct gl_renderbuffer_attachment *att
- = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
- assert(att);
- if (att->Type == GL_NONE) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
- fbo_incomplete("missing drawbuffer", j);
- return;
- }
- }
- }
-
- /* Check that the ReadBuffer is present */
- if (fb->ColorReadBuffer != GL_NONE) {
- const struct gl_renderbuffer_attachment *att
- = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
- assert(att);
- if (att->Type == GL_NONE) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
- fbo_incomplete("missing readbuffer", -1);
- return;
- }
- }
- }
-#else
- (void) j;
-#endif
-
- if (numImages == 0) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
- fbo_incomplete("no attachments", -1);
- return;
- }
-
- /* Provisionally set status = COMPLETE ... */
- fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
-
- /* ... but the driver may say the FB is incomplete.
- * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
- * if anything.
- */
- if (ctx->Driver.ValidateFramebuffer) {
- ctx->Driver.ValidateFramebuffer(ctx, fb);
- if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- fbo_incomplete("driver marked FBO as incomplete", -1);
- }
- }
-
- if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
- /*
- * Note that if ARB_framebuffer_object is supported and the attached
- * renderbuffers/textures are different sizes, the framebuffer
- * width/height will be set to the smallest width/height.
- */
- fb->Width = minWidth;
- fb->Height = minHeight;
-
- /* finally, update the visual info for the framebuffer */
- _mesa_update_framebuffer_visual(ctx, fb);
- }
-}
-
-
-GLboolean GLAPIENTRY
-_mesa_IsRenderbufferEXT(GLuint renderbuffer)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
- if (renderbuffer) {
- struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
- if (rb != NULL && rb != &DummyRenderbuffer)
- return GL_TRUE;
- }
- return GL_FALSE;
-}
-
-
-void GLAPIENTRY
-_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
-{
- struct gl_renderbuffer *newRb;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (target != GL_RENDERBUFFER_EXT) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
- return;
- }
-
- /* No need to flush here since the render buffer binding has no
- * effect on rendering state.
- */
-
- if (renderbuffer) {
- newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
- if (newRb == &DummyRenderbuffer) {
- /* ID was reserved, but no real renderbuffer object made yet */
- newRb = NULL;
- }
- else if (!newRb && ctx->Extensions.ARB_framebuffer_object) {
- /* All RB IDs must be Gen'd */
- _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
- return;
- }
-
- if (!newRb) {
- /* create new renderbuffer object */
- newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
- if (!newRb) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
- return;
- }
- ASSERT(newRb->AllocStorage);
- _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
- newRb->RefCount = 1; /* referenced by hash table */
- }
- }
- else {
- newRb = NULL;
- }
-
- ASSERT(newRb != &DummyRenderbuffer);
-
- _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
-}
-
-
-/**
- * If the given renderbuffer is anywhere attached to the framebuffer, detach
- * the renderbuffer.
- * This is used when a renderbuffer object is deleted.
- * The spec calls for unbinding.
- */
-static void
-detach_renderbuffer(struct gl_context *ctx,
- struct gl_framebuffer *fb,
- struct gl_renderbuffer *rb)
-{
- GLuint i;
- for (i = 0; i < BUFFER_COUNT; i++) {
- if (fb->Attachment[i].Renderbuffer == rb) {
- _mesa_remove_attachment(ctx, &fb->Attachment[i]);
- }
- }
- invalidate_framebuffer(fb);
-}
-
-
-void GLAPIENTRY
-_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
-{
- GLint i;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- for (i = 0; i < n; i++) {
- if (renderbuffers[i] > 0) {
- struct gl_renderbuffer *rb;
- rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
- if (rb) {
- /* check if deleting currently bound renderbuffer object */
- if (rb == ctx->CurrentRenderbuffer) {
- /* bind default */
- ASSERT(rb->RefCount >= 2);
- _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
- }
-
- if (ctx->DrawBuffer->Name) {
- detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
- }
- if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) {
- detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
- }
-
- /* Remove from hash table immediately, to free the ID.
- * But the object will not be freed until it's no longer
- * referenced anywhere else.
- */
- _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
-
- if (rb != &DummyRenderbuffer) {
- /* no longer referenced by hash table */
- _mesa_reference_renderbuffer(&rb, NULL);
- }
- }
- }
- }
-}
-
-
-void GLAPIENTRY
-_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLuint first;
- GLint i;
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (n < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
- return;
- }
-
- if (!renderbuffers)
- return;
-
- first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
-
- for (i = 0; i < n; i++) {
- GLuint name = first + i;
- renderbuffers[i] = name;
- /* insert dummy placeholder into hash table */
- _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
- _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
- _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
- }
-}
-
-
-/**
- * Given an internal format token for a render buffer, return the
- * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX,
- * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE,
- * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc).
- *
- * This is similar to _mesa_base_tex_format() but the set of valid
- * internal formats is different.
- *
- * Note that even if a format is determined to be legal here, validation
- * of the FBO may fail if the format is not supported by the driver/GPU.
- *
- * \param internalFormat as passed to glRenderbufferStorage()
- * \return the base internal format, or 0 if internalFormat is illegal
- */
-GLenum
-_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat)
-{
- /*
- * Notes: some formats such as alpha, luminance, etc. were added
- * with GL_ARB_framebuffer_object.
- */
- switch (internalFormat) {
- case GL_ALPHA:
- case GL_ALPHA4:
- case GL_ALPHA8:
- case GL_ALPHA12:
- case GL_ALPHA16:
- return ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0;
- case GL_LUMINANCE:
- case GL_LUMINANCE4:
- case GL_LUMINANCE8:
- case GL_LUMINANCE12:
- case GL_LUMINANCE16:
- return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0;
- case GL_LUMINANCE_ALPHA:
- case GL_LUMINANCE4_ALPHA4:
- case GL_LUMINANCE6_ALPHA2:
- case GL_LUMINANCE8_ALPHA8:
- case GL_LUMINANCE12_ALPHA4:
- case GL_LUMINANCE12_ALPHA12:
- case GL_LUMINANCE16_ALPHA16:
- return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0;
- case GL_INTENSITY:
- case GL_INTENSITY4:
- case GL_INTENSITY8:
- case GL_INTENSITY12:
- case GL_INTENSITY16:
- return ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0;
- case GL_RGB:
- case GL_R3_G3_B2:
- case GL_RGB4:
- case GL_RGB5:
- case GL_RGB8:
- case GL_RGB10:
- case GL_RGB12:
- case GL_RGB16:
- case GL_SRGB8_EXT:
- return GL_RGB;
- case GL_RGBA:
- case GL_RGBA2:
- case GL_RGBA4:
- case GL_RGB5_A1:
- case GL_RGBA8:
- case GL_RGB10_A2:
- case GL_RGBA12:
- case GL_RGBA16:
- case GL_RGBA16_SNORM:
- case GL_SRGB8_ALPHA8_EXT:
- return GL_RGBA;
- case GL_STENCIL_INDEX:
- case GL_STENCIL_INDEX1_EXT:
- case GL_STENCIL_INDEX4_EXT:
- case GL_STENCIL_INDEX8_EXT:
- case GL_STENCIL_INDEX16_EXT:
- return GL_STENCIL_INDEX;
- case GL_DEPTH_COMPONENT:
- case GL_DEPTH_COMPONENT16:
- case GL_DEPTH_COMPONENT24:
- case GL_DEPTH_COMPONENT32:
- return GL_DEPTH_COMPONENT;
- case GL_DEPTH_STENCIL_EXT:
- case GL_DEPTH24_STENCIL8_EXT:
- if (ctx->Extensions.EXT_packed_depth_stencil)
- return GL_DEPTH_STENCIL_EXT;
- else
- return 0;
- case GL_RED:
- case GL_R8:
- case GL_R16:
- return ctx->Extensions.ARB_texture_rg ? GL_RED : 0;
- case GL_RG:
- case GL_RG8:
- case GL_RG16:
- return ctx->Extensions.ARB_texture_rg ? GL_RG : 0;
- /* XXX add floating point and integer formats eventually */
- default:
- return 0;
- }
-}
-
-
-/** sentinal value, see below */
-#define NO_SAMPLES 1000
-
-
-/**
- * Helper function used by _mesa_RenderbufferStorageEXT() and
- * _mesa_RenderbufferStorageMultisample().
- * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT().
- */
-static void
-renderbuffer_storage(GLenum target, GLenum internalFormat,
- GLsizei width, GLsizei height, GLsizei samples)
-{
- const char *func = samples == NO_SAMPLES ?
- "glRenderbufferStorage" : "RenderbufferStorageMultisample";
- struct gl_renderbuffer *rb;
- GLenum baseFormat;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (target != GL_RENDERBUFFER_EXT) {
- _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
- return;
- }
-
- baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
- if (baseFormat == 0) {
- _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func);
- return;
- }
-
- if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
- _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
- return;
- }
-
- if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
- _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
- return;
- }
-
- if (samples == NO_SAMPLES) {
- /* NumSamples == 0 indicates non-multisampling */
- samples = 0;
- }
- else if (samples > (GLsizei) ctx->Const.MaxSamples) {
- /* note: driver may choose to use more samples than what's requested */
- _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
- return;
- }
-
- rb = ctx->CurrentRenderbuffer;
- if (!rb) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
- return;
- }
-
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- if (rb->InternalFormat == internalFormat &&
- rb->Width == (GLuint) width &&
- rb->Height == (GLuint) height) {
- /* no change in allocation needed */
- return;
- }
-
- /* These MUST get set by the AllocStorage func */
- rb->Format = MESA_FORMAT_NONE;
- rb->NumSamples = samples;
-
- /* Now allocate the storage */
- ASSERT(rb->AllocStorage);
- if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
- /* No error - check/set fields now */
- assert(rb->Format != MESA_FORMAT_NONE);
- assert(rb->Width == (GLuint) width);
- assert(rb->Height == (GLuint) height);
- rb->InternalFormat = internalFormat;
- rb->_BaseFormat = baseFormat;
- assert(rb->_BaseFormat != 0);
- }
- else {
- /* Probably ran out of memory - clear the fields */
- rb->Width = 0;
- rb->Height = 0;
- rb->Format = MESA_FORMAT_NONE;
- rb->InternalFormat = GL_NONE;
- rb->_BaseFormat = GL_NONE;
- rb->NumSamples = 0;
- }
-
- /*
- test_framebuffer_completeness(ctx, fb);
- */
- /* XXX if this renderbuffer is attached anywhere, invalidate attachment
- * points???
- */
-}
-
-
-#if FEATURE_OES_EGL_image
-void GLAPIENTRY
-_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
-{
- struct gl_renderbuffer *rb;
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (!ctx->Extensions.OES_EGL_image) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glEGLImageTargetRenderbufferStorageOES(unsupported)");
- return;
- }
-
- if (target != GL_RENDERBUFFER) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "EGLImageTargetRenderbufferStorageOES");
- return;
- }
-
- rb = ctx->CurrentRenderbuffer;
- if (!rb) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "EGLImageTargetRenderbufferStorageOES");
- return;
- }
-
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
-}
-#endif
-
-
-/**
- * Helper function for _mesa_GetRenderbufferParameterivEXT() and
- * _mesa_GetFramebufferAttachmentParameterivEXT()
- * We have to be careful to respect the base format. For example, if a
- * renderbuffer/texture was created with internalFormat=GL_RGB but the
- * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
- * we need to return zero.
- */
-static GLint
-get_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
-{
- switch (pname) {
- case GL_RENDERBUFFER_RED_SIZE_EXT:
- case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
- if (baseFormat == GL_RGB || baseFormat == GL_RGBA ||
- baseFormat == GL_RG || baseFormat == GL_RED)
- return _mesa_get_format_bits(format, pname);
- else
- return 0;
- case GL_RENDERBUFFER_GREEN_SIZE_EXT:
- case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
- if (baseFormat == GL_RGB || baseFormat == GL_RGBA || baseFormat == GL_RG)
- return _mesa_get_format_bits(format, pname);
- else
- return 0;
- case GL_RENDERBUFFER_BLUE_SIZE_EXT:
- case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
- if (baseFormat == GL_RGB || baseFormat == GL_RGBA)
- return _mesa_get_format_bits(format, pname);
- else
- return 0;
- case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
- case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
- if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA ||
- baseFormat == GL_LUMINANCE_ALPHA)
- return _mesa_get_format_bits(format, pname);
- else
- return 0;
- case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
- case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
- if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL)
- return _mesa_get_format_bits(format, pname);
- else
- return 0;
- case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
- case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
- if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL)
- return _mesa_get_format_bits(format, pname);
- else
- return 0;
- default:
- return 0;
- }
-}
-
-
-
-void GLAPIENTRY
-_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
- GLsizei width, GLsizei height)
-{
- /* GL_ARB_fbo says calling this function is equivalent to calling
- * glRenderbufferStorageMultisample() with samples=0. We pass in
- * a token value here just for error reporting purposes.
- */
- renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
-}
-
-
-void GLAPIENTRY
-_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
- GLenum internalFormat,
- GLsizei width, GLsizei height)
-{
- renderbuffer_storage(target, internalFormat, width, height, samples);
-}
-
-
-/**
- * OpenGL ES version of glRenderBufferStorage.
- */
-void GLAPIENTRY
-_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
- GLsizei width, GLsizei height)
-{
- switch (internalFormat) {
- case GL_RGB565:
- /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
- /* choose a closest format */
- internalFormat = GL_RGB5;
- break;
- default:
- break;
- }
-
- renderbuffer_storage(target, internalFormat, width, height, 0);
-}
-
-
-void GLAPIENTRY
-_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
-{
- struct gl_renderbuffer *rb;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (target != GL_RENDERBUFFER_EXT) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetRenderbufferParameterivEXT(target)");
- return;
- }
-
- rb = ctx->CurrentRenderbuffer;
- if (!rb) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetRenderbufferParameterivEXT");
- return;
- }
-
- /* No need to flush here since we're just quering state which is
- * not effected by rendering.
- */
-
- switch (pname) {
- case GL_RENDERBUFFER_WIDTH_EXT:
- *params = rb->Width;
- return;
- case GL_RENDERBUFFER_HEIGHT_EXT:
- *params = rb->Height;
- return;
- case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
- *params = rb->InternalFormat;
- return;
- case GL_RENDERBUFFER_RED_SIZE_EXT:
- case GL_RENDERBUFFER_GREEN_SIZE_EXT:
- case GL_RENDERBUFFER_BLUE_SIZE_EXT:
- case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
- case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
- case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
- *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
- break;
- case GL_RENDERBUFFER_SAMPLES:
- if (ctx->Extensions.ARB_framebuffer_object) {
- *params = rb->NumSamples;
- break;
- }
- /* fallthrough */
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetRenderbufferParameterivEXT(target)");
- return;
- }
-}
-
-
-GLboolean GLAPIENTRY
-_mesa_IsFramebufferEXT(GLuint framebuffer)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
- if (framebuffer) {
- struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
- if (rb != NULL && rb != &DummyFramebuffer)
- return GL_TRUE;
- }
- return GL_FALSE;
-}
-
-
-/**
- * Check if any of the attachments of the given framebuffer are textures
- * (render to texture). Call ctx->Driver.RenderTexture() for such
- * attachments.
- */
-static void
-check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
-{
- GLuint i;
- ASSERT(ctx->Driver.RenderTexture);
-
- if (fb->Name == 0)
- return; /* can't render to texture with winsys framebuffers */
-
- for (i = 0; i < BUFFER_COUNT; i++) {
- struct gl_renderbuffer_attachment *att = fb->Attachment + i;
- struct gl_texture_object *texObj = att->Texture;
- if (texObj
- && texObj->Image[att->CubeMapFace][att->TextureLevel]) {
- ctx->Driver.RenderTexture(ctx, fb, att);
- }
- }
-}
-
-
-/**
- * Examine all the framebuffer's attachments to see if any are textures.
- * If so, call ctx->Driver.FinishRenderTexture() for each texture to
- * notify the device driver that the texture image may have changed.
- */
-static void
-check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
-{
- if (fb->Name == 0)
- return; /* can't render to texture with winsys framebuffers */
-
- if (ctx->Driver.FinishRenderTexture) {
- GLuint i;
- for (i = 0; i < BUFFER_COUNT; i++) {
- struct gl_renderbuffer_attachment *att = fb->Attachment + i;
- if (att->Texture && att->Renderbuffer) {
- ctx->Driver.FinishRenderTexture(ctx, att);
- }
- }
- }
-}
-
-
-void GLAPIENTRY
-_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
-{
- struct gl_framebuffer *newDrawFb, *newReadFb;
- struct gl_framebuffer *oldDrawFb, *oldReadFb;
- GLboolean bindReadBuf, bindDrawBuf;
- GET_CURRENT_CONTEXT(ctx);
-
-#ifdef DEBUG
- if (ctx->Extensions.ARB_framebuffer_object) {
- ASSERT(ctx->Extensions.EXT_framebuffer_object);
- ASSERT(ctx->Extensions.EXT_framebuffer_blit);
- }
-#endif
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (!ctx->Extensions.EXT_framebuffer_object) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindFramebufferEXT(unsupported)");
- return;
- }
-
- switch (target) {
-#if FEATURE_EXT_framebuffer_blit
- case GL_DRAW_FRAMEBUFFER_EXT:
- if (!ctx->Extensions.EXT_framebuffer_blit) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
- return;
- }
- bindDrawBuf = GL_TRUE;
- bindReadBuf = GL_FALSE;
- break;
- case GL_READ_FRAMEBUFFER_EXT:
- if (!ctx->Extensions.EXT_framebuffer_blit) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
- return;
- }
- bindDrawBuf = GL_FALSE;
- bindReadBuf = GL_TRUE;
- break;
-#endif
- case GL_FRAMEBUFFER_EXT:
- bindDrawBuf = GL_TRUE;
- bindReadBuf = GL_TRUE;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
- return;
- }
-
- if (framebuffer) {
- /* Binding a user-created framebuffer object */
- newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
- if (newDrawFb == &DummyFramebuffer) {
- /* ID was reserved, but no real framebuffer object made yet */
- newDrawFb = NULL;
- }
- else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
- /* All FBO IDs must be Gen'd */
- _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
- return;
- }
-
- if (!newDrawFb) {
- /* create new framebuffer object */
- newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
- if (!newDrawFb) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
- return;
- }
- _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
- }
- newReadFb = newDrawFb;
- }
- else {
- /* Binding the window system framebuffer (which was originally set
- * with MakeCurrent).
- */
- newDrawFb = ctx->WinSysDrawBuffer;
- newReadFb = ctx->WinSysReadBuffer;
- }
-
- ASSERT(newDrawFb);
- ASSERT(newDrawFb != &DummyFramebuffer);
-
- /* save pointers to current/old framebuffers */
- oldDrawFb = ctx->DrawBuffer;
- oldReadFb = ctx->ReadBuffer;
-
- /* check if really changing bindings */
- if (oldDrawFb == newDrawFb)
- bindDrawBuf = GL_FALSE;
- if (oldReadFb == newReadFb)
- bindReadBuf = GL_FALSE;
-
- /*
- * OK, now bind the new Draw/Read framebuffers, if they're changing.
- *
- * We also check if we're beginning and/or ending render-to-texture.
- * When a framebuffer with texture attachments is unbound, call
- * ctx->Driver.FinishRenderTexture().
- * When a framebuffer with texture attachments is bound, call
- * ctx->Driver.RenderTexture().
- *
- * Note that if the ReadBuffer has texture attachments we don't consider
- * that a render-to-texture case.
- */
- if (bindReadBuf) {
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- /* check if old readbuffer was render-to-texture */
- check_end_texture_render(ctx, oldReadFb);
-
- _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
- }
-
- if (bindDrawBuf) {
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- /* check if old read/draw buffers were render-to-texture */
- if (!bindReadBuf)
- check_end_texture_render(ctx, oldReadFb);
-
- if (oldDrawFb != oldReadFb)
- check_end_texture_render(ctx, oldDrawFb);
-
- /* check if newly bound framebuffer has any texture attachments */
- check_begin_texture_render(ctx, newDrawFb);
-
- _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
- }
-
- if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
- ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
- }
-}
-
-
-void GLAPIENTRY
-_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
-{
- GLint i;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- for (i = 0; i < n; i++) {
- if (framebuffers[i] > 0) {
- struct gl_framebuffer *fb;
- fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
- if (fb) {
- ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
-
- /* check if deleting currently bound framebuffer object */
- if (ctx->Extensions.EXT_framebuffer_blit) {
- /* separate draw/read binding points */
- if (fb == ctx->DrawBuffer) {
- /* bind default */
- ASSERT(fb->RefCount >= 2);
- _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
- }
- if (fb == ctx->ReadBuffer) {
- /* bind default */
- ASSERT(fb->RefCount >= 2);
- _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
- }
- }
- else {
- /* only one binding point for read/draw buffers */
- if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
- /* bind default */
- ASSERT(fb->RefCount >= 2);
- _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- }
- }
-
- /* remove from hash table immediately, to free the ID */
- _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
-
- if (fb != &DummyFramebuffer) {
- /* But the object will not be freed until it's no longer
- * bound in any context.
- */
- _mesa_reference_framebuffer(&fb, NULL);
- }
- }
- }
- }
-}
-
-
-void GLAPIENTRY
-_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLuint first;
- GLint i;
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (n < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
- return;
- }
-
- if (!framebuffers)
- return;
-
- first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
-
- for (i = 0; i < n; i++) {
- GLuint name = first + i;
- framebuffers[i] = name;
- /* insert dummy placeholder into hash table */
- _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
- _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
- _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
- }
-}
-
-
-
-GLenum GLAPIENTRY
-_mesa_CheckFramebufferStatusEXT(GLenum target)
-{
- struct gl_framebuffer *buffer;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
-
- switch (target) {
-#if FEATURE_EXT_framebuffer_blit
- case GL_DRAW_FRAMEBUFFER_EXT:
- if (!ctx->Extensions.EXT_framebuffer_blit) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
- return 0;
- }
- buffer = ctx->DrawBuffer;
- break;
- case GL_READ_FRAMEBUFFER_EXT:
- if (!ctx->Extensions.EXT_framebuffer_blit) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
- return 0;
- }
- buffer = ctx->ReadBuffer;
- break;
-#endif
- case GL_FRAMEBUFFER_EXT:
- buffer = ctx->DrawBuffer;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
- return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
- }
-
- if (buffer->Name == 0) {
- /* The window system / default framebuffer is always complete */
- return GL_FRAMEBUFFER_COMPLETE_EXT;
- }
-
- /* No need to flush here */
-
- if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
- _mesa_test_framebuffer_completeness(ctx, buffer);
- }
-
- return buffer->_Status;
-}
-
-
-
-/**
- * Common code called by glFramebufferTexture1D/2D/3DEXT().
- */
-static void
-framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target,
- GLenum attachment, GLenum textarget, GLuint texture,
- GLint level, GLint zoffset)
-{
- struct gl_renderbuffer_attachment *att;
- struct gl_texture_object *texObj = NULL;
- struct gl_framebuffer *fb;
- GLboolean error = GL_FALSE;
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- switch (target) {
- case GL_READ_FRAMEBUFFER_EXT:
- error = !ctx->Extensions.EXT_framebuffer_blit;
- fb = ctx->ReadBuffer;
- break;
- case GL_DRAW_FRAMEBUFFER_EXT:
- error = !ctx->Extensions.EXT_framebuffer_blit;
- /* fall-through */
- case GL_FRAMEBUFFER_EXT:
- fb = ctx->DrawBuffer;
- break;
- default:
- error = GL_TRUE;
- }
-
- if (error) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
- return;
- }
-
- ASSERT(fb);
-
- /* check framebuffer binding */
- if (fb->Name == 0) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture%sEXT", caller);
- return;
- }
-
-
- /* The textarget, level, and zoffset parameters are only validated if
- * texture is non-zero.
- */
- if (texture) {
- GLboolean err = GL_TRUE;
-
- texObj = _mesa_lookup_texture(ctx, texture);
- if (texObj != NULL) {
- if (textarget == 0) {
- /* XXX what's the purpose of this? */
- err = (texObj->Target != GL_TEXTURE_3D) &&
- (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
- (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
- }
- else {
- err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
- ? !IS_CUBE_FACE(textarget)
- : (texObj->Target != textarget);
- }
- }
- else {
- /* can't render to a non-existant texture */
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture%sEXT(non existant texture)",
- caller);
- return;
- }
-
- if (err) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture%sEXT(texture target mismatch)",
- caller);
- return;
- }
-
- if (texObj->Target == GL_TEXTURE_3D) {
- const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
- if (zoffset < 0 || zoffset >= maxSize) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture%sEXT(zoffset)", caller);
- return;
- }
- }
- else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
- (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
- if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture%sEXT(layer)", caller);
- return;
- }
- }
-
- if ((level < 0) ||
- (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture%sEXT(level)", caller);
- return;
- }
- }
-
- att = _mesa_get_attachment(ctx, fb, attachment);
- if (att == NULL) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture%sEXT(attachment)", caller);
- return;
- }
-
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- _glthread_LOCK_MUTEX(fb->Mutex);
- if (texObj) {
- _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
- level, zoffset);
- /* Set the render-to-texture flag. We'll check this flag in
- * glTexImage() and friends to determine if we need to revalidate
- * any FBOs that might be rendering into this texture.
- * This flag never gets cleared since it's non-trivial to determine
- * when all FBOs might be done rendering to this texture. That's OK
- * though since it's uncommon to render to a texture then repeatedly
- * call glTexImage() to change images in the texture.
- */
- texObj->_RenderToTexture = GL_TRUE;
- }
- else {
- _mesa_remove_attachment(ctx, att);
- }
-
- invalidate_framebuffer(fb);
-
- _glthread_UNLOCK_MUTEX(fb->Mutex);
-}
-
-
-
-void GLAPIENTRY
-_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
- GLenum textarget, GLuint texture, GLint level)
-{
- GET_CURRENT_CONTEXT(ctx);
-
- if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture1DEXT(textarget)");
- return;
- }
-
- framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
- level, 0);
-}
-
-
-void GLAPIENTRY
-_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
- GLenum textarget, GLuint texture, GLint level)
-{
- GET_CURRENT_CONTEXT(ctx);
-
- if ((texture != 0) &&
- (textarget != GL_TEXTURE_2D) &&
- (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
- (!IS_CUBE_FACE(textarget))) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture2DEXT(textarget=0x%x)", textarget);
- return;
- }
-
- framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
- level, 0);
-}
-
-
-void GLAPIENTRY
-_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
- GLenum textarget, GLuint texture,
- GLint level, GLint zoffset)
-{
- GET_CURRENT_CONTEXT(ctx);
-
- if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture3DEXT(textarget)");
- return;
- }
-
- framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
- level, zoffset);
-}
-
-
-void GLAPIENTRY
-_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
- GLuint texture, GLint level, GLint layer)
-{
- GET_CURRENT_CONTEXT(ctx);
-
- framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
- level, layer);
-}
-
-
-void GLAPIENTRY
-_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
- GLenum renderbufferTarget,
- GLuint renderbuffer)
-{
- struct gl_renderbuffer_attachment *att;
- struct gl_framebuffer *fb;
- struct gl_renderbuffer *rb;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- switch (target) {
-#if FEATURE_EXT_framebuffer_blit
- case GL_DRAW_FRAMEBUFFER_EXT:
- if (!ctx->Extensions.EXT_framebuffer_blit) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferRenderbufferEXT(target)");
- return;
- }
- fb = ctx->DrawBuffer;
- break;
- case GL_READ_FRAMEBUFFER_EXT:
- if (!ctx->Extensions.EXT_framebuffer_blit) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferRenderbufferEXT(target)");
- return;
- }
- fb = ctx->ReadBuffer;
- break;
-#endif
- case GL_FRAMEBUFFER_EXT:
- fb = ctx->DrawBuffer;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferRenderbufferEXT(target)");
- return;
- }
-
- if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferRenderbufferEXT(renderbufferTarget)");
- return;
- }
-
- if (fb->Name == 0) {
- /* Can't attach new renderbuffers to a window system framebuffer */
- _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
- return;
- }
-
- att = _mesa_get_attachment(ctx, fb, attachment);
- if (att == NULL) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferRenderbufferEXT(invalid attachment %s)",
- _mesa_lookup_enum_by_nr(attachment));
- return;
- }
-
- if (renderbuffer) {
- rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
- if (!rb) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferRenderbufferEXT(non-existant"
- " renderbuffer %u)", renderbuffer);
- return;
- }
- else if (rb == &DummyRenderbuffer) {
- /* This is what NVIDIA does */
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferRenderbufferEXT(renderbuffer %u)",
- renderbuffer);
- return;
- }
- }
- else {
- /* remove renderbuffer attachment */
- rb = NULL;
- }
-
- if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
- rb && rb->Format != MESA_FORMAT_NONE) {
- /* make sure the renderbuffer is a depth/stencil format */
- const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
- if (baseFormat != GL_DEPTH_STENCIL) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferRenderbufferEXT(renderbuffer"
- " is not DEPTH_STENCIL format)");
- return;
- }
- }
-
-
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- assert(ctx->Driver.FramebufferRenderbuffer);
- ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
-
- /* Some subsequent GL commands may depend on the framebuffer's visual
- * after the binding is updated. Update visual info now.
- */
- _mesa_update_framebuffer_visual(ctx, fb);
-}
-
-
-void GLAPIENTRY
-_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
- GLenum pname, GLint *params)
-{
- const struct gl_renderbuffer_attachment *att;
- struct gl_framebuffer *buffer;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- switch (target) {
-#if FEATURE_EXT_framebuffer_blit
- case GL_DRAW_FRAMEBUFFER_EXT:
- if (!ctx->Extensions.EXT_framebuffer_blit) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameterivEXT(target)");
- return;
- }
- buffer = ctx->DrawBuffer;
- break;
- case GL_READ_FRAMEBUFFER_EXT:
- if (!ctx->Extensions.EXT_framebuffer_blit) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameterivEXT(target)");
- return;
- }
- buffer = ctx->ReadBuffer;
- break;
-#endif
- case GL_FRAMEBUFFER_EXT:
- buffer = ctx->DrawBuffer;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameterivEXT(target)");
- return;
- }
-
- if (buffer->Name == 0) {
- /* the default / window-system FBO */
- att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
- }
- else {
- /* user-created framebuffer FBO */
- att = _mesa_get_attachment(ctx, buffer, attachment);
- }
-
- if (att == NULL) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameterivEXT(attachment)");
- return;
- }
-
- if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
- /* the depth and stencil attachments must point to the same buffer */
- const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
- depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
- stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
- if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
- " attachments differ)");
- return;
- }
- }
-
- /* No need to flush here */
-
- switch (pname) {
- case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
- *params = buffer->Name == 0 ? GL_FRAMEBUFFER_DEFAULT : att->Type;
- return;
- case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
- if (att->Type == GL_RENDERBUFFER_EXT) {
- *params = att->Renderbuffer->Name;
- }
- else if (att->Type == GL_TEXTURE) {
- *params = att->Texture->Name;
- }
- else {
- assert(att->Type == GL_NONE);
- *params = 0;
- }
- return;
- case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
- if (att->Type == GL_TEXTURE) {
- *params = att->TextureLevel;
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameterivEXT(pname)");
- }
- return;
- case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
- if (att->Type == GL_TEXTURE) {
- if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
- *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
- }
- else {
- *params = 0;
- }
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameterivEXT(pname)");
- }
- return;
- case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
- if (att->Type == GL_TEXTURE) {
- if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
- *params = att->Zoffset;
- }
- else {
- *params = 0;
- }
- }
- else {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameterivEXT(pname)");
- }
- return;
- case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
- if (!ctx->Extensions.ARB_framebuffer_object) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameterivEXT(pname)");
- }
- else {
- if (ctx->Extensions.EXT_framebuffer_sRGB && ctx->Const.sRGBCapable) {
- *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
- }
- else {
- /* According to ARB_framebuffer_sRGB, we should return LINEAR
- * if the sRGB conversion is unsupported. */
- *params = GL_LINEAR;
- }
- }
- return;
- case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
- if (!ctx->Extensions.ARB_framebuffer_object) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameterivEXT(pname)");
- return;
- }
- else {
- gl_format format = att->Renderbuffer->Format;
- if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) {
- /* special cases */
- *params = GL_INDEX;
- }
- else {
- *params = _mesa_get_format_datatype(format);
- }
- }
- return;
- case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
- case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
- case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
- case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
- case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
- case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
- if (!ctx->Extensions.ARB_framebuffer_object) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameterivEXT(pname)");
- }
- else if (att->Texture) {
- const struct gl_texture_image *texImage =
- _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
- att->TextureLevel);
- if (texImage) {
- *params = get_component_bits(pname, texImage->_BaseFormat,
- texImage->TexFormat);
- }
- else {
- *params = 0;
- }
- }
- else if (att->Renderbuffer) {
- *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
- att->Renderbuffer->Format);
- }
- else {
- *params = 0;
- }
- return;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetFramebufferAttachmentParameterivEXT(pname)");
- return;
- }
-}
-
-
-void GLAPIENTRY
-_mesa_GenerateMipmapEXT(GLenum target)
-{
- struct gl_texture_object *texObj;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- switch (target) {
- case GL_TEXTURE_1D:
- case GL_TEXTURE_2D:
- case GL_TEXTURE_3D:
- case GL_TEXTURE_CUBE_MAP:
- /* OK, legal value */
- break;
- default:
- /* XXX need to implement GL_TEXTURE_1D_ARRAY and GL_TEXTURE_2D_ARRAY */
- _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
- return;
- }
-
- texObj = _mesa_get_current_tex_object(ctx, target);
-
- if (texObj->BaseLevel >= texObj->MaxLevel) {
- /* nothing to do */
- return;
- }
-
- if (texObj->Target == GL_TEXTURE_CUBE_MAP &&
- !_mesa_cube_complete(texObj)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGenerateMipmap(incomplete cube map)");
- return;
- }
-
- _mesa_lock_texture(ctx, texObj);
- if (target == GL_TEXTURE_CUBE_MAP) {
- GLuint face;
- for (face = 0; face < 6; face++)
- ctx->Driver.GenerateMipmap(ctx,
- GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
- texObj);
- }
- else {
- ctx->Driver.GenerateMipmap(ctx, target, texObj);
- }
- _mesa_unlock_texture(ctx, texObj);
-}
-
-
-#if FEATURE_EXT_framebuffer_blit
-
-static const struct gl_renderbuffer_attachment *
-find_attachment(const struct gl_framebuffer *fb,
- const struct gl_renderbuffer *rb)
-{
- GLuint i;
- for (i = 0; i < Elements(fb->Attachment); i++) {
- if (fb->Attachment[i].Renderbuffer == rb)
- return &fb->Attachment[i];
- }
- return NULL;
-}
-
-
-
-/**
- * Blit rectangular region, optionally from one framebuffer to another.
- *
- * Note, if the src buffer is multisampled and the dest is not, this is
- * when the samples must be resolved to a single color.
- */
-void GLAPIENTRY
-_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
- GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
- GLbitfield mask, GLenum filter)
-{
- const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
- GL_DEPTH_BUFFER_BIT |
- GL_STENCIL_BUFFER_BIT);
- const struct gl_framebuffer *readFb, *drawFb;
- const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
- GET_CURRENT_CONTEXT(ctx);
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
- FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
- if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx,
- "glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n",
- srcX0, srcY0, srcX1, srcY1,
- dstX0, dstY0, dstX1, dstY1,
- mask, _mesa_lookup_enum_by_nr(filter));
-
- if (ctx->NewState) {
- _mesa_update_state(ctx);
- }
-
- readFb = ctx->ReadBuffer;
- drawFb = ctx->DrawBuffer;
-
- if (!readFb || !drawFb) {
- /* This will normally never happen but someday we may want to
- * support MakeCurrent() with no drawables.
- */
- return;
- }
-
- /* check for complete framebuffers */
- if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
- readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
- "glBlitFramebufferEXT(incomplete draw/read buffers)");
- return;
- }
-
- if (filter != GL_NEAREST && filter != GL_LINEAR) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
- return;
- }
-
- if (mask & ~legalMaskBits) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
- return;
- }
-
- /* depth/stencil must be blitted with nearest filtering */
- if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
- && filter != GL_NEAREST) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
- return;
- }
-
- /* get color read/draw renderbuffers */
- if (mask & GL_COLOR_BUFFER_BIT) {
- colorReadRb = readFb->_ColorReadBuffer;
- colorDrawRb = drawFb->_ColorDrawBuffers[0];
- }
- else {
- colorReadRb = colorDrawRb = NULL;
- }
-
- if (mask & GL_STENCIL_BUFFER_BIT) {
- struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
- struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
- if (!readRb ||
- !drawRb ||
- _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
- _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebufferEXT(stencil buffer size mismatch");
- return;
- }
- }
-
- if (mask & GL_DEPTH_BUFFER_BIT) {
- struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
- struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
- if (!readRb ||
- !drawRb ||
- _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
- _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebufferEXT(depth buffer size mismatch");
- return;
- }
- }
-
- if (readFb->Visual.samples > 0 &&
- drawFb->Visual.samples > 0 &&
- readFb->Visual.samples != drawFb->Visual.samples) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebufferEXT(mismatched samples");
- return;
- }
-
- /* extra checks for multisample copies... */
- if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
- /* src and dest region sizes must be the same */
- if (srcX1 - srcX0 != dstX1 - dstX0 ||
- srcY1 - srcY0 != dstY1 - dstY0) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebufferEXT(bad src/dst multisample region sizes");
- return;
- }
-
- /* color formats must match */
- if (colorReadRb &&
- colorDrawRb &&
- colorReadRb->Format != colorDrawRb->Format) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBlitFramebufferEXT(bad src/dst multisample pixel formats");
- return;
- }
- }
-
- if (!ctx->Extensions.EXT_framebuffer_blit) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
- return;
- }
-
- /* Debug code */
- if (DEBUG_BLIT) {
- printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d,"
- " 0x%x, 0x%x)\n",
- srcX0, srcY0, srcX1, srcY1,
- dstX0, dstY0, dstX1, dstY1,
- mask, filter);
- if (colorReadRb) {
- const struct gl_renderbuffer_attachment *att;
-
- att = find_attachment(readFb, colorReadRb);
- printf(" Src FBO %u RB %u (%dx%d) ",
- readFb->Name, colorReadRb->Name,
- colorReadRb->Width, colorReadRb->Height);
- if (att && att->Texture) {
- printf("Tex %u tgt 0x%x level %u face %u",
- att->Texture->Name,
- att->Texture->Target,
- att->TextureLevel,
- att->CubeMapFace);
- }
- printf("\n");
-
- att = find_attachment(drawFb, colorDrawRb);
- printf(" Dst FBO %u RB %u (%dx%d) ",
- drawFb->Name, colorDrawRb->Name,
- colorDrawRb->Width, colorDrawRb->Height);
- if (att && att->Texture) {
- printf("Tex %u tgt 0x%x level %u face %u",
- att->Texture->Name,
- att->Texture->Target,
- att->TextureLevel,
- att->CubeMapFace);
- }
- printf("\n");
- }
- }
-
- ASSERT(ctx->Driver.BlitFramebuffer);
- ctx->Driver.BlitFramebuffer(ctx,
- srcX0, srcY0, srcX1, srcY1,
- dstX0, dstY0, dstX1, dstY1,
- mask, filter);
-}
-#endif /* FEATURE_EXT_framebuffer_blit */
-
-#if FEATURE_ARB_geometry_shader4
-void GLAPIENTRY
-_mesa_FramebufferTextureARB(GLenum target, GLenum attachment,
- GLuint texture, GLint level)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTextureARB "
- "not implemented!");
-}
-
-void GLAPIENTRY
-_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment,
- GLuint texture, GLint level, GLenum face)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTextureFaceARB "
- "not implemented!");
-}
-#endif /* FEATURE_ARB_geometry_shader4 */
+/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2009 VMware, Inc. 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. + */ + + +/* + * GL_EXT/ARB_framebuffer_object extensions + * + * Authors: + * Brian Paul + */ + + +#include "buffers.h" +#include "context.h" +#include "enums.h" +#include "fbobject.h" +#include "formats.h" +#include "framebuffer.h" +#include "hash.h" +#include "macros.h" +#include "mfeatures.h" +#include "mtypes.h" +#include "renderbuffer.h" +#include "state.h" +#include "teximage.h" +#include "texobj.h" + + +/** Set this to 1 to help debug FBO incompleteness problems */ +#define DEBUG_FBO 0 + +/** Set this to 1 to debug/log glBlitFramebuffer() calls */ +#define DEBUG_BLIT 0 + + +/** + * Notes: + * + * None of the GL_EXT_framebuffer_object functions are compiled into + * display lists. + */ + + + +/* + * When glGenRender/FramebuffersEXT() is called we insert pointers to + * these placeholder objects into the hash table. + * Later, when the object ID is first bound, we replace the placeholder + * with the real frame/renderbuffer. + */ +static struct gl_framebuffer DummyFramebuffer; +static struct gl_renderbuffer DummyRenderbuffer; + +/* We bind this framebuffer when applications pass a NULL + * drawable/surface in make current. */ +static struct gl_framebuffer IncompleteFramebuffer; + + +#define IS_CUBE_FACE(TARGET) \ + ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \ + (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) + + +static void +delete_dummy_renderbuffer(struct gl_renderbuffer *rb) +{ + /* no op */ +} + +static void +delete_dummy_framebuffer(struct gl_framebuffer *fb) +{ + /* no op */ +} + + +void +_mesa_init_fbobjects(struct gl_context *ctx) +{ + _glthread_INIT_MUTEX(DummyFramebuffer.Mutex); + _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex); + _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex); + DummyFramebuffer.Delete = delete_dummy_framebuffer; + DummyRenderbuffer.Delete = delete_dummy_renderbuffer; + IncompleteFramebuffer.Delete = delete_dummy_framebuffer; +} + +struct gl_framebuffer * +_mesa_get_incomplete_framebuffer(void) +{ + return &IncompleteFramebuffer; +} + +/** + * Helper routine for getting a gl_renderbuffer. + */ +struct gl_renderbuffer * +_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id) +{ + struct gl_renderbuffer *rb; + + if (id == 0) + return NULL; + + rb = (struct gl_renderbuffer *) + _mesa_HashLookup(ctx->Shared->RenderBuffers, id); + return rb; +} + + +/** + * Helper routine for getting a gl_framebuffer. + */ +struct gl_framebuffer * +_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id) +{ + struct gl_framebuffer *fb; + + if (id == 0) + return NULL; + + fb = (struct gl_framebuffer *) + _mesa_HashLookup(ctx->Shared->FrameBuffers, id); + return fb; +} + + +/** + * Mark the given framebuffer as invalid. This will force the + * test for framebuffer completeness to be done before the framebuffer + * is used. + */ +static void +invalidate_framebuffer(struct gl_framebuffer *fb) +{ + fb->_Status = 0; /* "indeterminate" */ +} + + +/** + * Return the gl_framebuffer object which corresponds to the given + * framebuffer target, such as GL_DRAW_FRAMEBUFFER. + * Check support for GL_EXT_framebuffer_blit to determine if certain + * targets are legal. + * \return gl_framebuffer pointer or NULL if target is illegal + */ +static struct gl_framebuffer * +get_framebuffer_target(struct gl_context *ctx, GLenum target) +{ + switch (target) { + case GL_DRAW_FRAMEBUFFER: + return ctx->Extensions.EXT_framebuffer_blit ? ctx->DrawBuffer : NULL; + case GL_READ_FRAMEBUFFER: + return ctx->Extensions.EXT_framebuffer_blit ? ctx->ReadBuffer : NULL; + case GL_FRAMEBUFFER_EXT: + return ctx->DrawBuffer; + default: + return NULL; + } +} + + +/** + * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding + * gl_renderbuffer_attachment object. + * This function is only used for user-created FB objects, not the + * default / window-system FB object. + * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to + * the depth buffer attachment point. + */ +struct gl_renderbuffer_attachment * +_mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum attachment) +{ + GLuint i; + + assert(fb->Name > 0); + + switch (attachment) { + case GL_COLOR_ATTACHMENT0_EXT: + case GL_COLOR_ATTACHMENT1_EXT: + case GL_COLOR_ATTACHMENT2_EXT: + case GL_COLOR_ATTACHMENT3_EXT: + case GL_COLOR_ATTACHMENT4_EXT: + case GL_COLOR_ATTACHMENT5_EXT: + case GL_COLOR_ATTACHMENT6_EXT: + case GL_COLOR_ATTACHMENT7_EXT: + case GL_COLOR_ATTACHMENT8_EXT: + case GL_COLOR_ATTACHMENT9_EXT: + case GL_COLOR_ATTACHMENT10_EXT: + case GL_COLOR_ATTACHMENT11_EXT: + case GL_COLOR_ATTACHMENT12_EXT: + case GL_COLOR_ATTACHMENT13_EXT: + case GL_COLOR_ATTACHMENT14_EXT: + case GL_COLOR_ATTACHMENT15_EXT: + i = attachment - GL_COLOR_ATTACHMENT0_EXT; + if (i >= ctx->Const.MaxColorAttachments) { + return NULL; + } + return &fb->Attachment[BUFFER_COLOR0 + i]; + case GL_DEPTH_STENCIL_ATTACHMENT: + /* fall-through */ + case GL_DEPTH_BUFFER: + /* fall-through / new in GL 3.0 */ + case GL_DEPTH_ATTACHMENT_EXT: + return &fb->Attachment[BUFFER_DEPTH]; + case GL_STENCIL_BUFFER: + /* fall-through / new in GL 3.0 */ + case GL_STENCIL_ATTACHMENT_EXT: + return &fb->Attachment[BUFFER_STENCIL]; + default: + return NULL; + } +} + + +/** + * As above, but only used for getting attachments of the default / + * window-system framebuffer (not user-created framebuffer objects). + */ +static struct gl_renderbuffer_attachment * +_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum attachment) +{ + assert(fb->Name == 0); + + switch (attachment) { + case GL_FRONT_LEFT: + return &fb->Attachment[BUFFER_FRONT_LEFT]; + case GL_FRONT_RIGHT: + return &fb->Attachment[BUFFER_FRONT_RIGHT]; + case GL_BACK_LEFT: + return &fb->Attachment[BUFFER_BACK_LEFT]; + case GL_BACK_RIGHT: + return &fb->Attachment[BUFFER_BACK_RIGHT]; + case GL_AUX0: + if (fb->Visual.numAuxBuffers == 1) { + return &fb->Attachment[BUFFER_AUX0]; + } + return NULL; + case GL_DEPTH_BUFFER: + /* fall-through / new in GL 3.0 */ + case GL_DEPTH_ATTACHMENT_EXT: + return &fb->Attachment[BUFFER_DEPTH]; + case GL_STENCIL_BUFFER: + /* fall-through / new in GL 3.0 */ + case GL_STENCIL_ATTACHMENT_EXT: + return &fb->Attachment[BUFFER_STENCIL]; + default: + return NULL; + } +} + + + +/** + * Remove any texture or renderbuffer attached to the given attachment + * point. Update reference counts, etc. + */ +void +_mesa_remove_attachment(struct gl_context *ctx, + struct gl_renderbuffer_attachment *att) +{ + if (att->Type == GL_TEXTURE) { + ASSERT(att->Texture); + if (ctx->Driver.FinishRenderTexture) { + /* tell driver that we're done rendering to this texture. */ + ctx->Driver.FinishRenderTexture(ctx, att); + } + _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ + ASSERT(!att->Texture); + } + if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { + ASSERT(!att->Texture); + _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */ + ASSERT(!att->Renderbuffer); + } + att->Type = GL_NONE; + att->Complete = GL_TRUE; +} + + +/** + * Bind a texture object to an attachment point. + * The previous binding, if any, will be removed first. + */ +void +_mesa_set_texture_attachment(struct gl_context *ctx, + struct gl_framebuffer *fb, + struct gl_renderbuffer_attachment *att, + struct gl_texture_object *texObj, + GLenum texTarget, GLuint level, GLuint zoffset) +{ + if (att->Texture == texObj) { + /* re-attaching same texture */ + ASSERT(att->Type == GL_TEXTURE); + if (ctx->Driver.FinishRenderTexture) + ctx->Driver.FinishRenderTexture(ctx, att); + } + else { + /* new attachment */ + if (ctx->Driver.FinishRenderTexture && att->Texture) + ctx->Driver.FinishRenderTexture(ctx, att); + _mesa_remove_attachment(ctx, att); + att->Type = GL_TEXTURE; + assert(!att->Texture); + _mesa_reference_texobj(&att->Texture, texObj); + } + + /* always update these fields */ + att->TextureLevel = level; + att->CubeMapFace = _mesa_tex_target_to_face(texTarget); + att->Zoffset = zoffset; + att->Complete = GL_FALSE; + + if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { + ctx->Driver.RenderTexture(ctx, fb, att); + } + + invalidate_framebuffer(fb); +} + + +/** + * Bind a renderbuffer to an attachment point. + * The previous binding, if any, will be removed first. + */ +void +_mesa_set_renderbuffer_attachment(struct gl_context *ctx, + struct gl_renderbuffer_attachment *att, + struct gl_renderbuffer *rb) +{ + /* XXX check if re-doing same attachment, exit early */ + _mesa_remove_attachment(ctx, att); + att->Type = GL_RENDERBUFFER_EXT; + att->Texture = NULL; /* just to be safe */ + att->Complete = GL_FALSE; + _mesa_reference_renderbuffer(&att->Renderbuffer, rb); +} + + +/** + * Fallback for ctx->Driver.FramebufferRenderbuffer() + * Attach a renderbuffer object to a framebuffer object. + */ +void +_mesa_framebuffer_renderbuffer(struct gl_context *ctx, + struct gl_framebuffer *fb, + GLenum attachment, struct gl_renderbuffer *rb) +{ + struct gl_renderbuffer_attachment *att; + + _glthread_LOCK_MUTEX(fb->Mutex); + + att = _mesa_get_attachment(ctx, fb, attachment); + ASSERT(att); + if (rb) { + _mesa_set_renderbuffer_attachment(ctx, att, rb); + if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { + /* do stencil attachment here (depth already done above) */ + att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT); + assert(att); + _mesa_set_renderbuffer_attachment(ctx, att, rb); + } + } + else { + _mesa_remove_attachment(ctx, att); + } + + invalidate_framebuffer(fb); + + _glthread_UNLOCK_MUTEX(fb->Mutex); +} + + +/** + * Fallback for ctx->Driver.ValidateFramebuffer() + * Check if the renderbuffer's formats are supported by the software + * renderer. + * Drivers should probably override this. + */ +void +_mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) +{ + gl_buffer_index buf; + for (buf = 0; buf < BUFFER_COUNT; buf++) { + const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer; + if (rb) { + switch (rb->_BaseFormat) { + case GL_ALPHA: + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE: + case GL_INTENSITY: + case GL_RED: + case GL_RG: + fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; + return; + default: + /* render buffer format is supported by software rendering */ + ; + } + } + } +} + + +/** + * For debug only. + */ +static void +att_incomplete(const char *msg) +{ +#if DEBUG_FBO + _mesa_debug(NULL, "attachment incomplete: %s\n", msg); +#else + (void) msg; +#endif +} + + +/** + * For debug only. + */ +static void +fbo_incomplete(const char *msg, int index) +{ +#if DEBUG_FBO + _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); +#else + (void) msg; + (void) index; +#endif +} + + +/** + * Is the given base format a legal format for a color renderbuffer? + */ +GLboolean +_mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat) +{ + switch (baseFormat) { + case GL_RGB: + case GL_RGBA: + return GL_TRUE; + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + case GL_ALPHA: + return ctx->Extensions.ARB_framebuffer_object; + case GL_RED: + case GL_RG: + return ctx->Extensions.ARB_texture_rg; + default: + return GL_FALSE; + } +} + + +/** + * Is the given base format a legal format for a depth/stencil renderbuffer? + */ +static GLboolean +is_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat) +{ + switch (baseFormat) { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_EXT: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Test if an attachment point is complete and update its Complete field. + * \param format if GL_COLOR, this is a color attachment point, + * if GL_DEPTH, this is a depth component attachment point, + * if GL_STENCIL, this is a stencil component attachment point. + */ +static void +test_attachment_completeness(const struct gl_context *ctx, GLenum format, + struct gl_renderbuffer_attachment *att) +{ + assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); + + /* assume complete */ + att->Complete = GL_TRUE; + + /* Look for reasons why the attachment might be incomplete */ + if (att->Type == GL_TEXTURE) { + const struct gl_texture_object *texObj = att->Texture; + struct gl_texture_image *texImage; + GLenum baseFormat; + + if (!texObj) { + att_incomplete("no texobj"); + att->Complete = GL_FALSE; + return; + } + + texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; + if (!texImage) { + att_incomplete("no teximage"); + att->Complete = GL_FALSE; + return; + } + if (texImage->Width < 1 || texImage->Height < 1) { + att_incomplete("teximage width/height=0"); + printf("texobj = %u\n", texObj->Name); + printf("level = %d\n", att->TextureLevel); + att->Complete = GL_FALSE; + return; + } + if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) { + att_incomplete("bad z offset"); + att->Complete = GL_FALSE; + return; + } + + baseFormat = _mesa_get_format_base_format(texImage->TexFormat); + + if (format == GL_COLOR) { + if (!_mesa_is_legal_color_format(ctx, baseFormat)) { + att_incomplete("bad format"); + att->Complete = GL_FALSE; + return; + } + if (_mesa_is_format_compressed(texImage->TexFormat)) { + att_incomplete("compressed internalformat"); + att->Complete = GL_FALSE; + return; + } + } + else if (format == GL_DEPTH) { + if (baseFormat == GL_DEPTH_COMPONENT) { + /* OK */ + } + else if (ctx->Extensions.EXT_packed_depth_stencil && + ctx->Extensions.ARB_depth_texture && + baseFormat == GL_DEPTH_STENCIL_EXT) { + /* OK */ + } + else { + att->Complete = GL_FALSE; + att_incomplete("bad depth format"); + return; + } + } + else { + ASSERT(format == GL_STENCIL); + if (ctx->Extensions.EXT_packed_depth_stencil && + ctx->Extensions.ARB_depth_texture && + baseFormat == GL_DEPTH_STENCIL_EXT) { + /* OK */ + } + else { + /* no such thing as stencil-only textures */ + att_incomplete("illegal stencil texture"); + att->Complete = GL_FALSE; + return; + } + } + } + else if (att->Type == GL_RENDERBUFFER_EXT) { + const GLenum baseFormat = + _mesa_get_format_base_format(att->Renderbuffer->Format); + + ASSERT(att->Renderbuffer); + if (!att->Renderbuffer->InternalFormat || + att->Renderbuffer->Width < 1 || + att->Renderbuffer->Height < 1) { + att_incomplete("0x0 renderbuffer"); + att->Complete = GL_FALSE; + return; + } + if (format == GL_COLOR) { + if (!_mesa_is_legal_color_format(ctx, baseFormat)) { + att_incomplete("bad renderbuffer color format"); + att->Complete = GL_FALSE; + return; + } + } + else if (format == GL_DEPTH) { + if (baseFormat == GL_DEPTH_COMPONENT) { + /* OK */ + } + else if (ctx->Extensions.EXT_packed_depth_stencil && + baseFormat == GL_DEPTH_STENCIL_EXT) { + /* OK */ + } + else { + att_incomplete("bad renderbuffer depth format"); + att->Complete = GL_FALSE; + return; + } + } + else { + assert(format == GL_STENCIL); + if (baseFormat == GL_STENCIL_INDEX) { + /* OK */ + } + else if (ctx->Extensions.EXT_packed_depth_stencil && + baseFormat == GL_DEPTH_STENCIL_EXT) { + /* OK */ + } + else { + att->Complete = GL_FALSE; + att_incomplete("bad renderbuffer stencil format"); + return; + } + } + } + else { + ASSERT(att->Type == GL_NONE); + /* complete */ + return; + } +} + + +/** + * Test if the given framebuffer object is complete and update its + * Status field with the results. + * Calls the ctx->Driver.ValidateFramebuffer() function to allow the + * driver to make hardware-specific validation/completeness checks. + * Also update the framebuffer's Width and Height fields if the + * framebuffer is complete. + */ +void +_mesa_test_framebuffer_completeness(struct gl_context *ctx, + struct gl_framebuffer *fb) +{ + GLuint numImages; + GLenum intFormat = GL_NONE; /* color buffers' internal format */ + GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0; + GLint numSamples = -1; + GLint i; + GLuint j; + + assert(fb->Name != 0); + + numImages = 0; + fb->Width = 0; + fb->Height = 0; + + /* Start at -2 to more easily loop over all attachment points. + * -2: depth buffer + * -1: stencil buffer + * >=0: color buffer + */ + for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { + struct gl_renderbuffer_attachment *att; + GLenum f; + gl_format attFormat; + + /* + * XXX for ARB_fbo, only check color buffers that are named by + * GL_READ_BUFFER and GL_DRAW_BUFFERi. + */ + + /* check for attachment completeness + */ + if (i == -2) { + att = &fb->Attachment[BUFFER_DEPTH]; + test_attachment_completeness(ctx, GL_DEPTH, att); + if (!att->Complete) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; + fbo_incomplete("depth attachment incomplete", -1); + return; + } + } + else if (i == -1) { + att = &fb->Attachment[BUFFER_STENCIL]; + test_attachment_completeness(ctx, GL_STENCIL, att); + if (!att->Complete) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; + fbo_incomplete("stencil attachment incomplete", -1); + return; + } + } + else { + att = &fb->Attachment[BUFFER_COLOR0 + i]; + test_attachment_completeness(ctx, GL_COLOR, att); + if (!att->Complete) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; + fbo_incomplete("color attachment incomplete", i); + return; + } + } + + /* get width, height, format of the renderbuffer/texture + */ + if (att->Type == GL_TEXTURE) { + const struct gl_texture_image *texImg + = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; + minWidth = MIN2(minWidth, texImg->Width); + maxWidth = MAX2(maxWidth, texImg->Width); + minHeight = MIN2(minHeight, texImg->Height); + maxHeight = MAX2(maxHeight, texImg->Height); + f = texImg->_BaseFormat; + attFormat = texImg->TexFormat; + numImages++; + if (!_mesa_is_legal_color_format(ctx, f) && + !is_legal_depth_format(ctx, f)) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; + fbo_incomplete("texture attachment incomplete", -1); + return; + } + } + else if (att->Type == GL_RENDERBUFFER_EXT) { + minWidth = MIN2(minWidth, att->Renderbuffer->Width); + maxWidth = MAX2(minWidth, att->Renderbuffer->Width); + minHeight = MIN2(minHeight, att->Renderbuffer->Height); + maxHeight = MAX2(minHeight, att->Renderbuffer->Height); + f = att->Renderbuffer->InternalFormat; + attFormat = att->Renderbuffer->Format; + numImages++; + } + else { + assert(att->Type == GL_NONE); + continue; + } + + if (numSamples < 0) { + /* first buffer */ + numSamples = att->Renderbuffer->NumSamples; + } + + /* check if integer color */ + fb->_IntegerColor = _mesa_is_format_integer_color(attFormat); + + /* Error-check width, height, format, samples + */ + if (numImages == 1) { + /* save format, num samples */ + if (i >= 0) { + intFormat = f; + } + } + else { + if (!ctx->Extensions.ARB_framebuffer_object) { + /* check that width, height, format are same */ + if (minWidth != maxWidth || minHeight != maxHeight) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; + fbo_incomplete("width or height mismatch", -1); + return; + } + /* check that all color buffer have same format */ + if (intFormat != GL_NONE && f != intFormat) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; + fbo_incomplete("format mismatch", -1); + return; + } + } + if (att->Renderbuffer && + att->Renderbuffer->NumSamples != numSamples) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; + fbo_incomplete("inconsistant number of samples", i); + return; + } + + } + } + +#if FEATURE_GL + if (ctx->API == API_OPENGL) { + /* Check that all DrawBuffers are present */ + for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { + if (fb->ColorDrawBuffer[j] != GL_NONE) { + const struct gl_renderbuffer_attachment *att + = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]); + assert(att); + if (att->Type == GL_NONE) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; + fbo_incomplete("missing drawbuffer", j); + return; + } + } + } + + /* Check that the ReadBuffer is present */ + if (fb->ColorReadBuffer != GL_NONE) { + const struct gl_renderbuffer_attachment *att + = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer); + assert(att); + if (att->Type == GL_NONE) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; + fbo_incomplete("missing readbuffer", -1); + return; + } + } + } +#else + (void) j; +#endif + + if (numImages == 0) { + fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; + fbo_incomplete("no attachments", -1); + return; + } + + /* Provisionally set status = COMPLETE ... */ + fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; + + /* ... but the driver may say the FB is incomplete. + * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED + * if anything. + */ + if (ctx->Driver.ValidateFramebuffer) { + ctx->Driver.ValidateFramebuffer(ctx, fb); + if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + fbo_incomplete("driver marked FBO as incomplete", -1); + } + } + + if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) { + /* + * Note that if ARB_framebuffer_object is supported and the attached + * renderbuffers/textures are different sizes, the framebuffer + * width/height will be set to the smallest width/height. + */ + fb->Width = minWidth; + fb->Height = minHeight; + + /* finally, update the visual info for the framebuffer */ + _mesa_update_framebuffer_visual(ctx, fb); + } +} + + +GLboolean GLAPIENTRY +_mesa_IsRenderbufferEXT(GLuint renderbuffer) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + if (renderbuffer) { + struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); + if (rb != NULL && rb != &DummyRenderbuffer) + return GL_TRUE; + } + return GL_FALSE; +} + + +void GLAPIENTRY +_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) +{ + struct gl_renderbuffer *newRb; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target != GL_RENDERBUFFER_EXT) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)"); + return; + } + + /* No need to flush here since the render buffer binding has no + * effect on rendering state. + */ + + if (renderbuffer) { + newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); + if (newRb == &DummyRenderbuffer) { + /* ID was reserved, but no real renderbuffer object made yet */ + newRb = NULL; + } + else if (!newRb && ctx->Extensions.ARB_framebuffer_object) { + /* All RB IDs must be Gen'd */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)"); + return; + } + + if (!newRb) { + /* create new renderbuffer object */ + newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); + if (!newRb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); + return; + } + ASSERT(newRb->AllocStorage); + _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); + newRb->RefCount = 1; /* referenced by hash table */ + } + } + else { + newRb = NULL; + } + + ASSERT(newRb != &DummyRenderbuffer); + + _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); +} + + +/** + * If the given renderbuffer is anywhere attached to the framebuffer, detach + * the renderbuffer. + * This is used when a renderbuffer object is deleted. + * The spec calls for unbinding. + */ +static void +detach_renderbuffer(struct gl_context *ctx, + struct gl_framebuffer *fb, + struct gl_renderbuffer *rb) +{ + GLuint i; + for (i = 0; i < BUFFER_COUNT; i++) { + if (fb->Attachment[i].Renderbuffer == rb) { + _mesa_remove_attachment(ctx, &fb->Attachment[i]); + } + } + invalidate_framebuffer(fb); +} + + +void GLAPIENTRY +_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) +{ + GLint i; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + for (i = 0; i < n; i++) { + if (renderbuffers[i] > 0) { + struct gl_renderbuffer *rb; + rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]); + if (rb) { + /* check if deleting currently bound renderbuffer object */ + if (rb == ctx->CurrentRenderbuffer) { + /* bind default */ + ASSERT(rb->RefCount >= 2); + _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + } + + if (ctx->DrawBuffer->Name) { + detach_renderbuffer(ctx, ctx->DrawBuffer, rb); + } + if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) { + detach_renderbuffer(ctx, ctx->ReadBuffer, rb); + } + + /* Remove from hash table immediately, to free the ID. + * But the object will not be freed until it's no longer + * referenced anywhere else. + */ + _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); + + if (rb != &DummyRenderbuffer) { + /* no longer referenced by hash table */ + _mesa_reference_renderbuffer(&rb, NULL); + } + } + } + } +} + + +void GLAPIENTRY +_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint first; + GLint i; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); + return; + } + + if (!renderbuffers) + return; + + first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); + + for (i = 0; i < n; i++) { + GLuint name = first + i; + renderbuffers[i] = name; + /* insert dummy placeholder into hash table */ + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); + _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer); + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); + } +} + + +/** + * Given an internal format token for a render buffer, return the + * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, + * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE, + * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc). + * + * This is similar to _mesa_base_tex_format() but the set of valid + * internal formats is different. + * + * Note that even if a format is determined to be legal here, validation + * of the FBO may fail if the format is not supported by the driver/GPU. + * + * \param internalFormat as passed to glRenderbufferStorage() + * \return the base internal format, or 0 if internalFormat is illegal + */ +GLenum +_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) +{ + /* + * Notes: some formats such as alpha, luminance, etc. were added + * with GL_ARB_framebuffer_object. + */ + switch (internalFormat) { + case GL_ALPHA: + case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + return ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE4_ALPHA4: + case GL_LUMINANCE6_ALPHA2: + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE12_ALPHA4: + case GL_LUMINANCE12_ALPHA12: + case GL_LUMINANCE16_ALPHA16: + return ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; + case GL_INTENSITY: + case GL_INTENSITY4: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + return ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; + case GL_RGB: + case GL_R3_G3_B2: + case GL_RGB4: + case GL_RGB5: + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + case GL_SRGB8_EXT: + return GL_RGB; + case GL_RGBA: + case GL_RGBA2: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: + case GL_RGBA16_SNORM: + case GL_SRGB8_ALPHA8_EXT: + return GL_RGBA; + case GL_STENCIL_INDEX: + case GL_STENCIL_INDEX1_EXT: + case GL_STENCIL_INDEX4_EXT: + case GL_STENCIL_INDEX8_EXT: + case GL_STENCIL_INDEX16_EXT: + return GL_STENCIL_INDEX; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT32: + return GL_DEPTH_COMPONENT; + case GL_DEPTH_STENCIL_EXT: + case GL_DEPTH24_STENCIL8_EXT: + if (ctx->Extensions.EXT_packed_depth_stencil) + return GL_DEPTH_STENCIL_EXT; + else + return 0; + case GL_RED: + case GL_R8: + case GL_R16: + return ctx->Extensions.ARB_texture_rg ? GL_RED : 0; + case GL_RG: + case GL_RG8: + case GL_RG16: + return ctx->Extensions.ARB_texture_rg ? GL_RG : 0; + /* XXX add floating point and integer formats eventually */ + default: + return 0; + } +} + + +/** sentinal value, see below */ +#define NO_SAMPLES 1000 + + +/** + * Helper function used by _mesa_RenderbufferStorageEXT() and + * _mesa_RenderbufferStorageMultisample(). + * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT(). + */ +static void +renderbuffer_storage(GLenum target, GLenum internalFormat, + GLsizei width, GLsizei height, GLsizei samples) +{ + const char *func = samples == NO_SAMPLES ? + "glRenderbufferStorage" : "RenderbufferStorageMultisample"; + struct gl_renderbuffer *rb; + GLenum baseFormat; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target != GL_RENDERBUFFER_EXT) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); + return; + } + + baseFormat = _mesa_base_fbo_format(ctx, internalFormat); + if (baseFormat == 0) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func); + return; + } + + if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func); + return; + } + + if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func); + return; + } + + if (samples == NO_SAMPLES) { + /* NumSamples == 0 indicates non-multisampling */ + samples = 0; + } + else if (samples > (GLsizei) ctx->Const.MaxSamples) { + /* note: driver may choose to use more samples than what's requested */ + _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func); + return; + } + + rb = ctx->CurrentRenderbuffer; + if (!rb) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); + return; + } + + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + if (rb->InternalFormat == internalFormat && + rb->Width == (GLuint) width && + rb->Height == (GLuint) height) { + /* no change in allocation needed */ + return; + } + + /* These MUST get set by the AllocStorage func */ + rb->Format = MESA_FORMAT_NONE; + rb->NumSamples = samples; + + /* Now allocate the storage */ + ASSERT(rb->AllocStorage); + if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { + /* No error - check/set fields now */ + assert(rb->Format != MESA_FORMAT_NONE); + assert(rb->Width == (GLuint) width); + assert(rb->Height == (GLuint) height); + rb->InternalFormat = internalFormat; + rb->_BaseFormat = baseFormat; + assert(rb->_BaseFormat != 0); + } + else { + /* Probably ran out of memory - clear the fields */ + rb->Width = 0; + rb->Height = 0; + rb->Format = MESA_FORMAT_NONE; + rb->InternalFormat = GL_NONE; + rb->_BaseFormat = GL_NONE; + rb->NumSamples = 0; + } + + /* + test_framebuffer_completeness(ctx, fb); + */ + /* XXX if this renderbuffer is attached anywhere, invalidate attachment + * points??? + */ +} + + +#if FEATURE_OES_EGL_image +void GLAPIENTRY +_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) +{ + struct gl_renderbuffer *rb; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!ctx->Extensions.OES_EGL_image) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glEGLImageTargetRenderbufferStorageOES(unsupported)"); + return; + } + + if (target != GL_RENDERBUFFER) { + _mesa_error(ctx, GL_INVALID_ENUM, + "EGLImageTargetRenderbufferStorageOES"); + return; + } + + rb = ctx->CurrentRenderbuffer; + if (!rb) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "EGLImageTargetRenderbufferStorageOES"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image); +} +#endif + + +/** + * Helper function for _mesa_GetRenderbufferParameterivEXT() and + * _mesa_GetFramebufferAttachmentParameterivEXT() + * We have to be careful to respect the base format. For example, if a + * renderbuffer/texture was created with internalFormat=GL_RGB but the + * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE + * we need to return zero. + */ +static GLint +get_component_bits(GLenum pname, GLenum baseFormat, gl_format format) +{ + switch (pname) { + case GL_RENDERBUFFER_RED_SIZE_EXT: + case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: + if (baseFormat == GL_RGB || baseFormat == GL_RGBA || + baseFormat == GL_RG || baseFormat == GL_RED) + return _mesa_get_format_bits(format, pname); + else + return 0; + case GL_RENDERBUFFER_GREEN_SIZE_EXT: + case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: + if (baseFormat == GL_RGB || baseFormat == GL_RGBA || baseFormat == GL_RG) + return _mesa_get_format_bits(format, pname); + else + return 0; + case GL_RENDERBUFFER_BLUE_SIZE_EXT: + case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: + if (baseFormat == GL_RGB || baseFormat == GL_RGBA) + return _mesa_get_format_bits(format, pname); + else + return 0; + case GL_RENDERBUFFER_ALPHA_SIZE_EXT: + case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: + if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA || + baseFormat == GL_LUMINANCE_ALPHA) + return _mesa_get_format_bits(format, pname); + else + return 0; + case GL_RENDERBUFFER_DEPTH_SIZE_EXT: + case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: + if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL) + return _mesa_get_format_bits(format, pname); + else + return 0; + case GL_RENDERBUFFER_STENCIL_SIZE_EXT: + case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: + if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL) + return _mesa_get_format_bits(format, pname); + else + return 0; + default: + return 0; + } +} + + + +void GLAPIENTRY +_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, + GLsizei width, GLsizei height) +{ + /* GL_ARB_fbo says calling this function is equivalent to calling + * glRenderbufferStorageMultisample() with samples=0. We pass in + * a token value here just for error reporting purposes. + */ + renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES); +} + + +void GLAPIENTRY +_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, + GLenum internalFormat, + GLsizei width, GLsizei height) +{ + renderbuffer_storage(target, internalFormat, width, height, samples); +} + + +/** + * OpenGL ES version of glRenderBufferStorage. + */ +void GLAPIENTRY +_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, + GLsizei width, GLsizei height) +{ + switch (internalFormat) { + case GL_RGB565: + /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */ + /* choose a closest format */ + internalFormat = GL_RGB5; + break; + default: + break; + } + + renderbuffer_storage(target, internalFormat, width, height, 0); +} + + +void GLAPIENTRY +_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) +{ + struct gl_renderbuffer *rb; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target != GL_RENDERBUFFER_EXT) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetRenderbufferParameterivEXT(target)"); + return; + } + + rb = ctx->CurrentRenderbuffer; + if (!rb) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetRenderbufferParameterivEXT"); + return; + } + + /* No need to flush here since we're just quering state which is + * not effected by rendering. + */ + + switch (pname) { + case GL_RENDERBUFFER_WIDTH_EXT: + *params = rb->Width; + return; + case GL_RENDERBUFFER_HEIGHT_EXT: + *params = rb->Height; + return; + case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: + *params = rb->InternalFormat; + return; + case GL_RENDERBUFFER_RED_SIZE_EXT: + case GL_RENDERBUFFER_GREEN_SIZE_EXT: + case GL_RENDERBUFFER_BLUE_SIZE_EXT: + case GL_RENDERBUFFER_ALPHA_SIZE_EXT: + case GL_RENDERBUFFER_DEPTH_SIZE_EXT: + case GL_RENDERBUFFER_STENCIL_SIZE_EXT: + *params = get_component_bits(pname, rb->_BaseFormat, rb->Format); + break; + case GL_RENDERBUFFER_SAMPLES: + if (ctx->Extensions.ARB_framebuffer_object) { + *params = rb->NumSamples; + break; + } + /* fallthrough */ + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetRenderbufferParameterivEXT(target)"); + return; + } +} + + +GLboolean GLAPIENTRY +_mesa_IsFramebufferEXT(GLuint framebuffer) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + if (framebuffer) { + struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); + if (rb != NULL && rb != &DummyFramebuffer) + return GL_TRUE; + } + return GL_FALSE; +} + + +/** + * Check if any of the attachments of the given framebuffer are textures + * (render to texture). Call ctx->Driver.RenderTexture() for such + * attachments. + */ +static void +check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) +{ + GLuint i; + ASSERT(ctx->Driver.RenderTexture); + + if (fb->Name == 0) + return; /* can't render to texture with winsys framebuffers */ + + for (i = 0; i < BUFFER_COUNT; i++) { + struct gl_renderbuffer_attachment *att = fb->Attachment + i; + struct gl_texture_object *texObj = att->Texture; + if (texObj + && texObj->Image[att->CubeMapFace][att->TextureLevel]) { + ctx->Driver.RenderTexture(ctx, fb, att); + } + } +} + + +/** + * Examine all the framebuffer's attachments to see if any are textures. + * If so, call ctx->Driver.FinishRenderTexture() for each texture to + * notify the device driver that the texture image may have changed. + */ +static void +check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) +{ + if (fb->Name == 0) + return; /* can't render to texture with winsys framebuffers */ + + if (ctx->Driver.FinishRenderTexture) { + GLuint i; + for (i = 0; i < BUFFER_COUNT; i++) { + struct gl_renderbuffer_attachment *att = fb->Attachment + i; + if (att->Texture && att->Renderbuffer) { + ctx->Driver.FinishRenderTexture(ctx, att); + } + } + } +} + + +void GLAPIENTRY +_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) +{ + struct gl_framebuffer *newDrawFb, *newReadFb; + struct gl_framebuffer *oldDrawFb, *oldReadFb; + GLboolean bindReadBuf, bindDrawBuf; + GET_CURRENT_CONTEXT(ctx); + +#ifdef DEBUG + if (ctx->Extensions.ARB_framebuffer_object) { + ASSERT(ctx->Extensions.EXT_framebuffer_object); + ASSERT(ctx->Extensions.EXT_framebuffer_blit); + } +#endif + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!ctx->Extensions.EXT_framebuffer_object) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindFramebufferEXT(unsupported)"); + return; + } + + switch (target) { +#if FEATURE_EXT_framebuffer_blit + case GL_DRAW_FRAMEBUFFER_EXT: + if (!ctx->Extensions.EXT_framebuffer_blit) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); + return; + } + bindDrawBuf = GL_TRUE; + bindReadBuf = GL_FALSE; + break; + case GL_READ_FRAMEBUFFER_EXT: + if (!ctx->Extensions.EXT_framebuffer_blit) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); + return; + } + bindDrawBuf = GL_FALSE; + bindReadBuf = GL_TRUE; + break; +#endif + case GL_FRAMEBUFFER_EXT: + bindDrawBuf = GL_TRUE; + bindReadBuf = GL_TRUE; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); + return; + } + + if (framebuffer) { + /* Binding a user-created framebuffer object */ + newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer); + if (newDrawFb == &DummyFramebuffer) { + /* ID was reserved, but no real framebuffer object made yet */ + newDrawFb = NULL; + } + else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) { + /* All FBO IDs must be Gen'd */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)"); + return; + } + + if (!newDrawFb) { + /* create new framebuffer object */ + newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); + if (!newDrawFb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); + return; + } + _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb); + } + newReadFb = newDrawFb; + } + else { + /* Binding the window system framebuffer (which was originally set + * with MakeCurrent). + */ + newDrawFb = ctx->WinSysDrawBuffer; + newReadFb = ctx->WinSysReadBuffer; + } + + ASSERT(newDrawFb); + ASSERT(newDrawFb != &DummyFramebuffer); + + /* save pointers to current/old framebuffers */ + oldDrawFb = ctx->DrawBuffer; + oldReadFb = ctx->ReadBuffer; + + /* check if really changing bindings */ + if (oldDrawFb == newDrawFb) + bindDrawBuf = GL_FALSE; + if (oldReadFb == newReadFb) + bindReadBuf = GL_FALSE; + + /* + * OK, now bind the new Draw/Read framebuffers, if they're changing. + * + * We also check if we're beginning and/or ending render-to-texture. + * When a framebuffer with texture attachments is unbound, call + * ctx->Driver.FinishRenderTexture(). + * When a framebuffer with texture attachments is bound, call + * ctx->Driver.RenderTexture(). + * + * Note that if the ReadBuffer has texture attachments we don't consider + * that a render-to-texture case. + */ + if (bindReadBuf) { + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + /* check if old readbuffer was render-to-texture */ + check_end_texture_render(ctx, oldReadFb); + + _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb); + } + + if (bindDrawBuf) { + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + /* check if old read/draw buffers were render-to-texture */ + if (!bindReadBuf) + check_end_texture_render(ctx, oldReadFb); + + if (oldDrawFb != oldReadFb) + check_end_texture_render(ctx, oldDrawFb); + + /* check if newly bound framebuffer has any texture attachments */ + check_begin_texture_render(ctx, newDrawFb); + + _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb); + } + + if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) { + ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb); + } +} + + +void GLAPIENTRY +_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) +{ + GLint i; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + for (i = 0; i < n; i++) { + if (framebuffers[i] > 0) { + struct gl_framebuffer *fb; + fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); + if (fb) { + ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); + + /* check if deleting currently bound framebuffer object */ + if (ctx->Extensions.EXT_framebuffer_blit) { + /* separate draw/read binding points */ + if (fb == ctx->DrawBuffer) { + /* bind default */ + ASSERT(fb->RefCount >= 2); + _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); + } + if (fb == ctx->ReadBuffer) { + /* bind default */ + ASSERT(fb->RefCount >= 2); + _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); + } + } + else { + /* only one binding point for read/draw buffers */ + if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) { + /* bind default */ + ASSERT(fb->RefCount >= 2); + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } + } + + /* remove from hash table immediately, to free the ID */ + _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); + + if (fb != &DummyFramebuffer) { + /* But the object will not be freed until it's no longer + * bound in any context. + */ + _mesa_reference_framebuffer(&fb, NULL); + } + } + } + } +} + + +void GLAPIENTRY +_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint first; + GLint i; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); + return; + } + + if (!framebuffers) + return; + + first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); + + for (i = 0; i < n; i++) { + GLuint name = first + i; + framebuffers[i] = name; + /* insert dummy placeholder into hash table */ + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); + _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); + } +} + + + +GLenum GLAPIENTRY +_mesa_CheckFramebufferStatusEXT(GLenum target) +{ + struct gl_framebuffer *buffer; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); + + buffer = get_framebuffer_target(ctx, target); + if (!buffer) { + _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); + return 0; + } + + if (buffer->Name == 0) { + /* The window system / default framebuffer is always complete */ + return GL_FRAMEBUFFER_COMPLETE_EXT; + } + + /* No need to flush here */ + + if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) { + _mesa_test_framebuffer_completeness(ctx, buffer); + } + + return buffer->_Status; +} + + + +/** + * Common code called by glFramebufferTexture1D/2D/3DEXT(). + */ +static void +framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, + GLenum attachment, GLenum textarget, GLuint texture, + GLint level, GLint zoffset) +{ + struct gl_renderbuffer_attachment *att; + struct gl_texture_object *texObj = NULL; + struct gl_framebuffer *fb; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferTexture%sEXT(target=0x%x)", caller, target); + return; + } + + /* check framebuffer binding */ + if (fb->Name == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTexture%sEXT", caller); + return; + } + + + /* The textarget, level, and zoffset parameters are only validated if + * texture is non-zero. + */ + if (texture) { + GLboolean err = GL_TRUE; + + texObj = _mesa_lookup_texture(ctx, texture); + if (texObj != NULL) { + if (textarget == 0) { + /* XXX what's the purpose of this? */ + err = (texObj->Target != GL_TEXTURE_3D) && + (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && + (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); + } + else { + err = (texObj->Target == GL_TEXTURE_CUBE_MAP) + ? !IS_CUBE_FACE(textarget) + : (texObj->Target != textarget); + } + } + else { + /* can't render to a non-existant texture */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTexture%sEXT(non existant texture)", + caller); + return; + } + + if (err) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTexture%sEXT(texture target mismatch)", + caller); + return; + } + + if (texObj->Target == GL_TEXTURE_3D) { + const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); + if (zoffset < 0 || zoffset >= maxSize) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glFramebufferTexture%sEXT(zoffset)", caller); + return; + } + } + else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || + (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { + if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glFramebufferTexture%sEXT(layer)", caller); + return; + } + } + + if ((level < 0) || + (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glFramebufferTexture%sEXT(level)", caller); + return; + } + } + + att = _mesa_get_attachment(ctx, fb, attachment); + if (att == NULL) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferTexture%sEXT(attachment)", caller); + return; + } + + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + _glthread_LOCK_MUTEX(fb->Mutex); + if (texObj) { + _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, + level, zoffset); + /* Set the render-to-texture flag. We'll check this flag in + * glTexImage() and friends to determine if we need to revalidate + * any FBOs that might be rendering into this texture. + * This flag never gets cleared since it's non-trivial to determine + * when all FBOs might be done rendering to this texture. That's OK + * though since it's uncommon to render to a texture then repeatedly + * call glTexImage() to change images in the texture. + */ + texObj->_RenderToTexture = GL_TRUE; + } + else { + _mesa_remove_attachment(ctx, att); + } + + invalidate_framebuffer(fb); + + _glthread_UNLOCK_MUTEX(fb->Mutex); +} + + + +void GLAPIENTRY +_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) +{ + GET_CURRENT_CONTEXT(ctx); + + if ((texture != 0) && (textarget != GL_TEXTURE_1D)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferTexture1DEXT(textarget)"); + return; + } + + framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, + level, 0); +} + + +void GLAPIENTRY +_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) +{ + GET_CURRENT_CONTEXT(ctx); + + if ((texture != 0) && + (textarget != GL_TEXTURE_2D) && + (textarget != GL_TEXTURE_RECTANGLE_ARB) && + (!IS_CUBE_FACE(textarget))) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTexture2DEXT(textarget=0x%x)", textarget); + return; + } + + framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, + level, 0); +} + + +void GLAPIENTRY +_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level, GLint zoffset) +{ + GET_CURRENT_CONTEXT(ctx); + + if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferTexture3DEXT(textarget)"); + return; + } + + framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, + level, zoffset); +} + + +void GLAPIENTRY +_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer) +{ + GET_CURRENT_CONTEXT(ctx); + + framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, + level, layer); +} + + +void GLAPIENTRY +_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, + GLenum renderbufferTarget, + GLuint renderbuffer) +{ + struct gl_renderbuffer_attachment *att; + struct gl_framebuffer *fb; + struct gl_renderbuffer *rb; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferRenderbufferEXT(target)"); + return; + } + + if (renderbufferTarget != GL_RENDERBUFFER_EXT) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferRenderbufferEXT(renderbufferTarget)"); + return; + } + + if (fb->Name == 0) { + /* Can't attach new renderbuffers to a window system framebuffer */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); + return; + } + + att = _mesa_get_attachment(ctx, fb, attachment); + if (att == NULL) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferRenderbufferEXT(invalid attachment %s)", + _mesa_lookup_enum_by_nr(attachment)); + return; + } + + if (renderbuffer) { + rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); + if (!rb) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferRenderbufferEXT(non-existant" + " renderbuffer %u)", renderbuffer); + return; + } + else if (rb == &DummyRenderbuffer) { + /* This is what NVIDIA does */ + _mesa_error(ctx, GL_INVALID_VALUE, + "glFramebufferRenderbufferEXT(renderbuffer %u)", + renderbuffer); + return; + } + } + else { + /* remove renderbuffer attachment */ + rb = NULL; + } + + if (attachment == GL_DEPTH_STENCIL_ATTACHMENT && + rb && rb->Format != MESA_FORMAT_NONE) { + /* make sure the renderbuffer is a depth/stencil format */ + const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); + if (baseFormat != GL_DEPTH_STENCIL) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferRenderbufferEXT(renderbuffer" + " is not DEPTH_STENCIL format)"); + return; + } + } + + + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + assert(ctx->Driver.FramebufferRenderbuffer); + ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); + + /* Some subsequent GL commands may depend on the framebuffer's visual + * after the binding is updated. Update visual info now. + */ + _mesa_update_framebuffer_visual(ctx, fb); +} + + +void GLAPIENTRY +_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, + GLenum pname, GLint *params) +{ + const struct gl_renderbuffer_attachment *att; + struct gl_framebuffer *buffer; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + buffer = get_framebuffer_target(ctx, target); + if (!buffer) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(target)"); + return; + } + + if (buffer->Name == 0) { + /* the default / window-system FBO */ + att = _mesa_get_fb0_attachment(ctx, buffer, attachment); + } + else { + /* user-created framebuffer FBO */ + att = _mesa_get_attachment(ctx, buffer, attachment); + } + + if (att == NULL) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(attachment)"); + return; + } + + if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { + /* the depth and stencil attachments must point to the same buffer */ + const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt; + depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT); + stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT); + if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL" + " attachments differ)"); + return; + } + } + + /* No need to flush here */ + + switch (pname) { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: + *params = buffer->Name == 0 ? GL_FRAMEBUFFER_DEFAULT : att->Type; + return; + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: + if (att->Type == GL_RENDERBUFFER_EXT) { + *params = att->Renderbuffer->Name; + } + else if (att->Type == GL_TEXTURE) { + *params = att->Texture->Name; + } + else { + assert(att->Type == GL_NONE); + *params = 0; + } + return; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: + if (att->Type == GL_TEXTURE) { + *params = att->TextureLevel; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } + return; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: + if (att->Type == GL_TEXTURE) { + if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { + *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; + } + else { + *params = 0; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } + return; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: + if (att->Type == GL_TEXTURE) { + if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) { + *params = att->Zoffset; + } + else { + *params = 0; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } + return; + case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: + if (!ctx->Extensions.ARB_framebuffer_object) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } + else { + if (ctx->Extensions.EXT_framebuffer_sRGB && ctx->Const.sRGBCapable) { + *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format); + } + else { + /* According to ARB_framebuffer_sRGB, we should return LINEAR + * if the sRGB conversion is unsupported. */ + *params = GL_LINEAR; + } + } + return; + case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: + if (!ctx->Extensions.ARB_framebuffer_object) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + return; + } + else { + gl_format format = att->Renderbuffer->Format; + if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) { + /* special cases */ + *params = GL_INDEX; + } + else { + *params = _mesa_get_format_datatype(format); + } + } + return; + case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: + if (!ctx->Extensions.ARB_framebuffer_object) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + } + else if (att->Texture) { + const struct gl_texture_image *texImage = + _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target, + att->TextureLevel); + if (texImage) { + *params = get_component_bits(pname, texImage->_BaseFormat, + texImage->TexFormat); + } + else { + *params = 0; + } + } + else if (att->Renderbuffer) { + *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat, + att->Renderbuffer->Format); + } + else { + *params = 0; + } + return; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameterivEXT(pname)"); + return; + } +} + + +void GLAPIENTRY +_mesa_GenerateMipmapEXT(GLenum target) +{ + struct gl_texture_object *texObj; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + switch (target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + case GL_TEXTURE_CUBE_MAP: + /* OK, legal value */ + break; + default: + /* XXX need to implement GL_TEXTURE_1D_ARRAY and GL_TEXTURE_2D_ARRAY */ + _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)"); + return; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + + if (texObj->BaseLevel >= texObj->MaxLevel) { + /* nothing to do */ + return; + } + + if (texObj->Target == GL_TEXTURE_CUBE_MAP && + !_mesa_cube_complete(texObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGenerateMipmap(incomplete cube map)"); + return; + } + + _mesa_lock_texture(ctx, texObj); + if (target == GL_TEXTURE_CUBE_MAP) { + GLuint face; + for (face = 0; face < 6; face++) + ctx->Driver.GenerateMipmap(ctx, + GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face, + texObj); + } + else { + ctx->Driver.GenerateMipmap(ctx, target, texObj); + } + _mesa_unlock_texture(ctx, texObj); +} + + +#if FEATURE_EXT_framebuffer_blit + +static const struct gl_renderbuffer_attachment * +find_attachment(const struct gl_framebuffer *fb, + const struct gl_renderbuffer *rb) +{ + GLuint i; + for (i = 0; i < Elements(fb->Attachment); i++) { + if (fb->Attachment[i].Renderbuffer == rb) + return &fb->Attachment[i]; + } + return NULL; +} + + + +/** + * Blit rectangular region, optionally from one framebuffer to another. + * + * Note, if the src buffer is multisampled and the dest is not, this is + * when the samples must be resolved to a single color. + */ +void GLAPIENTRY +_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT | + GL_DEPTH_BUFFER_BIT | + GL_STENCIL_BUFFER_BIT); + const struct gl_framebuffer *readFb, *drawFb; + const struct gl_renderbuffer *colorReadRb, *colorDrawRb; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + FLUSH_VERTICES(ctx, _NEW_BUFFERS); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, + "glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n", + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, _mesa_lookup_enum_by_nr(filter)); + + if (ctx->NewState) { + _mesa_update_state(ctx); + } + + readFb = ctx->ReadBuffer; + drawFb = ctx->DrawBuffer; + + if (!readFb || !drawFb) { + /* This will normally never happen but someday we may want to + * support MakeCurrent() with no drawables. + */ + return; + } + + /* check for complete framebuffers */ + if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || + readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "glBlitFramebufferEXT(incomplete draw/read buffers)"); + return; + } + + if (filter != GL_NEAREST && filter != GL_LINEAR) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)"); + return; + } + + if (mask & ~legalMaskBits) { + _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)"); + return; + } + + /* depth/stencil must be blitted with nearest filtering */ + if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) + && filter != GL_NEAREST) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter"); + return; + } + + /* get color read/draw renderbuffers */ + if (mask & GL_COLOR_BUFFER_BIT) { + colorReadRb = readFb->_ColorReadBuffer; + colorDrawRb = drawFb->_ColorDrawBuffers[0]; + } + else { + colorReadRb = colorDrawRb = NULL; + } + + if (mask & GL_STENCIL_BUFFER_BIT) { + struct gl_renderbuffer *readRb = readFb->_StencilBuffer; + struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer; + if (!readRb || + !drawRb || + _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) != + _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(stencil buffer size mismatch"); + return; + } + } + + if (mask & GL_DEPTH_BUFFER_BIT) { + struct gl_renderbuffer *readRb = readFb->_DepthBuffer; + struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer; + if (!readRb || + !drawRb || + _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) != + _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(depth buffer size mismatch"); + return; + } + } + + if (readFb->Visual.samples > 0 && + drawFb->Visual.samples > 0 && + readFb->Visual.samples != drawFb->Visual.samples) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(mismatched samples"); + return; + } + + /* extra checks for multisample copies... */ + if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) { + /* src and dest region sizes must be the same */ + if (srcX1 - srcX0 != dstX1 - dstX0 || + srcY1 - srcY0 != dstY1 - dstY0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(bad src/dst multisample region sizes"); + return; + } + + /* color formats must match */ + if (colorReadRb && + colorDrawRb && + colorReadRb->Format != colorDrawRb->Format) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitFramebufferEXT(bad src/dst multisample pixel formats"); + return; + } + } + + if (!ctx->Extensions.EXT_framebuffer_blit) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT"); + return; + } + + /* Debug code */ + if (DEBUG_BLIT) { + printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d," + " 0x%x, 0x%x)\n", + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, filter); + if (colorReadRb) { + const struct gl_renderbuffer_attachment *att; + + att = find_attachment(readFb, colorReadRb); + printf(" Src FBO %u RB %u (%dx%d) ", + readFb->Name, colorReadRb->Name, + colorReadRb->Width, colorReadRb->Height); + if (att && att->Texture) { + printf("Tex %u tgt 0x%x level %u face %u", + att->Texture->Name, + att->Texture->Target, + att->TextureLevel, + att->CubeMapFace); + } + printf("\n"); + + att = find_attachment(drawFb, colorDrawRb); + printf(" Dst FBO %u RB %u (%dx%d) ", + drawFb->Name, colorDrawRb->Name, + colorDrawRb->Width, colorDrawRb->Height); + if (att && att->Texture) { + printf("Tex %u tgt 0x%x level %u face %u", + att->Texture->Name, + att->Texture->Target, + att->TextureLevel, + att->CubeMapFace); + } + printf("\n"); + } + } + + ASSERT(ctx->Driver.BlitFramebuffer); + ctx->Driver.BlitFramebuffer(ctx, + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, filter); +} +#endif /* FEATURE_EXT_framebuffer_blit */ + +#if FEATURE_ARB_geometry_shader4 +void GLAPIENTRY +_mesa_FramebufferTextureARB(GLenum target, GLenum attachment, + GLuint texture, GLint level) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTextureARB " + "not implemented!"); +} + +void GLAPIENTRY +_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment, + GLuint texture, GLint level, GLenum face) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFramebufferTextureFaceARB " + "not implemented!"); +} +#endif /* FEATURE_ARB_geometry_shader4 */ diff --git a/mesalib/src/mesa/main/framebuffer.c b/mesalib/src/mesa/main/framebuffer.c index 948b3b7b5..227b214a5 100644 --- a/mesalib/src/mesa/main/framebuffer.c +++ b/mesalib/src/mesa/main/framebuffer.c @@ -794,15 +794,12 @@ update_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, ctx->Color.DrawBuffer, NULL); } - if (fb->ColorReadBuffer != ctx->Pixel.ReadBuffer) { - - } } else { /* This is a user-created framebuffer. * Completeness only matters for user-created framebuffers. */ - if (fb->_Status != GL_FRAMEBUFFER_COMPLETE) { + if (fb->_Status == 0) { _mesa_test_framebuffer_completeness(ctx, fb); } } diff --git a/mesalib/src/mesa/main/get.c b/mesalib/src/mesa/main/get.c index 3e5ddfcfd..336304c59 100644 --- a/mesalib/src/mesa/main/get.c +++ b/mesalib/src/mesa/main/get.c @@ -1,2533 +1,2527 @@ -/*
- * Copyright (C) 2010 Brian Paul All Rights Reserved.
- * Copyright (C) 2010 Intel Corporation
- *
- * 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.
- *
- * Author: Kristian Høgsberg <krh@bitplanet.net>
- */
-
-#include "glheader.h"
-#include "context.h"
-#include "enable.h"
-#include "enums.h"
-#include "extensions.h"
-#include "get.h"
-#include "macros.h"
-#include "mfeatures.h"
-#include "mtypes.h"
-#include "state.h"
-#include "texcompress.h"
-#include "framebuffer.h"
-
-/* This is a table driven implemetation of the glGet*v() functions.
- * The basic idea is that most getters just look up an int somewhere
- * in struct gl_context and then convert it to a bool or float according to
- * which of glGetIntegerv() glGetBooleanv() etc is being called.
- * Instead of generating code to do this, we can just record the enum
- * value and the offset into struct gl_context in an array of structs. Then
- * in glGet*(), we lookup the struct for the enum in question, and use
- * the offset to get the int we need.
- *
- * Sometimes we need to look up a float, a boolean, a bit in a
- * bitfield, a matrix or other types instead, so we need to track the
- * type of the value in struct gl_context. And sometimes the value isn't in
- * struct gl_context but in the drawbuffer, the array object, current texture
- * unit, or maybe it's a computed value. So we need to also track
- * where or how to find the value. Finally, we sometimes need to
- * check that one of a number of extensions are enabled, the GL
- * version or flush or call _mesa_update_state(). This is done by
- * attaching optional extra information to the value description
- * struct, it's sort of like an array of opcodes that describe extra
- * checks or actions.
- *
- * Putting all this together we end up with struct value_desc below,
- * and with a couple of macros to help, the table of struct value_desc
- * is about as concise as the specification in the old python script.
- */
-
-#undef CONST
-
-#define FLOAT_TO_BOOLEAN(X) ( (X) ? GL_TRUE : GL_FALSE )
-#define FLOAT_TO_FIXED(F) ( ((F) * 65536.0f > INT_MAX) ? INT_MAX : \
- ((F) * 65536.0f < INT_MIN) ? INT_MIN : \
- (GLint) ((F) * 65536.0f) )
-
-#define INT_TO_BOOLEAN(I) ( (I) ? GL_TRUE : GL_FALSE )
-#define INT_TO_FIXED(I) ( ((I) > SHRT_MAX) ? INT_MAX : \
- ((I) < SHRT_MIN) ? INT_MIN : \
- (GLint) ((I) * 65536) )
-
-#define INT64_TO_BOOLEAN(I) ( (I) ? GL_TRUE : GL_FALSE )
-#define INT64_TO_INT(I) ( (GLint)((I > INT_MAX) ? INT_MAX : ((I < INT_MIN) ? INT_MIN : (I))) )
-
-#define BOOLEAN_TO_INT(B) ( (GLint) (B) )
-#define BOOLEAN_TO_INT64(B) ( (GLint64) (B) )
-#define BOOLEAN_TO_FLOAT(B) ( (B) ? 1.0F : 0.0F )
-#define BOOLEAN_TO_FIXED(B) ( (GLint) ((B) ? 1 : 0) << 16 )
-
-#define ENUM_TO_INT64(E) ( (GLint64) (E) )
-#define ENUM_TO_FIXED(E) (E)
-
-enum value_type {
- TYPE_INVALID,
- TYPE_API_MASK,
- TYPE_INT,
- TYPE_INT_2,
- TYPE_INT_3,
- TYPE_INT_4,
- TYPE_INT_N,
- TYPE_INT64,
- TYPE_ENUM,
- TYPE_ENUM_2,
- TYPE_BOOLEAN,
- TYPE_BIT_0,
- TYPE_BIT_1,
- TYPE_BIT_2,
- TYPE_BIT_3,
- TYPE_BIT_4,
- TYPE_BIT_5,
- TYPE_FLOAT,
- TYPE_FLOAT_2,
- TYPE_FLOAT_3,
- TYPE_FLOAT_4,
- TYPE_FLOATN,
- TYPE_FLOATN_2,
- TYPE_FLOATN_3,
- TYPE_FLOATN_4,
- TYPE_DOUBLEN,
- TYPE_MATRIX,
- TYPE_MATRIX_T,
- TYPE_CONST
-};
-
-enum value_location {
- LOC_BUFFER,
- LOC_CONTEXT,
- LOC_ARRAY,
- LOC_TEXUNIT,
- LOC_CUSTOM
-};
-
-enum value_extra {
- EXTRA_END = 0x8000,
- EXTRA_VERSION_30,
- EXTRA_VERSION_31,
- EXTRA_VERSION_32,
- EXTRA_VERSION_ES2,
- EXTRA_NEW_BUFFERS,
- EXTRA_VALID_DRAW_BUFFER,
- EXTRA_VALID_TEXTURE_UNIT,
- EXTRA_FLUSH_CURRENT,
-};
-
-#define NO_EXTRA NULL
-#define NO_OFFSET 0
-
-struct value_desc {
- GLenum pname;
- GLubyte location; /**< enum value_location */
- GLubyte type; /**< enum value_type */
- int offset;
- const int *extra;
-};
-
-union value {
- GLfloat value_float;
- GLfloat value_float_4[4];
- GLmatrix *value_matrix;
- GLint value_int;
- GLint value_int_4[4];
- GLint64 value_int64;
- GLenum value_enum;
-
- /* Sigh, see GL_COMPRESSED_TEXTURE_FORMATS_ARB handling */
- struct {
- GLint n, ints[100];
- } value_int_n;
- GLboolean value_bool;
-};
-
-#define BUFFER_FIELD(field, type) \
- LOC_BUFFER, type, offsetof(struct gl_framebuffer, field)
-#define CONTEXT_FIELD(field, type) \
- LOC_CONTEXT, type, offsetof(struct gl_context, field)
-#define ARRAY_FIELD(field, type) \
- LOC_ARRAY, type, offsetof(struct gl_array_object, field)
-#define CONST(value) \
- LOC_CONTEXT, TYPE_CONST, value
-
-#define BUFFER_INT(field) BUFFER_FIELD(field, TYPE_INT)
-#define BUFFER_ENUM(field) BUFFER_FIELD(field, TYPE_ENUM)
-#define BUFFER_BOOL(field) BUFFER_FIELD(field, TYPE_BOOLEAN)
-
-#define CONTEXT_INT(field) CONTEXT_FIELD(field, TYPE_INT)
-#define CONTEXT_INT2(field) CONTEXT_FIELD(field, TYPE_INT_2)
-#define CONTEXT_INT64(field) CONTEXT_FIELD(field, TYPE_INT64)
-#define CONTEXT_ENUM(field) CONTEXT_FIELD(field, TYPE_ENUM)
-#define CONTEXT_ENUM2(field) CONTEXT_FIELD(field, TYPE_ENUM_2)
-#define CONTEXT_BOOL(field) CONTEXT_FIELD(field, TYPE_BOOLEAN)
-#define CONTEXT_BIT0(field) CONTEXT_FIELD(field, TYPE_BIT_0)
-#define CONTEXT_BIT1(field) CONTEXT_FIELD(field, TYPE_BIT_1)
-#define CONTEXT_BIT2(field) CONTEXT_FIELD(field, TYPE_BIT_2)
-#define CONTEXT_BIT3(field) CONTEXT_FIELD(field, TYPE_BIT_3)
-#define CONTEXT_BIT4(field) CONTEXT_FIELD(field, TYPE_BIT_4)
-#define CONTEXT_BIT5(field) CONTEXT_FIELD(field, TYPE_BIT_5)
-#define CONTEXT_FLOAT(field) CONTEXT_FIELD(field, TYPE_FLOAT)
-#define CONTEXT_FLOAT2(field) CONTEXT_FIELD(field, TYPE_FLOAT_2)
-#define CONTEXT_FLOAT3(field) CONTEXT_FIELD(field, TYPE_FLOAT_3)
-#define CONTEXT_FLOAT4(field) CONTEXT_FIELD(field, TYPE_FLOAT_4)
-#define CONTEXT_MATRIX(field) CONTEXT_FIELD(field, TYPE_MATRIX)
-#define CONTEXT_MATRIX_T(field) CONTEXT_FIELD(field, TYPE_MATRIX_T)
-
-#define ARRAY_INT(field) ARRAY_FIELD(field, TYPE_INT)
-#define ARRAY_ENUM(field) ARRAY_FIELD(field, TYPE_ENUM)
-#define ARRAY_BOOL(field) ARRAY_FIELD(field, TYPE_BOOLEAN)
-
-#define EXT(f) \
- offsetof(struct gl_extensions, f)
-
-#define EXTRA_EXT(e) \
- static const int extra_##e[] = { \
- EXT(e), EXTRA_END \
- }
-
-#define EXTRA_EXT2(e1, e2) \
- static const int extra_##e1##_##e2[] = { \
- EXT(e1), EXT(e2), EXTRA_END \
- }
-
-/* The 'extra' mechanism is a way to specify extra checks (such as
- * extensions or specific gl versions) or actions (flush current, new
- * buffers) that we need to do before looking up an enum. We need to
- * declare them all up front so we can refer to them in the value_desc
- * structs below. */
-
-static const int extra_new_buffers[] = {
- EXTRA_NEW_BUFFERS,
- EXTRA_END
-};
-
-static const int extra_valid_draw_buffer[] = {
- EXTRA_VALID_DRAW_BUFFER,
- EXTRA_END
-};
-
-static const int extra_valid_texture_unit[] = {
- EXTRA_VALID_TEXTURE_UNIT,
- EXTRA_END
-};
-
-static const int extra_flush_current_valid_texture_unit[] = {
- EXTRA_FLUSH_CURRENT,
- EXTRA_VALID_TEXTURE_UNIT,
- EXTRA_END
-};
-
-static const int extra_flush_current[] = {
- EXTRA_FLUSH_CURRENT,
- EXTRA_END
-};
-
-static const int extra_new_buffers_OES_read_format[] = {
- EXTRA_NEW_BUFFERS,
- EXT(OES_read_format),
- EXTRA_END
-};
-
-static const int extra_EXT_secondary_color_flush_current[] = {
- EXT(EXT_secondary_color),
- EXTRA_FLUSH_CURRENT,
- EXTRA_END
-};
-
-static const int extra_EXT_fog_coord_flush_current[] = {
- EXT(EXT_fog_coord),
- EXTRA_FLUSH_CURRENT,
- EXTRA_END
-};
-
-static const int extra_EXT_texture_integer[] = {
- EXT(EXT_texture_integer),
- EXTRA_END
-};
-
-static const int extra_EXT_gpu_shader4[] = {
- EXT(EXT_gpu_shader4),
- EXTRA_END
-};
-
-
-EXTRA_EXT(ARB_ES2_compatibility);
-EXTRA_EXT(ARB_multitexture);
-EXTRA_EXT(ARB_texture_cube_map);
-EXTRA_EXT(MESA_texture_array);
-EXTRA_EXT2(EXT_secondary_color, ARB_vertex_program);
-EXTRA_EXT(EXT_secondary_color);
-EXTRA_EXT(EXT_fog_coord);
-EXTRA_EXT(EXT_texture_lod_bias);
-EXTRA_EXT(EXT_texture_filter_anisotropic);
-EXTRA_EXT(IBM_rasterpos_clip);
-EXTRA_EXT(NV_point_sprite);
-EXTRA_EXT(SGIS_generate_mipmap);
-EXTRA_EXT(NV_vertex_program);
-EXTRA_EXT(NV_fragment_program);
-EXTRA_EXT(NV_texture_rectangle);
-EXTRA_EXT(EXT_stencil_two_side);
-EXTRA_EXT(NV_light_max_exponent);
-EXTRA_EXT(SGI_texture_color_table);
-EXTRA_EXT(EXT_depth_bounds_test);
-EXTRA_EXT(ARB_depth_clamp);
-EXTRA_EXT(ATI_fragment_shader);
-EXTRA_EXT(EXT_framebuffer_blit);
-EXTRA_EXT(ARB_shader_objects);
-EXTRA_EXT(EXT_provoking_vertex);
-EXTRA_EXT(ARB_fragment_shader);
-EXTRA_EXT(ARB_fragment_program);
-EXTRA_EXT2(ARB_framebuffer_object, EXT_framebuffer_multisample);
-EXTRA_EXT(EXT_framebuffer_object);
-EXTRA_EXT(APPLE_vertex_array_object);
-EXTRA_EXT(ARB_seamless_cube_map);
-EXTRA_EXT(EXT_compiled_vertex_array);
-EXTRA_EXT(ARB_sync);
-EXTRA_EXT(ARB_vertex_shader);
-EXTRA_EXT(EXT_transform_feedback);
-EXTRA_EXT(ARB_transform_feedback2);
-EXTRA_EXT(EXT_pixel_buffer_object);
-EXTRA_EXT(ARB_vertex_program);
-EXTRA_EXT2(NV_point_sprite, ARB_point_sprite);
-EXTRA_EXT2(ARB_fragment_program, NV_fragment_program);
-EXTRA_EXT2(ARB_vertex_program, NV_vertex_program);
-EXTRA_EXT2(ARB_vertex_program, ARB_fragment_program);
-EXTRA_EXT(ARB_vertex_buffer_object);
-EXTRA_EXT(ARB_geometry_shader4);
-EXTRA_EXT(ARB_copy_buffer);
-EXTRA_EXT(EXT_framebuffer_sRGB);
-
-static const int
-extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program[] = {
- EXT(ARB_vertex_program),
- EXT(ARB_fragment_program),
- EXT(NV_vertex_program),
- EXTRA_END
-};
-
-static const int
-extra_NV_vertex_program_ARB_vertex_program_ARB_fragment_program_NV_vertex_program[] = {
- EXT(NV_vertex_program),
- EXT(ARB_vertex_program),
- EXT(ARB_fragment_program),
- EXT(NV_vertex_program),
- EXTRA_END
-};
-
-static const int
-extra_NV_primitive_restart[] = {
- EXT(NV_primitive_restart),
- EXTRA_END
-};
-
-static const int extra_version_30[] = { EXTRA_VERSION_30, EXTRA_END };
-static const int extra_version_31[] = { EXTRA_VERSION_31, EXTRA_END };
-static const int extra_version_32[] = { EXTRA_VERSION_32, EXTRA_END };
-
-static const int
-extra_ARB_vertex_program_version_es2[] = {
- EXT(ARB_vertex_program),
- EXTRA_VERSION_ES2,
- EXTRA_END
-};
-
-#define API_OPENGL_BIT (1 << API_OPENGL)
-#define API_OPENGLES_BIT (1 << API_OPENGLES)
-#define API_OPENGLES2_BIT (1 << API_OPENGLES2)
-
-/* This is the big table describing all the enums we accept in
- * glGet*v(). The table is partitioned into six parts: enums
- * understood by all GL APIs (OpenGL, GLES and GLES2), enums shared
- * between OpenGL and GLES, enums exclusive to GLES, etc for the
- * remaining combinations. When we add the enums to the hash table in
- * _mesa_init_get_hash(), we only add the enums for the API we're
- * instantiating and the different sections are guarded by #if
- * FEATURE_GL etc to make sure we only compile in the enums we may
- * need. */
-
-static const struct value_desc values[] = {
- /* Enums shared between OpenGL, GLES1 and GLES2 */
- { 0, 0, TYPE_API_MASK,
- API_OPENGL_BIT | API_OPENGLES_BIT | API_OPENGLES2_BIT, NO_EXTRA},
- { GL_ALPHA_BITS, BUFFER_INT(Visual.alphaBits), extra_new_buffers },
- { GL_BLEND, CONTEXT_BIT0(Color.BlendEnabled), NO_EXTRA },
- { GL_BLEND_SRC, CONTEXT_ENUM(Color.Blend[0].SrcRGB), NO_EXTRA },
- { GL_BLUE_BITS, BUFFER_INT(Visual.blueBits), extra_new_buffers },
- { GL_COLOR_CLEAR_VALUE, CONTEXT_FIELD(Color.ClearColor[0], TYPE_FLOATN_4), NO_EXTRA },
- { GL_COLOR_WRITEMASK, LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA },
- { GL_CULL_FACE, CONTEXT_BOOL(Polygon.CullFlag), NO_EXTRA },
- { GL_CULL_FACE_MODE, CONTEXT_ENUM(Polygon.CullFaceMode), NO_EXTRA },
- { GL_DEPTH_BITS, BUFFER_INT(Visual.depthBits), NO_EXTRA },
- { GL_DEPTH_CLEAR_VALUE, CONTEXT_FIELD(Depth.Clear, TYPE_DOUBLEN), NO_EXTRA },
- { GL_DEPTH_FUNC, CONTEXT_ENUM(Depth.Func), NO_EXTRA },
- { GL_DEPTH_RANGE, CONTEXT_FIELD(Viewport.Near, TYPE_FLOATN_2), NO_EXTRA },
- { GL_DEPTH_TEST, CONTEXT_BOOL(Depth.Test), NO_EXTRA },
- { GL_DEPTH_WRITEMASK, CONTEXT_BOOL(Depth.Mask), NO_EXTRA },
- { GL_DITHER, CONTEXT_BOOL(Color.DitherFlag), NO_EXTRA },
- { GL_FRONT_FACE, CONTEXT_ENUM(Polygon.FrontFace), NO_EXTRA },
- { GL_GREEN_BITS, BUFFER_INT(Visual.greenBits), extra_new_buffers },
- { GL_LINE_WIDTH, CONTEXT_FLOAT(Line.Width), NO_EXTRA },
- { GL_ALIASED_LINE_WIDTH_RANGE, CONTEXT_FLOAT2(Const.MinLineWidth), NO_EXTRA },
- { GL_MAX_ELEMENTS_VERTICES, CONTEXT_INT(Const.MaxArrayLockSize), NO_EXTRA },
- { GL_MAX_ELEMENTS_INDICES, CONTEXT_INT(Const.MaxArrayLockSize), NO_EXTRA },
- { GL_MAX_TEXTURE_SIZE, LOC_CUSTOM, TYPE_INT,
- offsetof(struct gl_context, Const.MaxTextureLevels), NO_EXTRA },
- { GL_MAX_VIEWPORT_DIMS, CONTEXT_INT2(Const.MaxViewportWidth), NO_EXTRA },
- { GL_PACK_ALIGNMENT, CONTEXT_INT(Pack.Alignment), NO_EXTRA },
- { GL_ALIASED_POINT_SIZE_RANGE, CONTEXT_FLOAT2(Const.MinPointSize), NO_EXTRA },
- { GL_POLYGON_OFFSET_FACTOR, CONTEXT_FLOAT(Polygon.OffsetFactor ), NO_EXTRA },
- { GL_POLYGON_OFFSET_UNITS, CONTEXT_FLOAT(Polygon.OffsetUnits ), NO_EXTRA },
- { GL_POLYGON_OFFSET_FILL, CONTEXT_BOOL(Polygon.OffsetFill), NO_EXTRA },
- { GL_RED_BITS, BUFFER_INT(Visual.redBits), extra_new_buffers },
- { GL_SCISSOR_BOX, LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA },
- { GL_SCISSOR_TEST, CONTEXT_BOOL(Scissor.Enabled), NO_EXTRA },
- { GL_STENCIL_BITS, BUFFER_INT(Visual.stencilBits), NO_EXTRA },
- { GL_STENCIL_CLEAR_VALUE, CONTEXT_INT(Stencil.Clear), NO_EXTRA },
- { GL_STENCIL_FAIL, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA },
- { GL_STENCIL_FUNC, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA },
- { GL_STENCIL_PASS_DEPTH_FAIL, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA },
- { GL_STENCIL_PASS_DEPTH_PASS, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA },
- { GL_STENCIL_REF, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA },
- { GL_STENCIL_TEST, CONTEXT_BOOL(Stencil.Enabled), NO_EXTRA },
- { GL_STENCIL_VALUE_MASK, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA },
- { GL_STENCIL_WRITEMASK, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA },
- { GL_SUBPIXEL_BITS, CONTEXT_INT(Const.SubPixelBits), NO_EXTRA },
- { GL_TEXTURE_BINDING_2D, LOC_CUSTOM, TYPE_INT, TEXTURE_2D_INDEX, NO_EXTRA },
- { GL_UNPACK_ALIGNMENT, CONTEXT_INT(Unpack.Alignment), NO_EXTRA },
- { GL_VIEWPORT, LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA },
-
- /* GL_ARB_multitexture */
- { GL_ACTIVE_TEXTURE_ARB,
- LOC_CUSTOM, TYPE_INT, 0, extra_ARB_multitexture },
-
- /* Note that all the OES_* extensions require that the Mesa "struct
- * gl_extensions" include a member with the name of the extension.
- * That structure does not yet include OES extensions (and we're
- * not sure whether it will). If it does, all the OES_*
- * extensions below should mark the dependency. */
-
- /* GL_ARB_texture_cube_map */
- { GL_TEXTURE_BINDING_CUBE_MAP_ARB, LOC_CUSTOM, TYPE_INT,
- TEXTURE_CUBE_INDEX, extra_ARB_texture_cube_map },
- { GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, LOC_CUSTOM, TYPE_INT,
- offsetof(struct gl_context, Const.MaxCubeTextureLevels),
- extra_ARB_texture_cube_map }, /* XXX: OES_texture_cube_map */
-
- /* XXX: OES_blend_subtract */
- { GL_BLEND_SRC_RGB_EXT, CONTEXT_ENUM(Color.Blend[0].SrcRGB), NO_EXTRA },
- { GL_BLEND_DST_RGB_EXT, CONTEXT_ENUM(Color.Blend[0].DstRGB), NO_EXTRA },
- { GL_BLEND_SRC_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].SrcA), NO_EXTRA },
- { GL_BLEND_DST_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].DstA), NO_EXTRA },
-
- /* GL_BLEND_EQUATION_RGB, which is what we're really after, is
- * defined identically to GL_BLEND_EQUATION. */
- { GL_BLEND_EQUATION, CONTEXT_ENUM(Color.Blend[0].EquationRGB), NO_EXTRA },
- { GL_BLEND_EQUATION_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].EquationA), NO_EXTRA },
-
- /* GL_ARB_texture_compression */
- { GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA },
- { GL_COMPRESSED_TEXTURE_FORMATS_ARB, LOC_CUSTOM, TYPE_INT_N, 0, NO_EXTRA },
-
- /* GL_ARB_multisample */
- { GL_SAMPLE_ALPHA_TO_COVERAGE_ARB,
- CONTEXT_BOOL(Multisample.SampleAlphaToCoverage), NO_EXTRA },
- { GL_SAMPLE_COVERAGE_ARB, CONTEXT_BOOL(Multisample.SampleCoverage), NO_EXTRA },
- { GL_SAMPLE_COVERAGE_VALUE_ARB,
- CONTEXT_FLOAT(Multisample.SampleCoverageValue), NO_EXTRA },
- { GL_SAMPLE_COVERAGE_INVERT_ARB,
- CONTEXT_BOOL(Multisample.SampleCoverageInvert), NO_EXTRA },
- { GL_SAMPLE_BUFFERS_ARB, BUFFER_INT(Visual.sampleBuffers), NO_EXTRA },
- { GL_SAMPLES_ARB, BUFFER_INT(Visual.samples), NO_EXTRA },
-
- /* GL_SGIS_generate_mipmap */
- { GL_GENERATE_MIPMAP_HINT_SGIS, CONTEXT_ENUM(Hint.GenerateMipmap),
- extra_SGIS_generate_mipmap },
-
- /* GL_ARB_vertex_buffer_object */
- { GL_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA },
-
- /* GL_ARB_vertex_buffer_object */
- /* GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB - not supported */
- { GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, 0,
- extra_ARB_vertex_buffer_object },
-
- /* GL_ARB_copy_buffer */
- { GL_COPY_READ_BUFFER, LOC_CUSTOM, TYPE_INT, 0, extra_ARB_copy_buffer },
- { GL_COPY_WRITE_BUFFER, LOC_CUSTOM, TYPE_INT, 0, extra_ARB_copy_buffer },
-
- /* GL_OES_read_format */
- { GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, LOC_CUSTOM, TYPE_INT, 0,
- extra_new_buffers_OES_read_format },
- { GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, LOC_CUSTOM, TYPE_INT, 0,
- extra_new_buffers_OES_read_format },
-
- /* GL_EXT_framebuffer_object */
- { GL_FRAMEBUFFER_BINDING_EXT, BUFFER_INT(Name),
- extra_EXT_framebuffer_object },
- { GL_RENDERBUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0,
- extra_EXT_framebuffer_object },
- { GL_MAX_RENDERBUFFER_SIZE_EXT, CONTEXT_INT(Const.MaxRenderbufferSize),
- extra_EXT_framebuffer_object },
-
- /* This entry isn't spec'ed for GLES 2, but is needed for Mesa's
- * GLSL: */
- { GL_MAX_CLIP_PLANES, CONTEXT_INT(Const.MaxClipPlanes), NO_EXTRA },
-
-#if FEATURE_GL || FEATURE_ES1
- /* Enums in OpenGL and GLES1 */
- { 0, 0, TYPE_API_MASK, API_OPENGL_BIT | API_OPENGLES_BIT, NO_EXTRA },
- { GL_LIGHT0, CONTEXT_BOOL(Light.Light[0].Enabled), NO_EXTRA },
- { GL_LIGHT1, CONTEXT_BOOL(Light.Light[1].Enabled), NO_EXTRA },
- { GL_LIGHT2, CONTEXT_BOOL(Light.Light[2].Enabled), NO_EXTRA },
- { GL_LIGHT3, CONTEXT_BOOL(Light.Light[3].Enabled), NO_EXTRA },
- { GL_LIGHT4, CONTEXT_BOOL(Light.Light[4].Enabled), NO_EXTRA },
- { GL_LIGHT5, CONTEXT_BOOL(Light.Light[5].Enabled), NO_EXTRA },
- { GL_LIGHT6, CONTEXT_BOOL(Light.Light[6].Enabled), NO_EXTRA },
- { GL_LIGHT7, CONTEXT_BOOL(Light.Light[7].Enabled), NO_EXTRA },
- { GL_LIGHTING, CONTEXT_BOOL(Light.Enabled), NO_EXTRA },
- { GL_LIGHT_MODEL_AMBIENT,
- CONTEXT_FIELD(Light.Model.Ambient[0], TYPE_FLOATN_4), NO_EXTRA },
- { GL_LIGHT_MODEL_TWO_SIDE, CONTEXT_BOOL(Light.Model.TwoSide), NO_EXTRA },
- { GL_ALPHA_TEST, CONTEXT_BOOL(Color.AlphaEnabled), NO_EXTRA },
- { GL_ALPHA_TEST_FUNC, CONTEXT_ENUM(Color.AlphaFunc), NO_EXTRA },
- { GL_ALPHA_TEST_REF, CONTEXT_FIELD(Color.AlphaRef, TYPE_FLOATN), NO_EXTRA },
- { GL_BLEND_DST, CONTEXT_ENUM(Color.Blend[0].DstRGB), NO_EXTRA },
- { GL_CLIP_PLANE0, CONTEXT_BIT0(Transform.ClipPlanesEnabled), NO_EXTRA },
- { GL_CLIP_PLANE1, CONTEXT_BIT1(Transform.ClipPlanesEnabled), NO_EXTRA },
- { GL_CLIP_PLANE2, CONTEXT_BIT2(Transform.ClipPlanesEnabled), NO_EXTRA },
- { GL_CLIP_PLANE3, CONTEXT_BIT3(Transform.ClipPlanesEnabled), NO_EXTRA },
- { GL_CLIP_PLANE4, CONTEXT_BIT4(Transform.ClipPlanesEnabled), NO_EXTRA },
- { GL_CLIP_PLANE5, CONTEXT_BIT5(Transform.ClipPlanesEnabled), NO_EXTRA },
- { GL_COLOR_MATERIAL, CONTEXT_BOOL(Light.ColorMaterialEnabled), NO_EXTRA },
- { GL_CURRENT_COLOR,
- CONTEXT_FIELD(Current.Attrib[VERT_ATTRIB_COLOR0][0], TYPE_FLOATN_4),
- extra_flush_current },
- { GL_CURRENT_NORMAL,
- CONTEXT_FIELD(Current.Attrib[VERT_ATTRIB_NORMAL][0], TYPE_FLOATN_3),
- extra_flush_current },
- { GL_CURRENT_TEXTURE_COORDS, LOC_CUSTOM, TYPE_FLOAT_4, 0,
- extra_flush_current_valid_texture_unit },
- { GL_DISTANCE_ATTENUATION_EXT, CONTEXT_FLOAT3(Point.Params[0]), NO_EXTRA },
- { GL_FOG, CONTEXT_BOOL(Fog.Enabled), NO_EXTRA },
- { GL_FOG_COLOR, CONTEXT_FIELD(Fog.Color[0], TYPE_FLOATN_4), NO_EXTRA },
- { GL_FOG_DENSITY, CONTEXT_FLOAT(Fog.Density), NO_EXTRA },
- { GL_FOG_END, CONTEXT_FLOAT(Fog.End), NO_EXTRA },
- { GL_FOG_HINT, CONTEXT_ENUM(Hint.Fog), NO_EXTRA },
- { GL_FOG_MODE, CONTEXT_ENUM(Fog.Mode), NO_EXTRA },
- { GL_FOG_START, CONTEXT_FLOAT(Fog.Start), NO_EXTRA },
- { GL_LINE_SMOOTH, CONTEXT_BOOL(Line.SmoothFlag), NO_EXTRA },
- { GL_LINE_SMOOTH_HINT, CONTEXT_ENUM(Hint.LineSmooth), NO_EXTRA },
- { GL_LINE_WIDTH_RANGE, CONTEXT_FLOAT2(Const.MinLineWidthAA), NO_EXTRA },
- { GL_COLOR_LOGIC_OP, CONTEXT_BOOL(Color.ColorLogicOpEnabled), NO_EXTRA },
- { GL_LOGIC_OP_MODE, CONTEXT_ENUM(Color.LogicOp), NO_EXTRA },
- { GL_MATRIX_MODE, CONTEXT_ENUM(Transform.MatrixMode), NO_EXTRA },
- { GL_MAX_MODELVIEW_STACK_DEPTH, CONST(MAX_MODELVIEW_STACK_DEPTH), NO_EXTRA },
- { GL_MAX_PROJECTION_STACK_DEPTH, CONST(MAX_PROJECTION_STACK_DEPTH), NO_EXTRA },
- { GL_MAX_TEXTURE_STACK_DEPTH, CONST(MAX_TEXTURE_STACK_DEPTH), NO_EXTRA },
- { GL_MODELVIEW_MATRIX, CONTEXT_MATRIX(ModelviewMatrixStack.Top), NO_EXTRA },
- { GL_MODELVIEW_STACK_DEPTH, LOC_CUSTOM, TYPE_INT,
- offsetof(struct gl_context, ModelviewMatrixStack.Depth), NO_EXTRA },
- { GL_NORMALIZE, CONTEXT_BOOL(Transform.Normalize), NO_EXTRA },
- { GL_PACK_SKIP_IMAGES_EXT, CONTEXT_INT(Pack.SkipImages), NO_EXTRA },
- { GL_PERSPECTIVE_CORRECTION_HINT, CONTEXT_ENUM(Hint.PerspectiveCorrection), NO_EXTRA },
- { GL_POINT_SIZE, CONTEXT_FLOAT(Point.Size), NO_EXTRA },
- { GL_POINT_SIZE_RANGE, CONTEXT_FLOAT2(Const.MinPointSizeAA), NO_EXTRA },
- { GL_POINT_SMOOTH, CONTEXT_BOOL(Point.SmoothFlag), NO_EXTRA },
- { GL_POINT_SMOOTH_HINT, CONTEXT_ENUM(Hint.PointSmooth), NO_EXTRA },
- { GL_POINT_SIZE_MIN_EXT, CONTEXT_FLOAT(Point.MinSize), NO_EXTRA },
- { GL_POINT_SIZE_MAX_EXT, CONTEXT_FLOAT(Point.MaxSize), NO_EXTRA },
- { GL_POINT_FADE_THRESHOLD_SIZE_EXT, CONTEXT_FLOAT(Point.Threshold), NO_EXTRA },
- { GL_PROJECTION_MATRIX, CONTEXT_MATRIX(ProjectionMatrixStack.Top), NO_EXTRA },
- { GL_PROJECTION_STACK_DEPTH, LOC_CUSTOM, TYPE_INT,
- offsetof(struct gl_context, ProjectionMatrixStack.Depth), NO_EXTRA },
- { GL_RESCALE_NORMAL, CONTEXT_BOOL(Transform.RescaleNormals), NO_EXTRA },
- { GL_SHADE_MODEL, CONTEXT_ENUM(Light.ShadeModel), NO_EXTRA },
- { GL_TEXTURE_2D, LOC_CUSTOM, TYPE_BOOLEAN, 0, NO_EXTRA },
- { GL_TEXTURE_MATRIX, LOC_CUSTOM, TYPE_MATRIX, 0, extra_valid_texture_unit },
- { GL_TEXTURE_STACK_DEPTH, LOC_CUSTOM, TYPE_INT, 0,
- extra_valid_texture_unit },
-
- { GL_VERTEX_ARRAY, ARRAY_BOOL(Vertex.Enabled), NO_EXTRA },
- { GL_VERTEX_ARRAY_SIZE, ARRAY_INT(Vertex.Size), NO_EXTRA },
- { GL_VERTEX_ARRAY_TYPE, ARRAY_ENUM(Vertex.Type), NO_EXTRA },
- { GL_VERTEX_ARRAY_STRIDE, ARRAY_INT(Vertex.Stride), NO_EXTRA },
- { GL_NORMAL_ARRAY, ARRAY_ENUM(Normal.Enabled), NO_EXTRA },
- { GL_NORMAL_ARRAY_TYPE, ARRAY_ENUM(Normal.Type), NO_EXTRA },
- { GL_NORMAL_ARRAY_STRIDE, ARRAY_INT(Normal.Stride), NO_EXTRA },
- { GL_COLOR_ARRAY, ARRAY_BOOL(Color.Enabled), NO_EXTRA },
- { GL_COLOR_ARRAY_SIZE, ARRAY_INT(Color.Size), NO_EXTRA },
- { GL_COLOR_ARRAY_TYPE, ARRAY_ENUM(Color.Type), NO_EXTRA },
- { GL_COLOR_ARRAY_STRIDE, ARRAY_INT(Color.Stride), NO_EXTRA },
- { GL_TEXTURE_COORD_ARRAY,
- LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Enabled), NO_EXTRA },
- { GL_TEXTURE_COORD_ARRAY_SIZE,
- LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Size), NO_EXTRA },
- { GL_TEXTURE_COORD_ARRAY_TYPE,
- LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Type), NO_EXTRA },
- { GL_TEXTURE_COORD_ARRAY_STRIDE,
- LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Stride), NO_EXTRA },
-
- /* GL_ARB_ES2_compatibility */
- { GL_SHADER_COMPILER, CONST(1), extra_ARB_ES2_compatibility },
- { GL_MAX_VARYING_VECTORS, CONTEXT_INT(Const.MaxVarying),
- extra_ARB_ES2_compatibility },
- { GL_MAX_VERTEX_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0,
- extra_ARB_ES2_compatibility },
- { GL_MAX_FRAGMENT_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0,
- extra_ARB_ES2_compatibility },
-
- /* GL_ARB_multitexture */
- { GL_MAX_TEXTURE_UNITS_ARB,
- CONTEXT_INT(Const.MaxTextureUnits), extra_ARB_multitexture },
- { GL_CLIENT_ACTIVE_TEXTURE_ARB,
- LOC_CUSTOM, TYPE_INT, 0, extra_ARB_multitexture },
-
- /* GL_ARB_texture_cube_map */
- { GL_TEXTURE_CUBE_MAP_ARB, LOC_CUSTOM, TYPE_BOOLEAN, 0, NO_EXTRA },
- /* S, T, and R are always set at the same time */
- { GL_TEXTURE_GEN_STR_OES, LOC_TEXUNIT, TYPE_BIT_0,
- offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA },
-
- /* GL_ARB_multisample */
- { GL_MULTISAMPLE_ARB, CONTEXT_BOOL(Multisample.Enabled), NO_EXTRA },
- { GL_SAMPLE_ALPHA_TO_ONE_ARB, CONTEXT_BOOL(Multisample.SampleAlphaToOne), NO_EXTRA },
-
- /* GL_ARB_vertex_buffer_object */
- { GL_VERTEX_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT,
- offsetof(struct gl_array_object, Vertex.BufferObj), NO_EXTRA },
- { GL_NORMAL_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT,
- offsetof(struct gl_array_object, Normal.BufferObj), NO_EXTRA },
- { GL_COLOR_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT,
- offsetof(struct gl_array_object, Color.BufferObj), NO_EXTRA },
- { GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA },
-
- /* GL_OES_point_sprite */
- { GL_POINT_SPRITE_NV,
- CONTEXT_BOOL(Point.PointSprite),
- extra_NV_point_sprite_ARB_point_sprite },
-
- /* GL_ARB_fragment_shader */
- { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB,
- CONTEXT_INT(Const.FragmentProgram.MaxUniformComponents),
- extra_ARB_fragment_shader },
-
- /* GL_ARB_vertex_shader */
- { GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB,
- CONTEXT_INT(Const.VertexProgram.MaxUniformComponents),
- extra_ARB_vertex_shader },
- { GL_MAX_VARYING_FLOATS_ARB, LOC_CUSTOM, TYPE_INT, 0,
- extra_ARB_vertex_shader },
-
- /* GL_EXT_texture_lod_bias */
- { GL_MAX_TEXTURE_LOD_BIAS_EXT, CONTEXT_FLOAT(Const.MaxTextureLodBias),
- extra_EXT_texture_lod_bias },
-
- /* GL_EXT_texture_filter_anisotropic */
- { GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,
- CONTEXT_FLOAT(Const.MaxTextureMaxAnisotropy),
- extra_EXT_texture_filter_anisotropic },
-#endif /* FEATURE_GL || FEATURE_ES1 */
-
-#if FEATURE_ES1
- { 0, 0, TYPE_API_MASK, API_OPENGLES_BIT },
- /* XXX: OES_matrix_get */
- { GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES },
- { GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES },
- { GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES },
-
- /* OES_point_size_array */
- { GL_POINT_SIZE_ARRAY_OES, ARRAY_FIELD(PointSize.Enabled, TYPE_BOOLEAN) },
- { GL_POINT_SIZE_ARRAY_TYPE_OES, ARRAY_FIELD(PointSize.Type, TYPE_ENUM) },
- { GL_POINT_SIZE_ARRAY_STRIDE_OES, ARRAY_FIELD(PointSize.Stride, TYPE_INT) },
- { GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES, LOC_CUSTOM, TYPE_INT, 0 },
-#endif /* FEATURE_ES1 */
-
-#if FEATURE_GL || FEATURE_ES2
- { 0, 0, TYPE_API_MASK, API_OPENGL_BIT | API_OPENGLES2_BIT, NO_EXTRA },
- /* This entry isn't spec'ed for GLES 2, but is needed for Mesa's GLSL: */
- { GL_MAX_LIGHTS, CONTEXT_INT(Const.MaxLights), NO_EXTRA },
- { GL_MAX_TEXTURE_COORDS_ARB, /* == GL_MAX_TEXTURE_COORDS_NV */
- CONTEXT_INT(Const.MaxTextureCoordUnits),
- extra_ARB_fragment_program_NV_fragment_program },
-
- /* GL_ARB_draw_buffers */
- { GL_MAX_DRAW_BUFFERS_ARB, CONTEXT_INT(Const.MaxDrawBuffers), NO_EXTRA },
-
- { GL_BLEND_COLOR_EXT, CONTEXT_FIELD(Color.BlendColor[0], TYPE_FLOATN_4), NO_EXTRA },
- /* GL_ARB_fragment_program */
- { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, /* == GL_MAX_TEXTURE_IMAGE_UNITS_NV */
- CONTEXT_INT(Const.MaxTextureImageUnits),
- extra_ARB_fragment_program_NV_fragment_program },
- { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB,
- CONTEXT_INT(Const.MaxVertexTextureImageUnits), extra_ARB_vertex_shader },
- { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB,
- CONTEXT_INT(Const.MaxCombinedTextureImageUnits),
- extra_ARB_vertex_shader },
-
- /* GL_ARB_shader_objects
- * Actually, this token isn't part of GL_ARB_shader_objects, but is
- * close enough for now. */
- { GL_CURRENT_PROGRAM, LOC_CUSTOM, TYPE_INT, 0, extra_ARB_shader_objects },
-
- /* OpenGL 2.0 */
- { GL_STENCIL_BACK_FUNC, CONTEXT_ENUM(Stencil.Function[1]), NO_EXTRA },
- { GL_STENCIL_BACK_VALUE_MASK, CONTEXT_INT(Stencil.ValueMask[1]), NO_EXTRA },
- { GL_STENCIL_BACK_WRITEMASK, CONTEXT_INT(Stencil.WriteMask[1]), NO_EXTRA },
- { GL_STENCIL_BACK_REF, CONTEXT_INT(Stencil.Ref[1]), NO_EXTRA },
- { GL_STENCIL_BACK_FAIL, CONTEXT_ENUM(Stencil.FailFunc[1]), NO_EXTRA },
- { GL_STENCIL_BACK_PASS_DEPTH_FAIL, CONTEXT_ENUM(Stencil.ZFailFunc[1]), NO_EXTRA },
- { GL_STENCIL_BACK_PASS_DEPTH_PASS, CONTEXT_ENUM(Stencil.ZPassFunc[1]), NO_EXTRA },
-
- { GL_MAX_VERTEX_ATTRIBS_ARB,
- CONTEXT_INT(Const.VertexProgram.MaxAttribs),
- extra_ARB_vertex_program_version_es2 },
-
- /* OES_texture_3D */
- { GL_TEXTURE_BINDING_3D, LOC_CUSTOM, TYPE_INT, TEXTURE_3D_INDEX, NO_EXTRA },
- { GL_MAX_3D_TEXTURE_SIZE, LOC_CUSTOM, TYPE_INT,
- offsetof(struct gl_context, Const.Max3DTextureLevels), NO_EXTRA },
-
- /* GL_ARB_fragment_program/OES_standard_derivatives */
- { GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB,
- CONTEXT_ENUM(Hint.FragmentShaderDerivative), extra_ARB_fragment_shader },
-#endif /* FEATURE_GL || FEATURE_ES2 */
-
-#if FEATURE_ES2
- /* Enums unique to OpenGL ES 2.0 */
- { 0, 0, TYPE_API_MASK, API_OPENGLES2_BIT, NO_EXTRA },
- { GL_MAX_FRAGMENT_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA },
- { GL_MAX_VARYING_VECTORS, CONTEXT_INT(Const.MaxVarying), NO_EXTRA },
- { GL_MAX_VERTEX_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA },
- { GL_SHADER_COMPILER, CONST(1), NO_EXTRA },
- /* OES_get_program_binary */
- { GL_NUM_SHADER_BINARY_FORMATS, CONST(0), NO_EXTRA },
- { GL_SHADER_BINARY_FORMATS, CONST(0), NO_EXTRA },
-#endif /* FEATURE_ES2 */
-
-#if FEATURE_GL
- /* Remaining enums are only in OpenGL */
- { 0, 0, TYPE_API_MASK, API_OPENGL_BIT, NO_EXTRA },
- { GL_ACCUM_RED_BITS, BUFFER_INT(Visual.accumRedBits), NO_EXTRA },
- { GL_ACCUM_GREEN_BITS, BUFFER_INT(Visual.accumGreenBits), NO_EXTRA },
- { GL_ACCUM_BLUE_BITS, BUFFER_INT(Visual.accumBlueBits), NO_EXTRA },
- { GL_ACCUM_ALPHA_BITS, BUFFER_INT(Visual.accumAlphaBits), NO_EXTRA },
- { GL_ACCUM_CLEAR_VALUE, CONTEXT_FIELD(Accum.ClearColor[0], TYPE_FLOATN_4), NO_EXTRA },
- { GL_ALPHA_BIAS, CONTEXT_FLOAT(Pixel.AlphaBias), NO_EXTRA },
- { GL_ALPHA_SCALE, CONTEXT_FLOAT(Pixel.AlphaScale), NO_EXTRA },
- { GL_ATTRIB_STACK_DEPTH, CONTEXT_INT(AttribStackDepth), NO_EXTRA },
- { GL_AUTO_NORMAL, CONTEXT_BOOL(Eval.AutoNormal), NO_EXTRA },
- { GL_AUX_BUFFERS, BUFFER_INT(Visual.numAuxBuffers), NO_EXTRA },
- { GL_BLUE_BIAS, CONTEXT_FLOAT(Pixel.BlueBias), NO_EXTRA },
- { GL_BLUE_SCALE, CONTEXT_FLOAT(Pixel.BlueScale), NO_EXTRA },
- { GL_CLIENT_ATTRIB_STACK_DEPTH, CONTEXT_INT(ClientAttribStackDepth), NO_EXTRA },
- { GL_COLOR_MATERIAL_FACE, CONTEXT_ENUM(Light.ColorMaterialFace), NO_EXTRA },
- { GL_COLOR_MATERIAL_PARAMETER, CONTEXT_ENUM(Light.ColorMaterialMode), NO_EXTRA },
- { GL_CURRENT_INDEX,
- CONTEXT_FLOAT(Current.Attrib[VERT_ATTRIB_COLOR_INDEX][0]),
- extra_flush_current },
- { GL_CURRENT_RASTER_COLOR,
- CONTEXT_FIELD(Current.RasterColor[0], TYPE_FLOATN_4), NO_EXTRA },
- { GL_CURRENT_RASTER_DISTANCE, CONTEXT_FLOAT(Current.RasterDistance), NO_EXTRA },
- { GL_CURRENT_RASTER_INDEX, CONST(1), NO_EXTRA },
- { GL_CURRENT_RASTER_POSITION, CONTEXT_FLOAT4(Current.RasterPos[0]), NO_EXTRA },
- { GL_CURRENT_RASTER_SECONDARY_COLOR,
- CONTEXT_FIELD(Current.RasterSecondaryColor[0], TYPE_FLOATN_4), NO_EXTRA },
- { GL_CURRENT_RASTER_TEXTURE_COORDS, LOC_CUSTOM, TYPE_FLOAT_4, 0,
- extra_valid_texture_unit },
- { GL_CURRENT_RASTER_POSITION_VALID, CONTEXT_BOOL(Current.RasterPosValid), NO_EXTRA },
- { GL_DEPTH_BIAS, CONTEXT_FLOAT(Pixel.DepthBias), NO_EXTRA },
- { GL_DEPTH_SCALE, CONTEXT_FLOAT(Pixel.DepthScale), NO_EXTRA },
- { GL_DOUBLEBUFFER, BUFFER_INT(Visual.doubleBufferMode), NO_EXTRA },
- { GL_DRAW_BUFFER, BUFFER_ENUM(ColorDrawBuffer[0]), NO_EXTRA },
- { GL_EDGE_FLAG, LOC_CUSTOM, TYPE_BOOLEAN, 0, NO_EXTRA },
- { GL_FEEDBACK_BUFFER_SIZE, CONTEXT_INT(Feedback.BufferSize), NO_EXTRA },
- { GL_FEEDBACK_BUFFER_TYPE, CONTEXT_ENUM(Feedback.Type), NO_EXTRA },
- { GL_FOG_INDEX, CONTEXT_FLOAT(Fog.Index), NO_EXTRA },
- { GL_GREEN_BIAS, CONTEXT_FLOAT(Pixel.GreenBias), NO_EXTRA },
- { GL_GREEN_SCALE, CONTEXT_FLOAT(Pixel.GreenScale), NO_EXTRA },
- { GL_INDEX_BITS, BUFFER_INT(Visual.indexBits), extra_new_buffers },
- { GL_INDEX_CLEAR_VALUE, CONTEXT_INT(Color.ClearIndex), NO_EXTRA },
- { GL_INDEX_MODE, CONST(0) , NO_EXTRA},
- { GL_INDEX_OFFSET, CONTEXT_INT(Pixel.IndexOffset), NO_EXTRA },
- { GL_INDEX_SHIFT, CONTEXT_INT(Pixel.IndexShift), NO_EXTRA },
- { GL_INDEX_WRITEMASK, CONTEXT_INT(Color.IndexMask), NO_EXTRA },
- { GL_LIGHT_MODEL_COLOR_CONTROL, CONTEXT_ENUM(Light.Model.ColorControl), NO_EXTRA },
- { GL_LIGHT_MODEL_LOCAL_VIEWER, CONTEXT_BOOL(Light.Model.LocalViewer), NO_EXTRA },
- { GL_LINE_STIPPLE, CONTEXT_BOOL(Line.StippleFlag), NO_EXTRA },
- { GL_LINE_STIPPLE_PATTERN, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA },
- { GL_LINE_STIPPLE_REPEAT, CONTEXT_INT(Line.StippleFactor), NO_EXTRA },
- { GL_LINE_WIDTH_GRANULARITY, CONTEXT_FLOAT(Const.LineWidthGranularity), NO_EXTRA },
- { GL_LIST_BASE, CONTEXT_INT(List.ListBase), NO_EXTRA },
- { GL_LIST_INDEX, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA },
- { GL_LIST_MODE, LOC_CUSTOM, TYPE_ENUM, 0, NO_EXTRA },
- { GL_INDEX_LOGIC_OP, CONTEXT_BOOL(Color.IndexLogicOpEnabled), NO_EXTRA },
- { GL_MAP1_COLOR_4, CONTEXT_BOOL(Eval.Map1Color4), NO_EXTRA },
- { GL_MAP1_GRID_DOMAIN, CONTEXT_FLOAT2(Eval.MapGrid1u1), NO_EXTRA },
- { GL_MAP1_GRID_SEGMENTS, CONTEXT_INT(Eval.MapGrid1un), NO_EXTRA },
- { GL_MAP1_INDEX, CONTEXT_BOOL(Eval.Map1Index), NO_EXTRA },
- { GL_MAP1_NORMAL, CONTEXT_BOOL(Eval.Map1Normal), NO_EXTRA },
- { GL_MAP1_TEXTURE_COORD_1, CONTEXT_BOOL(Eval.Map1TextureCoord1), NO_EXTRA },
- { GL_MAP1_TEXTURE_COORD_2, CONTEXT_BOOL(Eval.Map1TextureCoord2), NO_EXTRA },
- { GL_MAP1_TEXTURE_COORD_3, CONTEXT_BOOL(Eval.Map1TextureCoord3), NO_EXTRA },
- { GL_MAP1_TEXTURE_COORD_4, CONTEXT_BOOL(Eval.Map1TextureCoord4), NO_EXTRA },
- { GL_MAP1_VERTEX_3, CONTEXT_BOOL(Eval.Map1Vertex3), NO_EXTRA },
- { GL_MAP1_VERTEX_4, CONTEXT_BOOL(Eval.Map1Vertex4), NO_EXTRA },
- { GL_MAP2_COLOR_4, CONTEXT_BOOL(Eval.Map2Color4), NO_EXTRA },
- { GL_MAP2_GRID_DOMAIN, LOC_CUSTOM, TYPE_FLOAT_4, 0, NO_EXTRA },
- { GL_MAP2_GRID_SEGMENTS, CONTEXT_INT2(Eval.MapGrid2un), NO_EXTRA },
- { GL_MAP2_INDEX, CONTEXT_BOOL(Eval.Map2Index), NO_EXTRA },
- { GL_MAP2_NORMAL, CONTEXT_BOOL(Eval.Map2Normal), NO_EXTRA },
- { GL_MAP2_TEXTURE_COORD_1, CONTEXT_BOOL(Eval.Map2TextureCoord1), NO_EXTRA },
- { GL_MAP2_TEXTURE_COORD_2, CONTEXT_BOOL(Eval.Map2TextureCoord2), NO_EXTRA },
- { GL_MAP2_TEXTURE_COORD_3, CONTEXT_BOOL(Eval.Map2TextureCoord3), NO_EXTRA },
- { GL_MAP2_TEXTURE_COORD_4, CONTEXT_BOOL(Eval.Map2TextureCoord4), NO_EXTRA },
- { GL_MAP2_VERTEX_3, CONTEXT_BOOL(Eval.Map2Vertex3), NO_EXTRA },
- { GL_MAP2_VERTEX_4, CONTEXT_BOOL(Eval.Map2Vertex4), NO_EXTRA },
- { GL_MAP_COLOR, CONTEXT_BOOL(Pixel.MapColorFlag), NO_EXTRA },
- { GL_MAP_STENCIL, CONTEXT_BOOL(Pixel.MapStencilFlag), NO_EXTRA },
- { GL_MAX_ATTRIB_STACK_DEPTH, CONST(MAX_ATTRIB_STACK_DEPTH), NO_EXTRA },
- { GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, CONST(MAX_CLIENT_ATTRIB_STACK_DEPTH), NO_EXTRA },
-
- { GL_MAX_EVAL_ORDER, CONST(MAX_EVAL_ORDER), NO_EXTRA },
- { GL_MAX_LIST_NESTING, CONST(MAX_LIST_NESTING), NO_EXTRA },
- { GL_MAX_NAME_STACK_DEPTH, CONST(MAX_NAME_STACK_DEPTH), NO_EXTRA },
- { GL_MAX_PIXEL_MAP_TABLE, CONST(MAX_PIXEL_MAP_TABLE), NO_EXTRA },
- { GL_NAME_STACK_DEPTH, CONTEXT_INT(Select.NameStackDepth), NO_EXTRA },
- { GL_PACK_LSB_FIRST, CONTEXT_BOOL(Pack.LsbFirst), NO_EXTRA },
- { GL_PACK_ROW_LENGTH, CONTEXT_INT(Pack.RowLength), NO_EXTRA },
- { GL_PACK_SKIP_PIXELS, CONTEXT_INT(Pack.SkipPixels), NO_EXTRA },
- { GL_PACK_SKIP_ROWS, CONTEXT_INT(Pack.SkipRows), NO_EXTRA },
- { GL_PACK_SWAP_BYTES, CONTEXT_BOOL(Pack.SwapBytes), NO_EXTRA },
- { GL_PACK_IMAGE_HEIGHT_EXT, CONTEXT_INT(Pack.ImageHeight), NO_EXTRA },
- { GL_PACK_INVERT_MESA, CONTEXT_BOOL(Pack.Invert), NO_EXTRA },
- { GL_PIXEL_MAP_A_TO_A_SIZE, CONTEXT_INT(PixelMaps.AtoA.Size), NO_EXTRA },
- { GL_PIXEL_MAP_B_TO_B_SIZE, CONTEXT_INT(PixelMaps.BtoB.Size), NO_EXTRA },
- { GL_PIXEL_MAP_G_TO_G_SIZE, CONTEXT_INT(PixelMaps.GtoG.Size), NO_EXTRA },
- { GL_PIXEL_MAP_I_TO_A_SIZE, CONTEXT_INT(PixelMaps.ItoA.Size), NO_EXTRA },
- { GL_PIXEL_MAP_I_TO_B_SIZE, CONTEXT_INT(PixelMaps.ItoB.Size), NO_EXTRA },
- { GL_PIXEL_MAP_I_TO_G_SIZE, CONTEXT_INT(PixelMaps.ItoG.Size), NO_EXTRA },
- { GL_PIXEL_MAP_I_TO_I_SIZE, CONTEXT_INT(PixelMaps.ItoI.Size), NO_EXTRA },
- { GL_PIXEL_MAP_I_TO_R_SIZE, CONTEXT_INT(PixelMaps.ItoR.Size), NO_EXTRA },
- { GL_PIXEL_MAP_R_TO_R_SIZE, CONTEXT_INT(PixelMaps.RtoR.Size), NO_EXTRA },
- { GL_PIXEL_MAP_S_TO_S_SIZE, CONTEXT_INT(PixelMaps.StoS.Size), NO_EXTRA },
- { GL_POINT_SIZE_GRANULARITY, CONTEXT_FLOAT(Const.PointSizeGranularity), NO_EXTRA },
- { GL_POLYGON_MODE, CONTEXT_ENUM2(Polygon.FrontMode), NO_EXTRA },
- { GL_POLYGON_OFFSET_BIAS_EXT, CONTEXT_FLOAT(Polygon.OffsetUnits), NO_EXTRA },
- { GL_POLYGON_OFFSET_POINT, CONTEXT_BOOL(Polygon.OffsetPoint), NO_EXTRA },
- { GL_POLYGON_OFFSET_LINE, CONTEXT_BOOL(Polygon.OffsetLine), NO_EXTRA },
- { GL_POLYGON_SMOOTH, CONTEXT_BOOL(Polygon.SmoothFlag), NO_EXTRA },
- { GL_POLYGON_SMOOTH_HINT, CONTEXT_ENUM(Hint.PolygonSmooth), NO_EXTRA },
- { GL_POLYGON_STIPPLE, CONTEXT_BOOL(Polygon.StippleFlag), NO_EXTRA },
- { GL_READ_BUFFER, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA },
- { GL_RED_BIAS, CONTEXT_FLOAT(Pixel.RedBias), NO_EXTRA },
- { GL_RED_SCALE, CONTEXT_FLOAT(Pixel.RedScale), NO_EXTRA },
- { GL_RENDER_MODE, CONTEXT_ENUM(RenderMode), NO_EXTRA },
- { GL_RGBA_MODE, CONST(1), NO_EXTRA },
- { GL_SELECTION_BUFFER_SIZE, CONTEXT_INT(Select.BufferSize), NO_EXTRA },
- { GL_SHARED_TEXTURE_PALETTE_EXT, CONTEXT_BOOL(Texture.SharedPalette), NO_EXTRA },
-
- { GL_STEREO, BUFFER_INT(Visual.stereoMode), NO_EXTRA },
-
- { GL_TEXTURE_1D, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA },
- { GL_TEXTURE_3D, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA },
- { GL_TEXTURE_1D_ARRAY_EXT, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA },
- { GL_TEXTURE_2D_ARRAY_EXT, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA },
-
- { GL_TEXTURE_BINDING_1D, LOC_CUSTOM, TYPE_INT, TEXTURE_1D_INDEX, NO_EXTRA },
- { GL_TEXTURE_BINDING_1D_ARRAY, LOC_CUSTOM, TYPE_INT,
- TEXTURE_1D_ARRAY_INDEX, extra_MESA_texture_array },
- { GL_TEXTURE_BINDING_2D_ARRAY, LOC_CUSTOM, TYPE_INT,
- TEXTURE_1D_ARRAY_INDEX, extra_MESA_texture_array },
- { GL_MAX_ARRAY_TEXTURE_LAYERS_EXT,
- CONTEXT_INT(Const.MaxArrayTextureLayers), extra_MESA_texture_array },
-
- { GL_TEXTURE_GEN_S, LOC_TEXUNIT, TYPE_BIT_0,
- offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA },
- { GL_TEXTURE_GEN_T, LOC_TEXUNIT, TYPE_BIT_1,
- offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA },
- { GL_TEXTURE_GEN_R, LOC_TEXUNIT, TYPE_BIT_2,
- offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA },
- { GL_TEXTURE_GEN_Q, LOC_TEXUNIT, TYPE_BIT_3,
- offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA },
- { GL_UNPACK_LSB_FIRST, CONTEXT_BOOL(Unpack.LsbFirst), NO_EXTRA },
- { GL_UNPACK_ROW_LENGTH, CONTEXT_INT(Unpack.RowLength), NO_EXTRA },
- { GL_UNPACK_SKIP_PIXELS, CONTEXT_INT(Unpack.SkipPixels), NO_EXTRA },
- { GL_UNPACK_SKIP_ROWS, CONTEXT_INT(Unpack.SkipRows), NO_EXTRA },
- { GL_UNPACK_SWAP_BYTES, CONTEXT_BOOL(Unpack.SwapBytes), NO_EXTRA },
- { GL_UNPACK_SKIP_IMAGES_EXT, CONTEXT_INT(Unpack.SkipImages), NO_EXTRA },
- { GL_UNPACK_IMAGE_HEIGHT_EXT, CONTEXT_INT(Unpack.ImageHeight), NO_EXTRA },
- { GL_UNPACK_CLIENT_STORAGE_APPLE, CONTEXT_BOOL(Unpack.ClientStorage), NO_EXTRA },
- { GL_ZOOM_X, CONTEXT_FLOAT(Pixel.ZoomX), NO_EXTRA },
- { GL_ZOOM_Y, CONTEXT_FLOAT(Pixel.ZoomY), NO_EXTRA },
-
- /* Vertex arrays */
- { GL_VERTEX_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA },
- { GL_NORMAL_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA },
- { GL_COLOR_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA },
- { GL_INDEX_ARRAY, ARRAY_BOOL(Index.Enabled), NO_EXTRA },
- { GL_INDEX_ARRAY_TYPE, ARRAY_ENUM(Index.Type), NO_EXTRA },
- { GL_INDEX_ARRAY_STRIDE, ARRAY_INT(Index.Stride), NO_EXTRA },
- { GL_INDEX_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA },
- { GL_TEXTURE_COORD_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA },
- { GL_EDGE_FLAG_ARRAY, ARRAY_BOOL(EdgeFlag.Enabled), NO_EXTRA },
- { GL_EDGE_FLAG_ARRAY_STRIDE, ARRAY_INT(EdgeFlag.Stride), NO_EXTRA },
- { GL_EDGE_FLAG_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA },
-
- /* GL_ARB_texture_compression */
- { GL_TEXTURE_COMPRESSION_HINT_ARB, CONTEXT_INT(Hint.TextureCompression), NO_EXTRA },
-
- /* GL_EXT_compiled_vertex_array */
- { GL_ARRAY_ELEMENT_LOCK_FIRST_EXT, CONTEXT_INT(Array.LockFirst),
- extra_EXT_compiled_vertex_array },
- { GL_ARRAY_ELEMENT_LOCK_COUNT_EXT, CONTEXT_INT(Array.LockCount),
- extra_EXT_compiled_vertex_array },
-
- /* GL_ARB_transpose_matrix */
- { GL_TRANSPOSE_MODELVIEW_MATRIX_ARB,
- CONTEXT_MATRIX_T(ModelviewMatrixStack), NO_EXTRA },
- { GL_TRANSPOSE_PROJECTION_MATRIX_ARB,
- CONTEXT_MATRIX_T(ProjectionMatrixStack.Top), NO_EXTRA },
- { GL_TRANSPOSE_TEXTURE_MATRIX_ARB, CONTEXT_MATRIX_T(TextureMatrixStack), NO_EXTRA },
-
- /* GL_SGI_texture_color_table */
- { GL_TEXTURE_COLOR_TABLE_SGI, LOC_TEXUNIT, TYPE_BOOLEAN,
- offsetof(struct gl_texture_unit, ColorTableEnabled),
- extra_SGI_texture_color_table },
-
- /* GL_EXT_secondary_color */
- { GL_COLOR_SUM_EXT, CONTEXT_BOOL(Fog.ColorSumEnabled),
- extra_EXT_secondary_color_ARB_vertex_program },
- { GL_CURRENT_SECONDARY_COLOR_EXT,
- CONTEXT_FIELD(Current.Attrib[VERT_ATTRIB_COLOR1][0], TYPE_FLOATN_4),
- extra_EXT_secondary_color_flush_current },
- { GL_SECONDARY_COLOR_ARRAY_EXT, ARRAY_BOOL(SecondaryColor.Enabled),
- extra_EXT_secondary_color },
- { GL_SECONDARY_COLOR_ARRAY_TYPE_EXT, ARRAY_ENUM(SecondaryColor.Type),
- extra_EXT_secondary_color },
- { GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT, ARRAY_INT(SecondaryColor.Stride),
- extra_EXT_secondary_color },
- { GL_SECONDARY_COLOR_ARRAY_SIZE_EXT, ARRAY_INT(SecondaryColor.Size),
- extra_EXT_secondary_color },
-
- /* GL_EXT_fog_coord */
- { GL_CURRENT_FOG_COORDINATE_EXT,
- CONTEXT_FLOAT(Current.Attrib[VERT_ATTRIB_FOG][0]),
- extra_EXT_fog_coord_flush_current },
- { GL_FOG_COORDINATE_ARRAY_EXT, ARRAY_BOOL(FogCoord.Enabled),
- extra_EXT_fog_coord },
- { GL_FOG_COORDINATE_ARRAY_TYPE_EXT, ARRAY_ENUM(FogCoord.Type),
- extra_EXT_fog_coord },
- { GL_FOG_COORDINATE_ARRAY_STRIDE_EXT, ARRAY_INT(FogCoord.Stride),
- extra_EXT_fog_coord },
- { GL_FOG_COORDINATE_SOURCE_EXT, CONTEXT_ENUM(Fog.FogCoordinateSource),
- extra_EXT_fog_coord },
-
- /* GL_IBM_rasterpos_clip */
- { GL_RASTER_POSITION_UNCLIPPED_IBM,
- CONTEXT_BOOL(Transform.RasterPositionUnclipped),
- extra_IBM_rasterpos_clip },
-
- /* GL_NV_point_sprite */
- { GL_POINT_SPRITE_R_MODE_NV,
- CONTEXT_ENUM(Point.SpriteRMode), extra_NV_point_sprite },
- { GL_POINT_SPRITE_COORD_ORIGIN, CONTEXT_ENUM(Point.SpriteOrigin),
- extra_NV_point_sprite_ARB_point_sprite },
-
- /* GL_NV_vertex_program */
- { GL_VERTEX_PROGRAM_BINDING_NV, LOC_CUSTOM, TYPE_INT, 0,
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY0_NV, ARRAY_BOOL(VertexAttrib[0].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY1_NV, ARRAY_BOOL(VertexAttrib[1].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY2_NV, ARRAY_BOOL(VertexAttrib[2].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY3_NV, ARRAY_BOOL(VertexAttrib[3].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY4_NV, ARRAY_BOOL(VertexAttrib[4].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY5_NV, ARRAY_BOOL(VertexAttrib[5].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY6_NV, ARRAY_BOOL(VertexAttrib[6].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY7_NV, ARRAY_BOOL(VertexAttrib[7].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY8_NV, ARRAY_BOOL(VertexAttrib[8].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY9_NV, ARRAY_BOOL(VertexAttrib[9].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY10_NV, ARRAY_BOOL(VertexAttrib[10].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY11_NV, ARRAY_BOOL(VertexAttrib[11].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY12_NV, ARRAY_BOOL(VertexAttrib[12].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY13_NV, ARRAY_BOOL(VertexAttrib[13].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY14_NV, ARRAY_BOOL(VertexAttrib[14].Enabled),
- extra_NV_vertex_program },
- { GL_VERTEX_ATTRIB_ARRAY15_NV, ARRAY_BOOL(VertexAttrib[15].Enabled),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB0_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[0]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB1_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[1]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB2_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[2]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB3_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[3]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB4_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[4]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB5_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[5]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB6_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[6]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB7_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[7]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB8_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[8]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB9_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[9]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB10_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[10]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB11_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[11]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB12_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[12]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB13_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[13]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB14_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[14]),
- extra_NV_vertex_program },
- { GL_MAP1_VERTEX_ATTRIB15_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[15]),
- extra_NV_vertex_program },
-
- /* GL_NV_fragment_program */
- { GL_FRAGMENT_PROGRAM_NV, CONTEXT_BOOL(FragmentProgram.Enabled),
- extra_NV_fragment_program },
- { GL_FRAGMENT_PROGRAM_BINDING_NV, LOC_CUSTOM, TYPE_INT, 0,
- extra_NV_fragment_program },
- { GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV,
- CONST(MAX_NV_FRAGMENT_PROGRAM_PARAMS),
- extra_NV_fragment_program },
-
- /* GL_NV_texture_rectangle */
- { GL_TEXTURE_RECTANGLE_NV,
- LOC_CUSTOM, TYPE_BOOLEAN, 0, extra_NV_texture_rectangle },
- { GL_TEXTURE_BINDING_RECTANGLE_NV,
- LOC_CUSTOM, TYPE_INT, TEXTURE_RECT_INDEX, extra_NV_texture_rectangle },
- { GL_MAX_RECTANGLE_TEXTURE_SIZE_NV,
- CONTEXT_INT(Const.MaxTextureRectSize), extra_NV_texture_rectangle },
-
- /* GL_EXT_stencil_two_side */
- { GL_STENCIL_TEST_TWO_SIDE_EXT, CONTEXT_BOOL(Stencil.TestTwoSide),
- extra_EXT_stencil_two_side },
- { GL_ACTIVE_STENCIL_FACE_EXT, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA },
-
- /* GL_NV_light_max_exponent */
- { GL_MAX_SHININESS_NV, CONTEXT_FLOAT(Const.MaxShininess),
- extra_NV_light_max_exponent },
- { GL_MAX_SPOT_EXPONENT_NV, CONTEXT_FLOAT(Const.MaxSpotExponent),
- extra_NV_light_max_exponent },
-
- /* GL_NV_primitive_restart */
- { GL_PRIMITIVE_RESTART_NV, CONTEXT_BOOL(Array.PrimitiveRestart),
- extra_NV_primitive_restart },
- { GL_PRIMITIVE_RESTART_INDEX_NV, CONTEXT_INT(Array.RestartIndex),
- extra_NV_primitive_restart },
-
- /* GL_ARB_vertex_buffer_object */
- { GL_INDEX_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT,
- offsetof(struct gl_array_object, Index.BufferObj), NO_EXTRA },
- { GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT,
- offsetof(struct gl_array_object, EdgeFlag.BufferObj), NO_EXTRA },
- { GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT,
- offsetof(struct gl_array_object, SecondaryColor.BufferObj), NO_EXTRA },
- { GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT,
- offsetof(struct gl_array_object, FogCoord.BufferObj), NO_EXTRA },
-
- /* GL_EXT_pixel_buffer_object */
- { GL_PIXEL_PACK_BUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0,
- extra_EXT_pixel_buffer_object },
- { GL_PIXEL_UNPACK_BUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0,
- extra_EXT_pixel_buffer_object },
-
- /* GL_ARB_vertex_program */
- { GL_VERTEX_PROGRAM_ARB, /* == GL_VERTEX_PROGRAM_NV */
- CONTEXT_BOOL(VertexProgram.Enabled),
- extra_ARB_vertex_program_NV_vertex_program },
- { GL_VERTEX_PROGRAM_POINT_SIZE_ARB, /* == GL_VERTEX_PROGRAM_POINT_SIZE_NV*/
- CONTEXT_BOOL(VertexProgram.PointSizeEnabled),
- extra_ARB_vertex_program_NV_vertex_program },
- { GL_VERTEX_PROGRAM_TWO_SIDE_ARB, /* == GL_VERTEX_PROGRAM_TWO_SIDE_NV */
- CONTEXT_BOOL(VertexProgram.TwoSideEnabled),
- extra_ARB_vertex_program_NV_vertex_program },
- { GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB, /* == GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV */
- CONTEXT_INT(Const.MaxProgramMatrixStackDepth),
- extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program },
- { GL_MAX_PROGRAM_MATRICES_ARB, /* == GL_MAX_TRACK_MATRICES_NV */
- CONTEXT_INT(Const.MaxProgramMatrices),
- extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program },
- { GL_CURRENT_MATRIX_STACK_DEPTH_ARB, /* == GL_CURRENT_MATRIX_STACK_DEPTH_NV */
- LOC_CUSTOM, TYPE_INT, 0,
- extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program },
-
- { GL_CURRENT_MATRIX_ARB, /* == GL_CURRENT_MATRIX_NV */
- LOC_CUSTOM, TYPE_MATRIX, 0,
- extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program },
- { GL_TRANSPOSE_CURRENT_MATRIX_ARB, /* == GL_CURRENT_MATRIX_NV */
- LOC_CUSTOM, TYPE_MATRIX, 0,
- extra_ARB_vertex_program_ARB_fragment_program },
-
- { GL_PROGRAM_ERROR_POSITION_ARB, /* == GL_PROGRAM_ERROR_POSITION_NV */
- CONTEXT_INT(Program.ErrorPos),
- extra_NV_vertex_program_ARB_vertex_program_ARB_fragment_program_NV_vertex_program },
-
- /* GL_ARB_fragment_program */
- { GL_FRAGMENT_PROGRAM_ARB, CONTEXT_BOOL(FragmentProgram.Enabled),
- extra_ARB_fragment_program },
-
- /* GL_EXT_depth_bounds_test */
- { GL_DEPTH_BOUNDS_TEST_EXT, CONTEXT_BOOL(Depth.BoundsTest),
- extra_EXT_depth_bounds_test },
- { GL_DEPTH_BOUNDS_EXT, CONTEXT_FLOAT2(Depth.BoundsMin),
- extra_EXT_depth_bounds_test },
-
- /* GL_ARB_depth_clamp*/
- { GL_DEPTH_CLAMP, CONTEXT_BOOL(Transform.DepthClamp),
- extra_ARB_depth_clamp },
-
- /* GL_ARB_draw_buffers */
- { GL_DRAW_BUFFER0_ARB, BUFFER_ENUM(ColorDrawBuffer[0]), NO_EXTRA },
- { GL_DRAW_BUFFER1_ARB, BUFFER_ENUM(ColorDrawBuffer[1]),
- extra_valid_draw_buffer },
- { GL_DRAW_BUFFER2_ARB, BUFFER_ENUM(ColorDrawBuffer[2]),
- extra_valid_draw_buffer },
- { GL_DRAW_BUFFER3_ARB, BUFFER_ENUM(ColorDrawBuffer[3]),
- extra_valid_draw_buffer },
- { GL_DRAW_BUFFER4_ARB, BUFFER_ENUM(ColorDrawBuffer[4]),
- extra_valid_draw_buffer },
- { GL_DRAW_BUFFER5_ARB, BUFFER_ENUM(ColorDrawBuffer[5]),
- extra_valid_draw_buffer },
- { GL_DRAW_BUFFER6_ARB, BUFFER_ENUM(ColorDrawBuffer[6]),
- extra_valid_draw_buffer },
- { GL_DRAW_BUFFER7_ARB, BUFFER_ENUM(ColorDrawBuffer[7]),
- extra_valid_draw_buffer },
-
- /* GL_ATI_fragment_shader */
- { GL_NUM_FRAGMENT_REGISTERS_ATI, CONST(6), extra_ATI_fragment_shader },
- { GL_NUM_FRAGMENT_CONSTANTS_ATI, CONST(8), extra_ATI_fragment_shader },
- { GL_NUM_PASSES_ATI, CONST(2), extra_ATI_fragment_shader },
- { GL_NUM_INSTRUCTIONS_PER_PASS_ATI, CONST(8), extra_ATI_fragment_shader },
- { GL_NUM_INSTRUCTIONS_TOTAL_ATI, CONST(16), extra_ATI_fragment_shader },
- { GL_COLOR_ALPHA_PAIRING_ATI, CONST(GL_TRUE), extra_ATI_fragment_shader },
- { GL_NUM_LOOPBACK_COMPONENTS_ATI, CONST(3), extra_ATI_fragment_shader },
- { GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI,
- CONST(3), extra_ATI_fragment_shader },
-
- /* GL_EXT_framebuffer_object */
- { GL_MAX_COLOR_ATTACHMENTS_EXT, CONTEXT_INT(Const.MaxColorAttachments),
- extra_EXT_framebuffer_object },
-
- /* GL_EXT_framebuffer_blit
- * NOTE: GL_DRAW_FRAMEBUFFER_BINDING_EXT == GL_FRAMEBUFFER_BINDING_EXT */
- { GL_READ_FRAMEBUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0,
- extra_EXT_framebuffer_blit },
-
- /* GL_EXT_provoking_vertex */
- { GL_PROVOKING_VERTEX_EXT,
- CONTEXT_BOOL(Light.ProvokingVertex), extra_EXT_provoking_vertex },
- { GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT,
- CONTEXT_BOOL(Const.QuadsFollowProvokingVertexConvention),
- extra_EXT_provoking_vertex },
-
- /* GL_ARB_framebuffer_object */
- { GL_MAX_SAMPLES, CONTEXT_INT(Const.MaxSamples),
- extra_ARB_framebuffer_object_EXT_framebuffer_multisample },
-
- /* GL_APPLE_vertex_array_object */
- { GL_VERTEX_ARRAY_BINDING_APPLE, ARRAY_INT(Name),
- extra_APPLE_vertex_array_object },
-
- /* GL_ARB_seamless_cube_map */
- { GL_TEXTURE_CUBE_MAP_SEAMLESS,
- CONTEXT_BOOL(Texture.CubeMapSeamless), extra_ARB_seamless_cube_map },
-
- /* GL_ARB_sync */
- { GL_MAX_SERVER_WAIT_TIMEOUT,
- CONTEXT_INT64(Const.MaxServerWaitTimeout), extra_ARB_sync },
-
- /* GL_EXT_texture_integer */
- { GL_RGBA_INTEGER_MODE_EXT, BUFFER_BOOL(_IntegerColor),
- extra_EXT_texture_integer },
-
- /* GL_EXT_transform_feedback */
- { GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, LOC_CUSTOM, TYPE_INT, 0,
- extra_EXT_transform_feedback },
- { GL_RASTERIZER_DISCARD, CONTEXT_BOOL(TransformFeedback.RasterDiscard),
- extra_EXT_transform_feedback },
- { GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,
- CONTEXT_INT(Const.MaxTransformFeedbackInterleavedComponents),
- extra_EXT_transform_feedback },
- { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
- CONTEXT_INT(Const.MaxTransformFeedbackSeparateAttribs),
- extra_EXT_transform_feedback },
- { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,
- CONTEXT_INT(Const.MaxTransformFeedbackSeparateComponents),
- extra_EXT_transform_feedback },
-
- /* GL_ARB_transform_feedback2 */
- { GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED, LOC_CUSTOM, TYPE_BOOLEAN, 0,
- extra_ARB_transform_feedback2 },
- { GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE, LOC_CUSTOM, TYPE_BOOLEAN, 0,
- extra_ARB_transform_feedback2 },
- { GL_TRANSFORM_FEEDBACK_BINDING, LOC_CUSTOM, TYPE_INT, 0,
- extra_ARB_transform_feedback2 },
-
- /* GL_ARB_geometry_shader4 */
- { GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB,
- CONTEXT_INT(Const.GeometryProgram.MaxGeometryTextureImageUnits),
- extra_ARB_geometry_shader4 },
- { GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB,
- CONTEXT_INT(Const.GeometryProgram.MaxGeometryOutputVertices),
- extra_ARB_geometry_shader4 },
- { GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB,
- CONTEXT_INT(Const.GeometryProgram.MaxGeometryTotalOutputComponents),
- extra_ARB_geometry_shader4 },
- { GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB,
- CONTEXT_INT(Const.GeometryProgram.MaxGeometryUniformComponents),
- extra_ARB_geometry_shader4 },
- { GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB,
- CONTEXT_INT(Const.GeometryProgram.MaxGeometryVaryingComponents),
- extra_ARB_geometry_shader4 },
- { GL_MAX_VERTEX_VARYING_COMPONENTS_ARB,
- CONTEXT_INT(Const.GeometryProgram.MaxVertexVaryingComponents),
- extra_ARB_geometry_shader4 },
-
- /* GL_EXT_gpu_shader4 / GL 3.0 */
- { GL_MIN_PROGRAM_TEXEL_OFFSET,
- CONTEXT_INT(Const.MinProgramTexelOffset),
- extra_EXT_gpu_shader4 },
- { GL_MAX_PROGRAM_TEXEL_OFFSET,
- CONTEXT_INT(Const.MaxProgramTexelOffset),
- extra_EXT_gpu_shader4 },
-
- /* GL 3.0 */
- { GL_NUM_EXTENSIONS, LOC_CUSTOM, TYPE_INT, 0, extra_version_30 },
- { GL_MAJOR_VERSION, CONTEXT_INT(VersionMajor), extra_version_30 },
- { GL_MINOR_VERSION, CONTEXT_INT(VersionMinor), extra_version_30 },
- { GL_CONTEXT_FLAGS, CONTEXT_INT(Const.ContextFlags), extra_version_30 },
-
- /* GL3.0 / GL_EXT_framebuffer_sRGB */
- { GL_FRAMEBUFFER_SRGB_EXT, CONTEXT_BOOL(Color.sRGBEnabled), extra_EXT_framebuffer_sRGB },
- { GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, BUFFER_INT(Visual.sRGBCapable), extra_EXT_framebuffer_sRGB },
-
- /* GL 3.1 */
- /* NOTE: different enum values for GL_PRIMITIVE_RESTART_NV
- * vs. GL_PRIMITIVE_RESTART!
- */
- { GL_PRIMITIVE_RESTART, CONTEXT_BOOL(Array.PrimitiveRestart),
- extra_version_31 },
- { GL_PRIMITIVE_RESTART_INDEX, CONTEXT_INT(Array.RestartIndex),
- extra_version_31 },
-
-
- /* GL 3.2 */
- { GL_CONTEXT_PROFILE_MASK, CONTEXT_INT(Const.ProfileMask),
- extra_version_32 },
-#endif /* FEATURE_GL */
-};
-
-/* All we need now is a way to look up the value struct from the enum.
- * The code generated by gcc for the old generated big switch
- * statement is a big, balanced, open coded if/else tree, essentially
- * an unrolled binary search. It would be natural to sort the new
- * enum table and use bsearch(), but we will use a read-only hash
- * table instead. bsearch() has a nice guaranteed worst case
- * performance, but we're also guaranteed to hit that worst case
- * (log2(n) iterations) for about half the enums. Instead, using an
- * open addressing hash table, we can find the enum on the first try
- * for 80% of the enums, 1 collision for 10% and never more than 5
- * collisions for any enum (typical numbers). And the code is very
- * simple, even though it feels a little magic. */
-
-static unsigned short table[1024];
-static const int prime_factor = 89, prime_step = 281;
-
-#ifdef GET_DEBUG
-static void
-print_table_stats(void)
-{
- int i, j, collisions[11], count, hash, mask;
- const struct value_desc *d;
-
- count = 0;
- mask = Elements(table) - 1;
- memset(collisions, 0, sizeof collisions);
-
- for (i = 0; i < Elements(table); i++) {
- if (!table[i])
- continue;
- count++;
- d = &values[table[i]];
- hash = (d->pname * prime_factor);
- j = 0;
- while (1) {
- if (values[table[hash & mask]].pname == d->pname)
- break;
- hash += prime_step;
- j++;
- }
-
- if (j < 10)
- collisions[j]++;
- else
- collisions[10]++;
- }
-
- printf("number of enums: %d (total %d)\n", count, Elements(values));
- for (i = 0; i < Elements(collisions) - 1; i++)
- if (collisions[i] > 0)
- printf(" %d enums with %d %scollisions\n",
- collisions[i], i, i == 10 ? "or more " : "");
-}
-#endif
-
-/**
- * Initialize the enum hash for a given API
- *
- * This is called from one_time_init() to insert the enum values that
- * are valid for the API in question into the enum hash table.
- *
- * \param the current context, for determining the API in question
- */
-void _mesa_init_get_hash(struct gl_context *ctx)
-{
- int i, hash, index, mask;
- int api_mask = 0, api_bit;
-
- mask = Elements(table) - 1;
- api_bit = 1 << ctx->API;
-
- for (i = 0; i < Elements(values); i++) {
- if (values[i].type == TYPE_API_MASK) {
- api_mask = values[i].offset;
- continue;
- }
- if (!(api_mask & api_bit))
- continue;
-
- hash = (values[i].pname * prime_factor) & mask;
- while (1) {
- index = hash & mask;
- if (!table[index]) {
- table[index] = i;
- break;
- }
- hash += prime_step;
- }
- }
-
-#ifdef GET_DEBUG
- print_table_stats();
-#endif
-}
-
-/**
- * Handle irregular enums
- *
- * Some values don't conform to the "well-known type at context
- * pointer + offset" pattern, so we have this function to catch all
- * the corner cases. Typically, it's a computed value or a one-off
- * pointer to a custom struct or something.
- *
- * In this case we can't return a pointer to the value, so we'll have
- * to use the temporary variable 'v' declared back in the calling
- * glGet*v() function to store the result.
- *
- * \param ctx the current context
- * \param d the struct value_desc that describes the enum
- * \param v pointer to the tmp declared in the calling glGet*v() function
- */
-static void
-find_custom_value(struct gl_context *ctx, const struct value_desc *d, union value *v)
-{
- struct gl_buffer_object *buffer_obj;
- struct gl_client_array *array;
- GLuint unit, *p;
-
- switch (d->pname) {
- case GL_TEXTURE_1D:
- case GL_TEXTURE_2D:
- case GL_TEXTURE_3D:
- case GL_TEXTURE_1D_ARRAY_EXT:
- case GL_TEXTURE_2D_ARRAY_EXT:
- case GL_TEXTURE_CUBE_MAP_ARB:
- case GL_TEXTURE_RECTANGLE_NV:
- v->value_bool = _mesa_IsEnabled(d->pname);
- break;
-
- case GL_LINE_STIPPLE_PATTERN:
- /* This is the only GLushort, special case it here by promoting
- * to an int rather than introducing a new type. */
- v->value_int = ctx->Line.StipplePattern;
- break;
-
- case GL_CURRENT_RASTER_TEXTURE_COORDS:
- unit = ctx->Texture.CurrentUnit;
- v->value_float_4[0] = ctx->Current.RasterTexCoords[unit][0];
- v->value_float_4[1] = ctx->Current.RasterTexCoords[unit][1];
- v->value_float_4[2] = ctx->Current.RasterTexCoords[unit][2];
- v->value_float_4[3] = ctx->Current.RasterTexCoords[unit][3];
- break;
-
- case GL_CURRENT_TEXTURE_COORDS:
- unit = ctx->Texture.CurrentUnit;
- v->value_float_4[0] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][0];
- v->value_float_4[1] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][1];
- v->value_float_4[2] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][2];
- v->value_float_4[3] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][3];
- break;
-
- case GL_COLOR_WRITEMASK:
- v->value_int_4[0] = ctx->Color.ColorMask[0][RCOMP] ? 1 : 0;
- v->value_int_4[1] = ctx->Color.ColorMask[0][GCOMP] ? 1 : 0;
- v->value_int_4[2] = ctx->Color.ColorMask[0][BCOMP] ? 1 : 0;
- v->value_int_4[3] = ctx->Color.ColorMask[0][ACOMP] ? 1 : 0;
- break;
-
- case GL_EDGE_FLAG:
- v->value_bool = ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG][0] == 1.0;
- break;
-
- case GL_READ_BUFFER:
- v->value_enum = ctx->ReadBuffer->ColorReadBuffer;
- break;
-
- case GL_MAP2_GRID_DOMAIN:
- v->value_float_4[0] = ctx->Eval.MapGrid2u1;
- v->value_float_4[1] = ctx->Eval.MapGrid2u2;
- v->value_float_4[2] = ctx->Eval.MapGrid2v1;
- v->value_float_4[3] = ctx->Eval.MapGrid2v2;
- break;
-
- case GL_TEXTURE_STACK_DEPTH:
- unit = ctx->Texture.CurrentUnit;
- v->value_int = ctx->TextureMatrixStack[unit].Depth + 1;
- break;
- case GL_TEXTURE_MATRIX:
- unit = ctx->Texture.CurrentUnit;
- v->value_matrix = ctx->TextureMatrixStack[unit].Top;
- break;
-
- case GL_TEXTURE_COORD_ARRAY:
- case GL_TEXTURE_COORD_ARRAY_SIZE:
- case GL_TEXTURE_COORD_ARRAY_TYPE:
- case GL_TEXTURE_COORD_ARRAY_STRIDE:
- array = &ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture];
- v->value_int = *(GLuint *) ((char *) array + d->offset);
- break;
-
- case GL_ACTIVE_TEXTURE_ARB:
- v->value_int = GL_TEXTURE0_ARB + ctx->Texture.CurrentUnit;
- break;
- case GL_CLIENT_ACTIVE_TEXTURE_ARB:
- v->value_int = GL_TEXTURE0_ARB + ctx->Array.ActiveTexture;
- break;
-
- case GL_MODELVIEW_STACK_DEPTH:
- case GL_PROJECTION_STACK_DEPTH:
- v->value_int = *(GLint *) ((char *) ctx + d->offset) + 1;
- break;
-
- case GL_MAX_TEXTURE_SIZE:
- case GL_MAX_3D_TEXTURE_SIZE:
- case GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB:
- p = (GLuint *) ((char *) ctx + d->offset);
- v->value_int = 1 << (*p - 1);
- break;
-
- case GL_SCISSOR_BOX:
- v->value_int_4[0] = ctx->Scissor.X;
- v->value_int_4[1] = ctx->Scissor.Y;
- v->value_int_4[2] = ctx->Scissor.Width;
- v->value_int_4[3] = ctx->Scissor.Height;
- break;
-
- case GL_LIST_INDEX:
- v->value_int =
- ctx->ListState.CurrentList ? ctx->ListState.CurrentList->Name : 0;
- break;
- case GL_LIST_MODE:
- if (!ctx->CompileFlag)
- v->value_enum = 0;
- else if (ctx->ExecuteFlag)
- v->value_enum = GL_COMPILE_AND_EXECUTE;
- else
- v->value_enum = GL_COMPILE;
- break;
-
- case GL_VIEWPORT:
- v->value_int_4[0] = ctx->Viewport.X;
- v->value_int_4[1] = ctx->Viewport.Y;
- v->value_int_4[2] = ctx->Viewport.Width;
- v->value_int_4[3] = ctx->Viewport.Height;
- break;
-
- case GL_ACTIVE_STENCIL_FACE_EXT:
- v->value_enum = ctx->Stencil.ActiveFace ? GL_BACK : GL_FRONT;
- break;
-
- case GL_STENCIL_FAIL:
- v->value_enum = ctx->Stencil.FailFunc[ctx->Stencil.ActiveFace];
- break;
- case GL_STENCIL_FUNC:
- v->value_enum = ctx->Stencil.Function[ctx->Stencil.ActiveFace];
- break;
- case GL_STENCIL_PASS_DEPTH_FAIL:
- v->value_enum = ctx->Stencil.ZFailFunc[ctx->Stencil.ActiveFace];
- break;
- case GL_STENCIL_PASS_DEPTH_PASS:
- v->value_enum = ctx->Stencil.ZPassFunc[ctx->Stencil.ActiveFace];
- break;
- case GL_STENCIL_REF:
- v->value_int = ctx->Stencil.Ref[ctx->Stencil.ActiveFace];
- break;
- case GL_STENCIL_VALUE_MASK:
- v->value_int = ctx->Stencil.ValueMask[ctx->Stencil.ActiveFace];
- break;
- case GL_STENCIL_WRITEMASK:
- v->value_int = ctx->Stencil.WriteMask[ctx->Stencil.ActiveFace];
- break;
-
- case GL_NUM_EXTENSIONS:
- v->value_int = _mesa_get_extension_count(ctx);
- break;
-
- case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
- v->value_int = _mesa_get_color_read_type(ctx);
- break;
- case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
- v->value_int = _mesa_get_color_read_format(ctx);
- break;
-
- case GL_CURRENT_MATRIX_STACK_DEPTH_ARB:
- v->value_int = ctx->CurrentStack->Depth + 1;
- break;
- case GL_CURRENT_MATRIX_ARB:
- case GL_TRANSPOSE_CURRENT_MATRIX_ARB:
- v->value_matrix = ctx->CurrentStack->Top;
- break;
-
- case GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB:
- v->value_int = _mesa_get_compressed_formats(ctx, NULL, GL_FALSE);
- break;
- case GL_COMPRESSED_TEXTURE_FORMATS_ARB:
- v->value_int_n.n =
- _mesa_get_compressed_formats(ctx, v->value_int_n.ints, GL_FALSE);
- ASSERT(v->value_int_n.n <= 100);
- break;
-
- case GL_MAX_VARYING_FLOATS_ARB:
- v->value_int = ctx->Const.MaxVarying * 4;
- break;
-
- /* Various object names */
-
- case GL_TEXTURE_BINDING_1D:
- case GL_TEXTURE_BINDING_2D:
- case GL_TEXTURE_BINDING_3D:
- case GL_TEXTURE_BINDING_1D_ARRAY_EXT:
- case GL_TEXTURE_BINDING_2D_ARRAY_EXT:
- case GL_TEXTURE_BINDING_CUBE_MAP_ARB:
- case GL_TEXTURE_BINDING_RECTANGLE_NV:
- unit = ctx->Texture.CurrentUnit;
- v->value_int =
- ctx->Texture.Unit[unit].CurrentTex[d->offset]->Name;
- break;
-
- /* GL_ARB_vertex_buffer_object */
- case GL_VERTEX_ARRAY_BUFFER_BINDING_ARB:
- case GL_NORMAL_ARRAY_BUFFER_BINDING_ARB:
- case GL_COLOR_ARRAY_BUFFER_BINDING_ARB:
- case GL_INDEX_ARRAY_BUFFER_BINDING_ARB:
- case GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB:
- case GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB:
- case GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB:
- buffer_obj = (struct gl_buffer_object *)
- ((char *) ctx->Array.ArrayObj + d->offset);
- v->value_int = buffer_obj->Name;
- break;
- case GL_ARRAY_BUFFER_BINDING_ARB:
- v->value_int = ctx->Array.ArrayBufferObj->Name;
- break;
- case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB:
- v->value_int =
- ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture].BufferObj->Name;
- break;
- case GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB:
- v->value_int = ctx->Array.ElementArrayBufferObj->Name;
- break;
-
- /* ARB_copy_buffer */
- case GL_COPY_READ_BUFFER:
- v->value_int = ctx->CopyReadBuffer->Name;
- break;
- case GL_COPY_WRITE_BUFFER:
- v->value_int = ctx->CopyWriteBuffer->Name;
- break;
-
- case GL_FRAGMENT_PROGRAM_BINDING_NV:
- v->value_int =
- ctx->FragmentProgram.Current ? ctx->FragmentProgram.Current->Base.Id : 0;
- break;
- case GL_VERTEX_PROGRAM_BINDING_NV:
- v->value_int =
- ctx->VertexProgram.Current ? ctx->VertexProgram.Current->Base.Id : 0;
- break;
- case GL_PIXEL_PACK_BUFFER_BINDING_EXT:
- v->value_int = ctx->Pack.BufferObj->Name;
- break;
- case GL_PIXEL_UNPACK_BUFFER_BINDING_EXT:
- v->value_int = ctx->Unpack.BufferObj->Name;
- break;
- case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
- v->value_int = ctx->TransformFeedback.CurrentBuffer->Name;
- break;
- case GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED:
- v->value_int = ctx->TransformFeedback.CurrentObject->Paused;
- break;
- case GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE:
- v->value_int = ctx->TransformFeedback.CurrentObject->Active;
- break;
- case GL_TRANSFORM_FEEDBACK_BINDING:
- v->value_int = ctx->TransformFeedback.CurrentObject->Name;
- break;
- case GL_CURRENT_PROGRAM:
- v->value_int =
- ctx->Shader.ActiveProgram ? ctx->Shader.ActiveProgram->Name : 0;
- break;
- case GL_READ_FRAMEBUFFER_BINDING_EXT:
- v->value_int = ctx->ReadBuffer->Name;
- break;
- case GL_RENDERBUFFER_BINDING_EXT:
- v->value_int =
- ctx->CurrentRenderbuffer ? ctx->CurrentRenderbuffer->Name : 0;
- break;
- case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES:
- v->value_int = ctx->Array.ArrayObj->PointSize.BufferObj->Name;
- break;
-
- case GL_MAX_VERTEX_UNIFORM_VECTORS:
- v->value_int = ctx->Const.VertexProgram.MaxUniformComponents / 4;
- break;
-
- case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
- v->value_int = ctx->Const.FragmentProgram.MaxUniformComponents / 4;
- break;
- }
-}
-
-/**
- * Check extra constraints on a struct value_desc descriptor
- *
- * If a struct value_desc has a non-NULL extra pointer, it means that
- * there are a number of extra constraints to check or actions to
- * perform. The extras is just an integer array where each integer
- * encode different constraints or actions.
- *
- * \param ctx current context
- * \param func name of calling glGet*v() function for error reporting
- * \param d the struct value_desc that has the extra constraints
- *
- * \return GL_FALSE if one of the constraints was not satisfied,
- * otherwise GL_TRUE.
- */
-static GLboolean
-check_extra(struct gl_context *ctx, const char *func, const struct value_desc *d)
-{
- const GLuint version = ctx->VersionMajor * 10 + ctx->VersionMinor;
- int total, enabled;
- const int *e;
-
- total = 0;
- enabled = 0;
- for (e = d->extra; *e != EXTRA_END; e++)
- switch (*e) {
- case EXTRA_VERSION_30:
- if (version >= 30) {
- total++;
- enabled++;
- }
- break;
- case EXTRA_VERSION_31:
- if (version >= 31) {
- total++;
- enabled++;
- }
- break;
- case EXTRA_VERSION_32:
- if (version >= 32) {
- total++;
- enabled++;
- }
- break;
- case EXTRA_VERSION_ES2:
- if (ctx->API == API_OPENGLES2) {
- total++;
- enabled++;
- }
- break;
- case EXTRA_NEW_BUFFERS:
- if (ctx->NewState & _NEW_BUFFERS)
- _mesa_update_state(ctx);
- break;
- case EXTRA_FLUSH_CURRENT:
- FLUSH_CURRENT(ctx, 0);
- break;
- case EXTRA_VALID_DRAW_BUFFER:
- if (d->pname - GL_DRAW_BUFFER0_ARB >= ctx->Const.MaxDrawBuffers) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "%s(draw buffer %u)",
- func, d->pname - GL_DRAW_BUFFER0_ARB);
- return GL_FALSE;
- }
- break;
- case EXTRA_VALID_TEXTURE_UNIT:
- if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "%s(texture %u)",
- func, ctx->Texture.CurrentUnit);
- return GL_FALSE;
- }
- break;
- case EXTRA_END:
- break;
- default: /* *e is a offset into the extension struct */
- total++;
- if (*(GLboolean *) ((char *) &ctx->Extensions + *e))
- enabled++;
- break;
- }
-
- if (total > 0 && enabled == 0) {
- _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", func,
- _mesa_lookup_enum_by_nr(d->pname));
- return GL_FALSE;
- }
-
- return GL_TRUE;
-}
-
-static const struct value_desc error_value =
- { 0, 0, TYPE_INVALID, NO_OFFSET, NO_EXTRA };
-
-/**
- * Find the struct value_desc corresponding to the enum 'pname'.
- *
- * We hash the enum value to get an index into the 'table' array,
- * which holds the index in the 'values' array of struct value_desc.
- * Once we've found the entry, we do the extra checks, if any, then
- * look up the value and return a pointer to it.
- *
- * If the value has to be computed (for example, it's the result of a
- * function call or we need to add 1 to it), we use the tmp 'v' to
- * store the result.
- *
- * \param func name of glGet*v() func for error reporting
- * \param pname the enum value we're looking up
- * \param p is were we return the pointer to the value
- * \param v a tmp union value variable in the calling glGet*v() function
- *
- * \return the struct value_desc corresponding to the enum or a struct
- * value_desc of TYPE_INVALID if not found. This lets the calling
- * glGet*v() function jump right into a switch statement and
- * handle errors there instead of having to check for NULL.
- */
-static const struct value_desc *
-find_value(const char *func, GLenum pname, void **p, union value *v)
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_texture_unit *unit;
- int mask, hash;
- const struct value_desc *d;
-
- mask = Elements(table) - 1;
- hash = (pname * prime_factor);
- while (1) {
- d = &values[table[hash & mask]];
-
- /* If the enum isn't valid, the hash walk ends with index 0,
- * which is the API mask entry at the beginning of values[]. */
- if (unlikely(d->type == TYPE_API_MASK)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", func,
- _mesa_lookup_enum_by_nr(pname));
- return &error_value;
- }
-
- if (likely(d->pname == pname))
- break;
-
- hash += prime_step;
- }
-
- if (unlikely(d->extra && !check_extra(ctx, func, d)))
- return &error_value;
-
- switch (d->location) {
- case LOC_BUFFER:
- *p = ((char *) ctx->DrawBuffer + d->offset);
- return d;
- case LOC_CONTEXT:
- *p = ((char *) ctx + d->offset);
- return d;
- case LOC_ARRAY:
- *p = ((char *) ctx->Array.ArrayObj + d->offset);
- return d;
- case LOC_TEXUNIT:
- unit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
- *p = ((char *) unit + d->offset);
- return d;
- case LOC_CUSTOM:
- find_custom_value(ctx, d, v);
- *p = v;
- return d;
- default:
- assert(0);
- break;
- }
-
- /* silence warning */
- return &error_value;
-}
-
-static const int transpose[] = {
- 0, 4, 8, 12,
- 1, 5, 9, 13,
- 2, 6, 10, 14,
- 3, 7, 11, 15
-};
-
-void GLAPIENTRY
-_mesa_GetBooleanv(GLenum pname, GLboolean *params)
-{
- const struct value_desc *d;
- union value v;
- GLmatrix *m;
- int shift, i;
- void *p;
-
- d = find_value("glGetBooleanv", pname, &p, &v);
- switch (d->type) {
- case TYPE_INVALID:
- break;
- case TYPE_CONST:
- params[0] = INT_TO_BOOLEAN(d->offset);
- break;
-
- case TYPE_FLOAT_4:
- case TYPE_FLOATN_4:
- params[3] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[3]);
- case TYPE_FLOAT_3:
- case TYPE_FLOATN_3:
- params[2] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[2]);
- case TYPE_FLOAT_2:
- case TYPE_FLOATN_2:
- params[1] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[1]);
- case TYPE_FLOAT:
- case TYPE_FLOATN:
- params[0] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[0]);
- break;
-
- case TYPE_DOUBLEN:
- params[0] = FLOAT_TO_BOOLEAN(((GLdouble *) p)[0]);
- break;
-
- case TYPE_INT_4:
- params[3] = INT_TO_BOOLEAN(((GLint *) p)[3]);
- case TYPE_INT_3:
- params[2] = INT_TO_BOOLEAN(((GLint *) p)[2]);
- case TYPE_INT_2:
- case TYPE_ENUM_2:
- params[1] = INT_TO_BOOLEAN(((GLint *) p)[1]);
- case TYPE_INT:
- case TYPE_ENUM:
- params[0] = INT_TO_BOOLEAN(((GLint *) p)[0]);
- break;
-
- case TYPE_INT_N:
- for (i = 0; i < v.value_int_n.n; i++)
- params[i] = INT_TO_BOOLEAN(v.value_int_n.ints[i]);
- break;
-
- case TYPE_INT64:
- params[0] = INT64_TO_BOOLEAN(((GLint64 *) p)[0]);
- break;
-
- case TYPE_BOOLEAN:
- params[0] = ((GLboolean*) p)[0];
- break;
-
- case TYPE_MATRIX:
- m = *(GLmatrix **) p;
- for (i = 0; i < 16; i++)
- params[i] = FLOAT_TO_BOOLEAN(m->m[i]);
- break;
-
- case TYPE_MATRIX_T:
- m = *(GLmatrix **) p;
- for (i = 0; i < 16; i++)
- params[i] = FLOAT_TO_BOOLEAN(m->m[transpose[i]]);
- break;
-
- case TYPE_BIT_0:
- case TYPE_BIT_1:
- case TYPE_BIT_2:
- case TYPE_BIT_3:
- case TYPE_BIT_4:
- case TYPE_BIT_5:
- shift = d->type - TYPE_BIT_0;
- params[0] = (*(GLbitfield *) p >> shift) & 1;
- break;
- }
-}
-
-void GLAPIENTRY
-_mesa_GetFloatv(GLenum pname, GLfloat *params)
-{
- const struct value_desc *d;
- union value v;
- GLmatrix *m;
- int shift, i;
- void *p;
-
- d = find_value("glGetFloatv", pname, &p, &v);
- switch (d->type) {
- case TYPE_INVALID:
- break;
- case TYPE_CONST:
- params[0] = (GLfloat) d->offset;
- break;
-
- case TYPE_FLOAT_4:
- case TYPE_FLOATN_4:
- params[3] = ((GLfloat *) p)[3];
- case TYPE_FLOAT_3:
- case TYPE_FLOATN_3:
- params[2] = ((GLfloat *) p)[2];
- case TYPE_FLOAT_2:
- case TYPE_FLOATN_2:
- params[1] = ((GLfloat *) p)[1];
- case TYPE_FLOAT:
- case TYPE_FLOATN:
- params[0] = ((GLfloat *) p)[0];
- break;
-
- case TYPE_DOUBLEN:
- params[0] = ((GLdouble *) p)[0];
- break;
-
- case TYPE_INT_4:
- params[3] = (GLfloat) (((GLint *) p)[3]);
- case TYPE_INT_3:
- params[2] = (GLfloat) (((GLint *) p)[2]);
- case TYPE_INT_2:
- case TYPE_ENUM_2:
- params[1] = (GLfloat) (((GLint *) p)[1]);
- case TYPE_INT:
- case TYPE_ENUM:
- params[0] = (GLfloat) (((GLint *) p)[0]);
- break;
-
- case TYPE_INT_N:
- for (i = 0; i < v.value_int_n.n; i++)
- params[i] = INT_TO_FLOAT(v.value_int_n.ints[i]);
- break;
-
- case TYPE_INT64:
- params[0] = ((GLint64 *) p)[0];
- break;
-
- case TYPE_BOOLEAN:
- params[0] = BOOLEAN_TO_FLOAT(*(GLboolean*) p);
- break;
-
- case TYPE_MATRIX:
- m = *(GLmatrix **) p;
- for (i = 0; i < 16; i++)
- params[i] = m->m[i];
- break;
-
- case TYPE_MATRIX_T:
- m = *(GLmatrix **) p;
- for (i = 0; i < 16; i++)
- params[i] = m->m[transpose[i]];
- break;
-
- case TYPE_BIT_0:
- case TYPE_BIT_1:
- case TYPE_BIT_2:
- case TYPE_BIT_3:
- case TYPE_BIT_4:
- case TYPE_BIT_5:
- shift = d->type - TYPE_BIT_0;
- params[0] = BOOLEAN_TO_FLOAT((*(GLbitfield *) p >> shift) & 1);
- break;
- }
-}
-
-void GLAPIENTRY
-_mesa_GetIntegerv(GLenum pname, GLint *params)
-{
- const struct value_desc *d;
- union value v;
- GLmatrix *m;
- int shift, i;
- void *p;
-
- d = find_value("glGetIntegerv", pname, &p, &v);
- switch (d->type) {
- case TYPE_INVALID:
- break;
- case TYPE_CONST:
- params[0] = d->offset;
- break;
-
- case TYPE_FLOAT_4:
- params[3] = IROUND(((GLfloat *) p)[3]);
- case TYPE_FLOAT_3:
- params[2] = IROUND(((GLfloat *) p)[2]);
- case TYPE_FLOAT_2:
- params[1] = IROUND(((GLfloat *) p)[1]);
- case TYPE_FLOAT:
- params[0] = IROUND(((GLfloat *) p)[0]);
- break;
-
- case TYPE_FLOATN_4:
- params[3] = FLOAT_TO_INT(((GLfloat *) p)[3]);
- case TYPE_FLOATN_3:
- params[2] = FLOAT_TO_INT(((GLfloat *) p)[2]);
- case TYPE_FLOATN_2:
- params[1] = FLOAT_TO_INT(((GLfloat *) p)[1]);
- case TYPE_FLOATN:
- params[0] = FLOAT_TO_INT(((GLfloat *) p)[0]);
- break;
-
- case TYPE_DOUBLEN:
- params[0] = FLOAT_TO_INT(((GLdouble *) p)[0]);
- break;
-
- case TYPE_INT_4:
- params[3] = ((GLint *) p)[3];
- case TYPE_INT_3:
- params[2] = ((GLint *) p)[2];
- case TYPE_INT_2:
- case TYPE_ENUM_2:
- params[1] = ((GLint *) p)[1];
- case TYPE_INT:
- case TYPE_ENUM:
- params[0] = ((GLint *) p)[0];
- break;
-
- case TYPE_INT_N:
- for (i = 0; i < v.value_int_n.n; i++)
- params[i] = v.value_int_n.ints[i];
- break;
-
- case TYPE_INT64:
- params[0] = INT64_TO_INT(((GLint64 *) p)[0]);
- break;
-
- case TYPE_BOOLEAN:
- params[0] = BOOLEAN_TO_INT(*(GLboolean*) p);
- break;
-
- case TYPE_MATRIX:
- m = *(GLmatrix **) p;
- for (i = 0; i < 16; i++)
- params[i] = FLOAT_TO_INT(m->m[i]);
- break;
-
- case TYPE_MATRIX_T:
- m = *(GLmatrix **) p;
- for (i = 0; i < 16; i++)
- params[i] = FLOAT_TO_INT(m->m[transpose[i]]);
- break;
-
- case TYPE_BIT_0:
- case TYPE_BIT_1:
- case TYPE_BIT_2:
- case TYPE_BIT_3:
- case TYPE_BIT_4:
- case TYPE_BIT_5:
- shift = d->type - TYPE_BIT_0;
- params[0] = (*(GLbitfield *) p >> shift) & 1;
- break;
- }
-}
-
-#if FEATURE_ARB_sync
-void GLAPIENTRY
-_mesa_GetInteger64v(GLenum pname, GLint64 *params)
-{
- const struct value_desc *d;
- union value v;
- GLmatrix *m;
- int shift, i;
- void *p;
-
- d = find_value("glGetInteger64v", pname, &p, &v);
- switch (d->type) {
- case TYPE_INVALID:
- break;
- case TYPE_CONST:
- params[0] = d->offset;
- break;
-
- case TYPE_FLOAT_4:
- params[3] = IROUND64(((GLfloat *) p)[3]);
- case TYPE_FLOAT_3:
- params[2] = IROUND64(((GLfloat *) p)[2]);
- case TYPE_FLOAT_2:
- params[1] = IROUND64(((GLfloat *) p)[1]);
- case TYPE_FLOAT:
- params[0] = IROUND64(((GLfloat *) p)[0]);
- break;
-
- case TYPE_FLOATN_4:
- params[3] = FLOAT_TO_INT64(((GLfloat *) p)[3]);
- case TYPE_FLOATN_3:
- params[2] = FLOAT_TO_INT64(((GLfloat *) p)[2]);
- case TYPE_FLOATN_2:
- params[1] = FLOAT_TO_INT64(((GLfloat *) p)[1]);
- case TYPE_FLOATN:
- params[0] = FLOAT_TO_INT64(((GLfloat *) p)[0]);
- break;
-
- case TYPE_DOUBLEN:
- params[0] = FLOAT_TO_INT64(((GLdouble *) p)[0]);
- break;
-
- case TYPE_INT_4:
- params[3] = ((GLint *) p)[3];
- case TYPE_INT_3:
- params[2] = ((GLint *) p)[2];
- case TYPE_INT_2:
- case TYPE_ENUM_2:
- params[1] = ((GLint *) p)[1];
- case TYPE_INT:
- case TYPE_ENUM:
- params[0] = ((GLint *) p)[0];
- break;
-
- case TYPE_INT_N:
- for (i = 0; i < v.value_int_n.n; i++)
- params[i] = INT_TO_BOOLEAN(v.value_int_n.ints[i]);
- break;
-
- case TYPE_INT64:
- params[0] = ((GLint64 *) p)[0];
- break;
-
- case TYPE_BOOLEAN:
- params[0] = ((GLboolean*) p)[0];
- break;
-
- case TYPE_MATRIX:
- m = *(GLmatrix **) p;
- for (i = 0; i < 16; i++)
- params[i] = FLOAT_TO_INT64(m->m[i]);
- break;
-
- case TYPE_MATRIX_T:
- m = *(GLmatrix **) p;
- for (i = 0; i < 16; i++)
- params[i] = FLOAT_TO_INT64(m->m[transpose[i]]);
- break;
-
- case TYPE_BIT_0:
- case TYPE_BIT_1:
- case TYPE_BIT_2:
- case TYPE_BIT_3:
- case TYPE_BIT_4:
- case TYPE_BIT_5:
- shift = d->type - TYPE_BIT_0;
- params[0] = (*(GLbitfield *) p >> shift) & 1;
- break;
- }
-}
-#endif /* FEATURE_ARB_sync */
-
-void GLAPIENTRY
-_mesa_GetDoublev(GLenum pname, GLdouble *params)
-{
- const struct value_desc *d;
- union value v;
- GLmatrix *m;
- int shift, i;
- void *p;
-
- d = find_value("glGetDoublev", pname, &p, &v);
- switch (d->type) {
- case TYPE_INVALID:
- break;
- case TYPE_CONST:
- params[0] = d->offset;
- break;
-
- case TYPE_FLOAT_4:
- case TYPE_FLOATN_4:
- params[3] = ((GLfloat *) p)[3];
- case TYPE_FLOAT_3:
- case TYPE_FLOATN_3:
- params[2] = ((GLfloat *) p)[2];
- case TYPE_FLOAT_2:
- case TYPE_FLOATN_2:
- params[1] = ((GLfloat *) p)[1];
- case TYPE_FLOAT:
- case TYPE_FLOATN:
- params[0] = ((GLfloat *) p)[0];
- break;
-
- case TYPE_DOUBLEN:
- params[0] = ((GLdouble *) p)[0];
- break;
-
- case TYPE_INT_4:
- params[3] = ((GLint *) p)[3];
- case TYPE_INT_3:
- params[2] = ((GLint *) p)[2];
- case TYPE_INT_2:
- case TYPE_ENUM_2:
- params[1] = ((GLint *) p)[1];
- case TYPE_INT:
- case TYPE_ENUM:
- params[0] = ((GLint *) p)[0];
- break;
-
- case TYPE_INT_N:
- for (i = 0; i < v.value_int_n.n; i++)
- params[i] = v.value_int_n.ints[i];
- break;
-
- case TYPE_INT64:
- params[0] = ((GLint64 *) p)[0];
- break;
-
- case TYPE_BOOLEAN:
- params[0] = *(GLboolean*) p;
- break;
-
- case TYPE_MATRIX:
- m = *(GLmatrix **) p;
- for (i = 0; i < 16; i++)
- params[i] = m->m[i];
- break;
-
- case TYPE_MATRIX_T:
- m = *(GLmatrix **) p;
- for (i = 0; i < 16; i++)
- params[i] = m->m[transpose[i]];
- break;
-
- case TYPE_BIT_0:
- case TYPE_BIT_1:
- case TYPE_BIT_2:
- case TYPE_BIT_3:
- case TYPE_BIT_4:
- case TYPE_BIT_5:
- shift = d->type - TYPE_BIT_0;
- params[0] = (*(GLbitfield *) p >> shift) & 1;
- break;
- }
-}
-
-static enum value_type
-find_value_indexed(const char *func, GLenum pname, int index, union value *v)
-{
- GET_CURRENT_CONTEXT(ctx);
-
- switch (pname) {
-
- case GL_BLEND:
- if (index >= ctx->Const.MaxDrawBuffers)
- goto invalid_value;
- if (!ctx->Extensions.EXT_draw_buffers2)
- goto invalid_enum;
- v->value_int = (ctx->Color.BlendEnabled >> index) & 1;
- return TYPE_INT;
-
- case GL_BLEND_SRC:
- /* fall-through */
- case GL_BLEND_SRC_RGB:
- if (index >= ctx->Const.MaxDrawBuffers)
- goto invalid_value;
- if (!ctx->Extensions.ARB_draw_buffers_blend)
- goto invalid_enum;
- v->value_int = ctx->Color.Blend[index].SrcRGB;
- return TYPE_INT;
- case GL_BLEND_SRC_ALPHA:
- if (index >= ctx->Const.MaxDrawBuffers)
- goto invalid_value;
- if (!ctx->Extensions.ARB_draw_buffers_blend)
- goto invalid_enum;
- v->value_int = ctx->Color.Blend[index].SrcA;
- return TYPE_INT;
- case GL_BLEND_DST:
- /* fall-through */
- case GL_BLEND_DST_RGB:
- if (index >= ctx->Const.MaxDrawBuffers)
- goto invalid_value;
- if (!ctx->Extensions.ARB_draw_buffers_blend)
- goto invalid_enum;
- v->value_int = ctx->Color.Blend[index].DstRGB;
- return TYPE_INT;
- case GL_BLEND_DST_ALPHA:
- if (index >= ctx->Const.MaxDrawBuffers)
- goto invalid_value;
- if (!ctx->Extensions.ARB_draw_buffers_blend)
- goto invalid_enum;
- v->value_int = ctx->Color.Blend[index].DstA;
- return TYPE_INT;
- case GL_BLEND_EQUATION_RGB:
- if (index >= ctx->Const.MaxDrawBuffers)
- goto invalid_value;
- if (!ctx->Extensions.ARB_draw_buffers_blend)
- goto invalid_enum;
- v->value_int = ctx->Color.Blend[index].EquationRGB;
- return TYPE_INT;
- case GL_BLEND_EQUATION_ALPHA:
- if (index >= ctx->Const.MaxDrawBuffers)
- goto invalid_value;
- if (!ctx->Extensions.ARB_draw_buffers_blend)
- goto invalid_enum;
- v->value_int = ctx->Color.Blend[index].EquationA;
- return TYPE_INT;
-
- case GL_COLOR_WRITEMASK:
- if (index >= ctx->Const.MaxDrawBuffers)
- goto invalid_value;
- if (!ctx->Extensions.EXT_draw_buffers2)
- goto invalid_enum;
- v->value_int_4[0] = ctx->Color.ColorMask[index][RCOMP] ? 1 : 0;
- v->value_int_4[1] = ctx->Color.ColorMask[index][GCOMP] ? 1 : 0;
- v->value_int_4[2] = ctx->Color.ColorMask[index][BCOMP] ? 1 : 0;
- v->value_int_4[3] = ctx->Color.ColorMask[index][ACOMP] ? 1 : 0;
- return TYPE_INT_4;
-
- case GL_TRANSFORM_FEEDBACK_BUFFER_START:
- if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs)
- goto invalid_value;
- if (!ctx->Extensions.EXT_transform_feedback)
- goto invalid_enum;
- v->value_int64 = ctx->TransformFeedback.CurrentObject->Offset[index];
- return TYPE_INT64;
-
- case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
- if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs)
- goto invalid_value;
- if (!ctx->Extensions.EXT_transform_feedback)
- goto invalid_enum;
- v->value_int64 = ctx->TransformFeedback.CurrentObject->Size[index];
- return TYPE_INT64;
-
- case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
- if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs)
- goto invalid_value;
- if (!ctx->Extensions.EXT_transform_feedback)
- goto invalid_enum;
- v->value_int = ctx->TransformFeedback.CurrentObject->Buffers[index]->Name;
- return TYPE_INT;
- }
-
- invalid_enum:
- _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", func,
- _mesa_lookup_enum_by_nr(pname));
- return TYPE_INVALID;
- invalid_value:
- _mesa_error(ctx, GL_INVALID_VALUE, "%s(pname=%s)", func,
- _mesa_lookup_enum_by_nr(pname));
- return TYPE_INVALID;
-}
-
-void GLAPIENTRY
-_mesa_GetBooleanIndexedv( GLenum pname, GLuint index, GLboolean *params )
-{
- union value v;
- enum value_type type =
- find_value_indexed("glGetBooleanIndexedv", pname, index, &v);
-
- switch (type) {
- case TYPE_INT:
- params[0] = INT_TO_BOOLEAN(v.value_int);
- break;
- case TYPE_INT_4:
- params[0] = INT_TO_BOOLEAN(v.value_int_4[0]);
- params[1] = INT_TO_BOOLEAN(v.value_int_4[1]);
- params[2] = INT_TO_BOOLEAN(v.value_int_4[2]);
- params[3] = INT_TO_BOOLEAN(v.value_int_4[3]);
- break;
- case TYPE_INT64:
- params[0] = INT64_TO_BOOLEAN(v.value_int);
- break;
- default:
- ; /* nothing - GL error was recorded */
- }
-}
-
-void GLAPIENTRY
-_mesa_GetIntegerIndexedv( GLenum pname, GLuint index, GLint *params )
-{
- union value v;
- enum value_type type =
- find_value_indexed("glGetIntegerIndexedv", pname, index, &v);
-
- switch (type) {
- case TYPE_INT:
- params[0] = v.value_int;
- break;
- case TYPE_INT_4:
- params[0] = v.value_int_4[0];
- params[1] = v.value_int_4[1];
- params[2] = v.value_int_4[2];
- params[3] = v.value_int_4[3];
- break;
- case TYPE_INT64:
- params[0] = INT64_TO_INT(v.value_int);
- break;
- default:
- ; /* nothing - GL error was recorded */
- }
-}
-
-#if FEATURE_ARB_sync
-void GLAPIENTRY
-_mesa_GetInteger64Indexedv( GLenum pname, GLuint index, GLint64 *params )
-{
- union value v;
- enum value_type type =
- find_value_indexed("glGetIntegerIndexedv", pname, index, &v);
-
- switch (type) {
- case TYPE_INT:
- params[0] = v.value_int;
- break;
- case TYPE_INT_4:
- params[0] = v.value_int_4[0];
- params[1] = v.value_int_4[1];
- params[2] = v.value_int_4[2];
- params[3] = v.value_int_4[3];
- break;
- case TYPE_INT64:
- params[0] = v.value_int;
- break;
- default:
- ; /* nothing - GL error was recorded */
- }
-}
-#endif /* FEATURE_ARB_sync */
-
-#if FEATURE_ES1
-void GLAPIENTRY
-_mesa_GetFixedv(GLenum pname, GLfixed *params)
-{
- const struct value_desc *d;
- union value v;
- GLmatrix *m;
- int shift, i;
- void *p;
-
- d = find_value("glGetDoublev", pname, &p, &v);
- switch (d->type) {
- case TYPE_INVALID:
- break;
- case TYPE_CONST:
- params[0] = INT_TO_FIXED(d->offset);
- break;
-
- case TYPE_FLOAT_4:
- case TYPE_FLOATN_4:
- params[3] = FLOAT_TO_FIXED(((GLfloat *) p)[3]);
- case TYPE_FLOAT_3:
- case TYPE_FLOATN_3:
- params[2] = FLOAT_TO_FIXED(((GLfloat *) p)[2]);
- case TYPE_FLOAT_2:
- case TYPE_FLOATN_2:
- params[1] = FLOAT_TO_FIXED(((GLfloat *) p)[1]);
- case TYPE_FLOAT:
- case TYPE_FLOATN:
- params[0] = FLOAT_TO_FIXED(((GLfloat *) p)[0]);
- break;
-
- case TYPE_DOUBLEN:
- params[0] = FLOAT_TO_FIXED(((GLdouble *) p)[0]);
- break;
-
- case TYPE_INT_4:
- params[3] = INT_TO_FIXED(((GLint *) p)[3]);
- case TYPE_INT_3:
- params[2] = INT_TO_FIXED(((GLint *) p)[2]);
- case TYPE_INT_2:
- case TYPE_ENUM_2:
- params[1] = INT_TO_FIXED(((GLint *) p)[1]);
- case TYPE_INT:
- case TYPE_ENUM:
- params[0] = INT_TO_FIXED(((GLint *) p)[0]);
- break;
-
- case TYPE_INT_N:
- for (i = 0; i < v.value_int_n.n; i++)
- params[i] = INT_TO_FIXED(v.value_int_n.ints[i]);
- break;
-
- case TYPE_INT64:
- params[0] = ((GLint64 *) p)[0];
- break;
-
- case TYPE_BOOLEAN:
- params[0] = BOOLEAN_TO_FIXED(((GLboolean*) p)[0]);
- break;
-
- case TYPE_MATRIX:
- m = *(GLmatrix **) p;
- for (i = 0; i < 16; i++)
- params[i] = FLOAT_TO_FIXED(m->m[i]);
- break;
-
- case TYPE_MATRIX_T:
- m = *(GLmatrix **) p;
- for (i = 0; i < 16; i++)
- params[i] = FLOAT_TO_FIXED(m->m[transpose[i]]);
- break;
-
- case TYPE_BIT_0:
- case TYPE_BIT_1:
- case TYPE_BIT_2:
- case TYPE_BIT_3:
- case TYPE_BIT_4:
- case TYPE_BIT_5:
- shift = d->type - TYPE_BIT_0;
- params[0] = BOOLEAN_TO_FIXED((*(GLbitfield *) p >> shift) & 1);
- break;
- }
-}
-#endif
+/* + * Copyright (C) 2010 Brian Paul All Rights Reserved. + * Copyright (C) 2010 Intel Corporation + * + * 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. + * + * Author: Kristian Høgsberg <krh@bitplanet.net> + */ + +#include "glheader.h" +#include "context.h" +#include "enable.h" +#include "enums.h" +#include "extensions.h" +#include "get.h" +#include "macros.h" +#include "mfeatures.h" +#include "mtypes.h" +#include "state.h" +#include "texcompress.h" +#include "framebuffer.h" + +/* This is a table driven implemetation of the glGet*v() functions. + * The basic idea is that most getters just look up an int somewhere + * in struct gl_context and then convert it to a bool or float according to + * which of glGetIntegerv() glGetBooleanv() etc is being called. + * Instead of generating code to do this, we can just record the enum + * value and the offset into struct gl_context in an array of structs. Then + * in glGet*(), we lookup the struct for the enum in question, and use + * the offset to get the int we need. + * + * Sometimes we need to look up a float, a boolean, a bit in a + * bitfield, a matrix or other types instead, so we need to track the + * type of the value in struct gl_context. And sometimes the value isn't in + * struct gl_context but in the drawbuffer, the array object, current texture + * unit, or maybe it's a computed value. So we need to also track + * where or how to find the value. Finally, we sometimes need to + * check that one of a number of extensions are enabled, the GL + * version or flush or call _mesa_update_state(). This is done by + * attaching optional extra information to the value description + * struct, it's sort of like an array of opcodes that describe extra + * checks or actions. + * + * Putting all this together we end up with struct value_desc below, + * and with a couple of macros to help, the table of struct value_desc + * is about as concise as the specification in the old python script. + */ + +#undef CONST + +#define FLOAT_TO_BOOLEAN(X) ( (X) ? GL_TRUE : GL_FALSE ) +#define FLOAT_TO_FIXED(F) ( ((F) * 65536.0f > INT_MAX) ? INT_MAX : \ + ((F) * 65536.0f < INT_MIN) ? INT_MIN : \ + (GLint) ((F) * 65536.0f) ) + +#define INT_TO_BOOLEAN(I) ( (I) ? GL_TRUE : GL_FALSE ) +#define INT_TO_FIXED(I) ( ((I) > SHRT_MAX) ? INT_MAX : \ + ((I) < SHRT_MIN) ? INT_MIN : \ + (GLint) ((I) * 65536) ) + +#define INT64_TO_BOOLEAN(I) ( (I) ? GL_TRUE : GL_FALSE ) +#define INT64_TO_INT(I) ( (GLint)((I > INT_MAX) ? INT_MAX : ((I < INT_MIN) ? INT_MIN : (I))) ) + +#define BOOLEAN_TO_INT(B) ( (GLint) (B) ) +#define BOOLEAN_TO_INT64(B) ( (GLint64) (B) ) +#define BOOLEAN_TO_FLOAT(B) ( (B) ? 1.0F : 0.0F ) +#define BOOLEAN_TO_FIXED(B) ( (GLint) ((B) ? 1 : 0) << 16 ) + +#define ENUM_TO_INT64(E) ( (GLint64) (E) ) +#define ENUM_TO_FIXED(E) (E) + +enum value_type { + TYPE_INVALID, + TYPE_API_MASK, + TYPE_INT, + TYPE_INT_2, + TYPE_INT_3, + TYPE_INT_4, + TYPE_INT_N, + TYPE_INT64, + TYPE_ENUM, + TYPE_ENUM_2, + TYPE_BOOLEAN, + TYPE_BIT_0, + TYPE_BIT_1, + TYPE_BIT_2, + TYPE_BIT_3, + TYPE_BIT_4, + TYPE_BIT_5, + TYPE_FLOAT, + TYPE_FLOAT_2, + TYPE_FLOAT_3, + TYPE_FLOAT_4, + TYPE_FLOATN, + TYPE_FLOATN_2, + TYPE_FLOATN_3, + TYPE_FLOATN_4, + TYPE_DOUBLEN, + TYPE_MATRIX, + TYPE_MATRIX_T, + TYPE_CONST +}; + +enum value_location { + LOC_BUFFER, + LOC_CONTEXT, + LOC_ARRAY, + LOC_TEXUNIT, + LOC_CUSTOM +}; + +enum value_extra { + EXTRA_END = 0x8000, + EXTRA_VERSION_30, + EXTRA_VERSION_31, + EXTRA_VERSION_32, + EXTRA_VERSION_ES2, + EXTRA_NEW_BUFFERS, + EXTRA_VALID_DRAW_BUFFER, + EXTRA_VALID_TEXTURE_UNIT, + EXTRA_FLUSH_CURRENT, +}; + +#define NO_EXTRA NULL +#define NO_OFFSET 0 + +struct value_desc { + GLenum pname; + GLubyte location; /**< enum value_location */ + GLubyte type; /**< enum value_type */ + int offset; + const int *extra; +}; + +union value { + GLfloat value_float; + GLfloat value_float_4[4]; + GLmatrix *value_matrix; + GLint value_int; + GLint value_int_4[4]; + GLint64 value_int64; + GLenum value_enum; + + /* Sigh, see GL_COMPRESSED_TEXTURE_FORMATS_ARB handling */ + struct { + GLint n, ints[100]; + } value_int_n; + GLboolean value_bool; +}; + +#define BUFFER_FIELD(field, type) \ + LOC_BUFFER, type, offsetof(struct gl_framebuffer, field) +#define CONTEXT_FIELD(field, type) \ + LOC_CONTEXT, type, offsetof(struct gl_context, field) +#define ARRAY_FIELD(field, type) \ + LOC_ARRAY, type, offsetof(struct gl_array_object, field) +#define CONST(value) \ + LOC_CONTEXT, TYPE_CONST, value + +#define BUFFER_INT(field) BUFFER_FIELD(field, TYPE_INT) +#define BUFFER_ENUM(field) BUFFER_FIELD(field, TYPE_ENUM) +#define BUFFER_BOOL(field) BUFFER_FIELD(field, TYPE_BOOLEAN) + +#define CONTEXT_INT(field) CONTEXT_FIELD(field, TYPE_INT) +#define CONTEXT_INT2(field) CONTEXT_FIELD(field, TYPE_INT_2) +#define CONTEXT_INT64(field) CONTEXT_FIELD(field, TYPE_INT64) +#define CONTEXT_ENUM(field) CONTEXT_FIELD(field, TYPE_ENUM) +#define CONTEXT_ENUM2(field) CONTEXT_FIELD(field, TYPE_ENUM_2) +#define CONTEXT_BOOL(field) CONTEXT_FIELD(field, TYPE_BOOLEAN) +#define CONTEXT_BIT0(field) CONTEXT_FIELD(field, TYPE_BIT_0) +#define CONTEXT_BIT1(field) CONTEXT_FIELD(field, TYPE_BIT_1) +#define CONTEXT_BIT2(field) CONTEXT_FIELD(field, TYPE_BIT_2) +#define CONTEXT_BIT3(field) CONTEXT_FIELD(field, TYPE_BIT_3) +#define CONTEXT_BIT4(field) CONTEXT_FIELD(field, TYPE_BIT_4) +#define CONTEXT_BIT5(field) CONTEXT_FIELD(field, TYPE_BIT_5) +#define CONTEXT_FLOAT(field) CONTEXT_FIELD(field, TYPE_FLOAT) +#define CONTEXT_FLOAT2(field) CONTEXT_FIELD(field, TYPE_FLOAT_2) +#define CONTEXT_FLOAT3(field) CONTEXT_FIELD(field, TYPE_FLOAT_3) +#define CONTEXT_FLOAT4(field) CONTEXT_FIELD(field, TYPE_FLOAT_4) +#define CONTEXT_MATRIX(field) CONTEXT_FIELD(field, TYPE_MATRIX) +#define CONTEXT_MATRIX_T(field) CONTEXT_FIELD(field, TYPE_MATRIX_T) + +#define ARRAY_INT(field) ARRAY_FIELD(field, TYPE_INT) +#define ARRAY_ENUM(field) ARRAY_FIELD(field, TYPE_ENUM) +#define ARRAY_BOOL(field) ARRAY_FIELD(field, TYPE_BOOLEAN) + +#define EXT(f) \ + offsetof(struct gl_extensions, f) + +#define EXTRA_EXT(e) \ + static const int extra_##e[] = { \ + EXT(e), EXTRA_END \ + } + +#define EXTRA_EXT2(e1, e2) \ + static const int extra_##e1##_##e2[] = { \ + EXT(e1), EXT(e2), EXTRA_END \ + } + +/* The 'extra' mechanism is a way to specify extra checks (such as + * extensions or specific gl versions) or actions (flush current, new + * buffers) that we need to do before looking up an enum. We need to + * declare them all up front so we can refer to them in the value_desc + * structs below. */ + +static const int extra_new_buffers[] = { + EXTRA_NEW_BUFFERS, + EXTRA_END +}; + +static const int extra_valid_draw_buffer[] = { + EXTRA_VALID_DRAW_BUFFER, + EXTRA_END +}; + +static const int extra_valid_texture_unit[] = { + EXTRA_VALID_TEXTURE_UNIT, + EXTRA_END +}; + +static const int extra_flush_current_valid_texture_unit[] = { + EXTRA_FLUSH_CURRENT, + EXTRA_VALID_TEXTURE_UNIT, + EXTRA_END +}; + +static const int extra_flush_current[] = { + EXTRA_FLUSH_CURRENT, + EXTRA_END +}; + +static const int extra_new_buffers_OES_read_format[] = { + EXTRA_NEW_BUFFERS, + EXT(OES_read_format), + EXTRA_END +}; + +static const int extra_EXT_secondary_color_flush_current[] = { + EXT(EXT_secondary_color), + EXTRA_FLUSH_CURRENT, + EXTRA_END +}; + +static const int extra_EXT_fog_coord_flush_current[] = { + EXT(EXT_fog_coord), + EXTRA_FLUSH_CURRENT, + EXTRA_END +}; + +static const int extra_EXT_texture_integer[] = { + EXT(EXT_texture_integer), + EXTRA_END +}; + +static const int extra_EXT_gpu_shader4[] = { + EXT(EXT_gpu_shader4), + EXTRA_END +}; + + +EXTRA_EXT(ARB_ES2_compatibility); +EXTRA_EXT(ARB_multitexture); +EXTRA_EXT(ARB_texture_cube_map); +EXTRA_EXT(MESA_texture_array); +EXTRA_EXT2(EXT_secondary_color, ARB_vertex_program); +EXTRA_EXT(EXT_secondary_color); +EXTRA_EXT(EXT_fog_coord); +EXTRA_EXT(EXT_texture_lod_bias); +EXTRA_EXT(EXT_texture_filter_anisotropic); +EXTRA_EXT(IBM_rasterpos_clip); +EXTRA_EXT(NV_point_sprite); +EXTRA_EXT(SGIS_generate_mipmap); +EXTRA_EXT(NV_vertex_program); +EXTRA_EXT(NV_fragment_program); +EXTRA_EXT(NV_texture_rectangle); +EXTRA_EXT(EXT_stencil_two_side); +EXTRA_EXT(NV_light_max_exponent); +EXTRA_EXT(EXT_depth_bounds_test); +EXTRA_EXT(ARB_depth_clamp); +EXTRA_EXT(ATI_fragment_shader); +EXTRA_EXT(EXT_framebuffer_blit); +EXTRA_EXT(ARB_shader_objects); +EXTRA_EXT(EXT_provoking_vertex); +EXTRA_EXT(ARB_fragment_shader); +EXTRA_EXT(ARB_fragment_program); +EXTRA_EXT2(ARB_framebuffer_object, EXT_framebuffer_multisample); +EXTRA_EXT(EXT_framebuffer_object); +EXTRA_EXT(APPLE_vertex_array_object); +EXTRA_EXT(ARB_seamless_cube_map); +EXTRA_EXT(EXT_compiled_vertex_array); +EXTRA_EXT(ARB_sync); +EXTRA_EXT(ARB_vertex_shader); +EXTRA_EXT(EXT_transform_feedback); +EXTRA_EXT(ARB_transform_feedback2); +EXTRA_EXT(EXT_pixel_buffer_object); +EXTRA_EXT(ARB_vertex_program); +EXTRA_EXT2(NV_point_sprite, ARB_point_sprite); +EXTRA_EXT2(ARB_fragment_program, NV_fragment_program); +EXTRA_EXT2(ARB_vertex_program, NV_vertex_program); +EXTRA_EXT2(ARB_vertex_program, ARB_fragment_program); +EXTRA_EXT(ARB_vertex_buffer_object); +EXTRA_EXT(ARB_geometry_shader4); +EXTRA_EXT(ARB_copy_buffer); +EXTRA_EXT(EXT_framebuffer_sRGB); + +static const int +extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program[] = { + EXT(ARB_vertex_program), + EXT(ARB_fragment_program), + EXT(NV_vertex_program), + EXTRA_END +}; + +static const int +extra_NV_vertex_program_ARB_vertex_program_ARB_fragment_program_NV_vertex_program[] = { + EXT(NV_vertex_program), + EXT(ARB_vertex_program), + EXT(ARB_fragment_program), + EXT(NV_vertex_program), + EXTRA_END +}; + +static const int +extra_NV_primitive_restart[] = { + EXT(NV_primitive_restart), + EXTRA_END +}; + +static const int extra_version_30[] = { EXTRA_VERSION_30, EXTRA_END }; +static const int extra_version_31[] = { EXTRA_VERSION_31, EXTRA_END }; +static const int extra_version_32[] = { EXTRA_VERSION_32, EXTRA_END }; + +static const int +extra_ARB_vertex_program_version_es2[] = { + EXT(ARB_vertex_program), + EXTRA_VERSION_ES2, + EXTRA_END +}; + +#define API_OPENGL_BIT (1 << API_OPENGL) +#define API_OPENGLES_BIT (1 << API_OPENGLES) +#define API_OPENGLES2_BIT (1 << API_OPENGLES2) + +/* This is the big table describing all the enums we accept in + * glGet*v(). The table is partitioned into six parts: enums + * understood by all GL APIs (OpenGL, GLES and GLES2), enums shared + * between OpenGL and GLES, enums exclusive to GLES, etc for the + * remaining combinations. When we add the enums to the hash table in + * _mesa_init_get_hash(), we only add the enums for the API we're + * instantiating and the different sections are guarded by #if + * FEATURE_GL etc to make sure we only compile in the enums we may + * need. */ + +static const struct value_desc values[] = { + /* Enums shared between OpenGL, GLES1 and GLES2 */ + { 0, 0, TYPE_API_MASK, + API_OPENGL_BIT | API_OPENGLES_BIT | API_OPENGLES2_BIT, NO_EXTRA}, + { GL_ALPHA_BITS, BUFFER_INT(Visual.alphaBits), extra_new_buffers }, + { GL_BLEND, CONTEXT_BIT0(Color.BlendEnabled), NO_EXTRA }, + { GL_BLEND_SRC, CONTEXT_ENUM(Color.Blend[0].SrcRGB), NO_EXTRA }, + { GL_BLUE_BITS, BUFFER_INT(Visual.blueBits), extra_new_buffers }, + { GL_COLOR_CLEAR_VALUE, CONTEXT_FIELD(Color.ClearColor[0], TYPE_FLOATN_4), NO_EXTRA }, + { GL_COLOR_WRITEMASK, LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA }, + { GL_CULL_FACE, CONTEXT_BOOL(Polygon.CullFlag), NO_EXTRA }, + { GL_CULL_FACE_MODE, CONTEXT_ENUM(Polygon.CullFaceMode), NO_EXTRA }, + { GL_DEPTH_BITS, BUFFER_INT(Visual.depthBits), NO_EXTRA }, + { GL_DEPTH_CLEAR_VALUE, CONTEXT_FIELD(Depth.Clear, TYPE_DOUBLEN), NO_EXTRA }, + { GL_DEPTH_FUNC, CONTEXT_ENUM(Depth.Func), NO_EXTRA }, + { GL_DEPTH_RANGE, CONTEXT_FIELD(Viewport.Near, TYPE_FLOATN_2), NO_EXTRA }, + { GL_DEPTH_TEST, CONTEXT_BOOL(Depth.Test), NO_EXTRA }, + { GL_DEPTH_WRITEMASK, CONTEXT_BOOL(Depth.Mask), NO_EXTRA }, + { GL_DITHER, CONTEXT_BOOL(Color.DitherFlag), NO_EXTRA }, + { GL_FRONT_FACE, CONTEXT_ENUM(Polygon.FrontFace), NO_EXTRA }, + { GL_GREEN_BITS, BUFFER_INT(Visual.greenBits), extra_new_buffers }, + { GL_LINE_WIDTH, CONTEXT_FLOAT(Line.Width), NO_EXTRA }, + { GL_ALIASED_LINE_WIDTH_RANGE, CONTEXT_FLOAT2(Const.MinLineWidth), NO_EXTRA }, + { GL_MAX_ELEMENTS_VERTICES, CONTEXT_INT(Const.MaxArrayLockSize), NO_EXTRA }, + { GL_MAX_ELEMENTS_INDICES, CONTEXT_INT(Const.MaxArrayLockSize), NO_EXTRA }, + { GL_MAX_TEXTURE_SIZE, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_context, Const.MaxTextureLevels), NO_EXTRA }, + { GL_MAX_VIEWPORT_DIMS, CONTEXT_INT2(Const.MaxViewportWidth), NO_EXTRA }, + { GL_PACK_ALIGNMENT, CONTEXT_INT(Pack.Alignment), NO_EXTRA }, + { GL_ALIASED_POINT_SIZE_RANGE, CONTEXT_FLOAT2(Const.MinPointSize), NO_EXTRA }, + { GL_POLYGON_OFFSET_FACTOR, CONTEXT_FLOAT(Polygon.OffsetFactor ), NO_EXTRA }, + { GL_POLYGON_OFFSET_UNITS, CONTEXT_FLOAT(Polygon.OffsetUnits ), NO_EXTRA }, + { GL_POLYGON_OFFSET_FILL, CONTEXT_BOOL(Polygon.OffsetFill), NO_EXTRA }, + { GL_RED_BITS, BUFFER_INT(Visual.redBits), extra_new_buffers }, + { GL_SCISSOR_BOX, LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA }, + { GL_SCISSOR_TEST, CONTEXT_BOOL(Scissor.Enabled), NO_EXTRA }, + { GL_STENCIL_BITS, BUFFER_INT(Visual.stencilBits), NO_EXTRA }, + { GL_STENCIL_CLEAR_VALUE, CONTEXT_INT(Stencil.Clear), NO_EXTRA }, + { GL_STENCIL_FAIL, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, + { GL_STENCIL_FUNC, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, + { GL_STENCIL_PASS_DEPTH_FAIL, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, + { GL_STENCIL_PASS_DEPTH_PASS, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, + { GL_STENCIL_REF, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA }, + { GL_STENCIL_TEST, CONTEXT_BOOL(Stencil.Enabled), NO_EXTRA }, + { GL_STENCIL_VALUE_MASK, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA }, + { GL_STENCIL_WRITEMASK, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA }, + { GL_SUBPIXEL_BITS, CONTEXT_INT(Const.SubPixelBits), NO_EXTRA }, + { GL_TEXTURE_BINDING_2D, LOC_CUSTOM, TYPE_INT, TEXTURE_2D_INDEX, NO_EXTRA }, + { GL_UNPACK_ALIGNMENT, CONTEXT_INT(Unpack.Alignment), NO_EXTRA }, + { GL_VIEWPORT, LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA }, + + /* GL_ARB_multitexture */ + { GL_ACTIVE_TEXTURE_ARB, + LOC_CUSTOM, TYPE_INT, 0, extra_ARB_multitexture }, + + /* Note that all the OES_* extensions require that the Mesa "struct + * gl_extensions" include a member with the name of the extension. + * That structure does not yet include OES extensions (and we're + * not sure whether it will). If it does, all the OES_* + * extensions below should mark the dependency. */ + + /* GL_ARB_texture_cube_map */ + { GL_TEXTURE_BINDING_CUBE_MAP_ARB, LOC_CUSTOM, TYPE_INT, + TEXTURE_CUBE_INDEX, extra_ARB_texture_cube_map }, + { GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_context, Const.MaxCubeTextureLevels), + extra_ARB_texture_cube_map }, /* XXX: OES_texture_cube_map */ + + /* XXX: OES_blend_subtract */ + { GL_BLEND_SRC_RGB_EXT, CONTEXT_ENUM(Color.Blend[0].SrcRGB), NO_EXTRA }, + { GL_BLEND_DST_RGB_EXT, CONTEXT_ENUM(Color.Blend[0].DstRGB), NO_EXTRA }, + { GL_BLEND_SRC_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].SrcA), NO_EXTRA }, + { GL_BLEND_DST_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].DstA), NO_EXTRA }, + + /* GL_BLEND_EQUATION_RGB, which is what we're really after, is + * defined identically to GL_BLEND_EQUATION. */ + { GL_BLEND_EQUATION, CONTEXT_ENUM(Color.Blend[0].EquationRGB), NO_EXTRA }, + { GL_BLEND_EQUATION_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].EquationA), NO_EXTRA }, + + /* GL_ARB_texture_compression */ + { GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, + { GL_COMPRESSED_TEXTURE_FORMATS_ARB, LOC_CUSTOM, TYPE_INT_N, 0, NO_EXTRA }, + + /* GL_ARB_multisample */ + { GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, + CONTEXT_BOOL(Multisample.SampleAlphaToCoverage), NO_EXTRA }, + { GL_SAMPLE_COVERAGE_ARB, CONTEXT_BOOL(Multisample.SampleCoverage), NO_EXTRA }, + { GL_SAMPLE_COVERAGE_VALUE_ARB, + CONTEXT_FLOAT(Multisample.SampleCoverageValue), NO_EXTRA }, + { GL_SAMPLE_COVERAGE_INVERT_ARB, + CONTEXT_BOOL(Multisample.SampleCoverageInvert), NO_EXTRA }, + { GL_SAMPLE_BUFFERS_ARB, BUFFER_INT(Visual.sampleBuffers), NO_EXTRA }, + { GL_SAMPLES_ARB, BUFFER_INT(Visual.samples), NO_EXTRA }, + + /* GL_SGIS_generate_mipmap */ + { GL_GENERATE_MIPMAP_HINT_SGIS, CONTEXT_ENUM(Hint.GenerateMipmap), + extra_SGIS_generate_mipmap }, + + /* GL_ARB_vertex_buffer_object */ + { GL_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, + + /* GL_ARB_vertex_buffer_object */ + /* GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB - not supported */ + { GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, 0, + extra_ARB_vertex_buffer_object }, + + /* GL_ARB_copy_buffer */ + { GL_COPY_READ_BUFFER, LOC_CUSTOM, TYPE_INT, 0, extra_ARB_copy_buffer }, + { GL_COPY_WRITE_BUFFER, LOC_CUSTOM, TYPE_INT, 0, extra_ARB_copy_buffer }, + + /* GL_OES_read_format */ + { GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, LOC_CUSTOM, TYPE_INT, 0, + extra_new_buffers_OES_read_format }, + { GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, LOC_CUSTOM, TYPE_INT, 0, + extra_new_buffers_OES_read_format }, + + /* GL_EXT_framebuffer_object */ + { GL_FRAMEBUFFER_BINDING_EXT, BUFFER_INT(Name), + extra_EXT_framebuffer_object }, + { GL_RENDERBUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0, + extra_EXT_framebuffer_object }, + { GL_MAX_RENDERBUFFER_SIZE_EXT, CONTEXT_INT(Const.MaxRenderbufferSize), + extra_EXT_framebuffer_object }, + + /* This entry isn't spec'ed for GLES 2, but is needed for Mesa's + * GLSL: */ + { GL_MAX_CLIP_PLANES, CONTEXT_INT(Const.MaxClipPlanes), NO_EXTRA }, + +#if FEATURE_GL || FEATURE_ES1 + /* Enums in OpenGL and GLES1 */ + { 0, 0, TYPE_API_MASK, API_OPENGL_BIT | API_OPENGLES_BIT, NO_EXTRA }, + { GL_LIGHT0, CONTEXT_BOOL(Light.Light[0].Enabled), NO_EXTRA }, + { GL_LIGHT1, CONTEXT_BOOL(Light.Light[1].Enabled), NO_EXTRA }, + { GL_LIGHT2, CONTEXT_BOOL(Light.Light[2].Enabled), NO_EXTRA }, + { GL_LIGHT3, CONTEXT_BOOL(Light.Light[3].Enabled), NO_EXTRA }, + { GL_LIGHT4, CONTEXT_BOOL(Light.Light[4].Enabled), NO_EXTRA }, + { GL_LIGHT5, CONTEXT_BOOL(Light.Light[5].Enabled), NO_EXTRA }, + { GL_LIGHT6, CONTEXT_BOOL(Light.Light[6].Enabled), NO_EXTRA }, + { GL_LIGHT7, CONTEXT_BOOL(Light.Light[7].Enabled), NO_EXTRA }, + { GL_LIGHTING, CONTEXT_BOOL(Light.Enabled), NO_EXTRA }, + { GL_LIGHT_MODEL_AMBIENT, + CONTEXT_FIELD(Light.Model.Ambient[0], TYPE_FLOATN_4), NO_EXTRA }, + { GL_LIGHT_MODEL_TWO_SIDE, CONTEXT_BOOL(Light.Model.TwoSide), NO_EXTRA }, + { GL_ALPHA_TEST, CONTEXT_BOOL(Color.AlphaEnabled), NO_EXTRA }, + { GL_ALPHA_TEST_FUNC, CONTEXT_ENUM(Color.AlphaFunc), NO_EXTRA }, + { GL_ALPHA_TEST_REF, CONTEXT_FIELD(Color.AlphaRef, TYPE_FLOATN), NO_EXTRA }, + { GL_BLEND_DST, CONTEXT_ENUM(Color.Blend[0].DstRGB), NO_EXTRA }, + { GL_CLIP_PLANE0, CONTEXT_BIT0(Transform.ClipPlanesEnabled), NO_EXTRA }, + { GL_CLIP_PLANE1, CONTEXT_BIT1(Transform.ClipPlanesEnabled), NO_EXTRA }, + { GL_CLIP_PLANE2, CONTEXT_BIT2(Transform.ClipPlanesEnabled), NO_EXTRA }, + { GL_CLIP_PLANE3, CONTEXT_BIT3(Transform.ClipPlanesEnabled), NO_EXTRA }, + { GL_CLIP_PLANE4, CONTEXT_BIT4(Transform.ClipPlanesEnabled), NO_EXTRA }, + { GL_CLIP_PLANE5, CONTEXT_BIT5(Transform.ClipPlanesEnabled), NO_EXTRA }, + { GL_COLOR_MATERIAL, CONTEXT_BOOL(Light.ColorMaterialEnabled), NO_EXTRA }, + { GL_CURRENT_COLOR, + CONTEXT_FIELD(Current.Attrib[VERT_ATTRIB_COLOR0][0], TYPE_FLOATN_4), + extra_flush_current }, + { GL_CURRENT_NORMAL, + CONTEXT_FIELD(Current.Attrib[VERT_ATTRIB_NORMAL][0], TYPE_FLOATN_3), + extra_flush_current }, + { GL_CURRENT_TEXTURE_COORDS, LOC_CUSTOM, TYPE_FLOAT_4, 0, + extra_flush_current_valid_texture_unit }, + { GL_DISTANCE_ATTENUATION_EXT, CONTEXT_FLOAT3(Point.Params[0]), NO_EXTRA }, + { GL_FOG, CONTEXT_BOOL(Fog.Enabled), NO_EXTRA }, + { GL_FOG_COLOR, CONTEXT_FIELD(Fog.Color[0], TYPE_FLOATN_4), NO_EXTRA }, + { GL_FOG_DENSITY, CONTEXT_FLOAT(Fog.Density), NO_EXTRA }, + { GL_FOG_END, CONTEXT_FLOAT(Fog.End), NO_EXTRA }, + { GL_FOG_HINT, CONTEXT_ENUM(Hint.Fog), NO_EXTRA }, + { GL_FOG_MODE, CONTEXT_ENUM(Fog.Mode), NO_EXTRA }, + { GL_FOG_START, CONTEXT_FLOAT(Fog.Start), NO_EXTRA }, + { GL_LINE_SMOOTH, CONTEXT_BOOL(Line.SmoothFlag), NO_EXTRA }, + { GL_LINE_SMOOTH_HINT, CONTEXT_ENUM(Hint.LineSmooth), NO_EXTRA }, + { GL_LINE_WIDTH_RANGE, CONTEXT_FLOAT2(Const.MinLineWidthAA), NO_EXTRA }, + { GL_COLOR_LOGIC_OP, CONTEXT_BOOL(Color.ColorLogicOpEnabled), NO_EXTRA }, + { GL_LOGIC_OP_MODE, CONTEXT_ENUM(Color.LogicOp), NO_EXTRA }, + { GL_MATRIX_MODE, CONTEXT_ENUM(Transform.MatrixMode), NO_EXTRA }, + { GL_MAX_MODELVIEW_STACK_DEPTH, CONST(MAX_MODELVIEW_STACK_DEPTH), NO_EXTRA }, + { GL_MAX_PROJECTION_STACK_DEPTH, CONST(MAX_PROJECTION_STACK_DEPTH), NO_EXTRA }, + { GL_MAX_TEXTURE_STACK_DEPTH, CONST(MAX_TEXTURE_STACK_DEPTH), NO_EXTRA }, + { GL_MODELVIEW_MATRIX, CONTEXT_MATRIX(ModelviewMatrixStack.Top), NO_EXTRA }, + { GL_MODELVIEW_STACK_DEPTH, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_context, ModelviewMatrixStack.Depth), NO_EXTRA }, + { GL_NORMALIZE, CONTEXT_BOOL(Transform.Normalize), NO_EXTRA }, + { GL_PACK_SKIP_IMAGES_EXT, CONTEXT_INT(Pack.SkipImages), NO_EXTRA }, + { GL_PERSPECTIVE_CORRECTION_HINT, CONTEXT_ENUM(Hint.PerspectiveCorrection), NO_EXTRA }, + { GL_POINT_SIZE, CONTEXT_FLOAT(Point.Size), NO_EXTRA }, + { GL_POINT_SIZE_RANGE, CONTEXT_FLOAT2(Const.MinPointSizeAA), NO_EXTRA }, + { GL_POINT_SMOOTH, CONTEXT_BOOL(Point.SmoothFlag), NO_EXTRA }, + { GL_POINT_SMOOTH_HINT, CONTEXT_ENUM(Hint.PointSmooth), NO_EXTRA }, + { GL_POINT_SIZE_MIN_EXT, CONTEXT_FLOAT(Point.MinSize), NO_EXTRA }, + { GL_POINT_SIZE_MAX_EXT, CONTEXT_FLOAT(Point.MaxSize), NO_EXTRA }, + { GL_POINT_FADE_THRESHOLD_SIZE_EXT, CONTEXT_FLOAT(Point.Threshold), NO_EXTRA }, + { GL_PROJECTION_MATRIX, CONTEXT_MATRIX(ProjectionMatrixStack.Top), NO_EXTRA }, + { GL_PROJECTION_STACK_DEPTH, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_context, ProjectionMatrixStack.Depth), NO_EXTRA }, + { GL_RESCALE_NORMAL, CONTEXT_BOOL(Transform.RescaleNormals), NO_EXTRA }, + { GL_SHADE_MODEL, CONTEXT_ENUM(Light.ShadeModel), NO_EXTRA }, + { GL_TEXTURE_2D, LOC_CUSTOM, TYPE_BOOLEAN, 0, NO_EXTRA }, + { GL_TEXTURE_MATRIX, LOC_CUSTOM, TYPE_MATRIX, 0, extra_valid_texture_unit }, + { GL_TEXTURE_STACK_DEPTH, LOC_CUSTOM, TYPE_INT, 0, + extra_valid_texture_unit }, + + { GL_VERTEX_ARRAY, ARRAY_BOOL(Vertex.Enabled), NO_EXTRA }, + { GL_VERTEX_ARRAY_SIZE, ARRAY_INT(Vertex.Size), NO_EXTRA }, + { GL_VERTEX_ARRAY_TYPE, ARRAY_ENUM(Vertex.Type), NO_EXTRA }, + { GL_VERTEX_ARRAY_STRIDE, ARRAY_INT(Vertex.Stride), NO_EXTRA }, + { GL_NORMAL_ARRAY, ARRAY_ENUM(Normal.Enabled), NO_EXTRA }, + { GL_NORMAL_ARRAY_TYPE, ARRAY_ENUM(Normal.Type), NO_EXTRA }, + { GL_NORMAL_ARRAY_STRIDE, ARRAY_INT(Normal.Stride), NO_EXTRA }, + { GL_COLOR_ARRAY, ARRAY_BOOL(Color.Enabled), NO_EXTRA }, + { GL_COLOR_ARRAY_SIZE, ARRAY_INT(Color.Size), NO_EXTRA }, + { GL_COLOR_ARRAY_TYPE, ARRAY_ENUM(Color.Type), NO_EXTRA }, + { GL_COLOR_ARRAY_STRIDE, ARRAY_INT(Color.Stride), NO_EXTRA }, + { GL_TEXTURE_COORD_ARRAY, + LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Enabled), NO_EXTRA }, + { GL_TEXTURE_COORD_ARRAY_SIZE, + LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Size), NO_EXTRA }, + { GL_TEXTURE_COORD_ARRAY_TYPE, + LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Type), NO_EXTRA }, + { GL_TEXTURE_COORD_ARRAY_STRIDE, + LOC_CUSTOM, TYPE_BOOLEAN, offsetof(struct gl_client_array, Stride), NO_EXTRA }, + + /* GL_ARB_ES2_compatibility */ + { GL_SHADER_COMPILER, CONST(1), extra_ARB_ES2_compatibility }, + { GL_MAX_VARYING_VECTORS, CONTEXT_INT(Const.MaxVarying), + extra_ARB_ES2_compatibility }, + { GL_MAX_VERTEX_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, + extra_ARB_ES2_compatibility }, + { GL_MAX_FRAGMENT_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, + extra_ARB_ES2_compatibility }, + + /* GL_ARB_multitexture */ + { GL_MAX_TEXTURE_UNITS_ARB, + CONTEXT_INT(Const.MaxTextureUnits), extra_ARB_multitexture }, + { GL_CLIENT_ACTIVE_TEXTURE_ARB, + LOC_CUSTOM, TYPE_INT, 0, extra_ARB_multitexture }, + + /* GL_ARB_texture_cube_map */ + { GL_TEXTURE_CUBE_MAP_ARB, LOC_CUSTOM, TYPE_BOOLEAN, 0, NO_EXTRA }, + /* S, T, and R are always set at the same time */ + { GL_TEXTURE_GEN_STR_OES, LOC_TEXUNIT, TYPE_BIT_0, + offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, + + /* GL_ARB_multisample */ + { GL_MULTISAMPLE_ARB, CONTEXT_BOOL(Multisample.Enabled), NO_EXTRA }, + { GL_SAMPLE_ALPHA_TO_ONE_ARB, CONTEXT_BOOL(Multisample.SampleAlphaToOne), NO_EXTRA }, + + /* GL_ARB_vertex_buffer_object */ + { GL_VERTEX_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, Vertex.BufferObj), NO_EXTRA }, + { GL_NORMAL_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, Normal.BufferObj), NO_EXTRA }, + { GL_COLOR_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, Color.BufferObj), NO_EXTRA }, + { GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, NO_OFFSET, NO_EXTRA }, + + /* GL_OES_point_sprite */ + { GL_POINT_SPRITE_NV, + CONTEXT_BOOL(Point.PointSprite), + extra_NV_point_sprite_ARB_point_sprite }, + + /* GL_ARB_fragment_shader */ + { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, + CONTEXT_INT(Const.FragmentProgram.MaxUniformComponents), + extra_ARB_fragment_shader }, + + /* GL_ARB_vertex_shader */ + { GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, + CONTEXT_INT(Const.VertexProgram.MaxUniformComponents), + extra_ARB_vertex_shader }, + { GL_MAX_VARYING_FLOATS_ARB, LOC_CUSTOM, TYPE_INT, 0, + extra_ARB_vertex_shader }, + + /* GL_EXT_texture_lod_bias */ + { GL_MAX_TEXTURE_LOD_BIAS_EXT, CONTEXT_FLOAT(Const.MaxTextureLodBias), + extra_EXT_texture_lod_bias }, + + /* GL_EXT_texture_filter_anisotropic */ + { GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, + CONTEXT_FLOAT(Const.MaxTextureMaxAnisotropy), + extra_EXT_texture_filter_anisotropic }, +#endif /* FEATURE_GL || FEATURE_ES1 */ + +#if FEATURE_ES1 + { 0, 0, TYPE_API_MASK, API_OPENGLES_BIT }, + /* XXX: OES_matrix_get */ + { GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES }, + { GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES }, + { GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES }, + + /* OES_point_size_array */ + { GL_POINT_SIZE_ARRAY_OES, ARRAY_FIELD(PointSize.Enabled, TYPE_BOOLEAN) }, + { GL_POINT_SIZE_ARRAY_TYPE_OES, ARRAY_FIELD(PointSize.Type, TYPE_ENUM) }, + { GL_POINT_SIZE_ARRAY_STRIDE_OES, ARRAY_FIELD(PointSize.Stride, TYPE_INT) }, + { GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES, LOC_CUSTOM, TYPE_INT, 0 }, +#endif /* FEATURE_ES1 */ + +#if FEATURE_GL || FEATURE_ES2 + { 0, 0, TYPE_API_MASK, API_OPENGL_BIT | API_OPENGLES2_BIT, NO_EXTRA }, + /* This entry isn't spec'ed for GLES 2, but is needed for Mesa's GLSL: */ + { GL_MAX_LIGHTS, CONTEXT_INT(Const.MaxLights), NO_EXTRA }, + { GL_MAX_TEXTURE_COORDS_ARB, /* == GL_MAX_TEXTURE_COORDS_NV */ + CONTEXT_INT(Const.MaxTextureCoordUnits), + extra_ARB_fragment_program_NV_fragment_program }, + + /* GL_ARB_draw_buffers */ + { GL_MAX_DRAW_BUFFERS_ARB, CONTEXT_INT(Const.MaxDrawBuffers), NO_EXTRA }, + + { GL_BLEND_COLOR_EXT, CONTEXT_FIELD(Color.BlendColor[0], TYPE_FLOATN_4), NO_EXTRA }, + /* GL_ARB_fragment_program */ + { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, /* == GL_MAX_TEXTURE_IMAGE_UNITS_NV */ + CONTEXT_INT(Const.MaxTextureImageUnits), + extra_ARB_fragment_program_NV_fragment_program }, + { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, + CONTEXT_INT(Const.MaxVertexTextureImageUnits), extra_ARB_vertex_shader }, + { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, + CONTEXT_INT(Const.MaxCombinedTextureImageUnits), + extra_ARB_vertex_shader }, + + /* GL_ARB_shader_objects + * Actually, this token isn't part of GL_ARB_shader_objects, but is + * close enough for now. */ + { GL_CURRENT_PROGRAM, LOC_CUSTOM, TYPE_INT, 0, extra_ARB_shader_objects }, + + /* OpenGL 2.0 */ + { GL_STENCIL_BACK_FUNC, CONTEXT_ENUM(Stencil.Function[1]), NO_EXTRA }, + { GL_STENCIL_BACK_VALUE_MASK, CONTEXT_INT(Stencil.ValueMask[1]), NO_EXTRA }, + { GL_STENCIL_BACK_WRITEMASK, CONTEXT_INT(Stencil.WriteMask[1]), NO_EXTRA }, + { GL_STENCIL_BACK_REF, CONTEXT_INT(Stencil.Ref[1]), NO_EXTRA }, + { GL_STENCIL_BACK_FAIL, CONTEXT_ENUM(Stencil.FailFunc[1]), NO_EXTRA }, + { GL_STENCIL_BACK_PASS_DEPTH_FAIL, CONTEXT_ENUM(Stencil.ZFailFunc[1]), NO_EXTRA }, + { GL_STENCIL_BACK_PASS_DEPTH_PASS, CONTEXT_ENUM(Stencil.ZPassFunc[1]), NO_EXTRA }, + + { GL_MAX_VERTEX_ATTRIBS_ARB, + CONTEXT_INT(Const.VertexProgram.MaxAttribs), + extra_ARB_vertex_program_version_es2 }, + + /* OES_texture_3D */ + { GL_TEXTURE_BINDING_3D, LOC_CUSTOM, TYPE_INT, TEXTURE_3D_INDEX, NO_EXTRA }, + { GL_MAX_3D_TEXTURE_SIZE, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_context, Const.Max3DTextureLevels), NO_EXTRA }, + + /* GL_ARB_fragment_program/OES_standard_derivatives */ + { GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB, + CONTEXT_ENUM(Hint.FragmentShaderDerivative), extra_ARB_fragment_shader }, +#endif /* FEATURE_GL || FEATURE_ES2 */ + +#if FEATURE_ES2 + /* Enums unique to OpenGL ES 2.0 */ + { 0, 0, TYPE_API_MASK, API_OPENGLES2_BIT, NO_EXTRA }, + { GL_MAX_FRAGMENT_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, + { GL_MAX_VARYING_VECTORS, CONTEXT_INT(Const.MaxVarying), NO_EXTRA }, + { GL_MAX_VERTEX_UNIFORM_VECTORS, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, + { GL_SHADER_COMPILER, CONST(1), NO_EXTRA }, + /* OES_get_program_binary */ + { GL_NUM_SHADER_BINARY_FORMATS, CONST(0), NO_EXTRA }, + { GL_SHADER_BINARY_FORMATS, CONST(0), NO_EXTRA }, +#endif /* FEATURE_ES2 */ + +#if FEATURE_GL + /* Remaining enums are only in OpenGL */ + { 0, 0, TYPE_API_MASK, API_OPENGL_BIT, NO_EXTRA }, + { GL_ACCUM_RED_BITS, BUFFER_INT(Visual.accumRedBits), NO_EXTRA }, + { GL_ACCUM_GREEN_BITS, BUFFER_INT(Visual.accumGreenBits), NO_EXTRA }, + { GL_ACCUM_BLUE_BITS, BUFFER_INT(Visual.accumBlueBits), NO_EXTRA }, + { GL_ACCUM_ALPHA_BITS, BUFFER_INT(Visual.accumAlphaBits), NO_EXTRA }, + { GL_ACCUM_CLEAR_VALUE, CONTEXT_FIELD(Accum.ClearColor[0], TYPE_FLOATN_4), NO_EXTRA }, + { GL_ALPHA_BIAS, CONTEXT_FLOAT(Pixel.AlphaBias), NO_EXTRA }, + { GL_ALPHA_SCALE, CONTEXT_FLOAT(Pixel.AlphaScale), NO_EXTRA }, + { GL_ATTRIB_STACK_DEPTH, CONTEXT_INT(AttribStackDepth), NO_EXTRA }, + { GL_AUTO_NORMAL, CONTEXT_BOOL(Eval.AutoNormal), NO_EXTRA }, + { GL_AUX_BUFFERS, BUFFER_INT(Visual.numAuxBuffers), NO_EXTRA }, + { GL_BLUE_BIAS, CONTEXT_FLOAT(Pixel.BlueBias), NO_EXTRA }, + { GL_BLUE_SCALE, CONTEXT_FLOAT(Pixel.BlueScale), NO_EXTRA }, + { GL_CLIENT_ATTRIB_STACK_DEPTH, CONTEXT_INT(ClientAttribStackDepth), NO_EXTRA }, + { GL_COLOR_MATERIAL_FACE, CONTEXT_ENUM(Light.ColorMaterialFace), NO_EXTRA }, + { GL_COLOR_MATERIAL_PARAMETER, CONTEXT_ENUM(Light.ColorMaterialMode), NO_EXTRA }, + { GL_CURRENT_INDEX, + CONTEXT_FLOAT(Current.Attrib[VERT_ATTRIB_COLOR_INDEX][0]), + extra_flush_current }, + { GL_CURRENT_RASTER_COLOR, + CONTEXT_FIELD(Current.RasterColor[0], TYPE_FLOATN_4), NO_EXTRA }, + { GL_CURRENT_RASTER_DISTANCE, CONTEXT_FLOAT(Current.RasterDistance), NO_EXTRA }, + { GL_CURRENT_RASTER_INDEX, CONST(1), NO_EXTRA }, + { GL_CURRENT_RASTER_POSITION, CONTEXT_FLOAT4(Current.RasterPos[0]), NO_EXTRA }, + { GL_CURRENT_RASTER_SECONDARY_COLOR, + CONTEXT_FIELD(Current.RasterSecondaryColor[0], TYPE_FLOATN_4), NO_EXTRA }, + { GL_CURRENT_RASTER_TEXTURE_COORDS, LOC_CUSTOM, TYPE_FLOAT_4, 0, + extra_valid_texture_unit }, + { GL_CURRENT_RASTER_POSITION_VALID, CONTEXT_BOOL(Current.RasterPosValid), NO_EXTRA }, + { GL_DEPTH_BIAS, CONTEXT_FLOAT(Pixel.DepthBias), NO_EXTRA }, + { GL_DEPTH_SCALE, CONTEXT_FLOAT(Pixel.DepthScale), NO_EXTRA }, + { GL_DOUBLEBUFFER, BUFFER_INT(Visual.doubleBufferMode), NO_EXTRA }, + { GL_DRAW_BUFFER, BUFFER_ENUM(ColorDrawBuffer[0]), NO_EXTRA }, + { GL_EDGE_FLAG, LOC_CUSTOM, TYPE_BOOLEAN, 0, NO_EXTRA }, + { GL_FEEDBACK_BUFFER_SIZE, CONTEXT_INT(Feedback.BufferSize), NO_EXTRA }, + { GL_FEEDBACK_BUFFER_TYPE, CONTEXT_ENUM(Feedback.Type), NO_EXTRA }, + { GL_FOG_INDEX, CONTEXT_FLOAT(Fog.Index), NO_EXTRA }, + { GL_GREEN_BIAS, CONTEXT_FLOAT(Pixel.GreenBias), NO_EXTRA }, + { GL_GREEN_SCALE, CONTEXT_FLOAT(Pixel.GreenScale), NO_EXTRA }, + { GL_INDEX_BITS, BUFFER_INT(Visual.indexBits), extra_new_buffers }, + { GL_INDEX_CLEAR_VALUE, CONTEXT_INT(Color.ClearIndex), NO_EXTRA }, + { GL_INDEX_MODE, CONST(0) , NO_EXTRA}, + { GL_INDEX_OFFSET, CONTEXT_INT(Pixel.IndexOffset), NO_EXTRA }, + { GL_INDEX_SHIFT, CONTEXT_INT(Pixel.IndexShift), NO_EXTRA }, + { GL_INDEX_WRITEMASK, CONTEXT_INT(Color.IndexMask), NO_EXTRA }, + { GL_LIGHT_MODEL_COLOR_CONTROL, CONTEXT_ENUM(Light.Model.ColorControl), NO_EXTRA }, + { GL_LIGHT_MODEL_LOCAL_VIEWER, CONTEXT_BOOL(Light.Model.LocalViewer), NO_EXTRA }, + { GL_LINE_STIPPLE, CONTEXT_BOOL(Line.StippleFlag), NO_EXTRA }, + { GL_LINE_STIPPLE_PATTERN, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, + { GL_LINE_STIPPLE_REPEAT, CONTEXT_INT(Line.StippleFactor), NO_EXTRA }, + { GL_LINE_WIDTH_GRANULARITY, CONTEXT_FLOAT(Const.LineWidthGranularity), NO_EXTRA }, + { GL_LIST_BASE, CONTEXT_INT(List.ListBase), NO_EXTRA }, + { GL_LIST_INDEX, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA }, + { GL_LIST_MODE, LOC_CUSTOM, TYPE_ENUM, 0, NO_EXTRA }, + { GL_INDEX_LOGIC_OP, CONTEXT_BOOL(Color.IndexLogicOpEnabled), NO_EXTRA }, + { GL_MAP1_COLOR_4, CONTEXT_BOOL(Eval.Map1Color4), NO_EXTRA }, + { GL_MAP1_GRID_DOMAIN, CONTEXT_FLOAT2(Eval.MapGrid1u1), NO_EXTRA }, + { GL_MAP1_GRID_SEGMENTS, CONTEXT_INT(Eval.MapGrid1un), NO_EXTRA }, + { GL_MAP1_INDEX, CONTEXT_BOOL(Eval.Map1Index), NO_EXTRA }, + { GL_MAP1_NORMAL, CONTEXT_BOOL(Eval.Map1Normal), NO_EXTRA }, + { GL_MAP1_TEXTURE_COORD_1, CONTEXT_BOOL(Eval.Map1TextureCoord1), NO_EXTRA }, + { GL_MAP1_TEXTURE_COORD_2, CONTEXT_BOOL(Eval.Map1TextureCoord2), NO_EXTRA }, + { GL_MAP1_TEXTURE_COORD_3, CONTEXT_BOOL(Eval.Map1TextureCoord3), NO_EXTRA }, + { GL_MAP1_TEXTURE_COORD_4, CONTEXT_BOOL(Eval.Map1TextureCoord4), NO_EXTRA }, + { GL_MAP1_VERTEX_3, CONTEXT_BOOL(Eval.Map1Vertex3), NO_EXTRA }, + { GL_MAP1_VERTEX_4, CONTEXT_BOOL(Eval.Map1Vertex4), NO_EXTRA }, + { GL_MAP2_COLOR_4, CONTEXT_BOOL(Eval.Map2Color4), NO_EXTRA }, + { GL_MAP2_GRID_DOMAIN, LOC_CUSTOM, TYPE_FLOAT_4, 0, NO_EXTRA }, + { GL_MAP2_GRID_SEGMENTS, CONTEXT_INT2(Eval.MapGrid2un), NO_EXTRA }, + { GL_MAP2_INDEX, CONTEXT_BOOL(Eval.Map2Index), NO_EXTRA }, + { GL_MAP2_NORMAL, CONTEXT_BOOL(Eval.Map2Normal), NO_EXTRA }, + { GL_MAP2_TEXTURE_COORD_1, CONTEXT_BOOL(Eval.Map2TextureCoord1), NO_EXTRA }, + { GL_MAP2_TEXTURE_COORD_2, CONTEXT_BOOL(Eval.Map2TextureCoord2), NO_EXTRA }, + { GL_MAP2_TEXTURE_COORD_3, CONTEXT_BOOL(Eval.Map2TextureCoord3), NO_EXTRA }, + { GL_MAP2_TEXTURE_COORD_4, CONTEXT_BOOL(Eval.Map2TextureCoord4), NO_EXTRA }, + { GL_MAP2_VERTEX_3, CONTEXT_BOOL(Eval.Map2Vertex3), NO_EXTRA }, + { GL_MAP2_VERTEX_4, CONTEXT_BOOL(Eval.Map2Vertex4), NO_EXTRA }, + { GL_MAP_COLOR, CONTEXT_BOOL(Pixel.MapColorFlag), NO_EXTRA }, + { GL_MAP_STENCIL, CONTEXT_BOOL(Pixel.MapStencilFlag), NO_EXTRA }, + { GL_MAX_ATTRIB_STACK_DEPTH, CONST(MAX_ATTRIB_STACK_DEPTH), NO_EXTRA }, + { GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, CONST(MAX_CLIENT_ATTRIB_STACK_DEPTH), NO_EXTRA }, + + { GL_MAX_EVAL_ORDER, CONST(MAX_EVAL_ORDER), NO_EXTRA }, + { GL_MAX_LIST_NESTING, CONST(MAX_LIST_NESTING), NO_EXTRA }, + { GL_MAX_NAME_STACK_DEPTH, CONST(MAX_NAME_STACK_DEPTH), NO_EXTRA }, + { GL_MAX_PIXEL_MAP_TABLE, CONST(MAX_PIXEL_MAP_TABLE), NO_EXTRA }, + { GL_NAME_STACK_DEPTH, CONTEXT_INT(Select.NameStackDepth), NO_EXTRA }, + { GL_PACK_LSB_FIRST, CONTEXT_BOOL(Pack.LsbFirst), NO_EXTRA }, + { GL_PACK_ROW_LENGTH, CONTEXT_INT(Pack.RowLength), NO_EXTRA }, + { GL_PACK_SKIP_PIXELS, CONTEXT_INT(Pack.SkipPixels), NO_EXTRA }, + { GL_PACK_SKIP_ROWS, CONTEXT_INT(Pack.SkipRows), NO_EXTRA }, + { GL_PACK_SWAP_BYTES, CONTEXT_BOOL(Pack.SwapBytes), NO_EXTRA }, + { GL_PACK_IMAGE_HEIGHT_EXT, CONTEXT_INT(Pack.ImageHeight), NO_EXTRA }, + { GL_PACK_INVERT_MESA, CONTEXT_BOOL(Pack.Invert), NO_EXTRA }, + { GL_PIXEL_MAP_A_TO_A_SIZE, CONTEXT_INT(PixelMaps.AtoA.Size), NO_EXTRA }, + { GL_PIXEL_MAP_B_TO_B_SIZE, CONTEXT_INT(PixelMaps.BtoB.Size), NO_EXTRA }, + { GL_PIXEL_MAP_G_TO_G_SIZE, CONTEXT_INT(PixelMaps.GtoG.Size), NO_EXTRA }, + { GL_PIXEL_MAP_I_TO_A_SIZE, CONTEXT_INT(PixelMaps.ItoA.Size), NO_EXTRA }, + { GL_PIXEL_MAP_I_TO_B_SIZE, CONTEXT_INT(PixelMaps.ItoB.Size), NO_EXTRA }, + { GL_PIXEL_MAP_I_TO_G_SIZE, CONTEXT_INT(PixelMaps.ItoG.Size), NO_EXTRA }, + { GL_PIXEL_MAP_I_TO_I_SIZE, CONTEXT_INT(PixelMaps.ItoI.Size), NO_EXTRA }, + { GL_PIXEL_MAP_I_TO_R_SIZE, CONTEXT_INT(PixelMaps.ItoR.Size), NO_EXTRA }, + { GL_PIXEL_MAP_R_TO_R_SIZE, CONTEXT_INT(PixelMaps.RtoR.Size), NO_EXTRA }, + { GL_PIXEL_MAP_S_TO_S_SIZE, CONTEXT_INT(PixelMaps.StoS.Size), NO_EXTRA }, + { GL_POINT_SIZE_GRANULARITY, CONTEXT_FLOAT(Const.PointSizeGranularity), NO_EXTRA }, + { GL_POLYGON_MODE, CONTEXT_ENUM2(Polygon.FrontMode), NO_EXTRA }, + { GL_POLYGON_OFFSET_BIAS_EXT, CONTEXT_FLOAT(Polygon.OffsetUnits), NO_EXTRA }, + { GL_POLYGON_OFFSET_POINT, CONTEXT_BOOL(Polygon.OffsetPoint), NO_EXTRA }, + { GL_POLYGON_OFFSET_LINE, CONTEXT_BOOL(Polygon.OffsetLine), NO_EXTRA }, + { GL_POLYGON_SMOOTH, CONTEXT_BOOL(Polygon.SmoothFlag), NO_EXTRA }, + { GL_POLYGON_SMOOTH_HINT, CONTEXT_ENUM(Hint.PolygonSmooth), NO_EXTRA }, + { GL_POLYGON_STIPPLE, CONTEXT_BOOL(Polygon.StippleFlag), NO_EXTRA }, + { GL_READ_BUFFER, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, + { GL_RED_BIAS, CONTEXT_FLOAT(Pixel.RedBias), NO_EXTRA }, + { GL_RED_SCALE, CONTEXT_FLOAT(Pixel.RedScale), NO_EXTRA }, + { GL_RENDER_MODE, CONTEXT_ENUM(RenderMode), NO_EXTRA }, + { GL_RGBA_MODE, CONST(1), NO_EXTRA }, + { GL_SELECTION_BUFFER_SIZE, CONTEXT_INT(Select.BufferSize), NO_EXTRA }, + { GL_SHARED_TEXTURE_PALETTE_EXT, CONTEXT_BOOL(Texture.SharedPalette), NO_EXTRA }, + + { GL_STEREO, BUFFER_INT(Visual.stereoMode), NO_EXTRA }, + + { GL_TEXTURE_1D, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA }, + { GL_TEXTURE_3D, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA }, + { GL_TEXTURE_1D_ARRAY_EXT, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA }, + { GL_TEXTURE_2D_ARRAY_EXT, LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA }, + + { GL_TEXTURE_BINDING_1D, LOC_CUSTOM, TYPE_INT, TEXTURE_1D_INDEX, NO_EXTRA }, + { GL_TEXTURE_BINDING_1D_ARRAY, LOC_CUSTOM, TYPE_INT, + TEXTURE_1D_ARRAY_INDEX, extra_MESA_texture_array }, + { GL_TEXTURE_BINDING_2D_ARRAY, LOC_CUSTOM, TYPE_INT, + TEXTURE_1D_ARRAY_INDEX, extra_MESA_texture_array }, + { GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, + CONTEXT_INT(Const.MaxArrayTextureLayers), extra_MESA_texture_array }, + + { GL_TEXTURE_GEN_S, LOC_TEXUNIT, TYPE_BIT_0, + offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, + { GL_TEXTURE_GEN_T, LOC_TEXUNIT, TYPE_BIT_1, + offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, + { GL_TEXTURE_GEN_R, LOC_TEXUNIT, TYPE_BIT_2, + offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, + { GL_TEXTURE_GEN_Q, LOC_TEXUNIT, TYPE_BIT_3, + offsetof(struct gl_texture_unit, TexGenEnabled), NO_EXTRA }, + { GL_UNPACK_LSB_FIRST, CONTEXT_BOOL(Unpack.LsbFirst), NO_EXTRA }, + { GL_UNPACK_ROW_LENGTH, CONTEXT_INT(Unpack.RowLength), NO_EXTRA }, + { GL_UNPACK_SKIP_PIXELS, CONTEXT_INT(Unpack.SkipPixels), NO_EXTRA }, + { GL_UNPACK_SKIP_ROWS, CONTEXT_INT(Unpack.SkipRows), NO_EXTRA }, + { GL_UNPACK_SWAP_BYTES, CONTEXT_BOOL(Unpack.SwapBytes), NO_EXTRA }, + { GL_UNPACK_SKIP_IMAGES_EXT, CONTEXT_INT(Unpack.SkipImages), NO_EXTRA }, + { GL_UNPACK_IMAGE_HEIGHT_EXT, CONTEXT_INT(Unpack.ImageHeight), NO_EXTRA }, + { GL_UNPACK_CLIENT_STORAGE_APPLE, CONTEXT_BOOL(Unpack.ClientStorage), NO_EXTRA }, + { GL_ZOOM_X, CONTEXT_FLOAT(Pixel.ZoomX), NO_EXTRA }, + { GL_ZOOM_Y, CONTEXT_FLOAT(Pixel.ZoomY), NO_EXTRA }, + + /* Vertex arrays */ + { GL_VERTEX_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, + { GL_NORMAL_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, + { GL_COLOR_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, + { GL_INDEX_ARRAY, ARRAY_BOOL(Index.Enabled), NO_EXTRA }, + { GL_INDEX_ARRAY_TYPE, ARRAY_ENUM(Index.Type), NO_EXTRA }, + { GL_INDEX_ARRAY_STRIDE, ARRAY_INT(Index.Stride), NO_EXTRA }, + { GL_INDEX_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, + { GL_TEXTURE_COORD_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, + { GL_EDGE_FLAG_ARRAY, ARRAY_BOOL(EdgeFlag.Enabled), NO_EXTRA }, + { GL_EDGE_FLAG_ARRAY_STRIDE, ARRAY_INT(EdgeFlag.Stride), NO_EXTRA }, + { GL_EDGE_FLAG_ARRAY_COUNT_EXT, CONST(0), NO_EXTRA }, + + /* GL_ARB_texture_compression */ + { GL_TEXTURE_COMPRESSION_HINT_ARB, CONTEXT_INT(Hint.TextureCompression), NO_EXTRA }, + + /* GL_EXT_compiled_vertex_array */ + { GL_ARRAY_ELEMENT_LOCK_FIRST_EXT, CONTEXT_INT(Array.LockFirst), + extra_EXT_compiled_vertex_array }, + { GL_ARRAY_ELEMENT_LOCK_COUNT_EXT, CONTEXT_INT(Array.LockCount), + extra_EXT_compiled_vertex_array }, + + /* GL_ARB_transpose_matrix */ + { GL_TRANSPOSE_MODELVIEW_MATRIX_ARB, + CONTEXT_MATRIX_T(ModelviewMatrixStack), NO_EXTRA }, + { GL_TRANSPOSE_PROJECTION_MATRIX_ARB, + CONTEXT_MATRIX_T(ProjectionMatrixStack.Top), NO_EXTRA }, + { GL_TRANSPOSE_TEXTURE_MATRIX_ARB, CONTEXT_MATRIX_T(TextureMatrixStack), NO_EXTRA }, + + /* GL_EXT_secondary_color */ + { GL_COLOR_SUM_EXT, CONTEXT_BOOL(Fog.ColorSumEnabled), + extra_EXT_secondary_color_ARB_vertex_program }, + { GL_CURRENT_SECONDARY_COLOR_EXT, + CONTEXT_FIELD(Current.Attrib[VERT_ATTRIB_COLOR1][0], TYPE_FLOATN_4), + extra_EXT_secondary_color_flush_current }, + { GL_SECONDARY_COLOR_ARRAY_EXT, ARRAY_BOOL(SecondaryColor.Enabled), + extra_EXT_secondary_color }, + { GL_SECONDARY_COLOR_ARRAY_TYPE_EXT, ARRAY_ENUM(SecondaryColor.Type), + extra_EXT_secondary_color }, + { GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT, ARRAY_INT(SecondaryColor.Stride), + extra_EXT_secondary_color }, + { GL_SECONDARY_COLOR_ARRAY_SIZE_EXT, ARRAY_INT(SecondaryColor.Size), + extra_EXT_secondary_color }, + + /* GL_EXT_fog_coord */ + { GL_CURRENT_FOG_COORDINATE_EXT, + CONTEXT_FLOAT(Current.Attrib[VERT_ATTRIB_FOG][0]), + extra_EXT_fog_coord_flush_current }, + { GL_FOG_COORDINATE_ARRAY_EXT, ARRAY_BOOL(FogCoord.Enabled), + extra_EXT_fog_coord }, + { GL_FOG_COORDINATE_ARRAY_TYPE_EXT, ARRAY_ENUM(FogCoord.Type), + extra_EXT_fog_coord }, + { GL_FOG_COORDINATE_ARRAY_STRIDE_EXT, ARRAY_INT(FogCoord.Stride), + extra_EXT_fog_coord }, + { GL_FOG_COORDINATE_SOURCE_EXT, CONTEXT_ENUM(Fog.FogCoordinateSource), + extra_EXT_fog_coord }, + + /* GL_IBM_rasterpos_clip */ + { GL_RASTER_POSITION_UNCLIPPED_IBM, + CONTEXT_BOOL(Transform.RasterPositionUnclipped), + extra_IBM_rasterpos_clip }, + + /* GL_NV_point_sprite */ + { GL_POINT_SPRITE_R_MODE_NV, + CONTEXT_ENUM(Point.SpriteRMode), extra_NV_point_sprite }, + { GL_POINT_SPRITE_COORD_ORIGIN, CONTEXT_ENUM(Point.SpriteOrigin), + extra_NV_point_sprite_ARB_point_sprite }, + + /* GL_NV_vertex_program */ + { GL_VERTEX_PROGRAM_BINDING_NV, LOC_CUSTOM, TYPE_INT, 0, + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY0_NV, ARRAY_BOOL(VertexAttrib[0].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY1_NV, ARRAY_BOOL(VertexAttrib[1].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY2_NV, ARRAY_BOOL(VertexAttrib[2].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY3_NV, ARRAY_BOOL(VertexAttrib[3].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY4_NV, ARRAY_BOOL(VertexAttrib[4].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY5_NV, ARRAY_BOOL(VertexAttrib[5].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY6_NV, ARRAY_BOOL(VertexAttrib[6].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY7_NV, ARRAY_BOOL(VertexAttrib[7].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY8_NV, ARRAY_BOOL(VertexAttrib[8].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY9_NV, ARRAY_BOOL(VertexAttrib[9].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY10_NV, ARRAY_BOOL(VertexAttrib[10].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY11_NV, ARRAY_BOOL(VertexAttrib[11].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY12_NV, ARRAY_BOOL(VertexAttrib[12].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY13_NV, ARRAY_BOOL(VertexAttrib[13].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY14_NV, ARRAY_BOOL(VertexAttrib[14].Enabled), + extra_NV_vertex_program }, + { GL_VERTEX_ATTRIB_ARRAY15_NV, ARRAY_BOOL(VertexAttrib[15].Enabled), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB0_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[0]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB1_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[1]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB2_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[2]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB3_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[3]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB4_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[4]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB5_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[5]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB6_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[6]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB7_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[7]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB8_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[8]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB9_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[9]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB10_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[10]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB11_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[11]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB12_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[12]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB13_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[13]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB14_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[14]), + extra_NV_vertex_program }, + { GL_MAP1_VERTEX_ATTRIB15_4_NV, CONTEXT_BOOL(Eval.Map1Attrib[15]), + extra_NV_vertex_program }, + + /* GL_NV_fragment_program */ + { GL_FRAGMENT_PROGRAM_NV, CONTEXT_BOOL(FragmentProgram.Enabled), + extra_NV_fragment_program }, + { GL_FRAGMENT_PROGRAM_BINDING_NV, LOC_CUSTOM, TYPE_INT, 0, + extra_NV_fragment_program }, + { GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV, + CONST(MAX_NV_FRAGMENT_PROGRAM_PARAMS), + extra_NV_fragment_program }, + + /* GL_NV_texture_rectangle */ + { GL_TEXTURE_RECTANGLE_NV, + LOC_CUSTOM, TYPE_BOOLEAN, 0, extra_NV_texture_rectangle }, + { GL_TEXTURE_BINDING_RECTANGLE_NV, + LOC_CUSTOM, TYPE_INT, TEXTURE_RECT_INDEX, extra_NV_texture_rectangle }, + { GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, + CONTEXT_INT(Const.MaxTextureRectSize), extra_NV_texture_rectangle }, + + /* GL_EXT_stencil_two_side */ + { GL_STENCIL_TEST_TWO_SIDE_EXT, CONTEXT_BOOL(Stencil.TestTwoSide), + extra_EXT_stencil_two_side }, + { GL_ACTIVE_STENCIL_FACE_EXT, LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA }, + + /* GL_NV_light_max_exponent */ + { GL_MAX_SHININESS_NV, CONTEXT_FLOAT(Const.MaxShininess), + extra_NV_light_max_exponent }, + { GL_MAX_SPOT_EXPONENT_NV, CONTEXT_FLOAT(Const.MaxSpotExponent), + extra_NV_light_max_exponent }, + + /* GL_NV_primitive_restart */ + { GL_PRIMITIVE_RESTART_NV, CONTEXT_BOOL(Array.PrimitiveRestart), + extra_NV_primitive_restart }, + { GL_PRIMITIVE_RESTART_INDEX_NV, CONTEXT_INT(Array.RestartIndex), + extra_NV_primitive_restart }, + + /* GL_ARB_vertex_buffer_object */ + { GL_INDEX_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, Index.BufferObj), NO_EXTRA }, + { GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, EdgeFlag.BufferObj), NO_EXTRA }, + { GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, SecondaryColor.BufferObj), NO_EXTRA }, + { GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB, LOC_CUSTOM, TYPE_INT, + offsetof(struct gl_array_object, FogCoord.BufferObj), NO_EXTRA }, + + /* GL_EXT_pixel_buffer_object */ + { GL_PIXEL_PACK_BUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0, + extra_EXT_pixel_buffer_object }, + { GL_PIXEL_UNPACK_BUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0, + extra_EXT_pixel_buffer_object }, + + /* GL_ARB_vertex_program */ + { GL_VERTEX_PROGRAM_ARB, /* == GL_VERTEX_PROGRAM_NV */ + CONTEXT_BOOL(VertexProgram.Enabled), + extra_ARB_vertex_program_NV_vertex_program }, + { GL_VERTEX_PROGRAM_POINT_SIZE_ARB, /* == GL_VERTEX_PROGRAM_POINT_SIZE_NV*/ + CONTEXT_BOOL(VertexProgram.PointSizeEnabled), + extra_ARB_vertex_program_NV_vertex_program }, + { GL_VERTEX_PROGRAM_TWO_SIDE_ARB, /* == GL_VERTEX_PROGRAM_TWO_SIDE_NV */ + CONTEXT_BOOL(VertexProgram.TwoSideEnabled), + extra_ARB_vertex_program_NV_vertex_program }, + { GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB, /* == GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV */ + CONTEXT_INT(Const.MaxProgramMatrixStackDepth), + extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, + { GL_MAX_PROGRAM_MATRICES_ARB, /* == GL_MAX_TRACK_MATRICES_NV */ + CONTEXT_INT(Const.MaxProgramMatrices), + extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, + { GL_CURRENT_MATRIX_STACK_DEPTH_ARB, /* == GL_CURRENT_MATRIX_STACK_DEPTH_NV */ + LOC_CUSTOM, TYPE_INT, 0, + extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, + + { GL_CURRENT_MATRIX_ARB, /* == GL_CURRENT_MATRIX_NV */ + LOC_CUSTOM, TYPE_MATRIX, 0, + extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, + { GL_TRANSPOSE_CURRENT_MATRIX_ARB, /* == GL_CURRENT_MATRIX_NV */ + LOC_CUSTOM, TYPE_MATRIX, 0, + extra_ARB_vertex_program_ARB_fragment_program }, + + { GL_PROGRAM_ERROR_POSITION_ARB, /* == GL_PROGRAM_ERROR_POSITION_NV */ + CONTEXT_INT(Program.ErrorPos), + extra_NV_vertex_program_ARB_vertex_program_ARB_fragment_program_NV_vertex_program }, + + /* GL_ARB_fragment_program */ + { GL_FRAGMENT_PROGRAM_ARB, CONTEXT_BOOL(FragmentProgram.Enabled), + extra_ARB_fragment_program }, + + /* GL_EXT_depth_bounds_test */ + { GL_DEPTH_BOUNDS_TEST_EXT, CONTEXT_BOOL(Depth.BoundsTest), + extra_EXT_depth_bounds_test }, + { GL_DEPTH_BOUNDS_EXT, CONTEXT_FLOAT2(Depth.BoundsMin), + extra_EXT_depth_bounds_test }, + + /* GL_ARB_depth_clamp*/ + { GL_DEPTH_CLAMP, CONTEXT_BOOL(Transform.DepthClamp), + extra_ARB_depth_clamp }, + + /* GL_ARB_draw_buffers */ + { GL_DRAW_BUFFER0_ARB, BUFFER_ENUM(ColorDrawBuffer[0]), NO_EXTRA }, + { GL_DRAW_BUFFER1_ARB, BUFFER_ENUM(ColorDrawBuffer[1]), + extra_valid_draw_buffer }, + { GL_DRAW_BUFFER2_ARB, BUFFER_ENUM(ColorDrawBuffer[2]), + extra_valid_draw_buffer }, + { GL_DRAW_BUFFER3_ARB, BUFFER_ENUM(ColorDrawBuffer[3]), + extra_valid_draw_buffer }, + { GL_DRAW_BUFFER4_ARB, BUFFER_ENUM(ColorDrawBuffer[4]), + extra_valid_draw_buffer }, + { GL_DRAW_BUFFER5_ARB, BUFFER_ENUM(ColorDrawBuffer[5]), + extra_valid_draw_buffer }, + { GL_DRAW_BUFFER6_ARB, BUFFER_ENUM(ColorDrawBuffer[6]), + extra_valid_draw_buffer }, + { GL_DRAW_BUFFER7_ARB, BUFFER_ENUM(ColorDrawBuffer[7]), + extra_valid_draw_buffer }, + + /* GL_ATI_fragment_shader */ + { GL_NUM_FRAGMENT_REGISTERS_ATI, CONST(6), extra_ATI_fragment_shader }, + { GL_NUM_FRAGMENT_CONSTANTS_ATI, CONST(8), extra_ATI_fragment_shader }, + { GL_NUM_PASSES_ATI, CONST(2), extra_ATI_fragment_shader }, + { GL_NUM_INSTRUCTIONS_PER_PASS_ATI, CONST(8), extra_ATI_fragment_shader }, + { GL_NUM_INSTRUCTIONS_TOTAL_ATI, CONST(16), extra_ATI_fragment_shader }, + { GL_COLOR_ALPHA_PAIRING_ATI, CONST(GL_TRUE), extra_ATI_fragment_shader }, + { GL_NUM_LOOPBACK_COMPONENTS_ATI, CONST(3), extra_ATI_fragment_shader }, + { GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI, + CONST(3), extra_ATI_fragment_shader }, + + /* GL_EXT_framebuffer_object */ + { GL_MAX_COLOR_ATTACHMENTS_EXT, CONTEXT_INT(Const.MaxColorAttachments), + extra_EXT_framebuffer_object }, + + /* GL_EXT_framebuffer_blit + * NOTE: GL_DRAW_FRAMEBUFFER_BINDING_EXT == GL_FRAMEBUFFER_BINDING_EXT */ + { GL_READ_FRAMEBUFFER_BINDING_EXT, LOC_CUSTOM, TYPE_INT, 0, + extra_EXT_framebuffer_blit }, + + /* GL_EXT_provoking_vertex */ + { GL_PROVOKING_VERTEX_EXT, + CONTEXT_BOOL(Light.ProvokingVertex), extra_EXT_provoking_vertex }, + { GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT, + CONTEXT_BOOL(Const.QuadsFollowProvokingVertexConvention), + extra_EXT_provoking_vertex }, + + /* GL_ARB_framebuffer_object */ + { GL_MAX_SAMPLES, CONTEXT_INT(Const.MaxSamples), + extra_ARB_framebuffer_object_EXT_framebuffer_multisample }, + + /* GL_APPLE_vertex_array_object */ + { GL_VERTEX_ARRAY_BINDING_APPLE, ARRAY_INT(Name), + extra_APPLE_vertex_array_object }, + + /* GL_ARB_seamless_cube_map */ + { GL_TEXTURE_CUBE_MAP_SEAMLESS, + CONTEXT_BOOL(Texture.CubeMapSeamless), extra_ARB_seamless_cube_map }, + + /* GL_ARB_sync */ + { GL_MAX_SERVER_WAIT_TIMEOUT, + CONTEXT_INT64(Const.MaxServerWaitTimeout), extra_ARB_sync }, + + /* GL_EXT_texture_integer */ + { GL_RGBA_INTEGER_MODE_EXT, BUFFER_BOOL(_IntegerColor), + extra_EXT_texture_integer }, + + /* GL_EXT_transform_feedback */ + { GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, LOC_CUSTOM, TYPE_INT, 0, + extra_EXT_transform_feedback }, + { GL_RASTERIZER_DISCARD, CONTEXT_BOOL(TransformFeedback.RasterDiscard), + extra_EXT_transform_feedback }, + { GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, + CONTEXT_INT(Const.MaxTransformFeedbackInterleavedComponents), + extra_EXT_transform_feedback }, + { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, + CONTEXT_INT(Const.MaxTransformFeedbackSeparateAttribs), + extra_EXT_transform_feedback }, + { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, + CONTEXT_INT(Const.MaxTransformFeedbackSeparateComponents), + extra_EXT_transform_feedback }, + + /* GL_ARB_transform_feedback2 */ + { GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED, LOC_CUSTOM, TYPE_BOOLEAN, 0, + extra_ARB_transform_feedback2 }, + { GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE, LOC_CUSTOM, TYPE_BOOLEAN, 0, + extra_ARB_transform_feedback2 }, + { GL_TRANSFORM_FEEDBACK_BINDING, LOC_CUSTOM, TYPE_INT, 0, + extra_ARB_transform_feedback2 }, + + /* GL_ARB_geometry_shader4 */ + { GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB, + CONTEXT_INT(Const.GeometryProgram.MaxGeometryTextureImageUnits), + extra_ARB_geometry_shader4 }, + { GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB, + CONTEXT_INT(Const.GeometryProgram.MaxGeometryOutputVertices), + extra_ARB_geometry_shader4 }, + { GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB, + CONTEXT_INT(Const.GeometryProgram.MaxGeometryTotalOutputComponents), + extra_ARB_geometry_shader4 }, + { GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB, + CONTEXT_INT(Const.GeometryProgram.MaxGeometryUniformComponents), + extra_ARB_geometry_shader4 }, + { GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB, + CONTEXT_INT(Const.GeometryProgram.MaxGeometryVaryingComponents), + extra_ARB_geometry_shader4 }, + { GL_MAX_VERTEX_VARYING_COMPONENTS_ARB, + CONTEXT_INT(Const.GeometryProgram.MaxVertexVaryingComponents), + extra_ARB_geometry_shader4 }, + + /* GL_EXT_gpu_shader4 / GL 3.0 */ + { GL_MIN_PROGRAM_TEXEL_OFFSET, + CONTEXT_INT(Const.MinProgramTexelOffset), + extra_EXT_gpu_shader4 }, + { GL_MAX_PROGRAM_TEXEL_OFFSET, + CONTEXT_INT(Const.MaxProgramTexelOffset), + extra_EXT_gpu_shader4 }, + + /* GL 3.0 */ + { GL_NUM_EXTENSIONS, LOC_CUSTOM, TYPE_INT, 0, extra_version_30 }, + { GL_MAJOR_VERSION, CONTEXT_INT(VersionMajor), extra_version_30 }, + { GL_MINOR_VERSION, CONTEXT_INT(VersionMinor), extra_version_30 }, + { GL_CONTEXT_FLAGS, CONTEXT_INT(Const.ContextFlags), extra_version_30 }, + + /* GL3.0 / GL_EXT_framebuffer_sRGB */ + { GL_FRAMEBUFFER_SRGB_EXT, CONTEXT_BOOL(Color.sRGBEnabled), extra_EXT_framebuffer_sRGB }, + { GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, BUFFER_INT(Visual.sRGBCapable), extra_EXT_framebuffer_sRGB }, + + /* GL 3.1 */ + /* NOTE: different enum values for GL_PRIMITIVE_RESTART_NV + * vs. GL_PRIMITIVE_RESTART! + */ + { GL_PRIMITIVE_RESTART, CONTEXT_BOOL(Array.PrimitiveRestart), + extra_version_31 }, + { GL_PRIMITIVE_RESTART_INDEX, CONTEXT_INT(Array.RestartIndex), + extra_version_31 }, + + + /* GL 3.2 */ + { GL_CONTEXT_PROFILE_MASK, CONTEXT_INT(Const.ProfileMask), + extra_version_32 }, +#endif /* FEATURE_GL */ +}; + +/* All we need now is a way to look up the value struct from the enum. + * The code generated by gcc for the old generated big switch + * statement is a big, balanced, open coded if/else tree, essentially + * an unrolled binary search. It would be natural to sort the new + * enum table and use bsearch(), but we will use a read-only hash + * table instead. bsearch() has a nice guaranteed worst case + * performance, but we're also guaranteed to hit that worst case + * (log2(n) iterations) for about half the enums. Instead, using an + * open addressing hash table, we can find the enum on the first try + * for 80% of the enums, 1 collision for 10% and never more than 5 + * collisions for any enum (typical numbers). And the code is very + * simple, even though it feels a little magic. */ + +static unsigned short table[1024]; +static const int prime_factor = 89, prime_step = 281; + +#ifdef GET_DEBUG +static void +print_table_stats(void) +{ + int i, j, collisions[11], count, hash, mask; + const struct value_desc *d; + + count = 0; + mask = Elements(table) - 1; + memset(collisions, 0, sizeof collisions); + + for (i = 0; i < Elements(table); i++) { + if (!table[i]) + continue; + count++; + d = &values[table[i]]; + hash = (d->pname * prime_factor); + j = 0; + while (1) { + if (values[table[hash & mask]].pname == d->pname) + break; + hash += prime_step; + j++; + } + + if (j < 10) + collisions[j]++; + else + collisions[10]++; + } + + printf("number of enums: %d (total %d)\n", count, Elements(values)); + for (i = 0; i < Elements(collisions) - 1; i++) + if (collisions[i] > 0) + printf(" %d enums with %d %scollisions\n", + collisions[i], i, i == 10 ? "or more " : ""); +} +#endif + +/** + * Initialize the enum hash for a given API + * + * This is called from one_time_init() to insert the enum values that + * are valid for the API in question into the enum hash table. + * + * \param the current context, for determining the API in question + */ +void _mesa_init_get_hash(struct gl_context *ctx) +{ + int i, hash, index, mask; + int api_mask = 0, api_bit; + + mask = Elements(table) - 1; + api_bit = 1 << ctx->API; + + for (i = 0; i < Elements(values); i++) { + if (values[i].type == TYPE_API_MASK) { + api_mask = values[i].offset; + continue; + } + if (!(api_mask & api_bit)) + continue; + + hash = (values[i].pname * prime_factor) & mask; + while (1) { + index = hash & mask; + if (!table[index]) { + table[index] = i; + break; + } + hash += prime_step; + } + } + +#ifdef GET_DEBUG + print_table_stats(); +#endif +} + +/** + * Handle irregular enums + * + * Some values don't conform to the "well-known type at context + * pointer + offset" pattern, so we have this function to catch all + * the corner cases. Typically, it's a computed value or a one-off + * pointer to a custom struct or something. + * + * In this case we can't return a pointer to the value, so we'll have + * to use the temporary variable 'v' declared back in the calling + * glGet*v() function to store the result. + * + * \param ctx the current context + * \param d the struct value_desc that describes the enum + * \param v pointer to the tmp declared in the calling glGet*v() function + */ +static void +find_custom_value(struct gl_context *ctx, const struct value_desc *d, union value *v) +{ + struct gl_buffer_object *buffer_obj; + struct gl_client_array *array; + GLuint unit, *p; + + switch (d->pname) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_TEXTURE_2D_ARRAY_EXT: + case GL_TEXTURE_CUBE_MAP_ARB: + case GL_TEXTURE_RECTANGLE_NV: + v->value_bool = _mesa_IsEnabled(d->pname); + break; + + case GL_LINE_STIPPLE_PATTERN: + /* This is the only GLushort, special case it here by promoting + * to an int rather than introducing a new type. */ + v->value_int = ctx->Line.StipplePattern; + break; + + case GL_CURRENT_RASTER_TEXTURE_COORDS: + unit = ctx->Texture.CurrentUnit; + v->value_float_4[0] = ctx->Current.RasterTexCoords[unit][0]; + v->value_float_4[1] = ctx->Current.RasterTexCoords[unit][1]; + v->value_float_4[2] = ctx->Current.RasterTexCoords[unit][2]; + v->value_float_4[3] = ctx->Current.RasterTexCoords[unit][3]; + break; + + case GL_CURRENT_TEXTURE_COORDS: + unit = ctx->Texture.CurrentUnit; + v->value_float_4[0] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][0]; + v->value_float_4[1] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][1]; + v->value_float_4[2] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][2]; + v->value_float_4[3] = ctx->Current.Attrib[VERT_ATTRIB_TEX0 + unit][3]; + break; + + case GL_COLOR_WRITEMASK: + v->value_int_4[0] = ctx->Color.ColorMask[0][RCOMP] ? 1 : 0; + v->value_int_4[1] = ctx->Color.ColorMask[0][GCOMP] ? 1 : 0; + v->value_int_4[2] = ctx->Color.ColorMask[0][BCOMP] ? 1 : 0; + v->value_int_4[3] = ctx->Color.ColorMask[0][ACOMP] ? 1 : 0; + break; + + case GL_EDGE_FLAG: + v->value_bool = ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG][0] == 1.0; + break; + + case GL_READ_BUFFER: + v->value_enum = ctx->ReadBuffer->ColorReadBuffer; + break; + + case GL_MAP2_GRID_DOMAIN: + v->value_float_4[0] = ctx->Eval.MapGrid2u1; + v->value_float_4[1] = ctx->Eval.MapGrid2u2; + v->value_float_4[2] = ctx->Eval.MapGrid2v1; + v->value_float_4[3] = ctx->Eval.MapGrid2v2; + break; + + case GL_TEXTURE_STACK_DEPTH: + unit = ctx->Texture.CurrentUnit; + v->value_int = ctx->TextureMatrixStack[unit].Depth + 1; + break; + case GL_TEXTURE_MATRIX: + unit = ctx->Texture.CurrentUnit; + v->value_matrix = ctx->TextureMatrixStack[unit].Top; + break; + + case GL_TEXTURE_COORD_ARRAY: + case GL_TEXTURE_COORD_ARRAY_SIZE: + case GL_TEXTURE_COORD_ARRAY_TYPE: + case GL_TEXTURE_COORD_ARRAY_STRIDE: + array = &ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture]; + v->value_int = *(GLuint *) ((char *) array + d->offset); + break; + + case GL_ACTIVE_TEXTURE_ARB: + v->value_int = GL_TEXTURE0_ARB + ctx->Texture.CurrentUnit; + break; + case GL_CLIENT_ACTIVE_TEXTURE_ARB: + v->value_int = GL_TEXTURE0_ARB + ctx->Array.ActiveTexture; + break; + + case GL_MODELVIEW_STACK_DEPTH: + case GL_PROJECTION_STACK_DEPTH: + v->value_int = *(GLint *) ((char *) ctx + d->offset) + 1; + break; + + case GL_MAX_TEXTURE_SIZE: + case GL_MAX_3D_TEXTURE_SIZE: + case GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB: + p = (GLuint *) ((char *) ctx + d->offset); + v->value_int = 1 << (*p - 1); + break; + + case GL_SCISSOR_BOX: + v->value_int_4[0] = ctx->Scissor.X; + v->value_int_4[1] = ctx->Scissor.Y; + v->value_int_4[2] = ctx->Scissor.Width; + v->value_int_4[3] = ctx->Scissor.Height; + break; + + case GL_LIST_INDEX: + v->value_int = + ctx->ListState.CurrentList ? ctx->ListState.CurrentList->Name : 0; + break; + case GL_LIST_MODE: + if (!ctx->CompileFlag) + v->value_enum = 0; + else if (ctx->ExecuteFlag) + v->value_enum = GL_COMPILE_AND_EXECUTE; + else + v->value_enum = GL_COMPILE; + break; + + case GL_VIEWPORT: + v->value_int_4[0] = ctx->Viewport.X; + v->value_int_4[1] = ctx->Viewport.Y; + v->value_int_4[2] = ctx->Viewport.Width; + v->value_int_4[3] = ctx->Viewport.Height; + break; + + case GL_ACTIVE_STENCIL_FACE_EXT: + v->value_enum = ctx->Stencil.ActiveFace ? GL_BACK : GL_FRONT; + break; + + case GL_STENCIL_FAIL: + v->value_enum = ctx->Stencil.FailFunc[ctx->Stencil.ActiveFace]; + break; + case GL_STENCIL_FUNC: + v->value_enum = ctx->Stencil.Function[ctx->Stencil.ActiveFace]; + break; + case GL_STENCIL_PASS_DEPTH_FAIL: + v->value_enum = ctx->Stencil.ZFailFunc[ctx->Stencil.ActiveFace]; + break; + case GL_STENCIL_PASS_DEPTH_PASS: + v->value_enum = ctx->Stencil.ZPassFunc[ctx->Stencil.ActiveFace]; + break; + case GL_STENCIL_REF: + v->value_int = ctx->Stencil.Ref[ctx->Stencil.ActiveFace]; + break; + case GL_STENCIL_VALUE_MASK: + v->value_int = ctx->Stencil.ValueMask[ctx->Stencil.ActiveFace]; + break; + case GL_STENCIL_WRITEMASK: + v->value_int = ctx->Stencil.WriteMask[ctx->Stencil.ActiveFace]; + break; + + case GL_NUM_EXTENSIONS: + v->value_int = _mesa_get_extension_count(ctx); + break; + + case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES: + v->value_int = _mesa_get_color_read_type(ctx); + break; + case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES: + v->value_int = _mesa_get_color_read_format(ctx); + break; + + case GL_CURRENT_MATRIX_STACK_DEPTH_ARB: + v->value_int = ctx->CurrentStack->Depth + 1; + break; + case GL_CURRENT_MATRIX_ARB: + case GL_TRANSPOSE_CURRENT_MATRIX_ARB: + v->value_matrix = ctx->CurrentStack->Top; + break; + + case GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB: + v->value_int = _mesa_get_compressed_formats(ctx, NULL, GL_FALSE); + break; + case GL_COMPRESSED_TEXTURE_FORMATS_ARB: + v->value_int_n.n = + _mesa_get_compressed_formats(ctx, v->value_int_n.ints, GL_FALSE); + ASSERT(v->value_int_n.n <= 100); + break; + + case GL_MAX_VARYING_FLOATS_ARB: + v->value_int = ctx->Const.MaxVarying * 4; + break; + + /* Various object names */ + + case GL_TEXTURE_BINDING_1D: + case GL_TEXTURE_BINDING_2D: + case GL_TEXTURE_BINDING_3D: + case GL_TEXTURE_BINDING_1D_ARRAY_EXT: + case GL_TEXTURE_BINDING_2D_ARRAY_EXT: + case GL_TEXTURE_BINDING_CUBE_MAP_ARB: + case GL_TEXTURE_BINDING_RECTANGLE_NV: + unit = ctx->Texture.CurrentUnit; + v->value_int = + ctx->Texture.Unit[unit].CurrentTex[d->offset]->Name; + break; + + /* GL_ARB_vertex_buffer_object */ + case GL_VERTEX_ARRAY_BUFFER_BINDING_ARB: + case GL_NORMAL_ARRAY_BUFFER_BINDING_ARB: + case GL_COLOR_ARRAY_BUFFER_BINDING_ARB: + case GL_INDEX_ARRAY_BUFFER_BINDING_ARB: + case GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB: + case GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB: + case GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB: + buffer_obj = (struct gl_buffer_object *) + ((char *) ctx->Array.ArrayObj + d->offset); + v->value_int = buffer_obj->Name; + break; + case GL_ARRAY_BUFFER_BINDING_ARB: + v->value_int = ctx->Array.ArrayBufferObj->Name; + break; + case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB: + v->value_int = + ctx->Array.ArrayObj->TexCoord[ctx->Array.ActiveTexture].BufferObj->Name; + break; + case GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB: + v->value_int = ctx->Array.ElementArrayBufferObj->Name; + break; + + /* ARB_copy_buffer */ + case GL_COPY_READ_BUFFER: + v->value_int = ctx->CopyReadBuffer->Name; + break; + case GL_COPY_WRITE_BUFFER: + v->value_int = ctx->CopyWriteBuffer->Name; + break; + + case GL_FRAGMENT_PROGRAM_BINDING_NV: + v->value_int = + ctx->FragmentProgram.Current ? ctx->FragmentProgram.Current->Base.Id : 0; + break; + case GL_VERTEX_PROGRAM_BINDING_NV: + v->value_int = + ctx->VertexProgram.Current ? ctx->VertexProgram.Current->Base.Id : 0; + break; + case GL_PIXEL_PACK_BUFFER_BINDING_EXT: + v->value_int = ctx->Pack.BufferObj->Name; + break; + case GL_PIXEL_UNPACK_BUFFER_BINDING_EXT: + v->value_int = ctx->Unpack.BufferObj->Name; + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + v->value_int = ctx->TransformFeedback.CurrentBuffer->Name; + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED: + v->value_int = ctx->TransformFeedback.CurrentObject->Paused; + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE: + v->value_int = ctx->TransformFeedback.CurrentObject->Active; + break; + case GL_TRANSFORM_FEEDBACK_BINDING: + v->value_int = ctx->TransformFeedback.CurrentObject->Name; + break; + case GL_CURRENT_PROGRAM: + v->value_int = + ctx->Shader.ActiveProgram ? ctx->Shader.ActiveProgram->Name : 0; + break; + case GL_READ_FRAMEBUFFER_BINDING_EXT: + v->value_int = ctx->ReadBuffer->Name; + break; + case GL_RENDERBUFFER_BINDING_EXT: + v->value_int = + ctx->CurrentRenderbuffer ? ctx->CurrentRenderbuffer->Name : 0; + break; + case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: + v->value_int = ctx->Array.ArrayObj->PointSize.BufferObj->Name; + break; + + case GL_MAX_VERTEX_UNIFORM_VECTORS: + v->value_int = ctx->Const.VertexProgram.MaxUniformComponents / 4; + break; + + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: + v->value_int = ctx->Const.FragmentProgram.MaxUniformComponents / 4; + break; + } +} + +/** + * Check extra constraints on a struct value_desc descriptor + * + * If a struct value_desc has a non-NULL extra pointer, it means that + * there are a number of extra constraints to check or actions to + * perform. The extras is just an integer array where each integer + * encode different constraints or actions. + * + * \param ctx current context + * \param func name of calling glGet*v() function for error reporting + * \param d the struct value_desc that has the extra constraints + * + * \return GL_FALSE if one of the constraints was not satisfied, + * otherwise GL_TRUE. + */ +static GLboolean +check_extra(struct gl_context *ctx, const char *func, const struct value_desc *d) +{ + const GLuint version = ctx->VersionMajor * 10 + ctx->VersionMinor; + int total, enabled; + const int *e; + + total = 0; + enabled = 0; + for (e = d->extra; *e != EXTRA_END; e++) + switch (*e) { + case EXTRA_VERSION_30: + if (version >= 30) { + total++; + enabled++; + } + break; + case EXTRA_VERSION_31: + if (version >= 31) { + total++; + enabled++; + } + break; + case EXTRA_VERSION_32: + if (version >= 32) { + total++; + enabled++; + } + break; + case EXTRA_VERSION_ES2: + if (ctx->API == API_OPENGLES2) { + total++; + enabled++; + } + break; + case EXTRA_NEW_BUFFERS: + if (ctx->NewState & _NEW_BUFFERS) + _mesa_update_state(ctx); + break; + case EXTRA_FLUSH_CURRENT: + FLUSH_CURRENT(ctx, 0); + break; + case EXTRA_VALID_DRAW_BUFFER: + if (d->pname - GL_DRAW_BUFFER0_ARB >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(draw buffer %u)", + func, d->pname - GL_DRAW_BUFFER0_ARB); + return GL_FALSE; + } + break; + case EXTRA_VALID_TEXTURE_UNIT: + if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(texture %u)", + func, ctx->Texture.CurrentUnit); + return GL_FALSE; + } + break; + case EXTRA_END: + break; + default: /* *e is a offset into the extension struct */ + total++; + if (*(GLboolean *) ((char *) &ctx->Extensions + *e)) + enabled++; + break; + } + + if (total > 0 && enabled == 0) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", func, + _mesa_lookup_enum_by_nr(d->pname)); + return GL_FALSE; + } + + return GL_TRUE; +} + +static const struct value_desc error_value = + { 0, 0, TYPE_INVALID, NO_OFFSET, NO_EXTRA }; + +/** + * Find the struct value_desc corresponding to the enum 'pname'. + * + * We hash the enum value to get an index into the 'table' array, + * which holds the index in the 'values' array of struct value_desc. + * Once we've found the entry, we do the extra checks, if any, then + * look up the value and return a pointer to it. + * + * If the value has to be computed (for example, it's the result of a + * function call or we need to add 1 to it), we use the tmp 'v' to + * store the result. + * + * \param func name of glGet*v() func for error reporting + * \param pname the enum value we're looking up + * \param p is were we return the pointer to the value + * \param v a tmp union value variable in the calling glGet*v() function + * + * \return the struct value_desc corresponding to the enum or a struct + * value_desc of TYPE_INVALID if not found. This lets the calling + * glGet*v() function jump right into a switch statement and + * handle errors there instead of having to check for NULL. + */ +static const struct value_desc * +find_value(const char *func, GLenum pname, void **p, union value *v) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_unit *unit; + int mask, hash; + const struct value_desc *d; + + mask = Elements(table) - 1; + hash = (pname * prime_factor); + while (1) { + d = &values[table[hash & mask]]; + + /* If the enum isn't valid, the hash walk ends with index 0, + * which is the API mask entry at the beginning of values[]. */ + if (unlikely(d->type == TYPE_API_MASK)) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", func, + _mesa_lookup_enum_by_nr(pname)); + return &error_value; + } + + if (likely(d->pname == pname)) + break; + + hash += prime_step; + } + + if (unlikely(d->extra && !check_extra(ctx, func, d))) + return &error_value; + + switch (d->location) { + case LOC_BUFFER: + *p = ((char *) ctx->DrawBuffer + d->offset); + return d; + case LOC_CONTEXT: + *p = ((char *) ctx + d->offset); + return d; + case LOC_ARRAY: + *p = ((char *) ctx->Array.ArrayObj + d->offset); + return d; + case LOC_TEXUNIT: + unit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + *p = ((char *) unit + d->offset); + return d; + case LOC_CUSTOM: + find_custom_value(ctx, d, v); + *p = v; + return d; + default: + assert(0); + break; + } + + /* silence warning */ + return &error_value; +} + +static const int transpose[] = { + 0, 4, 8, 12, + 1, 5, 9, 13, + 2, 6, 10, 14, + 3, 7, 11, 15 +}; + +void GLAPIENTRY +_mesa_GetBooleanv(GLenum pname, GLboolean *params) +{ + const struct value_desc *d; + union value v; + GLmatrix *m; + int shift, i; + void *p; + + d = find_value("glGetBooleanv", pname, &p, &v); + switch (d->type) { + case TYPE_INVALID: + break; + case TYPE_CONST: + params[0] = INT_TO_BOOLEAN(d->offset); + break; + + case TYPE_FLOAT_4: + case TYPE_FLOATN_4: + params[3] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[3]); + case TYPE_FLOAT_3: + case TYPE_FLOATN_3: + params[2] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[2]); + case TYPE_FLOAT_2: + case TYPE_FLOATN_2: + params[1] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[1]); + case TYPE_FLOAT: + case TYPE_FLOATN: + params[0] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[0]); + break; + + case TYPE_DOUBLEN: + params[0] = FLOAT_TO_BOOLEAN(((GLdouble *) p)[0]); + break; + + case TYPE_INT_4: + params[3] = INT_TO_BOOLEAN(((GLint *) p)[3]); + case TYPE_INT_3: + params[2] = INT_TO_BOOLEAN(((GLint *) p)[2]); + case TYPE_INT_2: + case TYPE_ENUM_2: + params[1] = INT_TO_BOOLEAN(((GLint *) p)[1]); + case TYPE_INT: + case TYPE_ENUM: + params[0] = INT_TO_BOOLEAN(((GLint *) p)[0]); + break; + + case TYPE_INT_N: + for (i = 0; i < v.value_int_n.n; i++) + params[i] = INT_TO_BOOLEAN(v.value_int_n.ints[i]); + break; + + case TYPE_INT64: + params[0] = INT64_TO_BOOLEAN(((GLint64 *) p)[0]); + break; + + case TYPE_BOOLEAN: + params[0] = ((GLboolean*) p)[0]; + break; + + case TYPE_MATRIX: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_BOOLEAN(m->m[i]); + break; + + case TYPE_MATRIX_T: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_BOOLEAN(m->m[transpose[i]]); + break; + + case TYPE_BIT_0: + case TYPE_BIT_1: + case TYPE_BIT_2: + case TYPE_BIT_3: + case TYPE_BIT_4: + case TYPE_BIT_5: + shift = d->type - TYPE_BIT_0; + params[0] = (*(GLbitfield *) p >> shift) & 1; + break; + } +} + +void GLAPIENTRY +_mesa_GetFloatv(GLenum pname, GLfloat *params) +{ + const struct value_desc *d; + union value v; + GLmatrix *m; + int shift, i; + void *p; + + d = find_value("glGetFloatv", pname, &p, &v); + switch (d->type) { + case TYPE_INVALID: + break; + case TYPE_CONST: + params[0] = (GLfloat) d->offset; + break; + + case TYPE_FLOAT_4: + case TYPE_FLOATN_4: + params[3] = ((GLfloat *) p)[3]; + case TYPE_FLOAT_3: + case TYPE_FLOATN_3: + params[2] = ((GLfloat *) p)[2]; + case TYPE_FLOAT_2: + case TYPE_FLOATN_2: + params[1] = ((GLfloat *) p)[1]; + case TYPE_FLOAT: + case TYPE_FLOATN: + params[0] = ((GLfloat *) p)[0]; + break; + + case TYPE_DOUBLEN: + params[0] = ((GLdouble *) p)[0]; + break; + + case TYPE_INT_4: + params[3] = (GLfloat) (((GLint *) p)[3]); + case TYPE_INT_3: + params[2] = (GLfloat) (((GLint *) p)[2]); + case TYPE_INT_2: + case TYPE_ENUM_2: + params[1] = (GLfloat) (((GLint *) p)[1]); + case TYPE_INT: + case TYPE_ENUM: + params[0] = (GLfloat) (((GLint *) p)[0]); + break; + + case TYPE_INT_N: + for (i = 0; i < v.value_int_n.n; i++) + params[i] = INT_TO_FLOAT(v.value_int_n.ints[i]); + break; + + case TYPE_INT64: + params[0] = ((GLint64 *) p)[0]; + break; + + case TYPE_BOOLEAN: + params[0] = BOOLEAN_TO_FLOAT(*(GLboolean*) p); + break; + + case TYPE_MATRIX: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = m->m[i]; + break; + + case TYPE_MATRIX_T: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = m->m[transpose[i]]; + break; + + case TYPE_BIT_0: + case TYPE_BIT_1: + case TYPE_BIT_2: + case TYPE_BIT_3: + case TYPE_BIT_4: + case TYPE_BIT_5: + shift = d->type - TYPE_BIT_0; + params[0] = BOOLEAN_TO_FLOAT((*(GLbitfield *) p >> shift) & 1); + break; + } +} + +void GLAPIENTRY +_mesa_GetIntegerv(GLenum pname, GLint *params) +{ + const struct value_desc *d; + union value v; + GLmatrix *m; + int shift, i; + void *p; + + d = find_value("glGetIntegerv", pname, &p, &v); + switch (d->type) { + case TYPE_INVALID: + break; + case TYPE_CONST: + params[0] = d->offset; + break; + + case TYPE_FLOAT_4: + params[3] = IROUND(((GLfloat *) p)[3]); + case TYPE_FLOAT_3: + params[2] = IROUND(((GLfloat *) p)[2]); + case TYPE_FLOAT_2: + params[1] = IROUND(((GLfloat *) p)[1]); + case TYPE_FLOAT: + params[0] = IROUND(((GLfloat *) p)[0]); + break; + + case TYPE_FLOATN_4: + params[3] = FLOAT_TO_INT(((GLfloat *) p)[3]); + case TYPE_FLOATN_3: + params[2] = FLOAT_TO_INT(((GLfloat *) p)[2]); + case TYPE_FLOATN_2: + params[1] = FLOAT_TO_INT(((GLfloat *) p)[1]); + case TYPE_FLOATN: + params[0] = FLOAT_TO_INT(((GLfloat *) p)[0]); + break; + + case TYPE_DOUBLEN: + params[0] = FLOAT_TO_INT(((GLdouble *) p)[0]); + break; + + case TYPE_INT_4: + params[3] = ((GLint *) p)[3]; + case TYPE_INT_3: + params[2] = ((GLint *) p)[2]; + case TYPE_INT_2: + case TYPE_ENUM_2: + params[1] = ((GLint *) p)[1]; + case TYPE_INT: + case TYPE_ENUM: + params[0] = ((GLint *) p)[0]; + break; + + case TYPE_INT_N: + for (i = 0; i < v.value_int_n.n; i++) + params[i] = v.value_int_n.ints[i]; + break; + + case TYPE_INT64: + params[0] = INT64_TO_INT(((GLint64 *) p)[0]); + break; + + case TYPE_BOOLEAN: + params[0] = BOOLEAN_TO_INT(*(GLboolean*) p); + break; + + case TYPE_MATRIX: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_INT(m->m[i]); + break; + + case TYPE_MATRIX_T: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_INT(m->m[transpose[i]]); + break; + + case TYPE_BIT_0: + case TYPE_BIT_1: + case TYPE_BIT_2: + case TYPE_BIT_3: + case TYPE_BIT_4: + case TYPE_BIT_5: + shift = d->type - TYPE_BIT_0; + params[0] = (*(GLbitfield *) p >> shift) & 1; + break; + } +} + +#if FEATURE_ARB_sync +void GLAPIENTRY +_mesa_GetInteger64v(GLenum pname, GLint64 *params) +{ + const struct value_desc *d; + union value v; + GLmatrix *m; + int shift, i; + void *p; + + d = find_value("glGetInteger64v", pname, &p, &v); + switch (d->type) { + case TYPE_INVALID: + break; + case TYPE_CONST: + params[0] = d->offset; + break; + + case TYPE_FLOAT_4: + params[3] = IROUND64(((GLfloat *) p)[3]); + case TYPE_FLOAT_3: + params[2] = IROUND64(((GLfloat *) p)[2]); + case TYPE_FLOAT_2: + params[1] = IROUND64(((GLfloat *) p)[1]); + case TYPE_FLOAT: + params[0] = IROUND64(((GLfloat *) p)[0]); + break; + + case TYPE_FLOATN_4: + params[3] = FLOAT_TO_INT64(((GLfloat *) p)[3]); + case TYPE_FLOATN_3: + params[2] = FLOAT_TO_INT64(((GLfloat *) p)[2]); + case TYPE_FLOATN_2: + params[1] = FLOAT_TO_INT64(((GLfloat *) p)[1]); + case TYPE_FLOATN: + params[0] = FLOAT_TO_INT64(((GLfloat *) p)[0]); + break; + + case TYPE_DOUBLEN: + params[0] = FLOAT_TO_INT64(((GLdouble *) p)[0]); + break; + + case TYPE_INT_4: + params[3] = ((GLint *) p)[3]; + case TYPE_INT_3: + params[2] = ((GLint *) p)[2]; + case TYPE_INT_2: + case TYPE_ENUM_2: + params[1] = ((GLint *) p)[1]; + case TYPE_INT: + case TYPE_ENUM: + params[0] = ((GLint *) p)[0]; + break; + + case TYPE_INT_N: + for (i = 0; i < v.value_int_n.n; i++) + params[i] = INT_TO_BOOLEAN(v.value_int_n.ints[i]); + break; + + case TYPE_INT64: + params[0] = ((GLint64 *) p)[0]; + break; + + case TYPE_BOOLEAN: + params[0] = ((GLboolean*) p)[0]; + break; + + case TYPE_MATRIX: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_INT64(m->m[i]); + break; + + case TYPE_MATRIX_T: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_INT64(m->m[transpose[i]]); + break; + + case TYPE_BIT_0: + case TYPE_BIT_1: + case TYPE_BIT_2: + case TYPE_BIT_3: + case TYPE_BIT_4: + case TYPE_BIT_5: + shift = d->type - TYPE_BIT_0; + params[0] = (*(GLbitfield *) p >> shift) & 1; + break; + } +} +#endif /* FEATURE_ARB_sync */ + +void GLAPIENTRY +_mesa_GetDoublev(GLenum pname, GLdouble *params) +{ + const struct value_desc *d; + union value v; + GLmatrix *m; + int shift, i; + void *p; + + d = find_value("glGetDoublev", pname, &p, &v); + switch (d->type) { + case TYPE_INVALID: + break; + case TYPE_CONST: + params[0] = d->offset; + break; + + case TYPE_FLOAT_4: + case TYPE_FLOATN_4: + params[3] = ((GLfloat *) p)[3]; + case TYPE_FLOAT_3: + case TYPE_FLOATN_3: + params[2] = ((GLfloat *) p)[2]; + case TYPE_FLOAT_2: + case TYPE_FLOATN_2: + params[1] = ((GLfloat *) p)[1]; + case TYPE_FLOAT: + case TYPE_FLOATN: + params[0] = ((GLfloat *) p)[0]; + break; + + case TYPE_DOUBLEN: + params[0] = ((GLdouble *) p)[0]; + break; + + case TYPE_INT_4: + params[3] = ((GLint *) p)[3]; + case TYPE_INT_3: + params[2] = ((GLint *) p)[2]; + case TYPE_INT_2: + case TYPE_ENUM_2: + params[1] = ((GLint *) p)[1]; + case TYPE_INT: + case TYPE_ENUM: + params[0] = ((GLint *) p)[0]; + break; + + case TYPE_INT_N: + for (i = 0; i < v.value_int_n.n; i++) + params[i] = v.value_int_n.ints[i]; + break; + + case TYPE_INT64: + params[0] = ((GLint64 *) p)[0]; + break; + + case TYPE_BOOLEAN: + params[0] = *(GLboolean*) p; + break; + + case TYPE_MATRIX: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = m->m[i]; + break; + + case TYPE_MATRIX_T: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = m->m[transpose[i]]; + break; + + case TYPE_BIT_0: + case TYPE_BIT_1: + case TYPE_BIT_2: + case TYPE_BIT_3: + case TYPE_BIT_4: + case TYPE_BIT_5: + shift = d->type - TYPE_BIT_0; + params[0] = (*(GLbitfield *) p >> shift) & 1; + break; + } +} + +static enum value_type +find_value_indexed(const char *func, GLenum pname, int index, union value *v) +{ + GET_CURRENT_CONTEXT(ctx); + + switch (pname) { + + case GL_BLEND: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.EXT_draw_buffers2) + goto invalid_enum; + v->value_int = (ctx->Color.BlendEnabled >> index) & 1; + return TYPE_INT; + + case GL_BLEND_SRC: + /* fall-through */ + case GL_BLEND_SRC_RGB: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.ARB_draw_buffers_blend) + goto invalid_enum; + v->value_int = ctx->Color.Blend[index].SrcRGB; + return TYPE_INT; + case GL_BLEND_SRC_ALPHA: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.ARB_draw_buffers_blend) + goto invalid_enum; + v->value_int = ctx->Color.Blend[index].SrcA; + return TYPE_INT; + case GL_BLEND_DST: + /* fall-through */ + case GL_BLEND_DST_RGB: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.ARB_draw_buffers_blend) + goto invalid_enum; + v->value_int = ctx->Color.Blend[index].DstRGB; + return TYPE_INT; + case GL_BLEND_DST_ALPHA: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.ARB_draw_buffers_blend) + goto invalid_enum; + v->value_int = ctx->Color.Blend[index].DstA; + return TYPE_INT; + case GL_BLEND_EQUATION_RGB: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.ARB_draw_buffers_blend) + goto invalid_enum; + v->value_int = ctx->Color.Blend[index].EquationRGB; + return TYPE_INT; + case GL_BLEND_EQUATION_ALPHA: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.ARB_draw_buffers_blend) + goto invalid_enum; + v->value_int = ctx->Color.Blend[index].EquationA; + return TYPE_INT; + + case GL_COLOR_WRITEMASK: + if (index >= ctx->Const.MaxDrawBuffers) + goto invalid_value; + if (!ctx->Extensions.EXT_draw_buffers2) + goto invalid_enum; + v->value_int_4[0] = ctx->Color.ColorMask[index][RCOMP] ? 1 : 0; + v->value_int_4[1] = ctx->Color.ColorMask[index][GCOMP] ? 1 : 0; + v->value_int_4[2] = ctx->Color.ColorMask[index][BCOMP] ? 1 : 0; + v->value_int_4[3] = ctx->Color.ColorMask[index][ACOMP] ? 1 : 0; + return TYPE_INT_4; + + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) + goto invalid_value; + if (!ctx->Extensions.EXT_transform_feedback) + goto invalid_enum; + v->value_int64 = ctx->TransformFeedback.CurrentObject->Offset[index]; + return TYPE_INT64; + + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) + goto invalid_value; + if (!ctx->Extensions.EXT_transform_feedback) + goto invalid_enum; + v->value_int64 = ctx->TransformFeedback.CurrentObject->Size[index]; + return TYPE_INT64; + + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) + goto invalid_value; + if (!ctx->Extensions.EXT_transform_feedback) + goto invalid_enum; + v->value_int = ctx->TransformFeedback.CurrentObject->Buffers[index]->Name; + return TYPE_INT; + } + + invalid_enum: + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", func, + _mesa_lookup_enum_by_nr(pname)); + return TYPE_INVALID; + invalid_value: + _mesa_error(ctx, GL_INVALID_VALUE, "%s(pname=%s)", func, + _mesa_lookup_enum_by_nr(pname)); + return TYPE_INVALID; +} + +void GLAPIENTRY +_mesa_GetBooleanIndexedv( GLenum pname, GLuint index, GLboolean *params ) +{ + union value v; + enum value_type type = + find_value_indexed("glGetBooleanIndexedv", pname, index, &v); + + switch (type) { + case TYPE_INT: + params[0] = INT_TO_BOOLEAN(v.value_int); + break; + case TYPE_INT_4: + params[0] = INT_TO_BOOLEAN(v.value_int_4[0]); + params[1] = INT_TO_BOOLEAN(v.value_int_4[1]); + params[2] = INT_TO_BOOLEAN(v.value_int_4[2]); + params[3] = INT_TO_BOOLEAN(v.value_int_4[3]); + break; + case TYPE_INT64: + params[0] = INT64_TO_BOOLEAN(v.value_int); + break; + default: + ; /* nothing - GL error was recorded */ + } +} + +void GLAPIENTRY +_mesa_GetIntegerIndexedv( GLenum pname, GLuint index, GLint *params ) +{ + union value v; + enum value_type type = + find_value_indexed("glGetIntegerIndexedv", pname, index, &v); + + switch (type) { + case TYPE_INT: + params[0] = v.value_int; + break; + case TYPE_INT_4: + params[0] = v.value_int_4[0]; + params[1] = v.value_int_4[1]; + params[2] = v.value_int_4[2]; + params[3] = v.value_int_4[3]; + break; + case TYPE_INT64: + params[0] = INT64_TO_INT(v.value_int); + break; + default: + ; /* nothing - GL error was recorded */ + } +} + +#if FEATURE_ARB_sync +void GLAPIENTRY +_mesa_GetInteger64Indexedv( GLenum pname, GLuint index, GLint64 *params ) +{ + union value v; + enum value_type type = + find_value_indexed("glGetIntegerIndexedv", pname, index, &v); + + switch (type) { + case TYPE_INT: + params[0] = v.value_int; + break; + case TYPE_INT_4: + params[0] = v.value_int_4[0]; + params[1] = v.value_int_4[1]; + params[2] = v.value_int_4[2]; + params[3] = v.value_int_4[3]; + break; + case TYPE_INT64: + params[0] = v.value_int; + break; + default: + ; /* nothing - GL error was recorded */ + } +} +#endif /* FEATURE_ARB_sync */ + +#if FEATURE_ES1 +void GLAPIENTRY +_mesa_GetFixedv(GLenum pname, GLfixed *params) +{ + const struct value_desc *d; + union value v; + GLmatrix *m; + int shift, i; + void *p; + + d = find_value("glGetDoublev", pname, &p, &v); + switch (d->type) { + case TYPE_INVALID: + break; + case TYPE_CONST: + params[0] = INT_TO_FIXED(d->offset); + break; + + case TYPE_FLOAT_4: + case TYPE_FLOATN_4: + params[3] = FLOAT_TO_FIXED(((GLfloat *) p)[3]); + case TYPE_FLOAT_3: + case TYPE_FLOATN_3: + params[2] = FLOAT_TO_FIXED(((GLfloat *) p)[2]); + case TYPE_FLOAT_2: + case TYPE_FLOATN_2: + params[1] = FLOAT_TO_FIXED(((GLfloat *) p)[1]); + case TYPE_FLOAT: + case TYPE_FLOATN: + params[0] = FLOAT_TO_FIXED(((GLfloat *) p)[0]); + break; + + case TYPE_DOUBLEN: + params[0] = FLOAT_TO_FIXED(((GLdouble *) p)[0]); + break; + + case TYPE_INT_4: + params[3] = INT_TO_FIXED(((GLint *) p)[3]); + case TYPE_INT_3: + params[2] = INT_TO_FIXED(((GLint *) p)[2]); + case TYPE_INT_2: + case TYPE_ENUM_2: + params[1] = INT_TO_FIXED(((GLint *) p)[1]); + case TYPE_INT: + case TYPE_ENUM: + params[0] = INT_TO_FIXED(((GLint *) p)[0]); + break; + + case TYPE_INT_N: + for (i = 0; i < v.value_int_n.n; i++) + params[i] = INT_TO_FIXED(v.value_int_n.ints[i]); + break; + + case TYPE_INT64: + params[0] = ((GLint64 *) p)[0]; + break; + + case TYPE_BOOLEAN: + params[0] = BOOLEAN_TO_FIXED(((GLboolean*) p)[0]); + break; + + case TYPE_MATRIX: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_FIXED(m->m[i]); + break; + + case TYPE_MATRIX_T: + m = *(GLmatrix **) p; + for (i = 0; i < 16; i++) + params[i] = FLOAT_TO_FIXED(m->m[transpose[i]]); + break; + + case TYPE_BIT_0: + case TYPE_BIT_1: + case TYPE_BIT_2: + case TYPE_BIT_3: + case TYPE_BIT_4: + case TYPE_BIT_5: + shift = d->type - TYPE_BIT_0; + params[0] = BOOLEAN_TO_FIXED((*(GLbitfield *) p >> shift) & 1); + break; + } +} +#endif diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h index d2888fa80..fcb06d49e 100644 --- a/mesalib/src/mesa/main/mtypes.h +++ b/mesalib/src/mesa/main/mtypes.h @@ -1,3367 +1,3355 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.7
- *
- * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- * Copyright (C) 2009 VMware, Inc. 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.
- */
-
-/**
- * \file mtypes.h
- * Main Mesa data structures.
- *
- * Please try to mark derived values with a leading underscore ('_').
- */
-
-#ifndef MTYPES_H
-#define MTYPES_H
-
-
-#include "main/glheader.h"
-#include "main/config.h"
-#include "main/mfeatures.h"
-#include "glapi/glapi.h"
-#include "math/m_matrix.h" /* GLmatrix */
-#include "main/simple_list.h" /* struct simple_node */
-#include "main/formats.h" /* MESA_FORMAT_COUNT */
-
-
-/**
- * Color channel data type.
- */
-#if CHAN_BITS == 8
- typedef GLubyte GLchan;
-#define CHAN_MAX 255
-#define CHAN_MAXF 255.0F
-#define CHAN_TYPE GL_UNSIGNED_BYTE
-#elif CHAN_BITS == 16
- typedef GLushort GLchan;
-#define CHAN_MAX 65535
-#define CHAN_MAXF 65535.0F
-#define CHAN_TYPE GL_UNSIGNED_SHORT
-#elif CHAN_BITS == 32
- typedef GLfloat GLchan;
-#define CHAN_MAX 1.0
-#define CHAN_MAXF 1.0F
-#define CHAN_TYPE GL_FLOAT
-#else
-#error "illegal number of color channel bits"
-#endif
-
-
-/**
- * Stencil buffer data type.
- */
-#if STENCIL_BITS==8
- typedef GLubyte GLstencil;
-#elif STENCIL_BITS==16
- typedef GLushort GLstencil;
-#else
-# error "illegal number of stencil bits"
-#endif
-
-
-/**
- * \name 64-bit extension of GLbitfield.
- */
-/*@{*/
-typedef GLuint64 GLbitfield64;
-
-/** Set a single bit */
-#define BITFIELD64_BIT(b) (1ULL << (b))
-
-
-/**
- * \name Some forward type declarations
- */
-/*@{*/
-struct _mesa_HashTable;
-struct gl_attrib_node;
-struct gl_list_extensions;
-struct gl_meta_state;
-struct gl_pixelstore_attrib;
-struct gl_program_cache;
-struct gl_texture_format;
-struct gl_texture_image;
-struct gl_texture_object;
-struct gl_context;
-struct st_context;
-/*@}*/
-
-
-/** Extra draw modes beyond GL_POINTS, GL_TRIANGLE_FAN, etc */
-#define PRIM_OUTSIDE_BEGIN_END (GL_POLYGON+1)
-#define PRIM_INSIDE_UNKNOWN_PRIM (GL_POLYGON+2)
-#define PRIM_UNKNOWN (GL_POLYGON+3)
-
-
-/**
- * Shader stages. Note that these will become 5 with tessellation.
- * These MUST have the same values as gallium's PIPE_SHADER_*
- */
-typedef enum
-{
- MESA_SHADER_VERTEX = 0,
- MESA_SHADER_FRAGMENT = 1,
- MESA_SHADER_GEOMETRY = 2,
- MESA_SHADER_TYPES = 3
-} gl_shader_type;
-
-
-
-/**
- * Indexes for vertex program attributes.
- * GL_NV_vertex_program aliases generic attributes over the conventional
- * attributes. In GL_ARB_vertex_program shader the aliasing is optional.
- * In GL_ARB_vertex_shader / OpenGL 2.0 the aliasing is disallowed (the
- * generic attributes are distinct/separate).
- */
-typedef enum
-{
- VERT_ATTRIB_POS = 0,
- VERT_ATTRIB_WEIGHT = 1,
- VERT_ATTRIB_NORMAL = 2,
- VERT_ATTRIB_COLOR0 = 3,
- VERT_ATTRIB_COLOR1 = 4,
- VERT_ATTRIB_FOG = 5,
- VERT_ATTRIB_COLOR_INDEX = 6,
- VERT_ATTRIB_POINT_SIZE = 6, /*alias*/
- VERT_ATTRIB_EDGEFLAG = 7,
- VERT_ATTRIB_TEX0 = 8,
- VERT_ATTRIB_TEX1 = 9,
- VERT_ATTRIB_TEX2 = 10,
- VERT_ATTRIB_TEX3 = 11,
- VERT_ATTRIB_TEX4 = 12,
- VERT_ATTRIB_TEX5 = 13,
- VERT_ATTRIB_TEX6 = 14,
- VERT_ATTRIB_TEX7 = 15,
- VERT_ATTRIB_GENERIC0 = 16,
- VERT_ATTRIB_GENERIC1 = 17,
- VERT_ATTRIB_GENERIC2 = 18,
- VERT_ATTRIB_GENERIC3 = 19,
- VERT_ATTRIB_GENERIC4 = 20,
- VERT_ATTRIB_GENERIC5 = 21,
- VERT_ATTRIB_GENERIC6 = 22,
- VERT_ATTRIB_GENERIC7 = 23,
- VERT_ATTRIB_GENERIC8 = 24,
- VERT_ATTRIB_GENERIC9 = 25,
- VERT_ATTRIB_GENERIC10 = 26,
- VERT_ATTRIB_GENERIC11 = 27,
- VERT_ATTRIB_GENERIC12 = 28,
- VERT_ATTRIB_GENERIC13 = 29,
- VERT_ATTRIB_GENERIC14 = 30,
- VERT_ATTRIB_GENERIC15 = 31,
- VERT_ATTRIB_MAX = 32
-} gl_vert_attrib;
-
-/**
- * Bitflags for vertex attributes.
- * These are used in bitfields in many places.
- */
-/*@{*/
-#define VERT_BIT_POS (1 << VERT_ATTRIB_POS)
-#define VERT_BIT_WEIGHT (1 << VERT_ATTRIB_WEIGHT)
-#define VERT_BIT_NORMAL (1 << VERT_ATTRIB_NORMAL)
-#define VERT_BIT_COLOR0 (1 << VERT_ATTRIB_COLOR0)
-#define VERT_BIT_COLOR1 (1 << VERT_ATTRIB_COLOR1)
-#define VERT_BIT_FOG (1 << VERT_ATTRIB_FOG)
-#define VERT_BIT_COLOR_INDEX (1 << VERT_ATTRIB_COLOR_INDEX)
-#define VERT_BIT_EDGEFLAG (1 << VERT_ATTRIB_EDGEFLAG)
-#define VERT_BIT_TEX0 (1 << VERT_ATTRIB_TEX0)
-#define VERT_BIT_TEX1 (1 << VERT_ATTRIB_TEX1)
-#define VERT_BIT_TEX2 (1 << VERT_ATTRIB_TEX2)
-#define VERT_BIT_TEX3 (1 << VERT_ATTRIB_TEX3)
-#define VERT_BIT_TEX4 (1 << VERT_ATTRIB_TEX4)
-#define VERT_BIT_TEX5 (1 << VERT_ATTRIB_TEX5)
-#define VERT_BIT_TEX6 (1 << VERT_ATTRIB_TEX6)
-#define VERT_BIT_TEX7 (1 << VERT_ATTRIB_TEX7)
-#define VERT_BIT_GENERIC0 (1 << VERT_ATTRIB_GENERIC0)
-#define VERT_BIT_GENERIC1 (1 << VERT_ATTRIB_GENERIC1)
-#define VERT_BIT_GENERIC2 (1 << VERT_ATTRIB_GENERIC2)
-#define VERT_BIT_GENERIC3 (1 << VERT_ATTRIB_GENERIC3)
-#define VERT_BIT_GENERIC4 (1 << VERT_ATTRIB_GENERIC4)
-#define VERT_BIT_GENERIC5 (1 << VERT_ATTRIB_GENERIC5)
-#define VERT_BIT_GENERIC6 (1 << VERT_ATTRIB_GENERIC6)
-#define VERT_BIT_GENERIC7 (1 << VERT_ATTRIB_GENERIC7)
-#define VERT_BIT_GENERIC8 (1 << VERT_ATTRIB_GENERIC8)
-#define VERT_BIT_GENERIC9 (1 << VERT_ATTRIB_GENERIC9)
-#define VERT_BIT_GENERIC10 (1 << VERT_ATTRIB_GENERIC10)
-#define VERT_BIT_GENERIC11 (1 << VERT_ATTRIB_GENERIC11)
-#define VERT_BIT_GENERIC12 (1 << VERT_ATTRIB_GENERIC12)
-#define VERT_BIT_GENERIC13 (1 << VERT_ATTRIB_GENERIC13)
-#define VERT_BIT_GENERIC14 (1 << VERT_ATTRIB_GENERIC14)
-#define VERT_BIT_GENERIC15 (1 << VERT_ATTRIB_GENERIC15)
-
-#define VERT_BIT_TEX(u) (1 << (VERT_ATTRIB_TEX0 + (u)))
-#define VERT_BIT_GENERIC(g) (1 << (VERT_ATTRIB_GENERIC0 + (g)))
-/*@}*/
-
-
-/**
- * Indexes for vertex program result attributes
- */
-typedef enum
-{
- VERT_RESULT_HPOS = 0,
- VERT_RESULT_COL0 = 1,
- VERT_RESULT_COL1 = 2,
- VERT_RESULT_FOGC = 3,
- VERT_RESULT_TEX0 = 4,
- VERT_RESULT_TEX1 = 5,
- VERT_RESULT_TEX2 = 6,
- VERT_RESULT_TEX3 = 7,
- VERT_RESULT_TEX4 = 8,
- VERT_RESULT_TEX5 = 9,
- VERT_RESULT_TEX6 = 10,
- VERT_RESULT_TEX7 = 11,
- VERT_RESULT_PSIZ = 12,
- VERT_RESULT_BFC0 = 13,
- VERT_RESULT_BFC1 = 14,
- VERT_RESULT_EDGE = 15,
- VERT_RESULT_VAR0 = 16, /**< shader varying */
- VERT_RESULT_MAX = (VERT_RESULT_VAR0 + MAX_VARYING)
-} gl_vert_result;
-
-
-/*********************************************/
-
-/**
- * Indexes for geometry program attributes.
- */
-typedef enum
-{
- GEOM_ATTRIB_POSITION = 0,
- GEOM_ATTRIB_COLOR0 = 1,
- GEOM_ATTRIB_COLOR1 = 2,
- GEOM_ATTRIB_SECONDARY_COLOR0 = 3,
- GEOM_ATTRIB_SECONDARY_COLOR1 = 4,
- GEOM_ATTRIB_FOG_FRAG_COORD = 5,
- GEOM_ATTRIB_POINT_SIZE = 6,
- GEOM_ATTRIB_CLIP_VERTEX = 7,
- GEOM_ATTRIB_PRIMITIVE_ID = 8,
- GEOM_ATTRIB_TEX_COORD = 9,
-
- GEOM_ATTRIB_VAR0 = 16,
- GEOM_ATTRIB_MAX = (GEOM_ATTRIB_VAR0 + MAX_VARYING)
-} gl_geom_attrib;
-
-/**
- * Bitflags for geometry attributes.
- * These are used in bitfields in many places.
- */
-/*@{*/
-#define GEOM_BIT_COLOR0 (1 << GEOM_ATTRIB_COLOR0)
-#define GEOM_BIT_COLOR1 (1 << GEOM_ATTRIB_COLOR1)
-#define GEOM_BIT_SCOLOR0 (1 << GEOM_ATTRIB_SECONDARY_COLOR0)
-#define GEOM_BIT_SCOLOR1 (1 << GEOM_ATTRIB_SECONDARY_COLOR1)
-#define GEOM_BIT_TEX_COORD (1 << GEOM_ATTRIB_TEX_COORD)
-#define GEOM_BIT_FOG_COORD (1 << GEOM_ATTRIB_FOG_FRAG_COORD)
-#define GEOM_BIT_POSITION (1 << GEOM_ATTRIB_POSITION)
-#define GEOM_BIT_POINT_SIDE (1 << GEOM_ATTRIB_POINT_SIZE)
-#define GEOM_BIT_CLIP_VERTEX (1 << GEOM_ATTRIB_CLIP_VERTEX)
-#define GEOM_BIT_PRIM_ID (1 << GEOM_ATTRIB_PRIMITIVE_ID)
-#define GEOM_BIT_VAR0 (1 << GEOM_ATTRIB_VAR0)
-
-#define GEOM_BIT_VAR(g) (1 << (GEOM_BIT_VAR0 + (g)))
-/*@}*/
-
-
-/**
- * Indexes for geometry program result attributes
- */
-typedef enum
-{
- GEOM_RESULT_POS = 0,
- GEOM_RESULT_COL0 = 1,
- GEOM_RESULT_COL1 = 2,
- GEOM_RESULT_SCOL0 = 3,
- GEOM_RESULT_SCOL1 = 4,
- GEOM_RESULT_FOGC = 5,
- GEOM_RESULT_TEX0 = 6,
- GEOM_RESULT_TEX1 = 7,
- GEOM_RESULT_TEX2 = 8,
- GEOM_RESULT_TEX3 = 9,
- GEOM_RESULT_TEX4 = 10,
- GEOM_RESULT_TEX5 = 11,
- GEOM_RESULT_TEX6 = 12,
- GEOM_RESULT_TEX7 = 13,
- GEOM_RESULT_PSIZ = 14,
- GEOM_RESULT_CLPV = 15,
- GEOM_RESULT_PRID = 16,
- GEOM_RESULT_LAYR = 17,
- GEOM_RESULT_VAR0 = 18, /**< shader varying, should really be 16 */
- /* ### we need to -2 because var0 is 18 instead 16 like in the others */
- GEOM_RESULT_MAX = (GEOM_RESULT_VAR0 + MAX_VARYING - 2)
-} gl_geom_result;
-
-
-/**
- * Indexes for fragment program input attributes.
- */
-typedef enum
-{
- FRAG_ATTRIB_WPOS = 0,
- FRAG_ATTRIB_COL0 = 1,
- FRAG_ATTRIB_COL1 = 2,
- FRAG_ATTRIB_FOGC = 3,
- FRAG_ATTRIB_TEX0 = 4,
- FRAG_ATTRIB_TEX1 = 5,
- FRAG_ATTRIB_TEX2 = 6,
- FRAG_ATTRIB_TEX3 = 7,
- FRAG_ATTRIB_TEX4 = 8,
- FRAG_ATTRIB_TEX5 = 9,
- FRAG_ATTRIB_TEX6 = 10,
- FRAG_ATTRIB_TEX7 = 11,
- FRAG_ATTRIB_FACE = 12, /**< front/back face */
- FRAG_ATTRIB_PNTC = 13, /**< sprite/point coord */
- FRAG_ATTRIB_VAR0 = 14, /**< shader varying */
- FRAG_ATTRIB_MAX = (FRAG_ATTRIB_VAR0 + MAX_VARYING)
-} gl_frag_attrib;
-
-/**
- * Bitflags for fragment program input attributes.
- */
-/*@{*/
-#define FRAG_BIT_WPOS (1 << FRAG_ATTRIB_WPOS)
-#define FRAG_BIT_COL0 (1 << FRAG_ATTRIB_COL0)
-#define FRAG_BIT_COL1 (1 << FRAG_ATTRIB_COL1)
-#define FRAG_BIT_FOGC (1 << FRAG_ATTRIB_FOGC)
-#define FRAG_BIT_FACE (1 << FRAG_ATTRIB_FACE)
-#define FRAG_BIT_PNTC (1 << FRAG_ATTRIB_PNTC)
-#define FRAG_BIT_TEX0 (1 << FRAG_ATTRIB_TEX0)
-#define FRAG_BIT_TEX1 (1 << FRAG_ATTRIB_TEX1)
-#define FRAG_BIT_TEX2 (1 << FRAG_ATTRIB_TEX2)
-#define FRAG_BIT_TEX3 (1 << FRAG_ATTRIB_TEX3)
-#define FRAG_BIT_TEX4 (1 << FRAG_ATTRIB_TEX4)
-#define FRAG_BIT_TEX5 (1 << FRAG_ATTRIB_TEX5)
-#define FRAG_BIT_TEX6 (1 << FRAG_ATTRIB_TEX6)
-#define FRAG_BIT_TEX7 (1 << FRAG_ATTRIB_TEX7)
-#define FRAG_BIT_VAR0 (1 << FRAG_ATTRIB_VAR0)
-
-#define FRAG_BIT_TEX(U) (FRAG_BIT_TEX0 << (U))
-#define FRAG_BIT_VAR(V) (FRAG_BIT_VAR0 << (V))
-
-#define FRAG_BITS_TEX_ANY (FRAG_BIT_TEX0| \
- FRAG_BIT_TEX1| \
- FRAG_BIT_TEX2| \
- FRAG_BIT_TEX3| \
- FRAG_BIT_TEX4| \
- FRAG_BIT_TEX5| \
- FRAG_BIT_TEX6| \
- FRAG_BIT_TEX7)
-/*@}*/
-
-
-/**
- * Fragment program results
- */
-typedef enum
-{
- FRAG_RESULT_DEPTH = 0,
- FRAG_RESULT_STENCIL = 1,
- FRAG_RESULT_COLOR = 2,
- FRAG_RESULT_DATA0 = 3,
- FRAG_RESULT_MAX = (FRAG_RESULT_DATA0 + MAX_DRAW_BUFFERS)
-} gl_frag_result;
-
-
-/**
- * Indexes for all renderbuffers
- */
-typedef enum
-{
- /* the four standard color buffers */
- BUFFER_FRONT_LEFT,
- BUFFER_BACK_LEFT,
- BUFFER_FRONT_RIGHT,
- BUFFER_BACK_RIGHT,
- BUFFER_DEPTH,
- BUFFER_STENCIL,
- BUFFER_ACCUM,
- /* optional aux buffer */
- BUFFER_AUX0,
- /* generic renderbuffers */
- BUFFER_COLOR0,
- BUFFER_COLOR1,
- BUFFER_COLOR2,
- BUFFER_COLOR3,
- BUFFER_COLOR4,
- BUFFER_COLOR5,
- BUFFER_COLOR6,
- BUFFER_COLOR7,
- BUFFER_COUNT
-} gl_buffer_index;
-
-/**
- * Bit flags for all renderbuffers
- */
-#define BUFFER_BIT_FRONT_LEFT (1 << BUFFER_FRONT_LEFT)
-#define BUFFER_BIT_BACK_LEFT (1 << BUFFER_BACK_LEFT)
-#define BUFFER_BIT_FRONT_RIGHT (1 << BUFFER_FRONT_RIGHT)
-#define BUFFER_BIT_BACK_RIGHT (1 << BUFFER_BACK_RIGHT)
-#define BUFFER_BIT_AUX0 (1 << BUFFER_AUX0)
-#define BUFFER_BIT_AUX1 (1 << BUFFER_AUX1)
-#define BUFFER_BIT_AUX2 (1 << BUFFER_AUX2)
-#define BUFFER_BIT_AUX3 (1 << BUFFER_AUX3)
-#define BUFFER_BIT_DEPTH (1 << BUFFER_DEPTH)
-#define BUFFER_BIT_STENCIL (1 << BUFFER_STENCIL)
-#define BUFFER_BIT_ACCUM (1 << BUFFER_ACCUM)
-#define BUFFER_BIT_COLOR0 (1 << BUFFER_COLOR0)
-#define BUFFER_BIT_COLOR1 (1 << BUFFER_COLOR1)
-#define BUFFER_BIT_COLOR2 (1 << BUFFER_COLOR2)
-#define BUFFER_BIT_COLOR3 (1 << BUFFER_COLOR3)
-#define BUFFER_BIT_COLOR4 (1 << BUFFER_COLOR4)
-#define BUFFER_BIT_COLOR5 (1 << BUFFER_COLOR5)
-#define BUFFER_BIT_COLOR6 (1 << BUFFER_COLOR6)
-#define BUFFER_BIT_COLOR7 (1 << BUFFER_COLOR7)
-
-/**
- * Mask of all the color buffer bits (but not accum).
- */
-#define BUFFER_BITS_COLOR (BUFFER_BIT_FRONT_LEFT | \
- BUFFER_BIT_BACK_LEFT | \
- BUFFER_BIT_FRONT_RIGHT | \
- BUFFER_BIT_BACK_RIGHT | \
- BUFFER_BIT_AUX0 | \
- BUFFER_BIT_COLOR0 | \
- BUFFER_BIT_COLOR1 | \
- BUFFER_BIT_COLOR2 | \
- BUFFER_BIT_COLOR3 | \
- BUFFER_BIT_COLOR4 | \
- BUFFER_BIT_COLOR5 | \
- BUFFER_BIT_COLOR6 | \
- BUFFER_BIT_COLOR7)
-
-
-/**
- * Framebuffer configuration (aka visual / pixelformat)
- * Note: some of these fields should be boolean, but it appears that
- * code in drivers/dri/common/util.c requires int-sized fields.
- */
-struct gl_config
-{
- GLboolean rgbMode;
- GLboolean floatMode;
- GLboolean colorIndexMode; /* XXX is this used anywhere? */
- GLuint doubleBufferMode;
- GLuint stereoMode;
-
- GLboolean haveAccumBuffer;
- GLboolean haveDepthBuffer;
- GLboolean haveStencilBuffer;
-
- GLint redBits, greenBits, blueBits, alphaBits; /* bits per comp */
- GLuint redMask, greenMask, blueMask, alphaMask;
- GLint rgbBits; /* total bits for rgb */
- GLint indexBits; /* total bits for colorindex */
-
- GLint accumRedBits, accumGreenBits, accumBlueBits, accumAlphaBits;
- GLint depthBits;
- GLint stencilBits;
-
- GLint numAuxBuffers;
-
- GLint level;
-
- /* EXT_visual_rating / GLX 1.2 */
- GLint visualRating;
-
- /* EXT_visual_info / GLX 1.2 */
- GLint transparentPixel;
- /* colors are floats scaled to ints */
- GLint transparentRed, transparentGreen, transparentBlue, transparentAlpha;
- GLint transparentIndex;
-
- /* ARB_multisample / SGIS_multisample */
- GLint sampleBuffers;
- GLint samples;
-
- /* SGIX_pbuffer / GLX 1.3 */
- GLint maxPbufferWidth;
- GLint maxPbufferHeight;
- GLint maxPbufferPixels;
- GLint optimalPbufferWidth; /* Only for SGIX_pbuffer. */
- GLint optimalPbufferHeight; /* Only for SGIX_pbuffer. */
-
- /* OML_swap_method */
- GLint swapMethod;
-
- /* EXT_texture_from_pixmap */
- GLint bindToTextureRgb;
- GLint bindToTextureRgba;
- GLint bindToMipmapTexture;
- GLint bindToTextureTargets;
- GLint yInverted;
-
- /* EXT_framebuffer_sRGB */
- GLint sRGBCapable;
-};
-
-
-/**
- * Data structure for color tables
- */
-struct gl_color_table
-{
- GLenum InternalFormat; /**< The user-specified format */
- GLenum _BaseFormat; /**< GL_ALPHA, GL_RGBA, GL_RGB, etc */
- GLuint Size; /**< number of entries in table */
- GLfloat *TableF; /**< Color table, floating point values */
- GLubyte *TableUB; /**< Color table, ubyte values */
- GLubyte RedSize;
- GLubyte GreenSize;
- GLubyte BlueSize;
- GLubyte AlphaSize;
- GLubyte LuminanceSize;
- GLubyte IntensitySize;
-};
-
-
-/**
- * \name Bit flags used for updating material values.
- */
-/*@{*/
-#define MAT_ATTRIB_FRONT_AMBIENT 0
-#define MAT_ATTRIB_BACK_AMBIENT 1
-#define MAT_ATTRIB_FRONT_DIFFUSE 2
-#define MAT_ATTRIB_BACK_DIFFUSE 3
-#define MAT_ATTRIB_FRONT_SPECULAR 4
-#define MAT_ATTRIB_BACK_SPECULAR 5
-#define MAT_ATTRIB_FRONT_EMISSION 6
-#define MAT_ATTRIB_BACK_EMISSION 7
-#define MAT_ATTRIB_FRONT_SHININESS 8
-#define MAT_ATTRIB_BACK_SHININESS 9
-#define MAT_ATTRIB_FRONT_INDEXES 10
-#define MAT_ATTRIB_BACK_INDEXES 11
-#define MAT_ATTRIB_MAX 12
-
-#define MAT_ATTRIB_AMBIENT(f) (MAT_ATTRIB_FRONT_AMBIENT+(f))
-#define MAT_ATTRIB_DIFFUSE(f) (MAT_ATTRIB_FRONT_DIFFUSE+(f))
-#define MAT_ATTRIB_SPECULAR(f) (MAT_ATTRIB_FRONT_SPECULAR+(f))
-#define MAT_ATTRIB_EMISSION(f) (MAT_ATTRIB_FRONT_EMISSION+(f))
-#define MAT_ATTRIB_SHININESS(f)(MAT_ATTRIB_FRONT_SHININESS+(f))
-#define MAT_ATTRIB_INDEXES(f) (MAT_ATTRIB_FRONT_INDEXES+(f))
-
-#define MAT_INDEX_AMBIENT 0
-#define MAT_INDEX_DIFFUSE 1
-#define MAT_INDEX_SPECULAR 2
-
-#define MAT_BIT_FRONT_AMBIENT (1<<MAT_ATTRIB_FRONT_AMBIENT)
-#define MAT_BIT_BACK_AMBIENT (1<<MAT_ATTRIB_BACK_AMBIENT)
-#define MAT_BIT_FRONT_DIFFUSE (1<<MAT_ATTRIB_FRONT_DIFFUSE)
-#define MAT_BIT_BACK_DIFFUSE (1<<MAT_ATTRIB_BACK_DIFFUSE)
-#define MAT_BIT_FRONT_SPECULAR (1<<MAT_ATTRIB_FRONT_SPECULAR)
-#define MAT_BIT_BACK_SPECULAR (1<<MAT_ATTRIB_BACK_SPECULAR)
-#define MAT_BIT_FRONT_EMISSION (1<<MAT_ATTRIB_FRONT_EMISSION)
-#define MAT_BIT_BACK_EMISSION (1<<MAT_ATTRIB_BACK_EMISSION)
-#define MAT_BIT_FRONT_SHININESS (1<<MAT_ATTRIB_FRONT_SHININESS)
-#define MAT_BIT_BACK_SHININESS (1<<MAT_ATTRIB_BACK_SHININESS)
-#define MAT_BIT_FRONT_INDEXES (1<<MAT_ATTRIB_FRONT_INDEXES)
-#define MAT_BIT_BACK_INDEXES (1<<MAT_ATTRIB_BACK_INDEXES)
-
-
-#define FRONT_MATERIAL_BITS (MAT_BIT_FRONT_EMISSION | \
- MAT_BIT_FRONT_AMBIENT | \
- MAT_BIT_FRONT_DIFFUSE | \
- MAT_BIT_FRONT_SPECULAR | \
- MAT_BIT_FRONT_SHININESS | \
- MAT_BIT_FRONT_INDEXES)
-
-#define BACK_MATERIAL_BITS (MAT_BIT_BACK_EMISSION | \
- MAT_BIT_BACK_AMBIENT | \
- MAT_BIT_BACK_DIFFUSE | \
- MAT_BIT_BACK_SPECULAR | \
- MAT_BIT_BACK_SHININESS | \
- MAT_BIT_BACK_INDEXES)
-
-#define ALL_MATERIAL_BITS (FRONT_MATERIAL_BITS | BACK_MATERIAL_BITS)
-/*@}*/
-
-
-#define EXP_TABLE_SIZE 512 /**< Specular exponent lookup table sizes */
-#define SHINE_TABLE_SIZE 256 /**< Material shininess lookup table sizes */
-
-/**
- * Material shininess lookup table.
- */
-struct gl_shine_tab
-{
- struct gl_shine_tab *next, *prev;
- GLfloat tab[SHINE_TABLE_SIZE+1];
- GLfloat shininess;
- GLuint refcount;
-};
-
-
-/**
- * Light source state.
- */
-struct gl_light
-{
- struct gl_light *next; /**< double linked list with sentinel */
- struct gl_light *prev;
-
- GLfloat Ambient[4]; /**< ambient color */
- GLfloat Diffuse[4]; /**< diffuse color */
- GLfloat Specular[4]; /**< specular color */
- GLfloat EyePosition[4]; /**< position in eye coordinates */
- GLfloat SpotDirection[4]; /**< spotlight direction in eye coordinates */
- GLfloat SpotExponent;
- GLfloat SpotCutoff; /**< in degrees */
- GLfloat _CosCutoffNeg; /**< = cos(SpotCutoff) */
- GLfloat _CosCutoff; /**< = MAX(0, cos(SpotCutoff)) */
- GLfloat ConstantAttenuation;
- GLfloat LinearAttenuation;
- GLfloat QuadraticAttenuation;
- GLboolean Enabled; /**< On/off flag */
-
- /**
- * \name Derived fields
- */
- /*@{*/
- GLbitfield _Flags; /**< State */
-
- GLfloat _Position[4]; /**< position in eye/obj coordinates */
- GLfloat _VP_inf_norm[3]; /**< Norm direction to infinite light */
- GLfloat _h_inf_norm[3]; /**< Norm( _VP_inf_norm + <0,0,1> ) */
- GLfloat _NormSpotDirection[4]; /**< normalized spotlight direction */
- GLfloat _VP_inf_spot_attenuation;
-
- GLfloat _SpotExpTable[EXP_TABLE_SIZE][2]; /**< to replace a pow() call */
- GLfloat _MatAmbient[2][3]; /**< material ambient * light ambient */
- GLfloat _MatDiffuse[2][3]; /**< material diffuse * light diffuse */
- GLfloat _MatSpecular[2][3]; /**< material spec * light specular */
- GLfloat _dli; /**< CI diffuse light intensity */
- GLfloat _sli; /**< CI specular light intensity */
- /*@}*/
-};
-
-
-/**
- * Light model state.
- */
-struct gl_lightmodel
-{
- GLfloat Ambient[4]; /**< ambient color */
- GLboolean LocalViewer; /**< Local (or infinite) view point? */
- GLboolean TwoSide; /**< Two (or one) sided lighting? */
- GLenum ColorControl; /**< either GL_SINGLE_COLOR
- * or GL_SEPARATE_SPECULAR_COLOR */
-};
-
-
-/**
- * Material state.
- */
-struct gl_material
-{
- GLfloat Attrib[MAT_ATTRIB_MAX][4];
-};
-
-
-/**
- * Accumulation buffer attribute group (GL_ACCUM_BUFFER_BIT)
- */
-struct gl_accum_attrib
-{
- GLfloat ClearColor[4]; /**< Accumulation buffer clear color */
-};
-
-
-/**
- * Color buffer attribute group (GL_COLOR_BUFFER_BIT).
- */
-struct gl_colorbuffer_attrib
-{
- GLuint ClearIndex; /**< Index to use for glClear */
- GLclampf ClearColor[4]; /**< Color to use for glClear */
-
- GLuint IndexMask; /**< Color index write mask */
- GLubyte ColorMask[MAX_DRAW_BUFFERS][4];/**< Each flag is 0xff or 0x0 */
-
- GLenum DrawBuffer[MAX_DRAW_BUFFERS]; /**< Which buffer to draw into */
-
- /**
- * \name alpha testing
- */
- /*@{*/
- GLboolean AlphaEnabled; /**< Alpha test enabled flag */
- GLenum AlphaFunc; /**< Alpha test function */
- GLclampf AlphaRef; /**< Alpha reference value */
- /*@}*/
-
- /**
- * \name Blending
- */
- /*@{*/
- GLbitfield BlendEnabled; /**< Per-buffer blend enable flags */
- GLfloat BlendColor[4]; /**< Blending color */
- struct
- {
- GLenum SrcRGB; /**< RGB blend source term */
- GLenum DstRGB; /**< RGB blend dest term */
- GLenum SrcA; /**< Alpha blend source term */
- GLenum DstA; /**< Alpha blend dest term */
- GLenum EquationRGB; /**< GL_ADD, GL_SUBTRACT, etc. */
- GLenum EquationA; /**< GL_ADD, GL_SUBTRACT, etc. */
- } Blend[MAX_DRAW_BUFFERS];
- /** Are the blend func terms currently different for each buffer/target? */
- GLboolean _BlendFuncPerBuffer;
- /** Are the blend equations currently different for each buffer/target? */
- GLboolean _BlendEquationPerBuffer;
- /*@}*/
-
- /**
- * \name Logic op
- */
- /*@{*/
- GLenum LogicOp; /**< Logic operator */
- GLboolean IndexLogicOpEnabled; /**< Color index logic op enabled flag */
- GLboolean ColorLogicOpEnabled; /**< RGBA logic op enabled flag */
- GLboolean _LogicOpEnabled; /**< RGBA logic op + EXT_blend_logic_op enabled flag */
- /*@}*/
-
- GLboolean DitherFlag; /**< Dither enable flag */
-
- GLenum ClampFragmentColor; /**< GL_TRUE, GL_FALSE or GL_FIXED_ONLY_ARB */
- GLenum ClampReadColor; /**< GL_TRUE, GL_FALSE or GL_FIXED_ONLY_ARB */
-
- GLboolean sRGBEnabled; /**< Framebuffer sRGB blending/updating requested */
-};
-
-
-/**
- * Current attribute group (GL_CURRENT_BIT).
- */
-struct gl_current_attrib
-{
- /**
- * \name Current vertex attributes.
- * \note Values are valid only after FLUSH_VERTICES has been called.
- * \note Index and Edgeflag current values are stored as floats in the
- * SIX and SEVEN attribute slots.
- */
- GLfloat Attrib[VERT_ATTRIB_MAX][4]; /**< Position, color, texcoords, etc */
-
- /**
- * \name Current raster position attributes (always valid).
- * \note This set of attributes is very similar to the SWvertex struct.
- */
- /*@{*/
- GLfloat RasterPos[4];
- GLfloat RasterDistance;
- GLfloat RasterColor[4];
- GLfloat RasterSecondaryColor[4];
- GLfloat RasterTexCoords[MAX_TEXTURE_COORD_UNITS][4];
- GLboolean RasterPosValid;
- /*@}*/
-};
-
-
-/**
- * Depth buffer attribute group (GL_DEPTH_BUFFER_BIT).
- */
-struct gl_depthbuffer_attrib
-{
- GLenum Func; /**< Function for depth buffer compare */
- GLclampd Clear; /**< Value to clear depth buffer to */
- GLboolean Test; /**< Depth buffering enabled flag */
- GLboolean Mask; /**< Depth buffer writable? */
- GLboolean BoundsTest; /**< GL_EXT_depth_bounds_test */
- GLfloat BoundsMin, BoundsMax;/**< GL_EXT_depth_bounds_test */
-};
-
-
-/**
- * Evaluator attribute group (GL_EVAL_BIT).
- */
-struct gl_eval_attrib
-{
- /**
- * \name Enable bits
- */
- /*@{*/
- GLboolean Map1Color4;
- GLboolean Map1Index;
- GLboolean Map1Normal;
- GLboolean Map1TextureCoord1;
- GLboolean Map1TextureCoord2;
- GLboolean Map1TextureCoord3;
- GLboolean Map1TextureCoord4;
- GLboolean Map1Vertex3;
- GLboolean Map1Vertex4;
- GLboolean Map1Attrib[16]; /* GL_NV_vertex_program */
- GLboolean Map2Color4;
- GLboolean Map2Index;
- GLboolean Map2Normal;
- GLboolean Map2TextureCoord1;
- GLboolean Map2TextureCoord2;
- GLboolean Map2TextureCoord3;
- GLboolean Map2TextureCoord4;
- GLboolean Map2Vertex3;
- GLboolean Map2Vertex4;
- GLboolean Map2Attrib[16]; /* GL_NV_vertex_program */
- GLboolean AutoNormal;
- /*@}*/
-
- /**
- * \name Map Grid endpoints and divisions and calculated du values
- */
- /*@{*/
- GLint MapGrid1un;
- GLfloat MapGrid1u1, MapGrid1u2, MapGrid1du;
- GLint MapGrid2un, MapGrid2vn;
- GLfloat MapGrid2u1, MapGrid2u2, MapGrid2du;
- GLfloat MapGrid2v1, MapGrid2v2, MapGrid2dv;
- /*@}*/
-};
-
-
-/**
- * Fog attribute group (GL_FOG_BIT).
- */
-struct gl_fog_attrib
-{
- GLboolean Enabled; /**< Fog enabled flag */
- GLfloat Color[4]; /**< Fog color */
- GLfloat Density; /**< Density >= 0.0 */
- GLfloat Start; /**< Start distance in eye coords */
- GLfloat End; /**< End distance in eye coords */
- GLfloat Index; /**< Fog index */
- GLenum Mode; /**< Fog mode */
- GLboolean ColorSumEnabled;
- GLenum FogCoordinateSource; /**< GL_EXT_fog_coord */
- GLfloat _Scale; /**< (End == Start) ? 1.0 : 1.0 / (End - Start) */
-};
-
-
-/**
- * \brief Layout qualifiers for gl_FragDepth.
- *
- * Extension AMD_conservative_depth allows gl_FragDepth to be redeclared with
- * a layout qualifier.
- *
- * \see enum ir_depth_layout
- */
-enum gl_frag_depth_layout {
- FRAG_DEPTH_LAYOUT_NONE, /**< No layout is specified. */
- FRAG_DEPTH_LAYOUT_ANY,
- FRAG_DEPTH_LAYOUT_GREATER,
- FRAG_DEPTH_LAYOUT_LESS,
- FRAG_DEPTH_LAYOUT_UNCHANGED
-};
-
-
-/**
- * Hint attribute group (GL_HINT_BIT).
- *
- * Values are always one of GL_FASTEST, GL_NICEST, or GL_DONT_CARE.
- */
-struct gl_hint_attrib
-{
- GLenum PerspectiveCorrection;
- GLenum PointSmooth;
- GLenum LineSmooth;
- GLenum PolygonSmooth;
- GLenum Fog;
- GLenum ClipVolumeClipping; /**< GL_EXT_clip_volume_hint */
- GLenum TextureCompression; /**< GL_ARB_texture_compression */
- GLenum GenerateMipmap; /**< GL_SGIS_generate_mipmap */
- GLenum FragmentShaderDerivative; /**< GL_ARB_fragment_shader */
-};
-
-/**
- * Light state flags.
- */
-/*@{*/
-#define LIGHT_SPOT 0x1
-#define LIGHT_LOCAL_VIEWER 0x2
-#define LIGHT_POSITIONAL 0x4
-#define LIGHT_NEED_VERTICES (LIGHT_POSITIONAL|LIGHT_LOCAL_VIEWER)
-/*@}*/
-
-
-/**
- * Lighting attribute group (GL_LIGHT_BIT).
- */
-struct gl_light_attrib
-{
- struct gl_light Light[MAX_LIGHTS]; /**< Array of light sources */
- struct gl_lightmodel Model; /**< Lighting model */
-
- /**
- * Must flush FLUSH_VERTICES before referencing:
- */
- /*@{*/
- struct gl_material Material; /**< Includes front & back values */
- /*@}*/
-
- GLboolean Enabled; /**< Lighting enabled flag */
- GLenum ShadeModel; /**< GL_FLAT or GL_SMOOTH */
- GLenum ProvokingVertex; /**< GL_EXT_provoking_vertex */
- GLenum ColorMaterialFace; /**< GL_FRONT, BACK or FRONT_AND_BACK */
- GLenum ColorMaterialMode; /**< GL_AMBIENT, GL_DIFFUSE, etc */
- GLbitfield ColorMaterialBitmask; /**< bitmask formed from Face and Mode */
- GLboolean ColorMaterialEnabled;
- GLenum ClampVertexColor;
-
- struct gl_light EnabledList; /**< List sentinel */
-
- /**
- * Derived state for optimizations:
- */
- /*@{*/
- GLboolean _NeedEyeCoords;
- GLboolean _NeedVertices; /**< Use fast shader? */
- GLbitfield _Flags; /**< LIGHT_* flags, see above */
- GLfloat _BaseColor[2][3];
- /*@}*/
-};
-
-
-/**
- * Line attribute group (GL_LINE_BIT).
- */
-struct gl_line_attrib
-{
- GLboolean SmoothFlag; /**< GL_LINE_SMOOTH enabled? */
- GLboolean StippleFlag; /**< GL_LINE_STIPPLE enabled? */
- GLushort StipplePattern; /**< Stipple pattern */
- GLint StippleFactor; /**< Stipple repeat factor */
- GLfloat Width; /**< Line width */
-};
-
-
-/**
- * Display list attribute group (GL_LIST_BIT).
- */
-struct gl_list_attrib
-{
- GLuint ListBase;
-};
-
-
-/**
- * Multisample attribute group (GL_MULTISAMPLE_BIT).
- */
-struct gl_multisample_attrib
-{
- GLboolean Enabled;
- GLboolean _Enabled; /**< true if Enabled and multisample buffer */
- GLboolean SampleAlphaToCoverage;
- GLboolean SampleAlphaToOne;
- GLboolean SampleCoverage;
- GLfloat SampleCoverageValue;
- GLboolean SampleCoverageInvert;
-};
-
-
-/**
- * A pixelmap (see glPixelMap)
- */
-struct gl_pixelmap
-{
- GLint Size;
- GLfloat Map[MAX_PIXEL_MAP_TABLE];
- GLubyte Map8[MAX_PIXEL_MAP_TABLE]; /**< converted to 8-bit color */
-};
-
-
-/**
- * Collection of all pixelmaps
- */
-struct gl_pixelmaps
-{
- struct gl_pixelmap RtoR; /**< i.e. GL_PIXEL_MAP_R_TO_R */
- struct gl_pixelmap GtoG;
- struct gl_pixelmap BtoB;
- struct gl_pixelmap AtoA;
- struct gl_pixelmap ItoR;
- struct gl_pixelmap ItoG;
- struct gl_pixelmap ItoB;
- struct gl_pixelmap ItoA;
- struct gl_pixelmap ItoI;
- struct gl_pixelmap StoS;
-};
-
-
-/**
- * Pixel attribute group (GL_PIXEL_MODE_BIT).
- */
-struct gl_pixel_attrib
-{
- GLenum ReadBuffer; /**< source buffer for glRead/CopyPixels() */
-
- /*--- Begin Pixel Transfer State ---*/
- /* Fields are in the order in which they're applied... */
-
- /** Scale & Bias (index shift, offset) */
- /*@{*/
- GLfloat RedBias, RedScale;
- GLfloat GreenBias, GreenScale;
- GLfloat BlueBias, BlueScale;
- GLfloat AlphaBias, AlphaScale;
- GLfloat DepthBias, DepthScale;
- GLint IndexShift, IndexOffset;
- /*@}*/
-
- /* Pixel Maps */
- /* Note: actual pixel maps are not part of this attrib group */
- GLboolean MapColorFlag;
- GLboolean MapStencilFlag;
-
- /*--- End Pixel Transfer State ---*/
-
- /** glPixelZoom */
- GLfloat ZoomX, ZoomY;
-
- /** GL_SGI_texture_color_table */
- GLfloat TextureColorTableScale[4]; /**< RGBA */
- GLfloat TextureColorTableBias[4]; /**< RGBA */
-};
-
-
-/**
- * Point attribute group (GL_POINT_BIT).
- */
-struct gl_point_attrib
-{
- GLboolean SmoothFlag; /**< True if GL_POINT_SMOOTH is enabled */
- GLfloat Size; /**< User-specified point size */
- GLfloat Params[3]; /**< GL_EXT_point_parameters */
- GLfloat MinSize, MaxSize; /**< GL_EXT_point_parameters */
- GLfloat Threshold; /**< GL_EXT_point_parameters */
- GLboolean _Attenuated; /**< True if Params != [1, 0, 0] */
- GLboolean PointSprite; /**< GL_NV/ARB_point_sprite */
- GLboolean CoordReplace[MAX_TEXTURE_COORD_UNITS]; /**< GL_ARB_point_sprite*/
- GLenum SpriteRMode; /**< GL_NV_point_sprite (only!) */
- GLenum SpriteOrigin; /**< GL_ARB_point_sprite */
-};
-
-
-/**
- * Polygon attribute group (GL_POLYGON_BIT).
- */
-struct gl_polygon_attrib
-{
- GLenum FrontFace; /**< Either GL_CW or GL_CCW */
- GLenum FrontMode; /**< Either GL_POINT, GL_LINE or GL_FILL */
- GLenum BackMode; /**< Either GL_POINT, GL_LINE or GL_FILL */
- GLboolean _FrontBit; /**< 0=GL_CCW, 1=GL_CW */
- GLboolean CullFlag; /**< Culling on/off flag */
- GLboolean SmoothFlag; /**< True if GL_POLYGON_SMOOTH is enabled */
- GLboolean StippleFlag; /**< True if GL_POLYGON_STIPPLE is enabled */
- GLenum CullFaceMode; /**< Culling mode GL_FRONT or GL_BACK */
- GLfloat OffsetFactor; /**< Polygon offset factor, from user */
- GLfloat OffsetUnits; /**< Polygon offset units, from user */
- GLboolean OffsetPoint; /**< Offset in GL_POINT mode */
- GLboolean OffsetLine; /**< Offset in GL_LINE mode */
- GLboolean OffsetFill; /**< Offset in GL_FILL mode */
-};
-
-
-/**
- * Scissor attributes (GL_SCISSOR_BIT).
- */
-struct gl_scissor_attrib
-{
- GLboolean Enabled; /**< Scissor test enabled? */
- GLint X, Y; /**< Lower left corner of box */
- GLsizei Width, Height; /**< Size of box */
-};
-
-
-/**
- * Stencil attribute group (GL_STENCIL_BUFFER_BIT).
- *
- * Three sets of stencil data are tracked so that OpenGL 2.0,
- * GL_EXT_stencil_two_side, and GL_ATI_separate_stencil can all be supported
- * simultaneously. In each of the stencil state arrays, element 0 corresponds
- * to GL_FRONT. Element 1 corresponds to the OpenGL 2.0 /
- * GL_ATI_separate_stencil GL_BACK state. Element 2 corresponds to the
- * GL_EXT_stencil_two_side GL_BACK state.
- *
- * The derived value \c _BackFace is either 1 or 2 depending on whether or
- * not GL_STENCIL_TEST_TWO_SIDE_EXT is enabled.
- *
- * The derived value \c _TestTwoSide is set when the front-face and back-face
- * stencil state are different.
- */
-struct gl_stencil_attrib
-{
- GLboolean Enabled; /**< Enabled flag */
- GLboolean TestTwoSide; /**< GL_EXT_stencil_two_side */
- GLubyte ActiveFace; /**< GL_EXT_stencil_two_side (0 or 2) */
- GLboolean _Enabled; /**< Enabled and stencil buffer present */
- GLboolean _TestTwoSide;
- GLubyte _BackFace; /**< Current back stencil state (1 or 2) */
- GLenum Function[3]; /**< Stencil function */
- GLenum FailFunc[3]; /**< Fail function */
- GLenum ZPassFunc[3]; /**< Depth buffer pass function */
- GLenum ZFailFunc[3]; /**< Depth buffer fail function */
- GLint Ref[3]; /**< Reference value */
- GLuint ValueMask[3]; /**< Value mask */
- GLuint WriteMask[3]; /**< Write mask */
- GLuint Clear; /**< Clear value */
-};
-
-
-/**
- * An index for each type of texture object. These correspond to the GL
- * texture target enums, such as GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP, etc.
- * Note: the order is from highest priority to lowest priority.
- */
-typedef enum
-{
- TEXTURE_2D_ARRAY_INDEX,
- TEXTURE_1D_ARRAY_INDEX,
- TEXTURE_CUBE_INDEX,
- TEXTURE_3D_INDEX,
- TEXTURE_RECT_INDEX,
- TEXTURE_2D_INDEX,
- TEXTURE_1D_INDEX,
- NUM_TEXTURE_TARGETS
-} gl_texture_index;
-
-
-/**
- * Bit flags for each type of texture object
- * Used for Texture.Unit[]._ReallyEnabled flags.
- */
-/*@{*/
-#define TEXTURE_2D_ARRAY_BIT (1 << TEXTURE_2D_ARRAY_INDEX)
-#define TEXTURE_1D_ARRAY_BIT (1 << TEXTURE_1D_ARRAY_INDEX)
-#define TEXTURE_CUBE_BIT (1 << TEXTURE_CUBE_INDEX)
-#define TEXTURE_3D_BIT (1 << TEXTURE_3D_INDEX)
-#define TEXTURE_RECT_BIT (1 << TEXTURE_RECT_INDEX)
-#define TEXTURE_2D_BIT (1 << TEXTURE_2D_INDEX)
-#define TEXTURE_1D_BIT (1 << TEXTURE_1D_INDEX)
-/*@}*/
-
-
-/**
- * TexGenEnabled flags.
- */
-/*@{*/
-#define S_BIT 1
-#define T_BIT 2
-#define R_BIT 4
-#define Q_BIT 8
-#define STR_BITS (S_BIT | T_BIT | R_BIT)
-/*@}*/
-
-
-/**
- * Bit flag versions of the corresponding GL_ constants.
- */
-/*@{*/
-#define TEXGEN_SPHERE_MAP 0x1
-#define TEXGEN_OBJ_LINEAR 0x2
-#define TEXGEN_EYE_LINEAR 0x4
-#define TEXGEN_REFLECTION_MAP_NV 0x8
-#define TEXGEN_NORMAL_MAP_NV 0x10
-
-#define TEXGEN_NEED_NORMALS (TEXGEN_SPHERE_MAP | \
- TEXGEN_REFLECTION_MAP_NV | \
- TEXGEN_NORMAL_MAP_NV)
-#define TEXGEN_NEED_EYE_COORD (TEXGEN_SPHERE_MAP | \
- TEXGEN_REFLECTION_MAP_NV | \
- TEXGEN_NORMAL_MAP_NV | \
- TEXGEN_EYE_LINEAR)
-/*@}*/
-
-
-
-/** Tex-gen enabled for texture unit? */
-#define ENABLE_TEXGEN(unit) (1 << (unit))
-
-/** Non-identity texture matrix for texture unit? */
-#define ENABLE_TEXMAT(unit) (1 << (unit))
-
-
-/**
- * Texel fetch function prototype. We use texel fetch functions to
- * extract RGBA, color indexes and depth components out of 1D, 2D and 3D
- * texture images. These functions help to isolate us from the gritty
- * details of all the various texture image encodings.
- *
- * \param texImage texture image.
- * \param col texel column.
- * \param row texel row.
- * \param img texel image level/layer.
- * \param texelOut output texel (up to 4 GLchans)
- */
-typedef void (*FetchTexelFuncC)( const struct gl_texture_image *texImage,
- GLint col, GLint row, GLint img,
- GLchan *texelOut );
-
-/**
- * As above, but returns floats.
- * Used for depth component images and for upcoming signed/float
- * texture images.
- */
-typedef void (*FetchTexelFuncF)( const struct gl_texture_image *texImage,
- GLint col, GLint row, GLint img,
- GLfloat *texelOut );
-
-
-typedef void (*StoreTexelFunc)(struct gl_texture_image *texImage,
- GLint col, GLint row, GLint img,
- const void *texel);
-
-
-/**
- * Texture image state. Describes the dimensions of a texture image,
- * the texel format and pointers to Texel Fetch functions.
- */
-struct gl_texture_image
-{
- GLint InternalFormat; /**< Internal format as given by the user */
- GLenum _BaseFormat; /**< Either GL_RGB, GL_RGBA, GL_ALPHA,
- * GL_LUMINANCE, GL_LUMINANCE_ALPHA,
- * GL_INTENSITY, GL_COLOR_INDEX,
- * GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT
- * only. Used for choosing TexEnv arithmetic.
- */
- gl_format TexFormat; /**< The actual texture memory format */
-
- GLuint Border; /**< 0 or 1 */
- GLuint Width; /**< = 2^WidthLog2 + 2*Border */
- GLuint Height; /**< = 2^HeightLog2 + 2*Border */
- GLuint Depth; /**< = 2^DepthLog2 + 2*Border */
- GLuint Width2; /**< = Width - 2*Border */
- GLuint Height2; /**< = Height - 2*Border */
- GLuint Depth2; /**< = Depth - 2*Border */
- GLuint WidthLog2; /**< = log2(Width2) */
- GLuint HeightLog2; /**< = log2(Height2) */
- GLuint DepthLog2; /**< = log2(Depth2) */
- GLuint MaxLog2; /**< = MAX(WidthLog2, HeightLog2) */
- GLfloat WidthScale; /**< used for mipmap LOD computation */
- GLfloat HeightScale; /**< used for mipmap LOD computation */
- GLfloat DepthScale; /**< used for mipmap LOD computation */
- GLboolean IsClientData; /**< Data owned by client? */
- GLboolean _IsPowerOfTwo; /**< Are all dimensions powers of two? */
-
- struct gl_texture_object *TexObject; /**< Pointer back to parent object */
-
- FetchTexelFuncC FetchTexelc; /**< GLchan texel fetch function pointer */
- FetchTexelFuncF FetchTexelf; /**< Float texel fetch function pointer */
-
- GLuint RowStride; /**< Padded width in units of texels */
- GLuint *ImageOffsets; /**< if 3D texture: array [Depth] of offsets to
- each 2D slice in 'Data', in texels */
- GLvoid *Data; /**< Image data, accessed via FetchTexel() */
-
- /**
- * \name For device driver:
- */
- /*@{*/
- void *DriverData; /**< Arbitrary device driver data */
- /*@}*/
-};
-
-
-/**
- * Indexes for cube map faces.
- */
-typedef enum
-{
- FACE_POS_X = 0,
- FACE_NEG_X = 1,
- FACE_POS_Y = 2,
- FACE_NEG_Y = 3,
- FACE_POS_Z = 4,
- FACE_NEG_Z = 5,
- MAX_FACES = 6
-} gl_face_index;
-
-
-/**
- * Texture object state. Contains the array of mipmap images, border color,
- * wrap modes, filter modes, shadow/texcompare state, and the per-texture
- * color palette.
- */
-struct gl_texture_object
-{
- _glthread_Mutex Mutex; /**< for thread safety */
- GLint RefCount; /**< reference count */
- GLuint Name; /**< the user-visible texture object ID */
- GLenum Target; /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */
- GLfloat Priority; /**< in [0,1] */
- union {
- GLfloat f[4];
- GLuint ui[4];
- GLint i[4];
- } BorderColor; /**< Interpreted according to texture format */
- GLenum WrapS; /**< S-axis texture image wrap mode */
- GLenum WrapT; /**< T-axis texture image wrap mode */
- GLenum WrapR; /**< R-axis texture image wrap mode */
- GLenum MinFilter; /**< minification filter */
- GLenum MagFilter; /**< magnification filter */
- GLfloat MinLod; /**< min lambda, OpenGL 1.2 */
- GLfloat MaxLod; /**< max lambda, OpenGL 1.2 */
- GLfloat LodBias; /**< OpenGL 1.4 */
- GLint BaseLevel; /**< min mipmap level, OpenGL 1.2 */
- GLint MaxLevel; /**< max mipmap level, OpenGL 1.2 */
- GLfloat MaxAnisotropy; /**< GL_EXT_texture_filter_anisotropic */
- GLenum CompareMode; /**< GL_ARB_shadow */
- GLenum CompareFunc; /**< GL_ARB_shadow */
- GLfloat CompareFailValue; /**< GL_ARB_shadow_ambient */
- GLenum DepthMode; /**< GL_ARB_depth_texture */
- GLint _MaxLevel; /**< actual max mipmap level (q in the spec) */
- GLfloat _MaxLambda; /**< = _MaxLevel - BaseLevel (q - b in spec) */
- GLint CropRect[4]; /**< GL_OES_draw_texture */
- GLenum Swizzle[4]; /**< GL_EXT_texture_swizzle */
- GLuint _Swizzle; /**< same as Swizzle, but SWIZZLE_* format */
- GLboolean GenerateMipmap; /**< GL_SGIS_generate_mipmap */
- GLboolean _Complete; /**< Is texture object complete? */
- GLboolean _RenderToTexture; /**< Any rendering to this texture? */
- GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */
- GLenum sRGBDecode; /**< GL_DECODE_EXT or GL_SKIP_DECODE_EXT */
-
- /** Actual texture images, indexed by [cube face] and [mipmap level] */
- struct gl_texture_image *Image[MAX_FACES][MAX_TEXTURE_LEVELS];
-
- /** GL_EXT_paletted_texture */
- struct gl_color_table Palette;
-
- /**
- * \name For device driver.
- * Note: instead of attaching driver data to this pointer, it's preferable
- * to instead use this struct as a base class for your own texture object
- * class. Driver->NewTextureObject() can be used to implement the
- * allocation.
- */
- void *DriverData; /**< Arbitrary device driver data */
-};
-
-
-/** Up to four combiner sources are possible with GL_NV_texture_env_combine4 */
-#define MAX_COMBINER_TERMS 4
-
-
-/**
- * Texture combine environment state.
- */
-struct gl_tex_env_combine_state
-{
- GLenum ModeRGB; /**< GL_REPLACE, GL_DECAL, GL_ADD, etc. */
- GLenum ModeA; /**< GL_REPLACE, GL_DECAL, GL_ADD, etc. */
- /** Source terms: GL_PRIMARY_COLOR, GL_TEXTURE, etc */
- GLenum SourceRGB[MAX_COMBINER_TERMS];
- GLenum SourceA[MAX_COMBINER_TERMS];
- /** Source operands: GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, etc */
- GLenum OperandRGB[MAX_COMBINER_TERMS];
- GLenum OperandA[MAX_COMBINER_TERMS];
- GLuint ScaleShiftRGB; /**< 0, 1 or 2 */
- GLuint ScaleShiftA; /**< 0, 1 or 2 */
- GLuint _NumArgsRGB; /**< Number of inputs used for the RGB combiner */
- GLuint _NumArgsA; /**< Number of inputs used for the A combiner */
-};
-
-
-/**
- * Texture coord generation state.
- */
-struct gl_texgen
-{
- GLenum Mode; /**< GL_EYE_LINEAR, GL_SPHERE_MAP, etc */
- GLbitfield _ModeBit; /**< TEXGEN_x bit corresponding to Mode */
- GLfloat ObjectPlane[4];
- GLfloat EyePlane[4];
-};
-
-
-/**
- * Texture unit state. Contains enable flags, texture environment/function/
- * combiners, texgen state, pointers to current texture objects and
- * post-filter color tables.
- */
-struct gl_texture_unit
-{
- GLbitfield Enabled; /**< bitmask of TEXTURE_*_BIT flags */
- GLbitfield _ReallyEnabled; /**< 0 or exactly one of TEXTURE_*_BIT flags */
-
- GLenum EnvMode; /**< GL_MODULATE, GL_DECAL, GL_BLEND, etc. */
- GLfloat EnvColor[4];
-
- struct gl_texgen GenS;
- struct gl_texgen GenT;
- struct gl_texgen GenR;
- struct gl_texgen GenQ;
- GLbitfield TexGenEnabled; /**< Bitwise-OR of [STRQ]_BIT values */
- GLbitfield _GenFlags; /**< Bitwise-OR of Gen[STRQ]._ModeBit */
-
- GLfloat LodBias; /**< for biasing mipmap levels */
- GLenum BumpTarget;
- GLfloat RotMatrix[4]; /* 2x2 matrix */
-
- /**
- * \name GL_EXT_texture_env_combine
- */
- struct gl_tex_env_combine_state Combine;
-
- /**
- * Derived state based on \c EnvMode and the \c BaseFormat of the
- * currently enabled texture.
- */
- struct gl_tex_env_combine_state _EnvMode;
-
- /**
- * Currently enabled combiner state. This will point to either
- * \c Combine or \c _EnvMode.
- */
- struct gl_tex_env_combine_state *_CurrentCombine;
-
- /** Current texture object pointers */
- struct gl_texture_object *CurrentTex[NUM_TEXTURE_TARGETS];
-
- /** Points to highest priority, complete and enabled texture object */
- struct gl_texture_object *_Current;
-
- /** GL_SGI_texture_color_table */
- /*@{*/
- struct gl_color_table ColorTable;
- struct gl_color_table ProxyColorTable;
- GLboolean ColorTableEnabled;
- /*@}*/
-};
-
-
-/**
- * Texture attribute group (GL_TEXTURE_BIT).
- */
-struct gl_texture_attrib
-{
- GLuint CurrentUnit; /**< GL_ACTIVE_TEXTURE */
- struct gl_texture_unit Unit[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
-
- struct gl_texture_object *ProxyTex[NUM_TEXTURE_TARGETS];
-
- /** GL_ARB_seamless_cubemap */
- GLboolean CubeMapSeamless;
-
- /** GL_EXT_shared_texture_palette */
- GLboolean SharedPalette;
- struct gl_color_table Palette;
-
- /** Texture units/samplers used by vertex or fragment texturing */
- GLbitfield _EnabledUnits;
-
- /** Texture coord units/sets used for fragment texturing */
- GLbitfield _EnabledCoordUnits;
-
- /** Texture coord units that have texgen enabled */
- GLbitfield _TexGenEnabled;
-
- /** Texture coord units that have non-identity matrices */
- GLbitfield _TexMatEnabled;
-
- /** Bitwise-OR of all Texture.Unit[i]._GenFlags */
- GLbitfield _GenFlags;
-};
-
-
-/**
- * Transformation attribute group (GL_TRANSFORM_BIT).
- */
-struct gl_transform_attrib
-{
- GLenum MatrixMode; /**< Matrix mode */
- GLfloat EyeUserPlane[MAX_CLIP_PLANES][4]; /**< User clip planes */
- GLfloat _ClipUserPlane[MAX_CLIP_PLANES][4]; /**< derived */
- GLbitfield ClipPlanesEnabled; /**< on/off bitmask */
- GLboolean Normalize; /**< Normalize all normals? */
- GLboolean RescaleNormals; /**< GL_EXT_rescale_normal */
- GLboolean RasterPositionUnclipped; /**< GL_IBM_rasterpos_clip */
- GLboolean DepthClamp; /**< GL_ARB_depth_clamp */
-
- GLfloat CullEyePos[4];
- GLfloat CullObjPos[4];
-};
-
-
-/**
- * Viewport attribute group (GL_VIEWPORT_BIT).
- */
-struct gl_viewport_attrib
-{
- GLint X, Y; /**< position */
- GLsizei Width, Height; /**< size */
- GLfloat Near, Far; /**< Depth buffer range */
- GLmatrix _WindowMap; /**< Mapping transformation as a matrix. */
-};
-
-
-/**
- * GL_ARB_vertex/pixel_buffer_object buffer object
- */
-struct gl_buffer_object
-{
- _glthread_Mutex Mutex;
- GLint RefCount;
- GLuint Name;
- GLenum Usage; /**< GL_STREAM_DRAW_ARB, GL_STREAM_READ_ARB, etc. */
- GLsizeiptrARB Size; /**< Size of buffer storage in bytes */
- GLubyte *Data; /**< Location of storage either in RAM or VRAM. */
- /** Fields describing a mapped buffer */
- /*@{*/
- GLbitfield AccessFlags; /**< Mask of GL_MAP_x_BIT flags */
- GLvoid *Pointer; /**< User-space address of mapping */
- GLintptr Offset; /**< Mapped offset */
- GLsizeiptr Length; /**< Mapped length */
- /*@}*/
- GLboolean Written; /**< Ever written to? (for debugging) */
- GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */
-};
-
-
-/**
- * Client pixel packing/unpacking attributes
- */
-struct gl_pixelstore_attrib
-{
- GLint Alignment;
- GLint RowLength;
- GLint SkipPixels;
- GLint SkipRows;
- GLint ImageHeight;
- GLint SkipImages;
- GLboolean SwapBytes;
- GLboolean LsbFirst;
- GLboolean ClientStorage; /**< GL_APPLE_client_storage */
- GLboolean Invert; /**< GL_MESA_pack_invert */
- struct gl_buffer_object *BufferObj; /**< GL_ARB_pixel_buffer_object */
-};
-
-
-/**
- * Client vertex array attributes
- */
-struct gl_client_array
-{
- GLint Size; /**< components per element (1,2,3,4) */
- GLenum Type; /**< datatype: GL_FLOAT, GL_INT, etc */
- GLenum Format; /**< default: GL_RGBA, but may be GL_BGRA */
- GLsizei Stride; /**< user-specified stride */
- GLsizei StrideB; /**< actual stride in bytes */
- const GLubyte *Ptr; /**< Points to array data */
- GLboolean Enabled; /**< Enabled flag is a boolean */
- GLboolean Normalized; /**< GL_ARB_vertex_program */
- GLboolean Integer; /**< Integer-valued? */
- GLuint InstanceDivisor; /**< GL_ARB_instanced_arrays */
- GLuint _ElementSize; /**< size of each element in bytes */
-
- struct gl_buffer_object *BufferObj;/**< GL_ARB_vertex_buffer_object */
- GLuint _MaxElement; /**< max element index into array buffer + 1 */
-};
-
-
-/**
- * Collection of vertex arrays. Defined by the GL_APPLE_vertex_array_object
- * extension, but a nice encapsulation in any case.
- */
-struct gl_array_object
-{
- /** Name of the array object as received from glGenVertexArrayAPPLE. */
- GLuint Name;
-
- GLint RefCount;
- _glthread_Mutex Mutex;
- GLboolean VBOonly; /**< require all arrays to live in VBOs? */
-
- /** Conventional vertex arrays */
- /*@{*/
- struct gl_client_array Vertex;
- struct gl_client_array Weight;
- struct gl_client_array Normal;
- struct gl_client_array Color;
- struct gl_client_array SecondaryColor;
- struct gl_client_array FogCoord;
- struct gl_client_array Index;
- struct gl_client_array EdgeFlag;
- struct gl_client_array TexCoord[MAX_TEXTURE_COORD_UNITS];
- struct gl_client_array PointSize;
- /*@}*/
-
- /**
- * Generic arrays for vertex programs/shaders.
- * For NV vertex programs, these attributes alias and take priority
- * over the conventional attribs above. For ARB vertex programs and
- * GLSL vertex shaders, these attributes are separate.
- */
- struct gl_client_array VertexAttrib[MAX_VERTEX_GENERIC_ATTRIBS];
-
- /** Mask of _NEW_ARRAY_* values indicating which arrays are enabled */
- GLbitfield _Enabled;
-
- /**
- * Min of all enabled arrays' _MaxElement. When arrays reside inside VBOs
- * we can determine the max legal (in bounds) glDrawElements array index.
- */
- GLuint _MaxElement;
-};
-
-
-/**
- * Vertex array state
- */
-struct gl_array_attrib
-{
- /** Currently bound array object. See _mesa_BindVertexArrayAPPLE() */
- struct gl_array_object *ArrayObj;
-
- /** The default vertex array object */
- struct gl_array_object *DefaultArrayObj;
-
- /** Array objects (GL_ARB/APPLE_vertex_array_object) */
- struct _mesa_HashTable *Objects;
-
- GLint ActiveTexture; /**< Client Active Texture */
- GLuint LockFirst; /**< GL_EXT_compiled_vertex_array */
- GLuint LockCount; /**< GL_EXT_compiled_vertex_array */
-
- /** GL 3.1 (slightly different from GL_NV_primitive_restart) */
- GLboolean PrimitiveRestart;
- GLuint RestartIndex;
-
- GLbitfield NewState; /**< mask of _NEW_ARRAY_* values */
- GLboolean RebindArrays; /**< whether the VBO module should rebind arrays */
-
- /* GL_ARB_vertex_buffer_object */
- struct gl_buffer_object *ArrayBufferObj;
- struct gl_buffer_object *ElementArrayBufferObj;
-};
-
-
-/**
- * Feedback buffer state
- */
-struct gl_feedback
-{
- GLenum Type;
- GLbitfield _Mask; /**< FB_* bits */
- GLfloat *Buffer;
- GLuint BufferSize;
- GLuint Count;
-};
-
-
-/**
- * Selection buffer state
- */
-struct gl_selection
-{
- GLuint *Buffer; /**< selection buffer */
- GLuint BufferSize; /**< size of the selection buffer */
- GLuint BufferCount; /**< number of values in the selection buffer */
- GLuint Hits; /**< number of records in the selection buffer */
- GLuint NameStackDepth; /**< name stack depth */
- GLuint NameStack[MAX_NAME_STACK_DEPTH]; /**< name stack */
- GLboolean HitFlag; /**< hit flag */
- GLfloat HitMinZ; /**< minimum hit depth */
- GLfloat HitMaxZ; /**< maximum hit depth */
-};
-
-
-/**
- * 1-D Evaluator control points
- */
-struct gl_1d_map
-{
- GLuint Order; /**< Number of control points */
- GLfloat u1, u2, du; /**< u1, u2, 1.0/(u2-u1) */
- GLfloat *Points; /**< Points to contiguous control points */
-};
-
-
-/**
- * 2-D Evaluator control points
- */
-struct gl_2d_map
-{
- GLuint Uorder; /**< Number of control points in U dimension */
- GLuint Vorder; /**< Number of control points in V dimension */
- GLfloat u1, u2, du;
- GLfloat v1, v2, dv;
- GLfloat *Points; /**< Points to contiguous control points */
-};
-
-
-/**
- * All evaluator control point state
- */
-struct gl_evaluators
-{
- /**
- * \name 1-D maps
- */
- /*@{*/
- struct gl_1d_map Map1Vertex3;
- struct gl_1d_map Map1Vertex4;
- struct gl_1d_map Map1Index;
- struct gl_1d_map Map1Color4;
- struct gl_1d_map Map1Normal;
- struct gl_1d_map Map1Texture1;
- struct gl_1d_map Map1Texture2;
- struct gl_1d_map Map1Texture3;
- struct gl_1d_map Map1Texture4;
- struct gl_1d_map Map1Attrib[16]; /**< GL_NV_vertex_program */
- /*@}*/
-
- /**
- * \name 2-D maps
- */
- /*@{*/
- struct gl_2d_map Map2Vertex3;
- struct gl_2d_map Map2Vertex4;
- struct gl_2d_map Map2Index;
- struct gl_2d_map Map2Color4;
- struct gl_2d_map Map2Normal;
- struct gl_2d_map Map2Texture1;
- struct gl_2d_map Map2Texture2;
- struct gl_2d_map Map2Texture3;
- struct gl_2d_map Map2Texture4;
- struct gl_2d_map Map2Attrib[16]; /**< GL_NV_vertex_program */
- /*@}*/
-};
-
-
-/**
- * Names of the various vertex/fragment program register files, etc.
- *
- * NOTE: first four tokens must fit into 2 bits (see t_vb_arbprogram.c)
- * All values should fit in a 4-bit field.
- *
- * NOTE: PROGRAM_ENV_PARAM, PROGRAM_STATE_VAR, PROGRAM_NAMED_PARAM,
- * PROGRAM_CONSTANT, and PROGRAM_UNIFORM can all be considered to
- * be "uniform" variables since they can only be set outside glBegin/End.
- * They're also all stored in the same Parameters array.
- */
-typedef enum
-{
- PROGRAM_TEMPORARY, /**< machine->Temporary[] */
- PROGRAM_INPUT, /**< machine->Inputs[] */
- PROGRAM_OUTPUT, /**< machine->Outputs[] */
- PROGRAM_VARYING, /**< machine->Inputs[]/Outputs[] */
- PROGRAM_LOCAL_PARAM, /**< gl_program->LocalParams[] */
- PROGRAM_ENV_PARAM, /**< gl_program->Parameters[] */
- PROGRAM_STATE_VAR, /**< gl_program->Parameters[] */
- PROGRAM_NAMED_PARAM, /**< gl_program->Parameters[] */
- PROGRAM_CONSTANT, /**< gl_program->Parameters[] */
- PROGRAM_UNIFORM, /**< gl_program->Parameters[] */
- PROGRAM_WRITE_ONLY, /**< A dummy, write-only register */
- PROGRAM_ADDRESS, /**< machine->AddressReg */
- PROGRAM_SAMPLER, /**< for shader samplers, compile-time only */
- PROGRAM_SYSTEM_VALUE,/**< InstanceId, PrimitiveID, etc. */
- PROGRAM_UNDEFINED, /**< Invalid/TBD value */
- PROGRAM_FILE_MAX
-} gl_register_file;
-
-
-/**
- * If the register file is PROGRAM_SYSTEM_VALUE, the register index will be
- * one of these values.
- */
-typedef enum
-{
- SYSTEM_VALUE_FRONT_FACE, /**< Fragment shader only (not done yet) */
- SYSTEM_VALUE_INSTANCE_ID, /**< Vertex shader only */
- SYSTEM_VALUE_MAX /**< Number of values */
-} gl_system_value;
-
-
-/** Vertex and fragment instructions */
-struct prog_instruction;
-struct gl_program_parameter_list;
-struct gl_uniform_list;
-
-
-/**
- * Base class for any kind of program object
- */
-struct gl_program
-{
- GLuint Id;
- GLubyte *String; /**< Null-terminated program text */
- GLint RefCount;
- GLenum Target; /**< GL_VERTEX/FRAGMENT_PROGRAM_ARB, GL_FRAGMENT_PROGRAM_NV */
- GLenum Format; /**< String encoding format */
- GLboolean Resident;
-
- struct prog_instruction *Instructions;
-
- GLbitfield InputsRead; /**< Bitmask of which input regs are read */
- GLbitfield64 OutputsWritten; /**< Bitmask of which output regs are written */
- GLbitfield SystemValuesRead; /**< Bitmask of SYSTEM_VALUE_x inputs used */
- GLbitfield InputFlags[MAX_PROGRAM_INPUTS]; /**< PROG_PARAM_BIT_x flags */
- GLbitfield OutputFlags[MAX_PROGRAM_OUTPUTS]; /**< PROG_PARAM_BIT_x flags */
- GLbitfield TexturesUsed[MAX_TEXTURE_UNITS]; /**< TEXTURE_x_BIT bitmask */
- GLbitfield SamplersUsed; /**< Bitfield of which samplers are used */
- GLbitfield ShadowSamplers; /**< Texture units used for shadow sampling. */
-
-
- /** Named parameters, constants, etc. from program text */
- struct gl_program_parameter_list *Parameters;
- /** Numbered local parameters */
- GLfloat LocalParams[MAX_PROGRAM_LOCAL_PARAMS][4];
-
- /** Vertex/fragment shader varying vars */
- struct gl_program_parameter_list *Varying;
- /** Vertex program user-defined attributes */
- struct gl_program_parameter_list *Attributes;
-
- /** Map from sampler unit to texture unit (set by glUniform1i()) */
- GLubyte SamplerUnits[MAX_SAMPLERS];
- /** Which texture target is being sampled (TEXTURE_1D/2D/3D/etc_INDEX) */
- gl_texture_index SamplerTargets[MAX_SAMPLERS];
-
- /** Bitmask of which register files are read/written with indirect
- * addressing. Mask of (1 << PROGRAM_x) bits.
- */
- GLbitfield IndirectRegisterFiles;
-
- /** Logical counts */
- /*@{*/
- GLuint NumInstructions;
- GLuint NumTemporaries;
- GLuint NumParameters;
- GLuint NumAttributes;
- GLuint NumAddressRegs;
- GLuint NumAluInstructions;
- GLuint NumTexInstructions;
- GLuint NumTexIndirections;
- /*@}*/
- /** Native, actual h/w counts */
- /*@{*/
- GLuint NumNativeInstructions;
- GLuint NumNativeTemporaries;
- GLuint NumNativeParameters;
- GLuint NumNativeAttributes;
- GLuint NumNativeAddressRegs;
- GLuint NumNativeAluInstructions;
- GLuint NumNativeTexInstructions;
- GLuint NumNativeTexIndirections;
- /*@}*/
-};
-
-
-/** Vertex program object */
-struct gl_vertex_program
-{
- struct gl_program Base; /**< base class */
- GLboolean IsNVProgram; /**< is this a GL_NV_vertex_program program? */
- GLboolean IsPositionInvariant;
-};
-
-
-/** Geometry program object */
-struct gl_geometry_program
-{
- struct gl_program Base; /**< base class */
-
- GLint VerticesOut;
- GLenum InputType; /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB,
- GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */
- GLenum OutputType; /**< GL_POINTS, GL_LINE_STRIP or GL_TRIANGLE_STRIP */
-};
-
-
-/** Fragment program object */
-struct gl_fragment_program
-{
- struct gl_program Base; /**< base class */
- GLenum FogOption;
- GLboolean UsesKill; /**< shader uses KIL instruction */
- GLboolean OriginUpperLeft;
- GLboolean PixelCenterInteger;
- enum gl_frag_depth_layout FragDepthLayout;
-};
-
-
-/**
- * State common to vertex and fragment programs.
- */
-struct gl_program_state
-{
- GLint ErrorPos; /* GL_PROGRAM_ERROR_POSITION_ARB/NV */
- const char *ErrorString; /* GL_PROGRAM_ERROR_STRING_ARB/NV */
-};
-
-
-/**
- * Context state for vertex programs.
- */
-struct gl_vertex_program_state
-{
- GLboolean Enabled; /**< User-set GL_VERTEX_PROGRAM_ARB/NV flag */
- GLboolean _Enabled; /**< Enabled and _valid_ user program? */
- GLboolean PointSizeEnabled; /**< GL_VERTEX_PROGRAM_POINT_SIZE_ARB/NV */
- GLboolean TwoSideEnabled; /**< GL_VERTEX_PROGRAM_TWO_SIDE_ARB/NV */
- struct gl_vertex_program *Current; /**< User-bound vertex program */
-
- /** Currently enabled and valid vertex program (including internal
- * programs, user-defined vertex programs and GLSL vertex shaders).
- * This is the program we must use when rendering.
- */
- struct gl_vertex_program *_Current;
-
- GLfloat Parameters[MAX_PROGRAM_ENV_PARAMS][4]; /**< Env params */
-
- /* For GL_NV_vertex_program only: */
- GLenum TrackMatrix[MAX_PROGRAM_ENV_PARAMS / 4];
- GLenum TrackMatrixTransform[MAX_PROGRAM_ENV_PARAMS / 4];
-
- /** Should fixed-function T&L be implemented with a vertex prog? */
- GLboolean _MaintainTnlProgram;
-
- /** Program to emulate fixed-function T&L (see above) */
- struct gl_vertex_program *_TnlProgram;
-
- /** Cache of fixed-function programs */
- struct gl_program_cache *Cache;
-
- GLboolean _Overriden;
-};
-
-
-/**
- * Context state for geometry programs.
- */
-struct gl_geometry_program_state
-{
- GLboolean Enabled; /**< GL_ARB_GEOMETRY_SHADER4 */
- GLboolean _Enabled; /**< Enabled and valid program? */
- struct gl_geometry_program *Current; /**< user-bound geometry program */
-
- /** Currently enabled and valid program (including internal programs
- * and compiled shader programs).
- */
- struct gl_geometry_program *_Current;
-
- GLfloat Parameters[MAX_PROGRAM_ENV_PARAMS][4]; /**< Env params */
-
- /** Cache of fixed-function programs */
- struct gl_program_cache *Cache;
-};
-
-/**
- * Context state for fragment programs.
- */
-struct gl_fragment_program_state
-{
- GLboolean Enabled; /**< User-set fragment program enable flag */
- GLboolean _Enabled; /**< Enabled and _valid_ user program? */
- struct gl_fragment_program *Current; /**< User-bound fragment program */
-
- /** Currently enabled and valid fragment program (including internal
- * programs, user-defined fragment programs and GLSL fragment shaders).
- * This is the program we must use when rendering.
- */
- struct gl_fragment_program *_Current;
-
- GLfloat Parameters[MAX_PROGRAM_ENV_PARAMS][4]; /**< Env params */
-
- /** Should fixed-function texturing be implemented with a fragment prog? */
- GLboolean _MaintainTexEnvProgram;
-
- /** Program to emulate fixed-function texture env/combine (see above) */
- struct gl_fragment_program *_TexEnvProgram;
-
- /** Cache of fixed-function programs */
- struct gl_program_cache *Cache;
-};
-
-
-/**
- * ATI_fragment_shader runtime state
- */
-#define ATI_FS_INPUT_PRIMARY 0
-#define ATI_FS_INPUT_SECONDARY 1
-
-struct atifs_instruction;
-struct atifs_setupinst;
-
-/**
- * ATI fragment shader
- */
-struct ati_fragment_shader
-{
- GLuint Id;
- GLint RefCount;
- struct atifs_instruction *Instructions[2];
- struct atifs_setupinst *SetupInst[2];
- GLfloat Constants[8][4];
- GLbitfield LocalConstDef; /**< Indicates which constants have been set */
- GLubyte numArithInstr[2];
- GLubyte regsAssigned[2];
- GLubyte NumPasses; /**< 1 or 2 */
- GLubyte cur_pass;
- GLubyte last_optype;
- GLboolean interpinp1;
- GLboolean isValid;
- GLuint swizzlerq;
-};
-
-/**
- * Context state for GL_ATI_fragment_shader
- */
-struct gl_ati_fragment_shader_state
-{
- GLboolean Enabled;
- GLboolean _Enabled; /**< enabled and valid shader? */
- GLboolean Compiling;
- GLfloat GlobalConstants[8][4];
- struct ati_fragment_shader *Current;
-};
-
-
-/**
- * Occlusion/timer query object.
- */
-struct gl_query_object
-{
- GLenum Target; /**< The query target, when active */
- GLuint Id; /**< hash table ID/name */
- GLuint64EXT Result; /**< the counter */
- GLboolean Active; /**< inside Begin/EndQuery */
- GLboolean Ready; /**< result is ready? */
-};
-
-
-/**
- * Context state for query objects.
- */
-struct gl_query_state
-{
- struct _mesa_HashTable *QueryObjects;
- struct gl_query_object *CurrentOcclusionObject; /* GL_ARB_occlusion_query */
- struct gl_query_object *CurrentTimerObject; /* GL_EXT_timer_query */
-
- /** GL_NV_conditional_render */
- struct gl_query_object *CondRenderQuery;
-
- /** GL_EXT_transform_feedback */
- struct gl_query_object *PrimitivesGenerated;
- struct gl_query_object *PrimitivesWritten;
-
- /** GL_ARB_timer_query */
- struct gl_query_object *TimeElapsed;
-
- GLenum CondRenderMode;
-};
-
-
-/** Sync object state */
-struct gl_sync_object {
- struct simple_node link;
- GLenum Type; /**< GL_SYNC_FENCE */
- GLuint Name; /**< Fence name */
- GLint RefCount; /**< Reference count */
- GLboolean DeletePending; /**< Object was deleted while there were still
- * live references (e.g., sync not yet finished)
- */
- GLenum SyncCondition;
- GLbitfield Flags; /**< Flags passed to glFenceSync */
- GLuint StatusFlag:1; /**< Has the sync object been signaled? */
-};
-
-
-/** Set by #pragma directives */
-struct gl_sl_pragmas
-{
- GLboolean IgnoreOptimize; /**< ignore #pragma optimize(on/off) ? */
- GLboolean IgnoreDebug; /**< ignore #pragma debug(on/off) ? */
- GLboolean Optimize; /**< defaults on */
- GLboolean Debug; /**< defaults off */
-};
-
-
-/**
- * A GLSL vertex or fragment shader object.
- */
-struct gl_shader
-{
- GLenum Type; /**< GL_FRAGMENT_SHADER || GL_VERTEX_SHADER || GL_GEOMETRY_SHADER_ARB (first field!) */
- GLuint Name; /**< AKA the handle */
- GLint RefCount; /**< Reference count */
- GLboolean DeletePending;
- GLboolean CompileStatus;
- const GLchar *Source; /**< Source code string */
- GLuint SourceChecksum; /**< for debug/logging purposes */
- struct gl_program *Program; /**< Post-compile assembly code */
- GLchar *InfoLog;
- struct gl_sl_pragmas Pragmas;
-
- unsigned Version; /**< GLSL version used for linking */
-
- struct exec_list *ir;
- struct glsl_symbol_table *symbols;
-
- /** Shaders containing built-in functions that are used for linking. */
- struct gl_shader *builtins_to_link[16];
- unsigned num_builtins_to_link;
-};
-
-
-/**
- * A GLSL program object.
- * Basically a linked collection of vertex and fragment shaders.
- */
-struct gl_shader_program
-{
- GLenum Type; /**< Always GL_SHADER_PROGRAM (internal token) */
- GLuint Name; /**< aka handle or ID */
- GLint RefCount; /**< Reference count */
- GLboolean DeletePending;
-
- GLuint NumShaders; /**< number of attached shaders */
- struct gl_shader **Shaders; /**< List of attached the shaders */
-
- /** User-defined attribute bindings (glBindAttribLocation) */
- struct gl_program_parameter_list *Attributes;
-
- /** Transform feedback varyings */
- struct {
- GLenum BufferMode;
- GLuint NumVarying;
- GLchar **VaryingNames; /**< Array [NumVarying] of char * */
- } TransformFeedback;
-
- /** Geometry shader state - copied into gl_geometry_program at link time */
- struct {
- GLint VerticesOut;
- GLenum InputType; /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB,
- GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */
- GLenum OutputType; /**< GL_POINTS, GL_LINE_STRIP or GL_TRIANGLE_STRIP */
- } Geom;
-
- /* post-link info: */
- struct gl_vertex_program *VertexProgram; /**< Linked vertex program */
- struct gl_fragment_program *FragmentProgram; /**< Linked fragment prog */
- struct gl_geometry_program *GeometryProgram; /**< Linked geometry prog */
- struct gl_uniform_list *Uniforms;
- struct gl_program_parameter_list *Varying;
- GLboolean LinkStatus; /**< GL_LINK_STATUS */
- GLboolean Validated;
- GLboolean _Used; /**< Ever used for drawing? */
- GLchar *InfoLog;
-
- unsigned Version; /**< GLSL version used for linking */
-
- /**
- * Per-stage shaders resulting from the first stage of linking.
- *
- * Set of linked shaders for this program. The array is accessed using the
- * \c MESA_SHADER_* defines. Entries for non-existent stages will be
- * \c NULL.
- */
- struct gl_shader *_LinkedShaders[MESA_SHADER_TYPES];
-};
-
-
-#define GLSL_DUMP 0x1 /**< Dump shaders to stdout */
-#define GLSL_LOG 0x2 /**< Write shaders to files */
-#define GLSL_OPT 0x4 /**< Force optimizations (override pragmas) */
-#define GLSL_NO_OPT 0x8 /**< Force no optimizations (override pragmas) */
-#define GLSL_UNIFORMS 0x10 /**< Print glUniform calls */
-#define GLSL_NOP_VERT 0x20 /**< Force no-op vertex shaders */
-#define GLSL_NOP_FRAG 0x40 /**< Force no-op fragment shaders */
-#define GLSL_USE_PROG 0x80 /**< Log glUseProgram calls */
-
-
-/**
- * Context state for GLSL vertex/fragment shaders.
- */
-struct gl_shader_state
-{
- /**
- * Programs used for rendering
- *
- * There is a separate program set for each shader stage. If
- * GL_EXT_separate_shader_objects is not supported, each of these must point
- * to \c NULL or to the same program.
- */
- struct gl_shader_program *CurrentVertexProgram;
- struct gl_shader_program *CurrentGeometryProgram;
- struct gl_shader_program *CurrentFragmentProgram;
-
- /**
- * Program used by glUniform calls.
- *
- * Explicitly set by \c glUseProgram and \c glActiveProgramEXT.
- */
- struct gl_shader_program *ActiveProgram;
-
- void *MemPool;
-
- GLbitfield Flags; /**< Mask of GLSL_x flags */
-};
-
-/**
- * Compiler options for a single GLSL shaders type
- */
-struct gl_shader_compiler_options
-{
- /** Driver-selectable options: */
- GLboolean EmitCondCodes; /**< Use condition codes? */
- GLboolean EmitNVTempInitialization; /**< 0-fill NV temp registers */
- /**
- * Attempts to flatten all ir_if (OPCODE_IF) for GPUs that can't
- * support control flow.
- */
- GLboolean EmitNoIfs;
- GLboolean EmitNoLoops;
- GLboolean EmitNoFunctions;
- GLboolean EmitNoCont; /**< Emit CONT opcode? */
- GLboolean EmitNoMainReturn; /**< Emit CONT/RET opcodes? */
- GLboolean EmitNoNoise; /**< Emit NOISE opcodes? */
- GLboolean EmitNoPow; /**< Emit POW opcodes? */
-
- /**
- * \name Forms of indirect addressing the driver cannot do.
- */
- /*@{*/
- GLboolean EmitNoIndirectInput; /**< No indirect addressing of inputs */
- GLboolean EmitNoIndirectOutput; /**< No indirect addressing of outputs */
- GLboolean EmitNoIndirectTemp; /**< No indirect addressing of temps */
- GLboolean EmitNoIndirectUniform; /**< No indirect addressing of constants */
- /*@}*/
-
- GLuint MaxUnrollIterations;
-
- struct gl_sl_pragmas DefaultPragmas; /**< Default #pragma settings */
-};
-
-/**
- * Transform feedback object state
- */
-struct gl_transform_feedback_object
-{
- GLuint Name; /**< AKA the object ID */
- GLint RefCount;
- GLboolean Active; /**< Is transform feedback enabled? */
- GLboolean Paused; /**< Is transform feedback paused? */
-
- /** The feedback buffers */
- GLuint BufferNames[MAX_FEEDBACK_ATTRIBS];
- struct gl_buffer_object *Buffers[MAX_FEEDBACK_ATTRIBS];
-
- /** Start of feedback data in dest buffer */
- GLintptr Offset[MAX_FEEDBACK_ATTRIBS];
- /** Max data to put into dest buffer (in bytes) */
- GLsizeiptr Size[MAX_FEEDBACK_ATTRIBS];
-};
-
-
-/**
- * Context state for transform feedback.
- */
-struct gl_transform_feedback
-{
- GLenum Mode; /**< GL_POINTS, GL_LINES or GL_TRIANGLES */
-
- GLboolean RasterDiscard; /**< GL_RASTERIZER_DISCARD */
-
- /** The general binding point (GL_TRANSFORM_FEEDBACK_BUFFER) */
- struct gl_buffer_object *CurrentBuffer;
-
- /** The table of all transform feedback objects */
- struct _mesa_HashTable *Objects;
-
- /** The current xform-fb object (GL_TRANSFORM_FEEDBACK_BINDING) */
- struct gl_transform_feedback_object *CurrentObject;
-
- /** The default xform-fb object (Name==0) */
- struct gl_transform_feedback_object *DefaultObject;
-};
-
-
-
-/**
- * State which can be shared by multiple contexts:
- */
-struct gl_shared_state
-{
- _glthread_Mutex Mutex; /**< for thread safety */
- GLint RefCount; /**< Reference count */
- struct _mesa_HashTable *DisplayList; /**< Display lists hash table */
- struct _mesa_HashTable *TexObjects; /**< Texture objects hash table */
-
- /** Default texture objects (shared by all texture units) */
- struct gl_texture_object *DefaultTex[NUM_TEXTURE_TARGETS];
-
- /** Fallback texture used when a bound texture is incomplete */
- struct gl_texture_object *FallbackTex;
-
- /**
- * \name Thread safety and statechange notification for texture
- * objects.
- *
- * \todo Improve the granularity of locking.
- */
- /*@{*/
- _glthread_Mutex TexMutex; /**< texobj thread safety */
- GLuint TextureStateStamp; /**< state notification for shared tex */
- /*@}*/
-
- /** Default buffer object for vertex arrays that aren't in VBOs */
- struct gl_buffer_object *NullBufferObj;
-
- /**
- * \name Vertex/geometry/fragment programs
- */
- /*@{*/
- struct _mesa_HashTable *Programs; /**< All vertex/fragment programs */
- struct gl_vertex_program *DefaultVertexProgram;
- struct gl_fragment_program *DefaultFragmentProgram;
- struct gl_geometry_program *DefaultGeometryProgram;
- /*@}*/
-
- /* GL_ATI_fragment_shader */
- struct _mesa_HashTable *ATIShaders;
- struct ati_fragment_shader *DefaultFragmentShader;
-
- struct _mesa_HashTable *BufferObjects;
-
- /** Table of both gl_shader and gl_shader_program objects */
- struct _mesa_HashTable *ShaderObjects;
-
- /* GL_EXT_framebuffer_object */
- struct _mesa_HashTable *RenderBuffers;
- struct _mesa_HashTable *FrameBuffers;
-
- /* GL_ARB_sync */
- struct simple_node SyncObjects;
-
- void *DriverData; /**< Device driver shared state */
-};
-
-
-
-
-/**
- * A renderbuffer stores colors or depth values or stencil values.
- * A framebuffer object will have a collection of these.
- * Data are read/written to the buffer with a handful of Get/Put functions.
- *
- * Instances of this object are allocated with the Driver's NewRenderbuffer
- * hook. Drivers will likely wrap this class inside a driver-specific
- * class to simulate inheritance.
- */
-struct gl_renderbuffer
-{
-#define RB_MAGIC 0xaabbccdd
- int Magic; /** XXX TEMPORARY DEBUG INFO */
- _glthread_Mutex Mutex; /**< for thread safety */
- GLuint ClassID; /**< Useful for drivers */
- GLuint Name;
- GLint RefCount;
- GLuint Width, Height;
- GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */
-
- GLenum InternalFormat; /**< The user-specified format */
- GLenum _BaseFormat; /**< Either GL_RGB, GL_RGBA, GL_DEPTH_COMPONENT or
- GL_STENCIL_INDEX. */
- gl_format Format; /**< The actual renderbuffer memory format */
-
- GLubyte NumSamples;
-
- GLenum DataType; /**< Type of values passed to the Get/Put functions */
- GLvoid *Data; /**< This may not be used by some kinds of RBs */
-
- /* Used to wrap one renderbuffer around another: */
- struct gl_renderbuffer *Wrapped;
-
- /* Delete this renderbuffer */
- void (*Delete)(struct gl_renderbuffer *rb);
-
- /* Allocate new storage for this renderbuffer */
- GLboolean (*AllocStorage)(struct gl_context *ctx, struct gl_renderbuffer *rb,
- GLenum internalFormat,
- GLuint width, GLuint height);
-
- /* Lock/Unlock are called before/after calling the Get/Put functions.
- * Not sure this is the right place for these yet.
- void (*Lock)(struct gl_context *ctx, struct gl_renderbuffer *rb);
- void (*Unlock)(struct gl_context *ctx, struct gl_renderbuffer *rb);
- */
-
- /* Return a pointer to the element/pixel at (x,y).
- * Should return NULL if the buffer memory can't be directly addressed.
- */
- void *(*GetPointer)(struct gl_context *ctx, struct gl_renderbuffer *rb,
- GLint x, GLint y);
-
- /* Get/Read a row of values.
- * The values will be of format _BaseFormat and type DataType.
- */
- void (*GetRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
- GLint x, GLint y, void *values);
-
- /* Get/Read values at arbitrary locations.
- * The values will be of format _BaseFormat and type DataType.
- */
- void (*GetValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
- const GLint x[], const GLint y[], void *values);
-
- /* Put/Write a row of values.
- * The values will be of format _BaseFormat and type DataType.
- */
- void (*PutRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
- GLint x, GLint y, const void *values, const GLubyte *mask);
-
- /* Put/Write a row of RGB values. This is a special-case routine that's
- * only used for RGBA renderbuffers when the source data is GL_RGB. That's
- * a common case for glDrawPixels and some triangle routines.
- * The values will be of format GL_RGB and type DataType.
- */
- void (*PutRowRGB)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
- GLint x, GLint y, const void *values, const GLubyte *mask);
-
-
- /* Put/Write a row of identical values.
- * The values will be of format _BaseFormat and type DataType.
- */
- void (*PutMonoRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
- GLint x, GLint y, const void *value, const GLubyte *mask);
-
- /* Put/Write values at arbitrary locations.
- * The values will be of format _BaseFormat and type DataType.
- */
- void (*PutValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count,
- const GLint x[], const GLint y[], const void *values,
- const GLubyte *mask);
- /* Put/Write identical values at arbitrary locations.
- * The values will be of format _BaseFormat and type DataType.
- */
- void (*PutMonoValues)(struct gl_context *ctx, struct gl_renderbuffer *rb,
- GLuint count, const GLint x[], const GLint y[],
- const void *value, const GLubyte *mask);
-};
-
-
-/**
- * A renderbuffer attachment points to either a texture object (and specifies
- * a mipmap level, cube face or 3D texture slice) or points to a renderbuffer.
- */
-struct gl_renderbuffer_attachment
-{
- GLenum Type; /**< \c GL_NONE or \c GL_TEXTURE or \c GL_RENDERBUFFER_EXT */
- GLboolean Complete;
-
- /**
- * If \c Type is \c GL_RENDERBUFFER_EXT, this stores a pointer to the
- * application supplied renderbuffer object.
- */
- struct gl_renderbuffer *Renderbuffer;
-
- /**
- * If \c Type is \c GL_TEXTURE, this stores a pointer to the application
- * supplied texture object.
- */
- struct gl_texture_object *Texture;
- GLuint TextureLevel; /**< Attached mipmap level. */
- GLuint CubeMapFace; /**< 0 .. 5, for cube map textures. */
- GLuint Zoffset; /**< Slice for 3D textures, or layer for both 1D
- * and 2D array textures */
-};
-
-
-/**
- * A framebuffer is a collection of renderbuffers (color, depth, stencil, etc).
- * In C++ terms, think of this as a base class from which device drivers
- * will make derived classes.
- */
-struct gl_framebuffer
-{
- _glthread_Mutex Mutex; /**< for thread safety */
- /**
- * If zero, this is a window system framebuffer. If non-zero, this
- * is a FBO framebuffer; note that for some devices (i.e. those with
- * a natural pixel coordinate system for FBOs that differs from the
- * OpenGL/Mesa coordinate system), this means that the viewport,
- * polygon face orientation, and polygon stipple will have to be inverted.
- */
- GLuint Name;
-
- GLint RefCount;
- GLboolean DeletePending;
-
- /**
- * The framebuffer's visual. Immutable if this is a window system buffer.
- * Computed from attachments if user-made FBO.
- */
- struct gl_config Visual;
-
- GLboolean Initialized;
-
- GLuint Width, Height; /**< size of frame buffer in pixels */
-
- /** \name Drawing bounds (Intersection of buffer size and scissor box) */
- /*@{*/
- GLint _Xmin, _Xmax; /**< inclusive */
- GLint _Ymin, _Ymax; /**< exclusive */
- /*@}*/
-
- /** \name Derived Z buffer stuff */
- /*@{*/
- GLuint _DepthMax; /**< Max depth buffer value */
- GLfloat _DepthMaxF; /**< Float max depth buffer value */
- GLfloat _MRD; /**< minimum resolvable difference in Z values */
- /*@}*/
-
- /** One of the GL_FRAMEBUFFER_(IN)COMPLETE_* tokens */
- GLenum _Status;
-
- /** Integer color values */
- GLboolean _IntegerColor;
-
- /** Array of all renderbuffer attachments, indexed by BUFFER_* tokens. */
- struct gl_renderbuffer_attachment Attachment[BUFFER_COUNT];
-
- /* In unextended OpenGL these vars are part of the GL_COLOR_BUFFER
- * attribute group and GL_PIXEL attribute group, respectively.
- */
- GLenum ColorDrawBuffer[MAX_DRAW_BUFFERS];
- GLenum ColorReadBuffer;
-
- /** Computed from ColorDraw/ReadBuffer above */
- GLuint _NumColorDrawBuffers;
- GLint _ColorDrawBufferIndexes[MAX_DRAW_BUFFERS]; /**< BUFFER_x or -1 */
- GLint _ColorReadBufferIndex; /* -1 = None */
- struct gl_renderbuffer *_ColorDrawBuffers[MAX_DRAW_BUFFERS];
- struct gl_renderbuffer *_ColorReadBuffer;
-
- /** The Actual depth/stencil buffers to use. May be wrappers around the
- * depth/stencil buffers attached above. */
- struct gl_renderbuffer *_DepthBuffer;
- struct gl_renderbuffer *_StencilBuffer;
-
- /** Delete this framebuffer */
- void (*Delete)(struct gl_framebuffer *fb);
-};
-
-
-/**
- * Precision info for shader datatypes. See glGetShaderPrecisionFormat().
- */
-struct gl_precision
-{
- GLushort RangeMin; /**< min value exponent */
- GLushort RangeMax; /**< max value exponent */
- GLushort Precision; /**< number of mantissa bits */
-};
-
-
-/**
- * Limits for vertex and fragment programs/shaders.
- */
-struct gl_program_constants
-{
- /* logical limits */
- GLuint MaxInstructions;
- GLuint MaxAluInstructions;
- GLuint MaxTexInstructions;
- GLuint MaxTexIndirections;
- GLuint MaxAttribs;
- GLuint MaxTemps;
- GLuint MaxAddressRegs;
- GLuint MaxParameters;
- GLuint MaxLocalParams;
- GLuint MaxEnvParams;
- /* native/hardware limits */
- GLuint MaxNativeInstructions;
- GLuint MaxNativeAluInstructions;
- GLuint MaxNativeTexInstructions;
- GLuint MaxNativeTexIndirections;
- GLuint MaxNativeAttribs;
- GLuint MaxNativeTemps;
- GLuint MaxNativeAddressRegs;
- GLuint MaxNativeParameters;
- /* For shaders */
- GLuint MaxUniformComponents;
- /* GL_ARB_geometry_shader4 */
- GLuint MaxGeometryTextureImageUnits;
- GLuint MaxGeometryVaryingComponents;
- GLuint MaxVertexVaryingComponents;
- GLuint MaxGeometryUniformComponents;
- GLuint MaxGeometryOutputVertices;
- GLuint MaxGeometryTotalOutputComponents;
- /* ES 2.0 and GL_ARB_ES2_compatibility */
- struct gl_precision LowFloat, MediumFloat, HighFloat;
- struct gl_precision LowInt, MediumInt, HighInt;
-};
-
-
-/**
- * Constants which may be overridden by device driver during context creation
- * but are never changed after that.
- */
-struct gl_constants
-{
- GLint MaxTextureMbytes; /**< Max memory per image, in MB */
- GLint MaxTextureLevels; /**< Max mipmap levels. */
- GLint Max3DTextureLevels; /**< Max mipmap levels for 3D textures */
- GLint MaxCubeTextureLevels; /**< Max mipmap levels for cube textures */
- GLint MaxArrayTextureLayers; /**< Max layers in array textures */
- GLint MaxTextureRectSize; /**< Max rectangle texture size, in pixes */
- GLuint MaxTextureCoordUnits;
- GLuint MaxTextureImageUnits;
- GLuint MaxVertexTextureImageUnits;
- GLuint MaxCombinedTextureImageUnits;
- GLuint MaxTextureUnits; /**< = MIN(CoordUnits, ImageUnits) */
- GLfloat MaxTextureMaxAnisotropy; /**< GL_EXT_texture_filter_anisotropic */
- GLfloat MaxTextureLodBias; /**< GL_EXT_texture_lod_bias */
-
- GLuint MaxArrayLockSize;
-
- GLint SubPixelBits;
-
- GLfloat MinPointSize, MaxPointSize; /**< aliased */
- GLfloat MinPointSizeAA, MaxPointSizeAA; /**< antialiased */
- GLfloat PointSizeGranularity;
- GLfloat MinLineWidth, MaxLineWidth; /**< aliased */
- GLfloat MinLineWidthAA, MaxLineWidthAA; /**< antialiased */
- GLfloat LineWidthGranularity;
-
- GLuint MaxColorTableSize;
-
- GLuint MaxClipPlanes;
- GLuint MaxLights;
- GLfloat MaxShininess; /**< GL_NV_light_max_exponent */
- GLfloat MaxSpotExponent; /**< GL_NV_light_max_exponent */
-
- GLuint MaxViewportWidth, MaxViewportHeight;
-
- struct gl_program_constants VertexProgram; /**< GL_ARB_vertex_program */
- struct gl_program_constants FragmentProgram; /**< GL_ARB_fragment_program */
- struct gl_program_constants GeometryProgram; /**< GL_ARB_geometry_shader4 */
- GLuint MaxProgramMatrices;
- GLuint MaxProgramMatrixStackDepth;
-
- /** vertex array / buffer object bounds checking */
- GLboolean CheckArrayBounds;
-
- GLuint MaxDrawBuffers; /**< GL_ARB_draw_buffers */
-
- GLuint MaxColorAttachments; /**< GL_EXT_framebuffer_object */
- GLuint MaxRenderbufferSize; /**< GL_EXT_framebuffer_object */
- GLuint MaxSamples; /**< GL_ARB_framebuffer_object */
-
- GLuint MaxVarying; /**< Number of float[4] varying parameters */
-
- GLuint GLSLVersion; /**< GLSL version supported (ex: 120 = 1.20) */
-
- /** Which texture units support GL_ATI_envmap_bumpmap as targets */
- GLbitfield SupportedBumpUnits;
-
- /**
- * Maximum amount of time, measured in nanseconds, that the server can wait.
- */
- GLuint64 MaxServerWaitTimeout;
-
- /** GL_EXT_provoking_vertex */
- GLboolean QuadsFollowProvokingVertexConvention;
-
- /** OpenGL version 3.0 */
- GLbitfield ContextFlags; /**< Ex: GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT */
-
- /** OpenGL version 3.2 */
- GLbitfield ProfileMask; /**< Mask of CONTEXT_x_PROFILE_BIT */
-
- /** GL_EXT_transform_feedback */
- GLuint MaxTransformFeedbackSeparateAttribs;
- GLuint MaxTransformFeedbackSeparateComponents;
- GLuint MaxTransformFeedbackInterleavedComponents;
-
- /** GL_EXT_gpu_shader4 */
- GLint MinProgramTexelOffset, MaxProgramTexelOffset;
-
- /* GL_EXT_framebuffer_sRGB */
- GLboolean sRGBCapable; /* can enable sRGB blend/update on FBOs */
-};
-
-
-/**
- * Enable flag for each OpenGL extension. Different device drivers will
- * enable different extensions at runtime.
- */
-struct gl_extensions
-{
- GLboolean dummy; /* don't remove this! */
- GLboolean dummy_true; /* Set true by _mesa_init_extensions(). */
- GLboolean dummy_false; /* Set false by _mesa_init_extensions(). */
- GLboolean ARB_ES2_compatibility;
- GLboolean ARB_blend_func_extended;
- GLboolean ARB_copy_buffer;
- GLboolean ARB_depth_buffer_float;
- GLboolean ARB_depth_clamp;
- GLboolean ARB_depth_texture;
- GLboolean ARB_draw_buffers;
- GLboolean ARB_draw_buffers_blend;
- GLboolean ARB_draw_elements_base_vertex;
- GLboolean ARB_draw_instanced;
- GLboolean ARB_fragment_coord_conventions;
- GLboolean ARB_fragment_program;
- GLboolean ARB_fragment_program_shadow;
- GLboolean ARB_fragment_shader;
- GLboolean ARB_framebuffer_object;
- GLboolean ARB_explicit_attrib_location;
- GLboolean ARB_geometry_shader4;
- GLboolean ARB_half_float_pixel;
- GLboolean ARB_half_float_vertex;
- GLboolean ARB_instanced_arrays;
- GLboolean ARB_map_buffer_range;
- GLboolean ARB_multisample;
- GLboolean ARB_multitexture;
- GLboolean ARB_occlusion_query;
- GLboolean ARB_occlusion_query2;
- GLboolean ARB_point_sprite;
- GLboolean ARB_sampler_objects;
- GLboolean ARB_seamless_cube_map;
- GLboolean ARB_shader_objects;
- GLboolean ARB_shader_stencil_export;
- GLboolean ARB_shading_language_100;
- GLboolean ARB_shadow;
- GLboolean ARB_shadow_ambient;
- GLboolean ARB_sync;
- GLboolean ARB_texture_border_clamp;
- GLboolean ARB_texture_buffer_object;
- GLboolean ARB_texture_compression;
- GLboolean ARB_texture_compression_rgtc;
- GLboolean ARB_texture_cube_map;
- GLboolean ARB_texture_env_combine;
- GLboolean ARB_texture_env_crossbar;
- GLboolean ARB_texture_env_dot3;
- GLboolean ARB_texture_float;
- GLboolean ARB_texture_mirrored_repeat;
- GLboolean ARB_texture_multisample;
- GLboolean ARB_texture_non_power_of_two;
- GLboolean ARB_texture_rg;
- GLboolean ARB_texture_rgb10_a2ui;
- GLboolean ARB_timer_query;
- GLboolean ARB_transform_feedback2;
- GLboolean ARB_transpose_matrix;
- GLboolean ARB_uniform_buffer_object;
- GLboolean ARB_vertex_array_object;
- GLboolean ARB_vertex_buffer_object;
- GLboolean ARB_vertex_program;
- GLboolean ARB_vertex_shader;
- GLboolean ARB_vertex_type_2_10_10_10_rev;
- GLboolean ARB_window_pos;
- GLboolean EXT_abgr;
- GLboolean EXT_bgra;
- GLboolean EXT_blend_color;
- GLboolean EXT_blend_equation_separate;
- GLboolean EXT_blend_func_separate;
- GLboolean EXT_blend_logic_op;
- GLboolean EXT_blend_minmax;
- GLboolean EXT_blend_subtract;
- GLboolean EXT_clip_volume_hint;
- GLboolean EXT_compiled_vertex_array;
- GLboolean EXT_copy_texture;
- GLboolean EXT_depth_bounds_test;
- GLboolean EXT_draw_buffers2;
- GLboolean EXT_draw_range_elements;
- GLboolean EXT_fog_coord;
- GLboolean EXT_framebuffer_blit;
- GLboolean EXT_framebuffer_multisample;
- GLboolean EXT_framebuffer_object;
- GLboolean EXT_framebuffer_sRGB;
- GLboolean EXT_gpu_program_parameters;
- GLboolean EXT_gpu_shader4;
- GLboolean EXT_multi_draw_arrays;
- GLboolean EXT_paletted_texture;
- GLboolean EXT_packed_depth_stencil;
- GLboolean EXT_packed_float;
- GLboolean EXT_packed_pixels;
- GLboolean EXT_pixel_buffer_object;
- GLboolean EXT_point_parameters;
- GLboolean EXT_polygon_offset;
- GLboolean EXT_provoking_vertex;
- GLboolean EXT_rescale_normal;
- GLboolean EXT_shadow_funcs;
- GLboolean EXT_secondary_color;
- GLboolean EXT_separate_shader_objects;
- GLboolean EXT_separate_specular_color;
- GLboolean EXT_shared_texture_palette;
- GLboolean EXT_stencil_wrap;
- GLboolean EXT_stencil_two_side;
- GLboolean EXT_subtexture;
- GLboolean EXT_texture;
- GLboolean EXT_texture_object;
- GLboolean EXT_texture3D;
- GLboolean EXT_texture_array;
- GLboolean EXT_texture_compression_s3tc;
- GLboolean EXT_texture_env_add;
- GLboolean EXT_texture_env_combine;
- GLboolean EXT_texture_env_dot3;
- GLboolean EXT_texture_filter_anisotropic;
- GLboolean EXT_texture_integer;
- GLboolean EXT_texture_lod_bias;
- GLboolean EXT_texture_mirror_clamp;
- GLboolean EXT_texture_shared_exponent;
- GLboolean EXT_texture_sRGB;
- GLboolean EXT_texture_sRGB_decode;
- GLboolean EXT_texture_swizzle;
- GLboolean EXT_transform_feedback;
- GLboolean EXT_timer_query;
- GLboolean EXT_vertex_array;
- GLboolean EXT_vertex_array_bgra;
- GLboolean EXT_vertex_array_set;
- GLboolean OES_standard_derivatives;
- /* vendor extensions */
- GLboolean AMD_conservative_depth;
- GLboolean APPLE_client_storage;
- GLboolean APPLE_packed_pixels;
- GLboolean APPLE_vertex_array_object;
- GLboolean APPLE_object_purgeable;
- GLboolean ATI_envmap_bumpmap;
- GLboolean ATI_texture_mirror_once;
- GLboolean ATI_texture_env_combine3;
- GLboolean ATI_fragment_shader;
- GLboolean ATI_separate_stencil;
- GLboolean IBM_rasterpos_clip;
- GLboolean IBM_multimode_draw_arrays;
- GLboolean MESA_pack_invert;
- GLboolean MESA_resize_buffers;
- GLboolean MESA_ycbcr_texture;
- GLboolean MESA_texture_array;
- GLboolean MESA_texture_signed_rgba;
- GLboolean NV_blend_square;
- GLboolean NV_conditional_render;
- GLboolean NV_fragment_program;
- GLboolean NV_fragment_program_option;
- GLboolean NV_light_max_exponent;
- GLboolean NV_point_sprite;
- GLboolean NV_primitive_restart;
- GLboolean NV_texgen_reflection;
- GLboolean NV_texture_env_combine4;
- GLboolean NV_texture_rectangle;
- GLboolean NV_vertex_program;
- GLboolean NV_vertex_program1_1;
- GLboolean OES_read_format;
- GLboolean SGI_texture_color_table;
- GLboolean SGIS_generate_mipmap;
- GLboolean SGIS_texture_edge_clamp;
- GLboolean SGIS_texture_lod;
- GLboolean TDFX_texture_compression_FXT1;
- GLboolean S3_s3tc;
- GLboolean OES_EGL_image;
- GLboolean OES_draw_texture;
- GLboolean EXT_texture_format_BGRA8888;
- GLboolean extension_sentinel;
- /** The extension string */
- const GLubyte *String;
- /** Number of supported extensions */
- GLuint Count;
-};
-
-
-/**
- * A stack of matrices (projection, modelview, color, texture, etc).
- */
-struct gl_matrix_stack
-{
- GLmatrix *Top; /**< points into Stack */
- GLmatrix *Stack; /**< array [MaxDepth] of GLmatrix */
- GLuint Depth; /**< 0 <= Depth < MaxDepth */
- GLuint MaxDepth; /**< size of Stack[] array */
- GLuint DirtyFlag; /**< _NEW_MODELVIEW or _NEW_PROJECTION, for example */
-};
-
-
-/**
- * \name Bits for image transfer operations
- * \sa __struct gl_contextRec::ImageTransferState.
- */
-/*@{*/
-#define IMAGE_SCALE_BIAS_BIT 0x1
-#define IMAGE_SHIFT_OFFSET_BIT 0x2
-#define IMAGE_MAP_COLOR_BIT 0x4
-#define IMAGE_CLAMP_BIT 0x800
-
-
-/** Pixel Transfer ops */
-#define IMAGE_BITS (IMAGE_SCALE_BIAS_BIT | \
- IMAGE_SHIFT_OFFSET_BIT | \
- IMAGE_MAP_COLOR_BIT)
-
-/**
- * \name Bits to indicate what state has changed.
- */
-/*@{*/
-#define _NEW_MODELVIEW (1 << 0) /**< gl_context::ModelView */
-#define _NEW_PROJECTION (1 << 1) /**< gl_context::Projection */
-#define _NEW_TEXTURE_MATRIX (1 << 2) /**< gl_context::TextureMatrix */
-#define _NEW_COLOR (1 << 3) /**< gl_context::Color */
-#define _NEW_DEPTH (1 << 4) /**< gl_context::Depth */
-#define _NEW_EVAL (1 << 5) /**< gl_context::Eval, EvalMap */
-#define _NEW_FOG (1 << 6) /**< gl_context::Fog */
-#define _NEW_HINT (1 << 7) /**< gl_context::Hint */
-#define _NEW_LIGHT (1 << 8) /**< gl_context::Light */
-#define _NEW_LINE (1 << 9) /**< gl_context::Line */
-#define _NEW_PIXEL (1 << 10) /**< gl_context::Pixel */
-#define _NEW_POINT (1 << 11) /**< gl_context::Point */
-#define _NEW_POLYGON (1 << 12) /**< gl_context::Polygon */
-#define _NEW_POLYGONSTIPPLE (1 << 13) /**< gl_context::PolygonStipple */
-#define _NEW_SCISSOR (1 << 14) /**< gl_context::Scissor */
-#define _NEW_STENCIL (1 << 15) /**< gl_context::Stencil */
-#define _NEW_TEXTURE (1 << 16) /**< gl_context::Texture */
-#define _NEW_TRANSFORM (1 << 17) /**< gl_context::Transform */
-#define _NEW_VIEWPORT (1 << 18) /**< gl_context::Viewport */
-#define _NEW_PACKUNPACK (1 << 19) /**< gl_context::Pack, Unpack */
-#define _NEW_ARRAY (1 << 20) /**< gl_context::Array */
-#define _NEW_RENDERMODE (1 << 21) /**< gl_context::RenderMode, etc */
-#define _NEW_BUFFERS (1 << 22) /**< gl_context::Visual, DrawBuffer, */
-#define _NEW_CURRENT_ATTRIB (1 << 23) /**< gl_context::Current */
-#define _NEW_MULTISAMPLE (1 << 24) /**< gl_context::Multisample */
-#define _NEW_TRACK_MATRIX (1 << 25) /**< gl_context::VertexProgram */
-#define _NEW_PROGRAM (1 << 26) /**< New program/shader state */
-#define _NEW_PROGRAM_CONSTANTS (1 << 27)
-#define _NEW_BUFFER_OBJECT (1 << 28)
-#define _NEW_ALL ~0
-/*@}*/
-
-
-/**
- * \name Bits to track array state changes
- *
- * Also used to summarize array enabled.
- */
-/*@{*/
-#define _NEW_ARRAY_VERTEX VERT_BIT_POS
-#define _NEW_ARRAY_WEIGHT VERT_BIT_WEIGHT
-#define _NEW_ARRAY_NORMAL VERT_BIT_NORMAL
-#define _NEW_ARRAY_COLOR0 VERT_BIT_COLOR0
-#define _NEW_ARRAY_COLOR1 VERT_BIT_COLOR1
-#define _NEW_ARRAY_FOGCOORD VERT_BIT_FOG
-#define _NEW_ARRAY_INDEX VERT_BIT_COLOR_INDEX
-#define _NEW_ARRAY_EDGEFLAG VERT_BIT_EDGEFLAG
-#define _NEW_ARRAY_POINT_SIZE VERT_BIT_COLOR_INDEX /* aliased */
-#define _NEW_ARRAY_TEXCOORD_0 VERT_BIT_TEX0
-#define _NEW_ARRAY_TEXCOORD_1 VERT_BIT_TEX1
-#define _NEW_ARRAY_TEXCOORD_2 VERT_BIT_TEX2
-#define _NEW_ARRAY_TEXCOORD_3 VERT_BIT_TEX3
-#define _NEW_ARRAY_TEXCOORD_4 VERT_BIT_TEX4
-#define _NEW_ARRAY_TEXCOORD_5 VERT_BIT_TEX5
-#define _NEW_ARRAY_TEXCOORD_6 VERT_BIT_TEX6
-#define _NEW_ARRAY_TEXCOORD_7 VERT_BIT_TEX7
-#define _NEW_ARRAY_ATTRIB_0 VERT_BIT_GENERIC0 /* start at bit 16 */
-#define _NEW_ARRAY_ALL 0xffffffff
-
-
-#define _NEW_ARRAY_TEXCOORD(i) (_NEW_ARRAY_TEXCOORD_0 << (i))
-#define _NEW_ARRAY_ATTRIB(i) (_NEW_ARRAY_ATTRIB_0 << (i))
-/*@}*/
-
-
-
-/**
- * \name A bunch of flags that we think might be useful to drivers.
- *
- * Set in the __struct gl_contextRec::_TriangleCaps bitfield.
- */
-/*@{*/
-#define DD_FLATSHADE 0x1
-#define DD_SEPARATE_SPECULAR 0x2
-#define DD_TRI_CULL_FRONT_BACK 0x4 /* special case on some hw */
-#define DD_TRI_LIGHT_TWOSIDE 0x8
-#define DD_TRI_UNFILLED 0x10
-#define DD_TRI_SMOOTH 0x20
-#define DD_TRI_STIPPLE 0x40
-#define DD_TRI_OFFSET 0x80
-#define DD_LINE_SMOOTH 0x100
-#define DD_LINE_STIPPLE 0x200
-#define DD_POINT_SMOOTH 0x400
-#define DD_POINT_ATTEN 0x800
-#define DD_TRI_TWOSTENCIL 0x1000
-/*@}*/
-
-
-/**
- * \name Define the state changes under which each of these bits might change
- */
-/*@{*/
-#define _DD_NEW_FLATSHADE _NEW_LIGHT
-#define _DD_NEW_SEPARATE_SPECULAR (_NEW_LIGHT | _NEW_FOG | _NEW_PROGRAM)
-#define _DD_NEW_TRI_CULL_FRONT_BACK _NEW_POLYGON
-#define _DD_NEW_TRI_LIGHT_TWOSIDE _NEW_LIGHT
-#define _DD_NEW_TRI_UNFILLED _NEW_POLYGON
-#define _DD_NEW_TRI_SMOOTH _NEW_POLYGON
-#define _DD_NEW_TRI_STIPPLE _NEW_POLYGON
-#define _DD_NEW_TRI_OFFSET _NEW_POLYGON
-#define _DD_NEW_LINE_SMOOTH _NEW_LINE
-#define _DD_NEW_LINE_STIPPLE _NEW_LINE
-#define _DD_NEW_LINE_WIDTH _NEW_LINE
-#define _DD_NEW_POINT_SMOOTH _NEW_POINT
-#define _DD_NEW_POINT_SIZE _NEW_POINT
-#define _DD_NEW_POINT_ATTEN _NEW_POINT
-/*@}*/
-
-
-/**
- * Composite state flags
- */
-/*@{*/
-#define _MESA_NEW_NEED_EYE_COORDS (_NEW_LIGHT | \
- _NEW_TEXTURE | \
- _NEW_POINT | \
- _NEW_PROGRAM | \
- _NEW_MODELVIEW)
-
-#define _MESA_NEW_NEED_NORMALS (_NEW_LIGHT | \
- _NEW_TEXTURE)
-
-#define _MESA_NEW_TRANSFER_STATE (_NEW_PIXEL)
-/*@}*/
-
-
-
-
-/* This has to be included here. */
-#include "dd.h"
-
-
-/**
- * Display list flags.
- * Strictly this is a tnl-private concept, but it doesn't seem
- * worthwhile adding a tnl private structure just to hold this one bit
- * of information:
- */
-#define DLIST_DANGLING_REFS 0x1
-
-
-/** Opaque declaration of display list payload data type */
-union gl_dlist_node;
-
-
-/**
- * Provide a location where information about a display list can be
- * collected. Could be extended with driverPrivate structures,
- * etc. in the future.
- */
-struct gl_display_list
-{
- GLuint Name;
- GLbitfield Flags; /**< DLIST_x flags */
- /** The dlist commands are in a linked list of nodes */
- union gl_dlist_node *Head;
-};
-
-
-/**
- * State used during display list compilation and execution.
- */
-struct gl_dlist_state
-{
- GLuint CallDepth; /**< Current recursion calling depth */
-
- struct gl_display_list *CurrentList; /**< List currently being compiled */
- union gl_dlist_node *CurrentBlock; /**< Pointer to current block of nodes */
- GLuint CurrentPos; /**< Index into current block of nodes */
-
- GLvertexformat ListVtxfmt;
-
- GLubyte ActiveAttribSize[VERT_ATTRIB_MAX];
- GLfloat CurrentAttrib[VERT_ATTRIB_MAX][4];
-
- GLubyte ActiveMaterialSize[MAT_ATTRIB_MAX];
- GLfloat CurrentMaterial[MAT_ATTRIB_MAX][4];
-
- GLubyte ActiveIndex;
- GLfloat CurrentIndex;
-
- GLubyte ActiveEdgeFlag;
- GLboolean CurrentEdgeFlag;
-
- struct {
- /* State known to have been set by the currently-compiling display
- * list. Used to eliminate some redundant state changes.
- */
- GLenum ShadeModel;
- } Current;
-};
-
-
-/**
- * Enum for the OpenGL APIs we know about and may support.
- */
-typedef enum
-{
- API_OPENGL,
- API_OPENGLES,
- API_OPENGLES2
-} gl_api;
-
-
-/**
- * Mesa rendering context.
- *
- * This is the central context data structure for Mesa. Almost all
- * OpenGL state is contained in this structure.
- * Think of this as a base class from which device drivers will derive
- * sub classes.
- *
- * The struct gl_context typedef names this structure.
- */
-struct gl_context
-{
- /** State possibly shared with other contexts in the address space */
- struct gl_shared_state *Shared;
-
- /** \name API function pointer tables */
- /*@{*/
- gl_api API;
- struct _glapi_table *Save; /**< Display list save functions */
- struct _glapi_table *Exec; /**< Execute functions */
- struct _glapi_table *CurrentDispatch; /**< == Save or Exec !! */
- /*@}*/
-
- struct gl_config Visual;
- struct gl_framebuffer *DrawBuffer; /**< buffer for writing */
- struct gl_framebuffer *ReadBuffer; /**< buffer for reading */
- struct gl_framebuffer *WinSysDrawBuffer; /**< set with MakeCurrent */
- struct gl_framebuffer *WinSysReadBuffer; /**< set with MakeCurrent */
-
- /**
- * Device driver function pointer table
- */
- struct dd_function_table Driver;
-
- void *DriverCtx; /**< Points to device driver context/state */
-
- /** Core/Driver constants */
- struct gl_constants Const;
-
- /** \name The various 4x4 matrix stacks */
- /*@{*/
- struct gl_matrix_stack ModelviewMatrixStack;
- struct gl_matrix_stack ProjectionMatrixStack;
- struct gl_matrix_stack TextureMatrixStack[MAX_TEXTURE_UNITS];
- struct gl_matrix_stack ProgramMatrixStack[MAX_PROGRAM_MATRICES];
- struct gl_matrix_stack *CurrentStack; /**< Points to one of the above stacks */
- /*@}*/
-
- /** Combined modelview and projection matrix */
- GLmatrix _ModelProjectMatrix;
-
- /** \name Display lists */
- struct gl_dlist_state ListState;
-
- GLboolean ExecuteFlag; /**< Execute GL commands? */
- GLboolean CompileFlag; /**< Compile GL commands into display list? */
-
- /** Extension information */
- struct gl_extensions Extensions;
-
- /** Version info */
- GLuint VersionMajor, VersionMinor;
- char *VersionString;
-
- /** \name State attribute stack (for glPush/PopAttrib) */
- /*@{*/
- GLuint AttribStackDepth;
- struct gl_attrib_node *AttribStack[MAX_ATTRIB_STACK_DEPTH];
- /*@}*/
-
- /** \name Renderer attribute groups
- *
- * We define a struct for each attribute group to make pushing and popping
- * attributes easy. Also it's a good organization.
- */
- /*@{*/
- struct gl_accum_attrib Accum; /**< Accum buffer attributes */
- struct gl_colorbuffer_attrib Color; /**< Color buffer attributes */
- struct gl_current_attrib Current; /**< Current attributes */
- struct gl_depthbuffer_attrib Depth; /**< Depth buffer attributes */
- struct gl_eval_attrib Eval; /**< Eval attributes */
- struct gl_fog_attrib Fog; /**< Fog attributes */
- struct gl_hint_attrib Hint; /**< Hint attributes */
- struct gl_light_attrib Light; /**< Light attributes */
- struct gl_line_attrib Line; /**< Line attributes */
- struct gl_list_attrib List; /**< List attributes */
- struct gl_multisample_attrib Multisample;
- struct gl_pixel_attrib Pixel; /**< Pixel attributes */
- struct gl_point_attrib Point; /**< Point attributes */
- struct gl_polygon_attrib Polygon; /**< Polygon attributes */
- GLuint PolygonStipple[32]; /**< Polygon stipple */
- struct gl_scissor_attrib Scissor; /**< Scissor attributes */
- struct gl_stencil_attrib Stencil; /**< Stencil buffer attributes */
- struct gl_texture_attrib Texture; /**< Texture attributes */
- struct gl_transform_attrib Transform; /**< Transformation attributes */
- struct gl_viewport_attrib Viewport; /**< Viewport attributes */
- /*@}*/
-
- /** \name Client attribute stack */
- /*@{*/
- GLuint ClientAttribStackDepth;
- struct gl_attrib_node *ClientAttribStack[MAX_CLIENT_ATTRIB_STACK_DEPTH];
- /*@}*/
-
- /** \name Client attribute groups */
- /*@{*/
- struct gl_array_attrib Array; /**< Vertex arrays */
- struct gl_pixelstore_attrib Pack; /**< Pixel packing */
- struct gl_pixelstore_attrib Unpack; /**< Pixel unpacking */
- struct gl_pixelstore_attrib DefaultPacking; /**< Default params */
- /*@}*/
-
- /** \name Other assorted state (not pushed/popped on attribute stack) */
- /*@{*/
- struct gl_pixelmaps PixelMaps;
-
- struct gl_evaluators EvalMap; /**< All evaluators */
- struct gl_feedback Feedback; /**< Feedback */
- struct gl_selection Select; /**< Selection */
-
- struct gl_program_state Program; /**< general program state */
- struct gl_vertex_program_state VertexProgram;
- struct gl_fragment_program_state FragmentProgram;
- struct gl_geometry_program_state GeometryProgram;
- struct gl_ati_fragment_shader_state ATIFragmentShader;
-
- struct gl_shader_state Shader; /**< GLSL shader object state */
- struct gl_shader_compiler_options ShaderCompilerOptions[MESA_SHADER_TYPES];
-
- struct gl_query_state Query; /**< occlusion, timer queries */
-
- struct gl_transform_feedback TransformFeedback;
-
- struct gl_buffer_object *CopyReadBuffer; /**< GL_ARB_copy_buffer */
- struct gl_buffer_object *CopyWriteBuffer; /**< GL_ARB_copy_buffer */
- /*@}*/
-
- struct gl_meta_state *Meta; /**< for "meta" operations */
-
- /* GL_EXT_framebuffer_object */
- struct gl_renderbuffer *CurrentRenderbuffer;
-
- GLenum ErrorValue; /**< Last error code */
-
- /**
- * Recognize and silence repeated error debug messages in buggy apps.
- */
- const char *ErrorDebugFmtString;
- GLuint ErrorDebugCount;
-
- GLenum RenderMode; /**< either GL_RENDER, GL_SELECT, GL_FEEDBACK */
- GLbitfield NewState; /**< bitwise-or of _NEW_* flags */
-
- GLboolean ViewportInitialized; /**< has viewport size been initialized? */
-
- GLbitfield varying_vp_inputs; /**< mask of VERT_BIT_* flags */
-
- /** \name Derived state */
- /*@{*/
- /** Bitwise-or of DD_* flags. Note that this bitfield may be used before
- * state validation so they need to always be current.
- */
- GLbitfield _TriangleCaps;
- GLbitfield _ImageTransferState;/**< bitwise-or of IMAGE_*_BIT flags */
- GLfloat _EyeZDir[3];
- GLfloat _ModelViewInvScale;
- GLboolean _NeedEyeCoords;
- GLboolean _ForceEyeCoords;
-
- GLuint TextureStateTimestamp; /**< detect changes to shared state */
-
- struct gl_shine_tab *_ShineTable[2]; /**< Active shine tables */
- struct gl_shine_tab *_ShineTabList; /**< MRU list of inactive shine tables */
- /**@}*/
-
- struct gl_list_extensions *ListExt; /**< driver dlist extensions */
-
- /** \name For debugging/development only */
- /*@{*/
- GLboolean FirstTimeCurrent;
- /*@}*/
-
- /** software compression/decompression supported or not */
- GLboolean Mesa_DXTn;
-
- GLboolean TextureFormatSupported[MESA_FORMAT_COUNT];
-
- /**
- * Use dp4 (rather than mul/mad) instructions for position
- * transformation?
- */
- GLboolean mvp_with_dp4;
-
- /**
- * \name Hooks for module contexts.
- *
- * These will eventually live in the driver or elsewhere.
- */
- /*@{*/
- void *swrast_context;
- void *swsetup_context;
- void *swtnl_context;
- void *swtnl_im;
- struct st_context *st;
- void *aelt_context;
- /*@}*/
-};
-
-
-#ifdef DEBUG
-extern int MESA_VERBOSE;
-extern int MESA_DEBUG_FLAGS;
-# define MESA_FUNCTION __FUNCTION__
-#else
-# define MESA_VERBOSE 0
-# define MESA_DEBUG_FLAGS 0
-# define MESA_FUNCTION "a function"
-# ifndef NDEBUG
-# define NDEBUG
-# endif
-#endif
-
-
-/** The MESA_VERBOSE var is a bitmask of these flags */
-enum _verbose
-{
- VERBOSE_VARRAY = 0x0001,
- VERBOSE_TEXTURE = 0x0002,
- VERBOSE_MATERIAL = 0x0004,
- VERBOSE_PIPELINE = 0x0008,
- VERBOSE_DRIVER = 0x0010,
- VERBOSE_STATE = 0x0020,
- VERBOSE_API = 0x0040,
- VERBOSE_DISPLAY_LIST = 0x0100,
- VERBOSE_LIGHTING = 0x0200,
- VERBOSE_PRIMS = 0x0400,
- VERBOSE_VERTS = 0x0800,
- VERBOSE_DISASSEM = 0x1000,
- VERBOSE_DRAW = 0x2000,
- VERBOSE_SWAPBUFFERS = 0x4000
-};
-
-
-/** The MESA_DEBUG_FLAGS var is a bitmask of these flags */
-enum _debug
-{
- DEBUG_ALWAYS_FLUSH = 0x1
-};
-
-
-
-#endif /* MTYPES_H */
+/* + * Mesa 3-D graphics library + * Version: 7.7 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. 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. + */ + +/** + * \file mtypes.h + * Main Mesa data structures. + * + * Please try to mark derived values with a leading underscore ('_'). + */ + +#ifndef MTYPES_H +#define MTYPES_H + + +#include "main/glheader.h" +#include "main/config.h" +#include "main/mfeatures.h" +#include "glapi/glapi.h" +#include "math/m_matrix.h" /* GLmatrix */ +#include "main/simple_list.h" /* struct simple_node */ +#include "main/formats.h" /* MESA_FORMAT_COUNT */ + + +/** + * Color channel data type. + */ +#if CHAN_BITS == 8 + typedef GLubyte GLchan; +#define CHAN_MAX 255 +#define CHAN_MAXF 255.0F +#define CHAN_TYPE GL_UNSIGNED_BYTE +#elif CHAN_BITS == 16 + typedef GLushort GLchan; +#define CHAN_MAX 65535 +#define CHAN_MAXF 65535.0F +#define CHAN_TYPE GL_UNSIGNED_SHORT +#elif CHAN_BITS == 32 + typedef GLfloat GLchan; +#define CHAN_MAX 1.0 +#define CHAN_MAXF 1.0F +#define CHAN_TYPE GL_FLOAT +#else +#error "illegal number of color channel bits" +#endif + + +/** + * Stencil buffer data type. + */ +#if STENCIL_BITS==8 + typedef GLubyte GLstencil; +#elif STENCIL_BITS==16 + typedef GLushort GLstencil; +#else +# error "illegal number of stencil bits" +#endif + + +/** + * \name 64-bit extension of GLbitfield. + */ +/*@{*/ +typedef GLuint64 GLbitfield64; + +/** Set a single bit */ +#define BITFIELD64_BIT(b) (1ULL << (b)) + + +/** + * \name Some forward type declarations + */ +/*@{*/ +struct _mesa_HashTable; +struct gl_attrib_node; +struct gl_list_extensions; +struct gl_meta_state; +struct gl_pixelstore_attrib; +struct gl_program_cache; +struct gl_texture_format; +struct gl_texture_image; +struct gl_texture_object; +struct gl_context; +struct st_context; +/*@}*/ + + +/** Extra draw modes beyond GL_POINTS, GL_TRIANGLE_FAN, etc */ +#define PRIM_OUTSIDE_BEGIN_END (GL_POLYGON+1) +#define PRIM_INSIDE_UNKNOWN_PRIM (GL_POLYGON+2) +#define PRIM_UNKNOWN (GL_POLYGON+3) + + +/** + * Shader stages. Note that these will become 5 with tessellation. + * These MUST have the same values as gallium's PIPE_SHADER_* + */ +typedef enum +{ + MESA_SHADER_VERTEX = 0, + MESA_SHADER_FRAGMENT = 1, + MESA_SHADER_GEOMETRY = 2, + MESA_SHADER_TYPES = 3 +} gl_shader_type; + + + +/** + * Indexes for vertex program attributes. + * GL_NV_vertex_program aliases generic attributes over the conventional + * attributes. In GL_ARB_vertex_program shader the aliasing is optional. + * In GL_ARB_vertex_shader / OpenGL 2.0 the aliasing is disallowed (the + * generic attributes are distinct/separate). + */ +typedef enum +{ + VERT_ATTRIB_POS = 0, + VERT_ATTRIB_WEIGHT = 1, + VERT_ATTRIB_NORMAL = 2, + VERT_ATTRIB_COLOR0 = 3, + VERT_ATTRIB_COLOR1 = 4, + VERT_ATTRIB_FOG = 5, + VERT_ATTRIB_COLOR_INDEX = 6, + VERT_ATTRIB_POINT_SIZE = 6, /*alias*/ + VERT_ATTRIB_EDGEFLAG = 7, + VERT_ATTRIB_TEX0 = 8, + VERT_ATTRIB_TEX1 = 9, + VERT_ATTRIB_TEX2 = 10, + VERT_ATTRIB_TEX3 = 11, + VERT_ATTRIB_TEX4 = 12, + VERT_ATTRIB_TEX5 = 13, + VERT_ATTRIB_TEX6 = 14, + VERT_ATTRIB_TEX7 = 15, + VERT_ATTRIB_GENERIC0 = 16, + VERT_ATTRIB_GENERIC1 = 17, + VERT_ATTRIB_GENERIC2 = 18, + VERT_ATTRIB_GENERIC3 = 19, + VERT_ATTRIB_GENERIC4 = 20, + VERT_ATTRIB_GENERIC5 = 21, + VERT_ATTRIB_GENERIC6 = 22, + VERT_ATTRIB_GENERIC7 = 23, + VERT_ATTRIB_GENERIC8 = 24, + VERT_ATTRIB_GENERIC9 = 25, + VERT_ATTRIB_GENERIC10 = 26, + VERT_ATTRIB_GENERIC11 = 27, + VERT_ATTRIB_GENERIC12 = 28, + VERT_ATTRIB_GENERIC13 = 29, + VERT_ATTRIB_GENERIC14 = 30, + VERT_ATTRIB_GENERIC15 = 31, + VERT_ATTRIB_MAX = 32 +} gl_vert_attrib; + +/** + * Bitflags for vertex attributes. + * These are used in bitfields in many places. + */ +/*@{*/ +#define VERT_BIT_POS (1 << VERT_ATTRIB_POS) +#define VERT_BIT_WEIGHT (1 << VERT_ATTRIB_WEIGHT) +#define VERT_BIT_NORMAL (1 << VERT_ATTRIB_NORMAL) +#define VERT_BIT_COLOR0 (1 << VERT_ATTRIB_COLOR0) +#define VERT_BIT_COLOR1 (1 << VERT_ATTRIB_COLOR1) +#define VERT_BIT_FOG (1 << VERT_ATTRIB_FOG) +#define VERT_BIT_COLOR_INDEX (1 << VERT_ATTRIB_COLOR_INDEX) +#define VERT_BIT_EDGEFLAG (1 << VERT_ATTRIB_EDGEFLAG) +#define VERT_BIT_TEX0 (1 << VERT_ATTRIB_TEX0) +#define VERT_BIT_TEX1 (1 << VERT_ATTRIB_TEX1) +#define VERT_BIT_TEX2 (1 << VERT_ATTRIB_TEX2) +#define VERT_BIT_TEX3 (1 << VERT_ATTRIB_TEX3) +#define VERT_BIT_TEX4 (1 << VERT_ATTRIB_TEX4) +#define VERT_BIT_TEX5 (1 << VERT_ATTRIB_TEX5) +#define VERT_BIT_TEX6 (1 << VERT_ATTRIB_TEX6) +#define VERT_BIT_TEX7 (1 << VERT_ATTRIB_TEX7) +#define VERT_BIT_GENERIC0 (1 << VERT_ATTRIB_GENERIC0) +#define VERT_BIT_GENERIC1 (1 << VERT_ATTRIB_GENERIC1) +#define VERT_BIT_GENERIC2 (1 << VERT_ATTRIB_GENERIC2) +#define VERT_BIT_GENERIC3 (1 << VERT_ATTRIB_GENERIC3) +#define VERT_BIT_GENERIC4 (1 << VERT_ATTRIB_GENERIC4) +#define VERT_BIT_GENERIC5 (1 << VERT_ATTRIB_GENERIC5) +#define VERT_BIT_GENERIC6 (1 << VERT_ATTRIB_GENERIC6) +#define VERT_BIT_GENERIC7 (1 << VERT_ATTRIB_GENERIC7) +#define VERT_BIT_GENERIC8 (1 << VERT_ATTRIB_GENERIC8) +#define VERT_BIT_GENERIC9 (1 << VERT_ATTRIB_GENERIC9) +#define VERT_BIT_GENERIC10 (1 << VERT_ATTRIB_GENERIC10) +#define VERT_BIT_GENERIC11 (1 << VERT_ATTRIB_GENERIC11) +#define VERT_BIT_GENERIC12 (1 << VERT_ATTRIB_GENERIC12) +#define VERT_BIT_GENERIC13 (1 << VERT_ATTRIB_GENERIC13) +#define VERT_BIT_GENERIC14 (1 << VERT_ATTRIB_GENERIC14) +#define VERT_BIT_GENERIC15 (1 << VERT_ATTRIB_GENERIC15) + +#define VERT_BIT_TEX(u) (1 << (VERT_ATTRIB_TEX0 + (u))) +#define VERT_BIT_GENERIC(g) (1 << (VERT_ATTRIB_GENERIC0 + (g))) +/*@}*/ + + +/** + * Indexes for vertex program result attributes + */ +typedef enum +{ + VERT_RESULT_HPOS = 0, + VERT_RESULT_COL0 = 1, + VERT_RESULT_COL1 = 2, + VERT_RESULT_FOGC = 3, + VERT_RESULT_TEX0 = 4, + VERT_RESULT_TEX1 = 5, + VERT_RESULT_TEX2 = 6, + VERT_RESULT_TEX3 = 7, + VERT_RESULT_TEX4 = 8, + VERT_RESULT_TEX5 = 9, + VERT_RESULT_TEX6 = 10, + VERT_RESULT_TEX7 = 11, + VERT_RESULT_PSIZ = 12, + VERT_RESULT_BFC0 = 13, + VERT_RESULT_BFC1 = 14, + VERT_RESULT_EDGE = 15, + VERT_RESULT_VAR0 = 16, /**< shader varying */ + VERT_RESULT_MAX = (VERT_RESULT_VAR0 + MAX_VARYING) +} gl_vert_result; + + +/*********************************************/ + +/** + * Indexes for geometry program attributes. + */ +typedef enum +{ + GEOM_ATTRIB_POSITION = 0, + GEOM_ATTRIB_COLOR0 = 1, + GEOM_ATTRIB_COLOR1 = 2, + GEOM_ATTRIB_SECONDARY_COLOR0 = 3, + GEOM_ATTRIB_SECONDARY_COLOR1 = 4, + GEOM_ATTRIB_FOG_FRAG_COORD = 5, + GEOM_ATTRIB_POINT_SIZE = 6, + GEOM_ATTRIB_CLIP_VERTEX = 7, + GEOM_ATTRIB_PRIMITIVE_ID = 8, + GEOM_ATTRIB_TEX_COORD = 9, + + GEOM_ATTRIB_VAR0 = 16, + GEOM_ATTRIB_MAX = (GEOM_ATTRIB_VAR0 + MAX_VARYING) +} gl_geom_attrib; + +/** + * Bitflags for geometry attributes. + * These are used in bitfields in many places. + */ +/*@{*/ +#define GEOM_BIT_COLOR0 (1 << GEOM_ATTRIB_COLOR0) +#define GEOM_BIT_COLOR1 (1 << GEOM_ATTRIB_COLOR1) +#define GEOM_BIT_SCOLOR0 (1 << GEOM_ATTRIB_SECONDARY_COLOR0) +#define GEOM_BIT_SCOLOR1 (1 << GEOM_ATTRIB_SECONDARY_COLOR1) +#define GEOM_BIT_TEX_COORD (1 << GEOM_ATTRIB_TEX_COORD) +#define GEOM_BIT_FOG_COORD (1 << GEOM_ATTRIB_FOG_FRAG_COORD) +#define GEOM_BIT_POSITION (1 << GEOM_ATTRIB_POSITION) +#define GEOM_BIT_POINT_SIDE (1 << GEOM_ATTRIB_POINT_SIZE) +#define GEOM_BIT_CLIP_VERTEX (1 << GEOM_ATTRIB_CLIP_VERTEX) +#define GEOM_BIT_PRIM_ID (1 << GEOM_ATTRIB_PRIMITIVE_ID) +#define GEOM_BIT_VAR0 (1 << GEOM_ATTRIB_VAR0) + +#define GEOM_BIT_VAR(g) (1 << (GEOM_BIT_VAR0 + (g))) +/*@}*/ + + +/** + * Indexes for geometry program result attributes + */ +typedef enum +{ + GEOM_RESULT_POS = 0, + GEOM_RESULT_COL0 = 1, + GEOM_RESULT_COL1 = 2, + GEOM_RESULT_SCOL0 = 3, + GEOM_RESULT_SCOL1 = 4, + GEOM_RESULT_FOGC = 5, + GEOM_RESULT_TEX0 = 6, + GEOM_RESULT_TEX1 = 7, + GEOM_RESULT_TEX2 = 8, + GEOM_RESULT_TEX3 = 9, + GEOM_RESULT_TEX4 = 10, + GEOM_RESULT_TEX5 = 11, + GEOM_RESULT_TEX6 = 12, + GEOM_RESULT_TEX7 = 13, + GEOM_RESULT_PSIZ = 14, + GEOM_RESULT_CLPV = 15, + GEOM_RESULT_PRID = 16, + GEOM_RESULT_LAYR = 17, + GEOM_RESULT_VAR0 = 18, /**< shader varying, should really be 16 */ + /* ### we need to -2 because var0 is 18 instead 16 like in the others */ + GEOM_RESULT_MAX = (GEOM_RESULT_VAR0 + MAX_VARYING - 2) +} gl_geom_result; + + +/** + * Indexes for fragment program input attributes. + */ +typedef enum +{ + FRAG_ATTRIB_WPOS = 0, + FRAG_ATTRIB_COL0 = 1, + FRAG_ATTRIB_COL1 = 2, + FRAG_ATTRIB_FOGC = 3, + FRAG_ATTRIB_TEX0 = 4, + FRAG_ATTRIB_TEX1 = 5, + FRAG_ATTRIB_TEX2 = 6, + FRAG_ATTRIB_TEX3 = 7, + FRAG_ATTRIB_TEX4 = 8, + FRAG_ATTRIB_TEX5 = 9, + FRAG_ATTRIB_TEX6 = 10, + FRAG_ATTRIB_TEX7 = 11, + FRAG_ATTRIB_FACE = 12, /**< front/back face */ + FRAG_ATTRIB_PNTC = 13, /**< sprite/point coord */ + FRAG_ATTRIB_VAR0 = 14, /**< shader varying */ + FRAG_ATTRIB_MAX = (FRAG_ATTRIB_VAR0 + MAX_VARYING) +} gl_frag_attrib; + +/** + * Bitflags for fragment program input attributes. + */ +/*@{*/ +#define FRAG_BIT_WPOS (1 << FRAG_ATTRIB_WPOS) +#define FRAG_BIT_COL0 (1 << FRAG_ATTRIB_COL0) +#define FRAG_BIT_COL1 (1 << FRAG_ATTRIB_COL1) +#define FRAG_BIT_FOGC (1 << FRAG_ATTRIB_FOGC) +#define FRAG_BIT_FACE (1 << FRAG_ATTRIB_FACE) +#define FRAG_BIT_PNTC (1 << FRAG_ATTRIB_PNTC) +#define FRAG_BIT_TEX0 (1 << FRAG_ATTRIB_TEX0) +#define FRAG_BIT_TEX1 (1 << FRAG_ATTRIB_TEX1) +#define FRAG_BIT_TEX2 (1 << FRAG_ATTRIB_TEX2) +#define FRAG_BIT_TEX3 (1 << FRAG_ATTRIB_TEX3) +#define FRAG_BIT_TEX4 (1 << FRAG_ATTRIB_TEX4) +#define FRAG_BIT_TEX5 (1 << FRAG_ATTRIB_TEX5) +#define FRAG_BIT_TEX6 (1 << FRAG_ATTRIB_TEX6) +#define FRAG_BIT_TEX7 (1 << FRAG_ATTRIB_TEX7) +#define FRAG_BIT_VAR0 (1 << FRAG_ATTRIB_VAR0) + +#define FRAG_BIT_TEX(U) (FRAG_BIT_TEX0 << (U)) +#define FRAG_BIT_VAR(V) (FRAG_BIT_VAR0 << (V)) + +#define FRAG_BITS_TEX_ANY (FRAG_BIT_TEX0| \ + FRAG_BIT_TEX1| \ + FRAG_BIT_TEX2| \ + FRAG_BIT_TEX3| \ + FRAG_BIT_TEX4| \ + FRAG_BIT_TEX5| \ + FRAG_BIT_TEX6| \ + FRAG_BIT_TEX7) +/*@}*/ + + +/** + * Fragment program results + */ +typedef enum +{ + FRAG_RESULT_DEPTH = 0, + FRAG_RESULT_STENCIL = 1, + FRAG_RESULT_COLOR = 2, + FRAG_RESULT_DATA0 = 3, + FRAG_RESULT_MAX = (FRAG_RESULT_DATA0 + MAX_DRAW_BUFFERS) +} gl_frag_result; + + +/** + * Indexes for all renderbuffers + */ +typedef enum +{ + /* the four standard color buffers */ + BUFFER_FRONT_LEFT, + BUFFER_BACK_LEFT, + BUFFER_FRONT_RIGHT, + BUFFER_BACK_RIGHT, + BUFFER_DEPTH, + BUFFER_STENCIL, + BUFFER_ACCUM, + /* optional aux buffer */ + BUFFER_AUX0, + /* generic renderbuffers */ + BUFFER_COLOR0, + BUFFER_COLOR1, + BUFFER_COLOR2, + BUFFER_COLOR3, + BUFFER_COLOR4, + BUFFER_COLOR5, + BUFFER_COLOR6, + BUFFER_COLOR7, + BUFFER_COUNT +} gl_buffer_index; + +/** + * Bit flags for all renderbuffers + */ +#define BUFFER_BIT_FRONT_LEFT (1 << BUFFER_FRONT_LEFT) +#define BUFFER_BIT_BACK_LEFT (1 << BUFFER_BACK_LEFT) +#define BUFFER_BIT_FRONT_RIGHT (1 << BUFFER_FRONT_RIGHT) +#define BUFFER_BIT_BACK_RIGHT (1 << BUFFER_BACK_RIGHT) +#define BUFFER_BIT_AUX0 (1 << BUFFER_AUX0) +#define BUFFER_BIT_AUX1 (1 << BUFFER_AUX1) +#define BUFFER_BIT_AUX2 (1 << BUFFER_AUX2) +#define BUFFER_BIT_AUX3 (1 << BUFFER_AUX3) +#define BUFFER_BIT_DEPTH (1 << BUFFER_DEPTH) +#define BUFFER_BIT_STENCIL (1 << BUFFER_STENCIL) +#define BUFFER_BIT_ACCUM (1 << BUFFER_ACCUM) +#define BUFFER_BIT_COLOR0 (1 << BUFFER_COLOR0) +#define BUFFER_BIT_COLOR1 (1 << BUFFER_COLOR1) +#define BUFFER_BIT_COLOR2 (1 << BUFFER_COLOR2) +#define BUFFER_BIT_COLOR3 (1 << BUFFER_COLOR3) +#define BUFFER_BIT_COLOR4 (1 << BUFFER_COLOR4) +#define BUFFER_BIT_COLOR5 (1 << BUFFER_COLOR5) +#define BUFFER_BIT_COLOR6 (1 << BUFFER_COLOR6) +#define BUFFER_BIT_COLOR7 (1 << BUFFER_COLOR7) + +/** + * Mask of all the color buffer bits (but not accum). + */ +#define BUFFER_BITS_COLOR (BUFFER_BIT_FRONT_LEFT | \ + BUFFER_BIT_BACK_LEFT | \ + BUFFER_BIT_FRONT_RIGHT | \ + BUFFER_BIT_BACK_RIGHT | \ + BUFFER_BIT_AUX0 | \ + BUFFER_BIT_COLOR0 | \ + BUFFER_BIT_COLOR1 | \ + BUFFER_BIT_COLOR2 | \ + BUFFER_BIT_COLOR3 | \ + BUFFER_BIT_COLOR4 | \ + BUFFER_BIT_COLOR5 | \ + BUFFER_BIT_COLOR6 | \ + BUFFER_BIT_COLOR7) + + +/** + * Framebuffer configuration (aka visual / pixelformat) + * Note: some of these fields should be boolean, but it appears that + * code in drivers/dri/common/util.c requires int-sized fields. + */ +struct gl_config +{ + GLboolean rgbMode; + GLboolean floatMode; + GLboolean colorIndexMode; /* XXX is this used anywhere? */ + GLuint doubleBufferMode; + GLuint stereoMode; + + GLboolean haveAccumBuffer; + GLboolean haveDepthBuffer; + GLboolean haveStencilBuffer; + + GLint redBits, greenBits, blueBits, alphaBits; /* bits per comp */ + GLuint redMask, greenMask, blueMask, alphaMask; + GLint rgbBits; /* total bits for rgb */ + GLint indexBits; /* total bits for colorindex */ + + GLint accumRedBits, accumGreenBits, accumBlueBits, accumAlphaBits; + GLint depthBits; + GLint stencilBits; + + GLint numAuxBuffers; + + GLint level; + + /* EXT_visual_rating / GLX 1.2 */ + GLint visualRating; + + /* EXT_visual_info / GLX 1.2 */ + GLint transparentPixel; + /* colors are floats scaled to ints */ + GLint transparentRed, transparentGreen, transparentBlue, transparentAlpha; + GLint transparentIndex; + + /* ARB_multisample / SGIS_multisample */ + GLint sampleBuffers; + GLint samples; + + /* SGIX_pbuffer / GLX 1.3 */ + GLint maxPbufferWidth; + GLint maxPbufferHeight; + GLint maxPbufferPixels; + GLint optimalPbufferWidth; /* Only for SGIX_pbuffer. */ + GLint optimalPbufferHeight; /* Only for SGIX_pbuffer. */ + + /* OML_swap_method */ + GLint swapMethod; + + /* EXT_texture_from_pixmap */ + GLint bindToTextureRgb; + GLint bindToTextureRgba; + GLint bindToMipmapTexture; + GLint bindToTextureTargets; + GLint yInverted; + + /* EXT_framebuffer_sRGB */ + GLint sRGBCapable; +}; + + +/** + * Data structure for color tables + */ +struct gl_color_table +{ + GLenum InternalFormat; /**< The user-specified format */ + GLenum _BaseFormat; /**< GL_ALPHA, GL_RGBA, GL_RGB, etc */ + GLuint Size; /**< number of entries in table */ + GLfloat *TableF; /**< Color table, floating point values */ + GLubyte *TableUB; /**< Color table, ubyte values */ + GLubyte RedSize; + GLubyte GreenSize; + GLubyte BlueSize; + GLubyte AlphaSize; + GLubyte LuminanceSize; + GLubyte IntensitySize; +}; + + +/** + * \name Bit flags used for updating material values. + */ +/*@{*/ +#define MAT_ATTRIB_FRONT_AMBIENT 0 +#define MAT_ATTRIB_BACK_AMBIENT 1 +#define MAT_ATTRIB_FRONT_DIFFUSE 2 +#define MAT_ATTRIB_BACK_DIFFUSE 3 +#define MAT_ATTRIB_FRONT_SPECULAR 4 +#define MAT_ATTRIB_BACK_SPECULAR 5 +#define MAT_ATTRIB_FRONT_EMISSION 6 +#define MAT_ATTRIB_BACK_EMISSION 7 +#define MAT_ATTRIB_FRONT_SHININESS 8 +#define MAT_ATTRIB_BACK_SHININESS 9 +#define MAT_ATTRIB_FRONT_INDEXES 10 +#define MAT_ATTRIB_BACK_INDEXES 11 +#define MAT_ATTRIB_MAX 12 + +#define MAT_ATTRIB_AMBIENT(f) (MAT_ATTRIB_FRONT_AMBIENT+(f)) +#define MAT_ATTRIB_DIFFUSE(f) (MAT_ATTRIB_FRONT_DIFFUSE+(f)) +#define MAT_ATTRIB_SPECULAR(f) (MAT_ATTRIB_FRONT_SPECULAR+(f)) +#define MAT_ATTRIB_EMISSION(f) (MAT_ATTRIB_FRONT_EMISSION+(f)) +#define MAT_ATTRIB_SHININESS(f)(MAT_ATTRIB_FRONT_SHININESS+(f)) +#define MAT_ATTRIB_INDEXES(f) (MAT_ATTRIB_FRONT_INDEXES+(f)) + +#define MAT_INDEX_AMBIENT 0 +#define MAT_INDEX_DIFFUSE 1 +#define MAT_INDEX_SPECULAR 2 + +#define MAT_BIT_FRONT_AMBIENT (1<<MAT_ATTRIB_FRONT_AMBIENT) +#define MAT_BIT_BACK_AMBIENT (1<<MAT_ATTRIB_BACK_AMBIENT) +#define MAT_BIT_FRONT_DIFFUSE (1<<MAT_ATTRIB_FRONT_DIFFUSE) +#define MAT_BIT_BACK_DIFFUSE (1<<MAT_ATTRIB_BACK_DIFFUSE) +#define MAT_BIT_FRONT_SPECULAR (1<<MAT_ATTRIB_FRONT_SPECULAR) +#define MAT_BIT_BACK_SPECULAR (1<<MAT_ATTRIB_BACK_SPECULAR) +#define MAT_BIT_FRONT_EMISSION (1<<MAT_ATTRIB_FRONT_EMISSION) +#define MAT_BIT_BACK_EMISSION (1<<MAT_ATTRIB_BACK_EMISSION) +#define MAT_BIT_FRONT_SHININESS (1<<MAT_ATTRIB_FRONT_SHININESS) +#define MAT_BIT_BACK_SHININESS (1<<MAT_ATTRIB_BACK_SHININESS) +#define MAT_BIT_FRONT_INDEXES (1<<MAT_ATTRIB_FRONT_INDEXES) +#define MAT_BIT_BACK_INDEXES (1<<MAT_ATTRIB_BACK_INDEXES) + + +#define FRONT_MATERIAL_BITS (MAT_BIT_FRONT_EMISSION | \ + MAT_BIT_FRONT_AMBIENT | \ + MAT_BIT_FRONT_DIFFUSE | \ + MAT_BIT_FRONT_SPECULAR | \ + MAT_BIT_FRONT_SHININESS | \ + MAT_BIT_FRONT_INDEXES) + +#define BACK_MATERIAL_BITS (MAT_BIT_BACK_EMISSION | \ + MAT_BIT_BACK_AMBIENT | \ + MAT_BIT_BACK_DIFFUSE | \ + MAT_BIT_BACK_SPECULAR | \ + MAT_BIT_BACK_SHININESS | \ + MAT_BIT_BACK_INDEXES) + +#define ALL_MATERIAL_BITS (FRONT_MATERIAL_BITS | BACK_MATERIAL_BITS) +/*@}*/ + + +#define EXP_TABLE_SIZE 512 /**< Specular exponent lookup table sizes */ +#define SHINE_TABLE_SIZE 256 /**< Material shininess lookup table sizes */ + +/** + * Material shininess lookup table. + */ +struct gl_shine_tab +{ + struct gl_shine_tab *next, *prev; + GLfloat tab[SHINE_TABLE_SIZE+1]; + GLfloat shininess; + GLuint refcount; +}; + + +/** + * Light source state. + */ +struct gl_light +{ + struct gl_light *next; /**< double linked list with sentinel */ + struct gl_light *prev; + + GLfloat Ambient[4]; /**< ambient color */ + GLfloat Diffuse[4]; /**< diffuse color */ + GLfloat Specular[4]; /**< specular color */ + GLfloat EyePosition[4]; /**< position in eye coordinates */ + GLfloat SpotDirection[4]; /**< spotlight direction in eye coordinates */ + GLfloat SpotExponent; + GLfloat SpotCutoff; /**< in degrees */ + GLfloat _CosCutoffNeg; /**< = cos(SpotCutoff) */ + GLfloat _CosCutoff; /**< = MAX(0, cos(SpotCutoff)) */ + GLfloat ConstantAttenuation; + GLfloat LinearAttenuation; + GLfloat QuadraticAttenuation; + GLboolean Enabled; /**< On/off flag */ + + /** + * \name Derived fields + */ + /*@{*/ + GLbitfield _Flags; /**< State */ + + GLfloat _Position[4]; /**< position in eye/obj coordinates */ + GLfloat _VP_inf_norm[3]; /**< Norm direction to infinite light */ + GLfloat _h_inf_norm[3]; /**< Norm( _VP_inf_norm + <0,0,1> ) */ + GLfloat _NormSpotDirection[4]; /**< normalized spotlight direction */ + GLfloat _VP_inf_spot_attenuation; + + GLfloat _SpotExpTable[EXP_TABLE_SIZE][2]; /**< to replace a pow() call */ + GLfloat _MatAmbient[2][3]; /**< material ambient * light ambient */ + GLfloat _MatDiffuse[2][3]; /**< material diffuse * light diffuse */ + GLfloat _MatSpecular[2][3]; /**< material spec * light specular */ + GLfloat _dli; /**< CI diffuse light intensity */ + GLfloat _sli; /**< CI specular light intensity */ + /*@}*/ +}; + + +/** + * Light model state. + */ +struct gl_lightmodel +{ + GLfloat Ambient[4]; /**< ambient color */ + GLboolean LocalViewer; /**< Local (or infinite) view point? */ + GLboolean TwoSide; /**< Two (or one) sided lighting? */ + GLenum ColorControl; /**< either GL_SINGLE_COLOR + * or GL_SEPARATE_SPECULAR_COLOR */ +}; + + +/** + * Material state. + */ +struct gl_material +{ + GLfloat Attrib[MAT_ATTRIB_MAX][4]; +}; + + +/** + * Accumulation buffer attribute group (GL_ACCUM_BUFFER_BIT) + */ +struct gl_accum_attrib +{ + GLfloat ClearColor[4]; /**< Accumulation buffer clear color */ +}; + + +/** + * Color buffer attribute group (GL_COLOR_BUFFER_BIT). + */ +struct gl_colorbuffer_attrib +{ + GLuint ClearIndex; /**< Index to use for glClear */ + GLclampf ClearColor[4]; /**< Color to use for glClear */ + + GLuint IndexMask; /**< Color index write mask */ + GLubyte ColorMask[MAX_DRAW_BUFFERS][4];/**< Each flag is 0xff or 0x0 */ + + GLenum DrawBuffer[MAX_DRAW_BUFFERS]; /**< Which buffer to draw into */ + + /** + * \name alpha testing + */ + /*@{*/ + GLboolean AlphaEnabled; /**< Alpha test enabled flag */ + GLenum AlphaFunc; /**< Alpha test function */ + GLclampf AlphaRef; /**< Alpha reference value */ + /*@}*/ + + /** + * \name Blending + */ + /*@{*/ + GLbitfield BlendEnabled; /**< Per-buffer blend enable flags */ + GLfloat BlendColor[4]; /**< Blending color */ + struct + { + GLenum SrcRGB; /**< RGB blend source term */ + GLenum DstRGB; /**< RGB blend dest term */ + GLenum SrcA; /**< Alpha blend source term */ + GLenum DstA; /**< Alpha blend dest term */ + GLenum EquationRGB; /**< GL_ADD, GL_SUBTRACT, etc. */ + GLenum EquationA; /**< GL_ADD, GL_SUBTRACT, etc. */ + } Blend[MAX_DRAW_BUFFERS]; + /** Are the blend func terms currently different for each buffer/target? */ + GLboolean _BlendFuncPerBuffer; + /** Are the blend equations currently different for each buffer/target? */ + GLboolean _BlendEquationPerBuffer; + /*@}*/ + + /** + * \name Logic op + */ + /*@{*/ + GLenum LogicOp; /**< Logic operator */ + GLboolean IndexLogicOpEnabled; /**< Color index logic op enabled flag */ + GLboolean ColorLogicOpEnabled; /**< RGBA logic op enabled flag */ + GLboolean _LogicOpEnabled; /**< RGBA logic op + EXT_blend_logic_op enabled flag */ + /*@}*/ + + GLboolean DitherFlag; /**< Dither enable flag */ + + GLenum ClampFragmentColor; /**< GL_TRUE, GL_FALSE or GL_FIXED_ONLY_ARB */ + GLenum ClampReadColor; /**< GL_TRUE, GL_FALSE or GL_FIXED_ONLY_ARB */ + + GLboolean sRGBEnabled; /**< Framebuffer sRGB blending/updating requested */ +}; + + +/** + * Current attribute group (GL_CURRENT_BIT). + */ +struct gl_current_attrib +{ + /** + * \name Current vertex attributes. + * \note Values are valid only after FLUSH_VERTICES has been called. + * \note Index and Edgeflag current values are stored as floats in the + * SIX and SEVEN attribute slots. + */ + GLfloat Attrib[VERT_ATTRIB_MAX][4]; /**< Position, color, texcoords, etc */ + + /** + * \name Current raster position attributes (always valid). + * \note This set of attributes is very similar to the SWvertex struct. + */ + /*@{*/ + GLfloat RasterPos[4]; + GLfloat RasterDistance; + GLfloat RasterColor[4]; + GLfloat RasterSecondaryColor[4]; + GLfloat RasterTexCoords[MAX_TEXTURE_COORD_UNITS][4]; + GLboolean RasterPosValid; + /*@}*/ +}; + + +/** + * Depth buffer attribute group (GL_DEPTH_BUFFER_BIT). + */ +struct gl_depthbuffer_attrib +{ + GLenum Func; /**< Function for depth buffer compare */ + GLclampd Clear; /**< Value to clear depth buffer to */ + GLboolean Test; /**< Depth buffering enabled flag */ + GLboolean Mask; /**< Depth buffer writable? */ + GLboolean BoundsTest; /**< GL_EXT_depth_bounds_test */ + GLfloat BoundsMin, BoundsMax;/**< GL_EXT_depth_bounds_test */ +}; + + +/** + * Evaluator attribute group (GL_EVAL_BIT). + */ +struct gl_eval_attrib +{ + /** + * \name Enable bits + */ + /*@{*/ + GLboolean Map1Color4; + GLboolean Map1Index; + GLboolean Map1Normal; + GLboolean Map1TextureCoord1; + GLboolean Map1TextureCoord2; + GLboolean Map1TextureCoord3; + GLboolean Map1TextureCoord4; + GLboolean Map1Vertex3; + GLboolean Map1Vertex4; + GLboolean Map1Attrib[16]; /* GL_NV_vertex_program */ + GLboolean Map2Color4; + GLboolean Map2Index; + GLboolean Map2Normal; + GLboolean Map2TextureCoord1; + GLboolean Map2TextureCoord2; + GLboolean Map2TextureCoord3; + GLboolean Map2TextureCoord4; + GLboolean Map2Vertex3; + GLboolean Map2Vertex4; + GLboolean Map2Attrib[16]; /* GL_NV_vertex_program */ + GLboolean AutoNormal; + /*@}*/ + + /** + * \name Map Grid endpoints and divisions and calculated du values + */ + /*@{*/ + GLint MapGrid1un; + GLfloat MapGrid1u1, MapGrid1u2, MapGrid1du; + GLint MapGrid2un, MapGrid2vn; + GLfloat MapGrid2u1, MapGrid2u2, MapGrid2du; + GLfloat MapGrid2v1, MapGrid2v2, MapGrid2dv; + /*@}*/ +}; + + +/** + * Fog attribute group (GL_FOG_BIT). + */ +struct gl_fog_attrib +{ + GLboolean Enabled; /**< Fog enabled flag */ + GLfloat Color[4]; /**< Fog color */ + GLfloat Density; /**< Density >= 0.0 */ + GLfloat Start; /**< Start distance in eye coords */ + GLfloat End; /**< End distance in eye coords */ + GLfloat Index; /**< Fog index */ + GLenum Mode; /**< Fog mode */ + GLboolean ColorSumEnabled; + GLenum FogCoordinateSource; /**< GL_EXT_fog_coord */ + GLfloat _Scale; /**< (End == Start) ? 1.0 : 1.0 / (End - Start) */ +}; + + +/** + * \brief Layout qualifiers for gl_FragDepth. + * + * Extension AMD_conservative_depth allows gl_FragDepth to be redeclared with + * a layout qualifier. + * + * \see enum ir_depth_layout + */ +enum gl_frag_depth_layout { + FRAG_DEPTH_LAYOUT_NONE, /**< No layout is specified. */ + FRAG_DEPTH_LAYOUT_ANY, + FRAG_DEPTH_LAYOUT_GREATER, + FRAG_DEPTH_LAYOUT_LESS, + FRAG_DEPTH_LAYOUT_UNCHANGED +}; + + +/** + * Hint attribute group (GL_HINT_BIT). + * + * Values are always one of GL_FASTEST, GL_NICEST, or GL_DONT_CARE. + */ +struct gl_hint_attrib +{ + GLenum PerspectiveCorrection; + GLenum PointSmooth; + GLenum LineSmooth; + GLenum PolygonSmooth; + GLenum Fog; + GLenum ClipVolumeClipping; /**< GL_EXT_clip_volume_hint */ + GLenum TextureCompression; /**< GL_ARB_texture_compression */ + GLenum GenerateMipmap; /**< GL_SGIS_generate_mipmap */ + GLenum FragmentShaderDerivative; /**< GL_ARB_fragment_shader */ +}; + +/** + * Light state flags. + */ +/*@{*/ +#define LIGHT_SPOT 0x1 +#define LIGHT_LOCAL_VIEWER 0x2 +#define LIGHT_POSITIONAL 0x4 +#define LIGHT_NEED_VERTICES (LIGHT_POSITIONAL|LIGHT_LOCAL_VIEWER) +/*@}*/ + + +/** + * Lighting attribute group (GL_LIGHT_BIT). + */ +struct gl_light_attrib +{ + struct gl_light Light[MAX_LIGHTS]; /**< Array of light sources */ + struct gl_lightmodel Model; /**< Lighting model */ + + /** + * Must flush FLUSH_VERTICES before referencing: + */ + /*@{*/ + struct gl_material Material; /**< Includes front & back values */ + /*@}*/ + + GLboolean Enabled; /**< Lighting enabled flag */ + GLenum ShadeModel; /**< GL_FLAT or GL_SMOOTH */ + GLenum ProvokingVertex; /**< GL_EXT_provoking_vertex */ + GLenum ColorMaterialFace; /**< GL_FRONT, BACK or FRONT_AND_BACK */ + GLenum ColorMaterialMode; /**< GL_AMBIENT, GL_DIFFUSE, etc */ + GLbitfield ColorMaterialBitmask; /**< bitmask formed from Face and Mode */ + GLboolean ColorMaterialEnabled; + GLenum ClampVertexColor; + + struct gl_light EnabledList; /**< List sentinel */ + + /** + * Derived state for optimizations: + */ + /*@{*/ + GLboolean _NeedEyeCoords; + GLboolean _NeedVertices; /**< Use fast shader? */ + GLbitfield _Flags; /**< LIGHT_* flags, see above */ + GLfloat _BaseColor[2][3]; + /*@}*/ +}; + + +/** + * Line attribute group (GL_LINE_BIT). + */ +struct gl_line_attrib +{ + GLboolean SmoothFlag; /**< GL_LINE_SMOOTH enabled? */ + GLboolean StippleFlag; /**< GL_LINE_STIPPLE enabled? */ + GLushort StipplePattern; /**< Stipple pattern */ + GLint StippleFactor; /**< Stipple repeat factor */ + GLfloat Width; /**< Line width */ +}; + + +/** + * Display list attribute group (GL_LIST_BIT). + */ +struct gl_list_attrib +{ + GLuint ListBase; +}; + + +/** + * Multisample attribute group (GL_MULTISAMPLE_BIT). + */ +struct gl_multisample_attrib +{ + GLboolean Enabled; + GLboolean _Enabled; /**< true if Enabled and multisample buffer */ + GLboolean SampleAlphaToCoverage; + GLboolean SampleAlphaToOne; + GLboolean SampleCoverage; + GLfloat SampleCoverageValue; + GLboolean SampleCoverageInvert; +}; + + +/** + * A pixelmap (see glPixelMap) + */ +struct gl_pixelmap +{ + GLint Size; + GLfloat Map[MAX_PIXEL_MAP_TABLE]; + GLubyte Map8[MAX_PIXEL_MAP_TABLE]; /**< converted to 8-bit color */ +}; + + +/** + * Collection of all pixelmaps + */ +struct gl_pixelmaps +{ + struct gl_pixelmap RtoR; /**< i.e. GL_PIXEL_MAP_R_TO_R */ + struct gl_pixelmap GtoG; + struct gl_pixelmap BtoB; + struct gl_pixelmap AtoA; + struct gl_pixelmap ItoR; + struct gl_pixelmap ItoG; + struct gl_pixelmap ItoB; + struct gl_pixelmap ItoA; + struct gl_pixelmap ItoI; + struct gl_pixelmap StoS; +}; + + +/** + * Pixel attribute group (GL_PIXEL_MODE_BIT). + */ +struct gl_pixel_attrib +{ + GLenum ReadBuffer; /**< source buffer for glRead/CopyPixels() */ + + /*--- Begin Pixel Transfer State ---*/ + /* Fields are in the order in which they're applied... */ + + /** Scale & Bias (index shift, offset) */ + /*@{*/ + GLfloat RedBias, RedScale; + GLfloat GreenBias, GreenScale; + GLfloat BlueBias, BlueScale; + GLfloat AlphaBias, AlphaScale; + GLfloat DepthBias, DepthScale; + GLint IndexShift, IndexOffset; + /*@}*/ + + /* Pixel Maps */ + /* Note: actual pixel maps are not part of this attrib group */ + GLboolean MapColorFlag; + GLboolean MapStencilFlag; + + /*--- End Pixel Transfer State ---*/ + + /** glPixelZoom */ + GLfloat ZoomX, ZoomY; +}; + + +/** + * Point attribute group (GL_POINT_BIT). + */ +struct gl_point_attrib +{ + GLboolean SmoothFlag; /**< True if GL_POINT_SMOOTH is enabled */ + GLfloat Size; /**< User-specified point size */ + GLfloat Params[3]; /**< GL_EXT_point_parameters */ + GLfloat MinSize, MaxSize; /**< GL_EXT_point_parameters */ + GLfloat Threshold; /**< GL_EXT_point_parameters */ + GLboolean _Attenuated; /**< True if Params != [1, 0, 0] */ + GLboolean PointSprite; /**< GL_NV/ARB_point_sprite */ + GLboolean CoordReplace[MAX_TEXTURE_COORD_UNITS]; /**< GL_ARB_point_sprite*/ + GLenum SpriteRMode; /**< GL_NV_point_sprite (only!) */ + GLenum SpriteOrigin; /**< GL_ARB_point_sprite */ +}; + + +/** + * Polygon attribute group (GL_POLYGON_BIT). + */ +struct gl_polygon_attrib +{ + GLenum FrontFace; /**< Either GL_CW or GL_CCW */ + GLenum FrontMode; /**< Either GL_POINT, GL_LINE or GL_FILL */ + GLenum BackMode; /**< Either GL_POINT, GL_LINE or GL_FILL */ + GLboolean _FrontBit; /**< 0=GL_CCW, 1=GL_CW */ + GLboolean CullFlag; /**< Culling on/off flag */ + GLboolean SmoothFlag; /**< True if GL_POLYGON_SMOOTH is enabled */ + GLboolean StippleFlag; /**< True if GL_POLYGON_STIPPLE is enabled */ + GLenum CullFaceMode; /**< Culling mode GL_FRONT or GL_BACK */ + GLfloat OffsetFactor; /**< Polygon offset factor, from user */ + GLfloat OffsetUnits; /**< Polygon offset units, from user */ + GLboolean OffsetPoint; /**< Offset in GL_POINT mode */ + GLboolean OffsetLine; /**< Offset in GL_LINE mode */ + GLboolean OffsetFill; /**< Offset in GL_FILL mode */ +}; + + +/** + * Scissor attributes (GL_SCISSOR_BIT). + */ +struct gl_scissor_attrib +{ + GLboolean Enabled; /**< Scissor test enabled? */ + GLint X, Y; /**< Lower left corner of box */ + GLsizei Width, Height; /**< Size of box */ +}; + + +/** + * Stencil attribute group (GL_STENCIL_BUFFER_BIT). + * + * Three sets of stencil data are tracked so that OpenGL 2.0, + * GL_EXT_stencil_two_side, and GL_ATI_separate_stencil can all be supported + * simultaneously. In each of the stencil state arrays, element 0 corresponds + * to GL_FRONT. Element 1 corresponds to the OpenGL 2.0 / + * GL_ATI_separate_stencil GL_BACK state. Element 2 corresponds to the + * GL_EXT_stencil_two_side GL_BACK state. + * + * The derived value \c _BackFace is either 1 or 2 depending on whether or + * not GL_STENCIL_TEST_TWO_SIDE_EXT is enabled. + * + * The derived value \c _TestTwoSide is set when the front-face and back-face + * stencil state are different. + */ +struct gl_stencil_attrib +{ + GLboolean Enabled; /**< Enabled flag */ + GLboolean TestTwoSide; /**< GL_EXT_stencil_two_side */ + GLubyte ActiveFace; /**< GL_EXT_stencil_two_side (0 or 2) */ + GLboolean _Enabled; /**< Enabled and stencil buffer present */ + GLboolean _TestTwoSide; + GLubyte _BackFace; /**< Current back stencil state (1 or 2) */ + GLenum Function[3]; /**< Stencil function */ + GLenum FailFunc[3]; /**< Fail function */ + GLenum ZPassFunc[3]; /**< Depth buffer pass function */ + GLenum ZFailFunc[3]; /**< Depth buffer fail function */ + GLint Ref[3]; /**< Reference value */ + GLuint ValueMask[3]; /**< Value mask */ + GLuint WriteMask[3]; /**< Write mask */ + GLuint Clear; /**< Clear value */ +}; + + +/** + * An index for each type of texture object. These correspond to the GL + * texture target enums, such as GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP, etc. + * Note: the order is from highest priority to lowest priority. + */ +typedef enum +{ + TEXTURE_2D_ARRAY_INDEX, + TEXTURE_1D_ARRAY_INDEX, + TEXTURE_CUBE_INDEX, + TEXTURE_3D_INDEX, + TEXTURE_RECT_INDEX, + TEXTURE_2D_INDEX, + TEXTURE_1D_INDEX, + NUM_TEXTURE_TARGETS +} gl_texture_index; + + +/** + * Bit flags for each type of texture object + * Used for Texture.Unit[]._ReallyEnabled flags. + */ +/*@{*/ +#define TEXTURE_2D_ARRAY_BIT (1 << TEXTURE_2D_ARRAY_INDEX) +#define TEXTURE_1D_ARRAY_BIT (1 << TEXTURE_1D_ARRAY_INDEX) +#define TEXTURE_CUBE_BIT (1 << TEXTURE_CUBE_INDEX) +#define TEXTURE_3D_BIT (1 << TEXTURE_3D_INDEX) +#define TEXTURE_RECT_BIT (1 << TEXTURE_RECT_INDEX) +#define TEXTURE_2D_BIT (1 << TEXTURE_2D_INDEX) +#define TEXTURE_1D_BIT (1 << TEXTURE_1D_INDEX) +/*@}*/ + + +/** + * TexGenEnabled flags. + */ +/*@{*/ +#define S_BIT 1 +#define T_BIT 2 +#define R_BIT 4 +#define Q_BIT 8 +#define STR_BITS (S_BIT | T_BIT | R_BIT) +/*@}*/ + + +/** + * Bit flag versions of the corresponding GL_ constants. + */ +/*@{*/ +#define TEXGEN_SPHERE_MAP 0x1 +#define TEXGEN_OBJ_LINEAR 0x2 +#define TEXGEN_EYE_LINEAR 0x4 +#define TEXGEN_REFLECTION_MAP_NV 0x8 +#define TEXGEN_NORMAL_MAP_NV 0x10 + +#define TEXGEN_NEED_NORMALS (TEXGEN_SPHERE_MAP | \ + TEXGEN_REFLECTION_MAP_NV | \ + TEXGEN_NORMAL_MAP_NV) +#define TEXGEN_NEED_EYE_COORD (TEXGEN_SPHERE_MAP | \ + TEXGEN_REFLECTION_MAP_NV | \ + TEXGEN_NORMAL_MAP_NV | \ + TEXGEN_EYE_LINEAR) +/*@}*/ + + + +/** Tex-gen enabled for texture unit? */ +#define ENABLE_TEXGEN(unit) (1 << (unit)) + +/** Non-identity texture matrix for texture unit? */ +#define ENABLE_TEXMAT(unit) (1 << (unit)) + + +/** + * Texel fetch function prototype. We use texel fetch functions to + * extract RGBA, color indexes and depth components out of 1D, 2D and 3D + * texture images. These functions help to isolate us from the gritty + * details of all the various texture image encodings. + * + * \param texImage texture image. + * \param col texel column. + * \param row texel row. + * \param img texel image level/layer. + * \param texelOut output texel (up to 4 GLchans) + */ +typedef void (*FetchTexelFuncC)( const struct gl_texture_image *texImage, + GLint col, GLint row, GLint img, + GLchan *texelOut ); + +/** + * As above, but returns floats. + * Used for depth component images and for upcoming signed/float + * texture images. + */ +typedef void (*FetchTexelFuncF)( const struct gl_texture_image *texImage, + GLint col, GLint row, GLint img, + GLfloat *texelOut ); + + +typedef void (*StoreTexelFunc)(struct gl_texture_image *texImage, + GLint col, GLint row, GLint img, + const void *texel); + + +/** + * Texture image state. Describes the dimensions of a texture image, + * the texel format and pointers to Texel Fetch functions. + */ +struct gl_texture_image +{ + GLint InternalFormat; /**< Internal format as given by the user */ + GLenum _BaseFormat; /**< Either GL_RGB, GL_RGBA, GL_ALPHA, + * GL_LUMINANCE, GL_LUMINANCE_ALPHA, + * GL_INTENSITY, GL_COLOR_INDEX, + * GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT + * only. Used for choosing TexEnv arithmetic. + */ + gl_format TexFormat; /**< The actual texture memory format */ + + GLuint Border; /**< 0 or 1 */ + GLuint Width; /**< = 2^WidthLog2 + 2*Border */ + GLuint Height; /**< = 2^HeightLog2 + 2*Border */ + GLuint Depth; /**< = 2^DepthLog2 + 2*Border */ + GLuint Width2; /**< = Width - 2*Border */ + GLuint Height2; /**< = Height - 2*Border */ + GLuint Depth2; /**< = Depth - 2*Border */ + GLuint WidthLog2; /**< = log2(Width2) */ + GLuint HeightLog2; /**< = log2(Height2) */ + GLuint DepthLog2; /**< = log2(Depth2) */ + GLuint MaxLog2; /**< = MAX(WidthLog2, HeightLog2) */ + GLfloat WidthScale; /**< used for mipmap LOD computation */ + GLfloat HeightScale; /**< used for mipmap LOD computation */ + GLfloat DepthScale; /**< used for mipmap LOD computation */ + GLboolean IsClientData; /**< Data owned by client? */ + GLboolean _IsPowerOfTwo; /**< Are all dimensions powers of two? */ + + struct gl_texture_object *TexObject; /**< Pointer back to parent object */ + + FetchTexelFuncC FetchTexelc; /**< GLchan texel fetch function pointer */ + FetchTexelFuncF FetchTexelf; /**< Float texel fetch function pointer */ + + GLuint RowStride; /**< Padded width in units of texels */ + GLuint *ImageOffsets; /**< if 3D texture: array [Depth] of offsets to + each 2D slice in 'Data', in texels */ + GLvoid *Data; /**< Image data, accessed via FetchTexel() */ + + /** + * \name For device driver: + */ + /*@{*/ + void *DriverData; /**< Arbitrary device driver data */ + /*@}*/ +}; + + +/** + * Indexes for cube map faces. + */ +typedef enum +{ + FACE_POS_X = 0, + FACE_NEG_X = 1, + FACE_POS_Y = 2, + FACE_NEG_Y = 3, + FACE_POS_Z = 4, + FACE_NEG_Z = 5, + MAX_FACES = 6 +} gl_face_index; + + +/** + * Texture object state. Contains the array of mipmap images, border color, + * wrap modes, filter modes, shadow/texcompare state, and the per-texture + * color palette. + */ +struct gl_texture_object +{ + _glthread_Mutex Mutex; /**< for thread safety */ + GLint RefCount; /**< reference count */ + GLuint Name; /**< the user-visible texture object ID */ + GLenum Target; /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */ + GLfloat Priority; /**< in [0,1] */ + union { + GLfloat f[4]; + GLuint ui[4]; + GLint i[4]; + } BorderColor; /**< Interpreted according to texture format */ + GLenum WrapS; /**< S-axis texture image wrap mode */ + GLenum WrapT; /**< T-axis texture image wrap mode */ + GLenum WrapR; /**< R-axis texture image wrap mode */ + GLenum MinFilter; /**< minification filter */ + GLenum MagFilter; /**< magnification filter */ + GLfloat MinLod; /**< min lambda, OpenGL 1.2 */ + GLfloat MaxLod; /**< max lambda, OpenGL 1.2 */ + GLfloat LodBias; /**< OpenGL 1.4 */ + GLint BaseLevel; /**< min mipmap level, OpenGL 1.2 */ + GLint MaxLevel; /**< max mipmap level, OpenGL 1.2 */ + GLfloat MaxAnisotropy; /**< GL_EXT_texture_filter_anisotropic */ + GLenum CompareMode; /**< GL_ARB_shadow */ + GLenum CompareFunc; /**< GL_ARB_shadow */ + GLfloat CompareFailValue; /**< GL_ARB_shadow_ambient */ + GLenum DepthMode; /**< GL_ARB_depth_texture */ + GLint _MaxLevel; /**< actual max mipmap level (q in the spec) */ + GLfloat _MaxLambda; /**< = _MaxLevel - BaseLevel (q - b in spec) */ + GLint CropRect[4]; /**< GL_OES_draw_texture */ + GLenum Swizzle[4]; /**< GL_EXT_texture_swizzle */ + GLuint _Swizzle; /**< same as Swizzle, but SWIZZLE_* format */ + GLboolean GenerateMipmap; /**< GL_SGIS_generate_mipmap */ + GLboolean _Complete; /**< Is texture object complete? */ + GLboolean _RenderToTexture; /**< Any rendering to this texture? */ + GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */ + GLenum sRGBDecode; /**< GL_DECODE_EXT or GL_SKIP_DECODE_EXT */ + + /** Actual texture images, indexed by [cube face] and [mipmap level] */ + struct gl_texture_image *Image[MAX_FACES][MAX_TEXTURE_LEVELS]; + + /** GL_EXT_paletted_texture */ + struct gl_color_table Palette; + + /** + * \name For device driver. + * Note: instead of attaching driver data to this pointer, it's preferable + * to instead use this struct as a base class for your own texture object + * class. Driver->NewTextureObject() can be used to implement the + * allocation. + */ + void *DriverData; /**< Arbitrary device driver data */ +}; + + +/** Up to four combiner sources are possible with GL_NV_texture_env_combine4 */ +#define MAX_COMBINER_TERMS 4 + + +/** + * Texture combine environment state. + */ +struct gl_tex_env_combine_state +{ + GLenum ModeRGB; /**< GL_REPLACE, GL_DECAL, GL_ADD, etc. */ + GLenum ModeA; /**< GL_REPLACE, GL_DECAL, GL_ADD, etc. */ + /** Source terms: GL_PRIMARY_COLOR, GL_TEXTURE, etc */ + GLenum SourceRGB[MAX_COMBINER_TERMS]; + GLenum SourceA[MAX_COMBINER_TERMS]; + /** Source operands: GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, etc */ + GLenum OperandRGB[MAX_COMBINER_TERMS]; + GLenum OperandA[MAX_COMBINER_TERMS]; + GLuint ScaleShiftRGB; /**< 0, 1 or 2 */ + GLuint ScaleShiftA; /**< 0, 1 or 2 */ + GLuint _NumArgsRGB; /**< Number of inputs used for the RGB combiner */ + GLuint _NumArgsA; /**< Number of inputs used for the A combiner */ +}; + + +/** + * Texture coord generation state. + */ +struct gl_texgen +{ + GLenum Mode; /**< GL_EYE_LINEAR, GL_SPHERE_MAP, etc */ + GLbitfield _ModeBit; /**< TEXGEN_x bit corresponding to Mode */ + GLfloat ObjectPlane[4]; + GLfloat EyePlane[4]; +}; + + +/** + * Texture unit state. Contains enable flags, texture environment/function/ + * combiners, texgen state, pointers to current texture objects and + * post-filter color tables. + */ +struct gl_texture_unit +{ + GLbitfield Enabled; /**< bitmask of TEXTURE_*_BIT flags */ + GLbitfield _ReallyEnabled; /**< 0 or exactly one of TEXTURE_*_BIT flags */ + + GLenum EnvMode; /**< GL_MODULATE, GL_DECAL, GL_BLEND, etc. */ + GLfloat EnvColor[4]; + + struct gl_texgen GenS; + struct gl_texgen GenT; + struct gl_texgen GenR; + struct gl_texgen GenQ; + GLbitfield TexGenEnabled; /**< Bitwise-OR of [STRQ]_BIT values */ + GLbitfield _GenFlags; /**< Bitwise-OR of Gen[STRQ]._ModeBit */ + + GLfloat LodBias; /**< for biasing mipmap levels */ + GLenum BumpTarget; + GLfloat RotMatrix[4]; /* 2x2 matrix */ + + /** + * \name GL_EXT_texture_env_combine + */ + struct gl_tex_env_combine_state Combine; + + /** + * Derived state based on \c EnvMode and the \c BaseFormat of the + * currently enabled texture. + */ + struct gl_tex_env_combine_state _EnvMode; + + /** + * Currently enabled combiner state. This will point to either + * \c Combine or \c _EnvMode. + */ + struct gl_tex_env_combine_state *_CurrentCombine; + + /** Current texture object pointers */ + struct gl_texture_object *CurrentTex[NUM_TEXTURE_TARGETS]; + + /** Points to highest priority, complete and enabled texture object */ + struct gl_texture_object *_Current; +}; + + +/** + * Texture attribute group (GL_TEXTURE_BIT). + */ +struct gl_texture_attrib +{ + GLuint CurrentUnit; /**< GL_ACTIVE_TEXTURE */ + struct gl_texture_unit Unit[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; + + struct gl_texture_object *ProxyTex[NUM_TEXTURE_TARGETS]; + + /** GL_ARB_seamless_cubemap */ + GLboolean CubeMapSeamless; + + /** GL_EXT_shared_texture_palette */ + GLboolean SharedPalette; + struct gl_color_table Palette; + + /** Texture units/samplers used by vertex or fragment texturing */ + GLbitfield _EnabledUnits; + + /** Texture coord units/sets used for fragment texturing */ + GLbitfield _EnabledCoordUnits; + + /** Texture coord units that have texgen enabled */ + GLbitfield _TexGenEnabled; + + /** Texture coord units that have non-identity matrices */ + GLbitfield _TexMatEnabled; + + /** Bitwise-OR of all Texture.Unit[i]._GenFlags */ + GLbitfield _GenFlags; +}; + + +/** + * Transformation attribute group (GL_TRANSFORM_BIT). + */ +struct gl_transform_attrib +{ + GLenum MatrixMode; /**< Matrix mode */ + GLfloat EyeUserPlane[MAX_CLIP_PLANES][4]; /**< User clip planes */ + GLfloat _ClipUserPlane[MAX_CLIP_PLANES][4]; /**< derived */ + GLbitfield ClipPlanesEnabled; /**< on/off bitmask */ + GLboolean Normalize; /**< Normalize all normals? */ + GLboolean RescaleNormals; /**< GL_EXT_rescale_normal */ + GLboolean RasterPositionUnclipped; /**< GL_IBM_rasterpos_clip */ + GLboolean DepthClamp; /**< GL_ARB_depth_clamp */ + + GLfloat CullEyePos[4]; + GLfloat CullObjPos[4]; +}; + + +/** + * Viewport attribute group (GL_VIEWPORT_BIT). + */ +struct gl_viewport_attrib +{ + GLint X, Y; /**< position */ + GLsizei Width, Height; /**< size */ + GLfloat Near, Far; /**< Depth buffer range */ + GLmatrix _WindowMap; /**< Mapping transformation as a matrix. */ +}; + + +/** + * GL_ARB_vertex/pixel_buffer_object buffer object + */ +struct gl_buffer_object +{ + _glthread_Mutex Mutex; + GLint RefCount; + GLuint Name; + GLenum Usage; /**< GL_STREAM_DRAW_ARB, GL_STREAM_READ_ARB, etc. */ + GLsizeiptrARB Size; /**< Size of buffer storage in bytes */ + GLubyte *Data; /**< Location of storage either in RAM or VRAM. */ + /** Fields describing a mapped buffer */ + /*@{*/ + GLbitfield AccessFlags; /**< Mask of GL_MAP_x_BIT flags */ + GLvoid *Pointer; /**< User-space address of mapping */ + GLintptr Offset; /**< Mapped offset */ + GLsizeiptr Length; /**< Mapped length */ + /*@}*/ + GLboolean Written; /**< Ever written to? (for debugging) */ + GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */ +}; + + +/** + * Client pixel packing/unpacking attributes + */ +struct gl_pixelstore_attrib +{ + GLint Alignment; + GLint RowLength; + GLint SkipPixels; + GLint SkipRows; + GLint ImageHeight; + GLint SkipImages; + GLboolean SwapBytes; + GLboolean LsbFirst; + GLboolean ClientStorage; /**< GL_APPLE_client_storage */ + GLboolean Invert; /**< GL_MESA_pack_invert */ + struct gl_buffer_object *BufferObj; /**< GL_ARB_pixel_buffer_object */ +}; + + +/** + * Client vertex array attributes + */ +struct gl_client_array +{ + GLint Size; /**< components per element (1,2,3,4) */ + GLenum Type; /**< datatype: GL_FLOAT, GL_INT, etc */ + GLenum Format; /**< default: GL_RGBA, but may be GL_BGRA */ + GLsizei Stride; /**< user-specified stride */ + GLsizei StrideB; /**< actual stride in bytes */ + const GLubyte *Ptr; /**< Points to array data */ + GLboolean Enabled; /**< Enabled flag is a boolean */ + GLboolean Normalized; /**< GL_ARB_vertex_program */ + GLboolean Integer; /**< Integer-valued? */ + GLuint InstanceDivisor; /**< GL_ARB_instanced_arrays */ + GLuint _ElementSize; /**< size of each element in bytes */ + + struct gl_buffer_object *BufferObj;/**< GL_ARB_vertex_buffer_object */ + GLuint _MaxElement; /**< max element index into array buffer + 1 */ +}; + + +/** + * Collection of vertex arrays. Defined by the GL_APPLE_vertex_array_object + * extension, but a nice encapsulation in any case. + */ +struct gl_array_object +{ + /** Name of the array object as received from glGenVertexArrayAPPLE. */ + GLuint Name; + + GLint RefCount; + _glthread_Mutex Mutex; + GLboolean VBOonly; /**< require all arrays to live in VBOs? */ + + /** Conventional vertex arrays */ + /*@{*/ + struct gl_client_array Vertex; + struct gl_client_array Weight; + struct gl_client_array Normal; + struct gl_client_array Color; + struct gl_client_array SecondaryColor; + struct gl_client_array FogCoord; + struct gl_client_array Index; + struct gl_client_array EdgeFlag; + struct gl_client_array TexCoord[MAX_TEXTURE_COORD_UNITS]; + struct gl_client_array PointSize; + /*@}*/ + + /** + * Generic arrays for vertex programs/shaders. + * For NV vertex programs, these attributes alias and take priority + * over the conventional attribs above. For ARB vertex programs and + * GLSL vertex shaders, these attributes are separate. + */ + struct gl_client_array VertexAttrib[MAX_VERTEX_GENERIC_ATTRIBS]; + + /** Mask of _NEW_ARRAY_* values indicating which arrays are enabled */ + GLbitfield _Enabled; + + /** + * Min of all enabled arrays' _MaxElement. When arrays reside inside VBOs + * we can determine the max legal (in bounds) glDrawElements array index. + */ + GLuint _MaxElement; +}; + + +/** + * Vertex array state + */ +struct gl_array_attrib +{ + /** Currently bound array object. See _mesa_BindVertexArrayAPPLE() */ + struct gl_array_object *ArrayObj; + + /** The default vertex array object */ + struct gl_array_object *DefaultArrayObj; + + /** Array objects (GL_ARB/APPLE_vertex_array_object) */ + struct _mesa_HashTable *Objects; + + GLint ActiveTexture; /**< Client Active Texture */ + GLuint LockFirst; /**< GL_EXT_compiled_vertex_array */ + GLuint LockCount; /**< GL_EXT_compiled_vertex_array */ + + /** GL 3.1 (slightly different from GL_NV_primitive_restart) */ + GLboolean PrimitiveRestart; + GLuint RestartIndex; + + GLbitfield NewState; /**< mask of _NEW_ARRAY_* values */ + GLboolean RebindArrays; /**< whether the VBO module should rebind arrays */ + + /* GL_ARB_vertex_buffer_object */ + struct gl_buffer_object *ArrayBufferObj; + struct gl_buffer_object *ElementArrayBufferObj; +}; + + +/** + * Feedback buffer state + */ +struct gl_feedback +{ + GLenum Type; + GLbitfield _Mask; /**< FB_* bits */ + GLfloat *Buffer; + GLuint BufferSize; + GLuint Count; +}; + + +/** + * Selection buffer state + */ +struct gl_selection +{ + GLuint *Buffer; /**< selection buffer */ + GLuint BufferSize; /**< size of the selection buffer */ + GLuint BufferCount; /**< number of values in the selection buffer */ + GLuint Hits; /**< number of records in the selection buffer */ + GLuint NameStackDepth; /**< name stack depth */ + GLuint NameStack[MAX_NAME_STACK_DEPTH]; /**< name stack */ + GLboolean HitFlag; /**< hit flag */ + GLfloat HitMinZ; /**< minimum hit depth */ + GLfloat HitMaxZ; /**< maximum hit depth */ +}; + + +/** + * 1-D Evaluator control points + */ +struct gl_1d_map +{ + GLuint Order; /**< Number of control points */ + GLfloat u1, u2, du; /**< u1, u2, 1.0/(u2-u1) */ + GLfloat *Points; /**< Points to contiguous control points */ +}; + + +/** + * 2-D Evaluator control points + */ +struct gl_2d_map +{ + GLuint Uorder; /**< Number of control points in U dimension */ + GLuint Vorder; /**< Number of control points in V dimension */ + GLfloat u1, u2, du; + GLfloat v1, v2, dv; + GLfloat *Points; /**< Points to contiguous control points */ +}; + + +/** + * All evaluator control point state + */ +struct gl_evaluators +{ + /** + * \name 1-D maps + */ + /*@{*/ + struct gl_1d_map Map1Vertex3; + struct gl_1d_map Map1Vertex4; + struct gl_1d_map Map1Index; + struct gl_1d_map Map1Color4; + struct gl_1d_map Map1Normal; + struct gl_1d_map Map1Texture1; + struct gl_1d_map Map1Texture2; + struct gl_1d_map Map1Texture3; + struct gl_1d_map Map1Texture4; + struct gl_1d_map Map1Attrib[16]; /**< GL_NV_vertex_program */ + /*@}*/ + + /** + * \name 2-D maps + */ + /*@{*/ + struct gl_2d_map Map2Vertex3; + struct gl_2d_map Map2Vertex4; + struct gl_2d_map Map2Index; + struct gl_2d_map Map2Color4; + struct gl_2d_map Map2Normal; + struct gl_2d_map Map2Texture1; + struct gl_2d_map Map2Texture2; + struct gl_2d_map Map2Texture3; + struct gl_2d_map Map2Texture4; + struct gl_2d_map Map2Attrib[16]; /**< GL_NV_vertex_program */ + /*@}*/ +}; + + +/** + * Names of the various vertex/fragment program register files, etc. + * + * NOTE: first four tokens must fit into 2 bits (see t_vb_arbprogram.c) + * All values should fit in a 4-bit field. + * + * NOTE: PROGRAM_ENV_PARAM, PROGRAM_STATE_VAR, PROGRAM_NAMED_PARAM, + * PROGRAM_CONSTANT, and PROGRAM_UNIFORM can all be considered to + * be "uniform" variables since they can only be set outside glBegin/End. + * They're also all stored in the same Parameters array. + */ +typedef enum +{ + PROGRAM_TEMPORARY, /**< machine->Temporary[] */ + PROGRAM_INPUT, /**< machine->Inputs[] */ + PROGRAM_OUTPUT, /**< machine->Outputs[] */ + PROGRAM_VARYING, /**< machine->Inputs[]/Outputs[] */ + PROGRAM_LOCAL_PARAM, /**< gl_program->LocalParams[] */ + PROGRAM_ENV_PARAM, /**< gl_program->Parameters[] */ + PROGRAM_STATE_VAR, /**< gl_program->Parameters[] */ + PROGRAM_NAMED_PARAM, /**< gl_program->Parameters[] */ + PROGRAM_CONSTANT, /**< gl_program->Parameters[] */ + PROGRAM_UNIFORM, /**< gl_program->Parameters[] */ + PROGRAM_WRITE_ONLY, /**< A dummy, write-only register */ + PROGRAM_ADDRESS, /**< machine->AddressReg */ + PROGRAM_SAMPLER, /**< for shader samplers, compile-time only */ + PROGRAM_SYSTEM_VALUE,/**< InstanceId, PrimitiveID, etc. */ + PROGRAM_UNDEFINED, /**< Invalid/TBD value */ + PROGRAM_FILE_MAX +} gl_register_file; + + +/** + * If the register file is PROGRAM_SYSTEM_VALUE, the register index will be + * one of these values. + */ +typedef enum +{ + SYSTEM_VALUE_FRONT_FACE, /**< Fragment shader only (not done yet) */ + SYSTEM_VALUE_INSTANCE_ID, /**< Vertex shader only */ + SYSTEM_VALUE_MAX /**< Number of values */ +} gl_system_value; + + +/** Vertex and fragment instructions */ +struct prog_instruction; +struct gl_program_parameter_list; +struct gl_uniform_list; + + +/** + * Base class for any kind of program object + */ +struct gl_program +{ + GLuint Id; + GLubyte *String; /**< Null-terminated program text */ + GLint RefCount; + GLenum Target; /**< GL_VERTEX/FRAGMENT_PROGRAM_ARB, GL_FRAGMENT_PROGRAM_NV */ + GLenum Format; /**< String encoding format */ + GLboolean Resident; + + struct prog_instruction *Instructions; + + GLbitfield InputsRead; /**< Bitmask of which input regs are read */ + GLbitfield64 OutputsWritten; /**< Bitmask of which output regs are written */ + GLbitfield SystemValuesRead; /**< Bitmask of SYSTEM_VALUE_x inputs used */ + GLbitfield InputFlags[MAX_PROGRAM_INPUTS]; /**< PROG_PARAM_BIT_x flags */ + GLbitfield OutputFlags[MAX_PROGRAM_OUTPUTS]; /**< PROG_PARAM_BIT_x flags */ + GLbitfield TexturesUsed[MAX_TEXTURE_UNITS]; /**< TEXTURE_x_BIT bitmask */ + GLbitfield SamplersUsed; /**< Bitfield of which samplers are used */ + GLbitfield ShadowSamplers; /**< Texture units used for shadow sampling. */ + + + /** Named parameters, constants, etc. from program text */ + struct gl_program_parameter_list *Parameters; + /** Numbered local parameters */ + GLfloat LocalParams[MAX_PROGRAM_LOCAL_PARAMS][4]; + + /** Vertex/fragment shader varying vars */ + struct gl_program_parameter_list *Varying; + /** Vertex program user-defined attributes */ + struct gl_program_parameter_list *Attributes; + + /** Map from sampler unit to texture unit (set by glUniform1i()) */ + GLubyte SamplerUnits[MAX_SAMPLERS]; + /** Which texture target is being sampled (TEXTURE_1D/2D/3D/etc_INDEX) */ + gl_texture_index SamplerTargets[MAX_SAMPLERS]; + + /** Bitmask of which register files are read/written with indirect + * addressing. Mask of (1 << PROGRAM_x) bits. + */ + GLbitfield IndirectRegisterFiles; + + /** Logical counts */ + /*@{*/ + GLuint NumInstructions; + GLuint NumTemporaries; + GLuint NumParameters; + GLuint NumAttributes; + GLuint NumAddressRegs; + GLuint NumAluInstructions; + GLuint NumTexInstructions; + GLuint NumTexIndirections; + /*@}*/ + /** Native, actual h/w counts */ + /*@{*/ + GLuint NumNativeInstructions; + GLuint NumNativeTemporaries; + GLuint NumNativeParameters; + GLuint NumNativeAttributes; + GLuint NumNativeAddressRegs; + GLuint NumNativeAluInstructions; + GLuint NumNativeTexInstructions; + GLuint NumNativeTexIndirections; + /*@}*/ +}; + + +/** Vertex program object */ +struct gl_vertex_program +{ + struct gl_program Base; /**< base class */ + GLboolean IsNVProgram; /**< is this a GL_NV_vertex_program program? */ + GLboolean IsPositionInvariant; +}; + + +/** Geometry program object */ +struct gl_geometry_program +{ + struct gl_program Base; /**< base class */ + + GLint VerticesOut; + GLenum InputType; /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB, + GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */ + GLenum OutputType; /**< GL_POINTS, GL_LINE_STRIP or GL_TRIANGLE_STRIP */ +}; + + +/** Fragment program object */ +struct gl_fragment_program +{ + struct gl_program Base; /**< base class */ + GLenum FogOption; + GLboolean UsesKill; /**< shader uses KIL instruction */ + GLboolean OriginUpperLeft; + GLboolean PixelCenterInteger; + enum gl_frag_depth_layout FragDepthLayout; +}; + + +/** + * State common to vertex and fragment programs. + */ +struct gl_program_state +{ + GLint ErrorPos; /* GL_PROGRAM_ERROR_POSITION_ARB/NV */ + const char *ErrorString; /* GL_PROGRAM_ERROR_STRING_ARB/NV */ +}; + + +/** + * Context state for vertex programs. + */ +struct gl_vertex_program_state +{ + GLboolean Enabled; /**< User-set GL_VERTEX_PROGRAM_ARB/NV flag */ + GLboolean _Enabled; /**< Enabled and _valid_ user program? */ + GLboolean PointSizeEnabled; /**< GL_VERTEX_PROGRAM_POINT_SIZE_ARB/NV */ + GLboolean TwoSideEnabled; /**< GL_VERTEX_PROGRAM_TWO_SIDE_ARB/NV */ + struct gl_vertex_program *Current; /**< User-bound vertex program */ + + /** Currently enabled and valid vertex program (including internal + * programs, user-defined vertex programs and GLSL vertex shaders). + * This is the program we must use when rendering. + */ + struct gl_vertex_program *_Current; + + GLfloat Parameters[MAX_PROGRAM_ENV_PARAMS][4]; /**< Env params */ + + /* For GL_NV_vertex_program only: */ + GLenum TrackMatrix[MAX_PROGRAM_ENV_PARAMS / 4]; + GLenum TrackMatrixTransform[MAX_PROGRAM_ENV_PARAMS / 4]; + + /** Should fixed-function T&L be implemented with a vertex prog? */ + GLboolean _MaintainTnlProgram; + + /** Program to emulate fixed-function T&L (see above) */ + struct gl_vertex_program *_TnlProgram; + + /** Cache of fixed-function programs */ + struct gl_program_cache *Cache; + + GLboolean _Overriden; +}; + + +/** + * Context state for geometry programs. + */ +struct gl_geometry_program_state +{ + GLboolean Enabled; /**< GL_ARB_GEOMETRY_SHADER4 */ + GLboolean _Enabled; /**< Enabled and valid program? */ + struct gl_geometry_program *Current; /**< user-bound geometry program */ + + /** Currently enabled and valid program (including internal programs + * and compiled shader programs). + */ + struct gl_geometry_program *_Current; + + GLfloat Parameters[MAX_PROGRAM_ENV_PARAMS][4]; /**< Env params */ + + /** Cache of fixed-function programs */ + struct gl_program_cache *Cache; +}; + +/** + * Context state for fragment programs. + */ +struct gl_fragment_program_state +{ + GLboolean Enabled; /**< User-set fragment program enable flag */ + GLboolean _Enabled; /**< Enabled and _valid_ user program? */ + struct gl_fragment_program *Current; /**< User-bound fragment program */ + + /** Currently enabled and valid fragment program (including internal + * programs, user-defined fragment programs and GLSL fragment shaders). + * This is the program we must use when rendering. + */ + struct gl_fragment_program *_Current; + + GLfloat Parameters[MAX_PROGRAM_ENV_PARAMS][4]; /**< Env params */ + + /** Should fixed-function texturing be implemented with a fragment prog? */ + GLboolean _MaintainTexEnvProgram; + + /** Program to emulate fixed-function texture env/combine (see above) */ + struct gl_fragment_program *_TexEnvProgram; + + /** Cache of fixed-function programs */ + struct gl_program_cache *Cache; +}; + + +/** + * ATI_fragment_shader runtime state + */ +#define ATI_FS_INPUT_PRIMARY 0 +#define ATI_FS_INPUT_SECONDARY 1 + +struct atifs_instruction; +struct atifs_setupinst; + +/** + * ATI fragment shader + */ +struct ati_fragment_shader +{ + GLuint Id; + GLint RefCount; + struct atifs_instruction *Instructions[2]; + struct atifs_setupinst *SetupInst[2]; + GLfloat Constants[8][4]; + GLbitfield LocalConstDef; /**< Indicates which constants have been set */ + GLubyte numArithInstr[2]; + GLubyte regsAssigned[2]; + GLubyte NumPasses; /**< 1 or 2 */ + GLubyte cur_pass; + GLubyte last_optype; + GLboolean interpinp1; + GLboolean isValid; + GLuint swizzlerq; +}; + +/** + * Context state for GL_ATI_fragment_shader + */ +struct gl_ati_fragment_shader_state +{ + GLboolean Enabled; + GLboolean _Enabled; /**< enabled and valid shader? */ + GLboolean Compiling; + GLfloat GlobalConstants[8][4]; + struct ati_fragment_shader *Current; +}; + + +/** + * Occlusion/timer query object. + */ +struct gl_query_object +{ + GLenum Target; /**< The query target, when active */ + GLuint Id; /**< hash table ID/name */ + GLuint64EXT Result; /**< the counter */ + GLboolean Active; /**< inside Begin/EndQuery */ + GLboolean Ready; /**< result is ready? */ +}; + + +/** + * Context state for query objects. + */ +struct gl_query_state +{ + struct _mesa_HashTable *QueryObjects; + struct gl_query_object *CurrentOcclusionObject; /* GL_ARB_occlusion_query */ + struct gl_query_object *CurrentTimerObject; /* GL_EXT_timer_query */ + + /** GL_NV_conditional_render */ + struct gl_query_object *CondRenderQuery; + + /** GL_EXT_transform_feedback */ + struct gl_query_object *PrimitivesGenerated; + struct gl_query_object *PrimitivesWritten; + + /** GL_ARB_timer_query */ + struct gl_query_object *TimeElapsed; + + GLenum CondRenderMode; +}; + + +/** Sync object state */ +struct gl_sync_object { + struct simple_node link; + GLenum Type; /**< GL_SYNC_FENCE */ + GLuint Name; /**< Fence name */ + GLint RefCount; /**< Reference count */ + GLboolean DeletePending; /**< Object was deleted while there were still + * live references (e.g., sync not yet finished) + */ + GLenum SyncCondition; + GLbitfield Flags; /**< Flags passed to glFenceSync */ + GLuint StatusFlag:1; /**< Has the sync object been signaled? */ +}; + + +/** Set by #pragma directives */ +struct gl_sl_pragmas +{ + GLboolean IgnoreOptimize; /**< ignore #pragma optimize(on/off) ? */ + GLboolean IgnoreDebug; /**< ignore #pragma debug(on/off) ? */ + GLboolean Optimize; /**< defaults on */ + GLboolean Debug; /**< defaults off */ +}; + + +/** + * A GLSL vertex or fragment shader object. + */ +struct gl_shader +{ + GLenum Type; /**< GL_FRAGMENT_SHADER || GL_VERTEX_SHADER || GL_GEOMETRY_SHADER_ARB (first field!) */ + GLuint Name; /**< AKA the handle */ + GLint RefCount; /**< Reference count */ + GLboolean DeletePending; + GLboolean CompileStatus; + const GLchar *Source; /**< Source code string */ + GLuint SourceChecksum; /**< for debug/logging purposes */ + struct gl_program *Program; /**< Post-compile assembly code */ + GLchar *InfoLog; + struct gl_sl_pragmas Pragmas; + + unsigned Version; /**< GLSL version used for linking */ + + struct exec_list *ir; + struct glsl_symbol_table *symbols; + + /** Shaders containing built-in functions that are used for linking. */ + struct gl_shader *builtins_to_link[16]; + unsigned num_builtins_to_link; +}; + + +/** + * A GLSL program object. + * Basically a linked collection of vertex and fragment shaders. + */ +struct gl_shader_program +{ + GLenum Type; /**< Always GL_SHADER_PROGRAM (internal token) */ + GLuint Name; /**< aka handle or ID */ + GLint RefCount; /**< Reference count */ + GLboolean DeletePending; + + GLuint NumShaders; /**< number of attached shaders */ + struct gl_shader **Shaders; /**< List of attached the shaders */ + + /** User-defined attribute bindings (glBindAttribLocation) */ + struct gl_program_parameter_list *Attributes; + + /** Transform feedback varyings */ + struct { + GLenum BufferMode; + GLuint NumVarying; + GLchar **VaryingNames; /**< Array [NumVarying] of char * */ + } TransformFeedback; + + /** Geometry shader state - copied into gl_geometry_program at link time */ + struct { + GLint VerticesOut; + GLenum InputType; /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB, + GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */ + GLenum OutputType; /**< GL_POINTS, GL_LINE_STRIP or GL_TRIANGLE_STRIP */ + } Geom; + + /* post-link info: */ + struct gl_vertex_program *VertexProgram; /**< Linked vertex program */ + struct gl_fragment_program *FragmentProgram; /**< Linked fragment prog */ + struct gl_geometry_program *GeometryProgram; /**< Linked geometry prog */ + struct gl_uniform_list *Uniforms; + struct gl_program_parameter_list *Varying; + GLboolean LinkStatus; /**< GL_LINK_STATUS */ + GLboolean Validated; + GLboolean _Used; /**< Ever used for drawing? */ + GLchar *InfoLog; + + unsigned Version; /**< GLSL version used for linking */ + + /** + * Per-stage shaders resulting from the first stage of linking. + * + * Set of linked shaders for this program. The array is accessed using the + * \c MESA_SHADER_* defines. Entries for non-existent stages will be + * \c NULL. + */ + struct gl_shader *_LinkedShaders[MESA_SHADER_TYPES]; +}; + + +#define GLSL_DUMP 0x1 /**< Dump shaders to stdout */ +#define GLSL_LOG 0x2 /**< Write shaders to files */ +#define GLSL_OPT 0x4 /**< Force optimizations (override pragmas) */ +#define GLSL_NO_OPT 0x8 /**< Force no optimizations (override pragmas) */ +#define GLSL_UNIFORMS 0x10 /**< Print glUniform calls */ +#define GLSL_NOP_VERT 0x20 /**< Force no-op vertex shaders */ +#define GLSL_NOP_FRAG 0x40 /**< Force no-op fragment shaders */ +#define GLSL_USE_PROG 0x80 /**< Log glUseProgram calls */ + + +/** + * Context state for GLSL vertex/fragment shaders. + */ +struct gl_shader_state +{ + /** + * Programs used for rendering + * + * There is a separate program set for each shader stage. If + * GL_EXT_separate_shader_objects is not supported, each of these must point + * to \c NULL or to the same program. + */ + struct gl_shader_program *CurrentVertexProgram; + struct gl_shader_program *CurrentGeometryProgram; + struct gl_shader_program *CurrentFragmentProgram; + + /** + * Program used by glUniform calls. + * + * Explicitly set by \c glUseProgram and \c glActiveProgramEXT. + */ + struct gl_shader_program *ActiveProgram; + + void *MemPool; + + GLbitfield Flags; /**< Mask of GLSL_x flags */ +}; + +/** + * Compiler options for a single GLSL shaders type + */ +struct gl_shader_compiler_options +{ + /** Driver-selectable options: */ + GLboolean EmitCondCodes; /**< Use condition codes? */ + GLboolean EmitNVTempInitialization; /**< 0-fill NV temp registers */ + /** + * Attempts to flatten all ir_if (OPCODE_IF) for GPUs that can't + * support control flow. + */ + GLboolean EmitNoIfs; + GLboolean EmitNoLoops; + GLboolean EmitNoFunctions; + GLboolean EmitNoCont; /**< Emit CONT opcode? */ + GLboolean EmitNoMainReturn; /**< Emit CONT/RET opcodes? */ + GLboolean EmitNoNoise; /**< Emit NOISE opcodes? */ + GLboolean EmitNoPow; /**< Emit POW opcodes? */ + + /** + * \name Forms of indirect addressing the driver cannot do. + */ + /*@{*/ + GLboolean EmitNoIndirectInput; /**< No indirect addressing of inputs */ + GLboolean EmitNoIndirectOutput; /**< No indirect addressing of outputs */ + GLboolean EmitNoIndirectTemp; /**< No indirect addressing of temps */ + GLboolean EmitNoIndirectUniform; /**< No indirect addressing of constants */ + /*@}*/ + + GLuint MaxUnrollIterations; + + struct gl_sl_pragmas DefaultPragmas; /**< Default #pragma settings */ +}; + +/** + * Transform feedback object state + */ +struct gl_transform_feedback_object +{ + GLuint Name; /**< AKA the object ID */ + GLint RefCount; + GLboolean Active; /**< Is transform feedback enabled? */ + GLboolean Paused; /**< Is transform feedback paused? */ + + /** The feedback buffers */ + GLuint BufferNames[MAX_FEEDBACK_ATTRIBS]; + struct gl_buffer_object *Buffers[MAX_FEEDBACK_ATTRIBS]; + + /** Start of feedback data in dest buffer */ + GLintptr Offset[MAX_FEEDBACK_ATTRIBS]; + /** Max data to put into dest buffer (in bytes) */ + GLsizeiptr Size[MAX_FEEDBACK_ATTRIBS]; +}; + + +/** + * Context state for transform feedback. + */ +struct gl_transform_feedback +{ + GLenum Mode; /**< GL_POINTS, GL_LINES or GL_TRIANGLES */ + + GLboolean RasterDiscard; /**< GL_RASTERIZER_DISCARD */ + + /** The general binding point (GL_TRANSFORM_FEEDBACK_BUFFER) */ + struct gl_buffer_object *CurrentBuffer; + + /** The table of all transform feedback objects */ + struct _mesa_HashTable *Objects; + + /** The current xform-fb object (GL_TRANSFORM_FEEDBACK_BINDING) */ + struct gl_transform_feedback_object *CurrentObject; + + /** The default xform-fb object (Name==0) */ + struct gl_transform_feedback_object *DefaultObject; +}; + + + +/** + * State which can be shared by multiple contexts: + */ +struct gl_shared_state +{ + _glthread_Mutex Mutex; /**< for thread safety */ + GLint RefCount; /**< Reference count */ + struct _mesa_HashTable *DisplayList; /**< Display lists hash table */ + struct _mesa_HashTable *TexObjects; /**< Texture objects hash table */ + + /** Default texture objects (shared by all texture units) */ + struct gl_texture_object *DefaultTex[NUM_TEXTURE_TARGETS]; + + /** Fallback texture used when a bound texture is incomplete */ + struct gl_texture_object *FallbackTex; + + /** + * \name Thread safety and statechange notification for texture + * objects. + * + * \todo Improve the granularity of locking. + */ + /*@{*/ + _glthread_Mutex TexMutex; /**< texobj thread safety */ + GLuint TextureStateStamp; /**< state notification for shared tex */ + /*@}*/ + + /** Default buffer object for vertex arrays that aren't in VBOs */ + struct gl_buffer_object *NullBufferObj; + + /** + * \name Vertex/geometry/fragment programs + */ + /*@{*/ + struct _mesa_HashTable *Programs; /**< All vertex/fragment programs */ + struct gl_vertex_program *DefaultVertexProgram; + struct gl_fragment_program *DefaultFragmentProgram; + struct gl_geometry_program *DefaultGeometryProgram; + /*@}*/ + + /* GL_ATI_fragment_shader */ + struct _mesa_HashTable *ATIShaders; + struct ati_fragment_shader *DefaultFragmentShader; + + struct _mesa_HashTable *BufferObjects; + + /** Table of both gl_shader and gl_shader_program objects */ + struct _mesa_HashTable *ShaderObjects; + + /* GL_EXT_framebuffer_object */ + struct _mesa_HashTable *RenderBuffers; + struct _mesa_HashTable *FrameBuffers; + + /* GL_ARB_sync */ + struct simple_node SyncObjects; + + void *DriverData; /**< Device driver shared state */ +}; + + + + +/** + * A renderbuffer stores colors or depth values or stencil values. + * A framebuffer object will have a collection of these. + * Data are read/written to the buffer with a handful of Get/Put functions. + * + * Instances of this object are allocated with the Driver's NewRenderbuffer + * hook. Drivers will likely wrap this class inside a driver-specific + * class to simulate inheritance. + */ +struct gl_renderbuffer +{ +#define RB_MAGIC 0xaabbccdd + int Magic; /** XXX TEMPORARY DEBUG INFO */ + _glthread_Mutex Mutex; /**< for thread safety */ + GLuint ClassID; /**< Useful for drivers */ + GLuint Name; + GLint RefCount; + GLuint Width, Height; + GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */ + + GLenum InternalFormat; /**< The user-specified format */ + GLenum _BaseFormat; /**< Either GL_RGB, GL_RGBA, GL_DEPTH_COMPONENT or + GL_STENCIL_INDEX. */ + gl_format Format; /**< The actual renderbuffer memory format */ + + GLubyte NumSamples; + + GLenum DataType; /**< Type of values passed to the Get/Put functions */ + GLvoid *Data; /**< This may not be used by some kinds of RBs */ + + /* Used to wrap one renderbuffer around another: */ + struct gl_renderbuffer *Wrapped; + + /* Delete this renderbuffer */ + void (*Delete)(struct gl_renderbuffer *rb); + + /* Allocate new storage for this renderbuffer */ + GLboolean (*AllocStorage)(struct gl_context *ctx, struct gl_renderbuffer *rb, + GLenum internalFormat, + GLuint width, GLuint height); + + /* Lock/Unlock are called before/after calling the Get/Put functions. + * Not sure this is the right place for these yet. + void (*Lock)(struct gl_context *ctx, struct gl_renderbuffer *rb); + void (*Unlock)(struct gl_context *ctx, struct gl_renderbuffer *rb); + */ + + /* Return a pointer to the element/pixel at (x,y). + * Should return NULL if the buffer memory can't be directly addressed. + */ + void *(*GetPointer)(struct gl_context *ctx, struct gl_renderbuffer *rb, + GLint x, GLint y); + + /* Get/Read a row of values. + * The values will be of format _BaseFormat and type DataType. + */ + void (*GetRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, void *values); + + /* Get/Read values at arbitrary locations. + * The values will be of format _BaseFormat and type DataType. + */ + void (*GetValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], void *values); + + /* Put/Write a row of values. + * The values will be of format _BaseFormat and type DataType. + */ + void (*PutRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask); + + /* Put/Write a row of RGB values. This is a special-case routine that's + * only used for RGBA renderbuffers when the source data is GL_RGB. That's + * a common case for glDrawPixels and some triangle routines. + * The values will be of format GL_RGB and type DataType. + */ + void (*PutRowRGB)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *values, const GLubyte *mask); + + + /* Put/Write a row of identical values. + * The values will be of format _BaseFormat and type DataType. + */ + void (*PutMonoRow)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, + GLint x, GLint y, const void *value, const GLubyte *mask); + + /* Put/Write values at arbitrary locations. + * The values will be of format _BaseFormat and type DataType. + */ + void (*PutValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, + const GLint x[], const GLint y[], const void *values, + const GLubyte *mask); + /* Put/Write identical values at arbitrary locations. + * The values will be of format _BaseFormat and type DataType. + */ + void (*PutMonoValues)(struct gl_context *ctx, struct gl_renderbuffer *rb, + GLuint count, const GLint x[], const GLint y[], + const void *value, const GLubyte *mask); +}; + + +/** + * A renderbuffer attachment points to either a texture object (and specifies + * a mipmap level, cube face or 3D texture slice) or points to a renderbuffer. + */ +struct gl_renderbuffer_attachment +{ + GLenum Type; /**< \c GL_NONE or \c GL_TEXTURE or \c GL_RENDERBUFFER_EXT */ + GLboolean Complete; + + /** + * If \c Type is \c GL_RENDERBUFFER_EXT, this stores a pointer to the + * application supplied renderbuffer object. + */ + struct gl_renderbuffer *Renderbuffer; + + /** + * If \c Type is \c GL_TEXTURE, this stores a pointer to the application + * supplied texture object. + */ + struct gl_texture_object *Texture; + GLuint TextureLevel; /**< Attached mipmap level. */ + GLuint CubeMapFace; /**< 0 .. 5, for cube map textures. */ + GLuint Zoffset; /**< Slice for 3D textures, or layer for both 1D + * and 2D array textures */ +}; + + +/** + * A framebuffer is a collection of renderbuffers (color, depth, stencil, etc). + * In C++ terms, think of this as a base class from which device drivers + * will make derived classes. + */ +struct gl_framebuffer +{ + _glthread_Mutex Mutex; /**< for thread safety */ + /** + * If zero, this is a window system framebuffer. If non-zero, this + * is a FBO framebuffer; note that for some devices (i.e. those with + * a natural pixel coordinate system for FBOs that differs from the + * OpenGL/Mesa coordinate system), this means that the viewport, + * polygon face orientation, and polygon stipple will have to be inverted. + */ + GLuint Name; + + GLint RefCount; + GLboolean DeletePending; + + /** + * The framebuffer's visual. Immutable if this is a window system buffer. + * Computed from attachments if user-made FBO. + */ + struct gl_config Visual; + + GLboolean Initialized; + + GLuint Width, Height; /**< size of frame buffer in pixels */ + + /** \name Drawing bounds (Intersection of buffer size and scissor box) */ + /*@{*/ + GLint _Xmin, _Xmax; /**< inclusive */ + GLint _Ymin, _Ymax; /**< exclusive */ + /*@}*/ + + /** \name Derived Z buffer stuff */ + /*@{*/ + GLuint _DepthMax; /**< Max depth buffer value */ + GLfloat _DepthMaxF; /**< Float max depth buffer value */ + GLfloat _MRD; /**< minimum resolvable difference in Z values */ + /*@}*/ + + /** One of the GL_FRAMEBUFFER_(IN)COMPLETE_* tokens */ + GLenum _Status; + + /** Integer color values */ + GLboolean _IntegerColor; + + /** Array of all renderbuffer attachments, indexed by BUFFER_* tokens. */ + struct gl_renderbuffer_attachment Attachment[BUFFER_COUNT]; + + /* In unextended OpenGL these vars are part of the GL_COLOR_BUFFER + * attribute group and GL_PIXEL attribute group, respectively. + */ + GLenum ColorDrawBuffer[MAX_DRAW_BUFFERS]; + GLenum ColorReadBuffer; + + /** Computed from ColorDraw/ReadBuffer above */ + GLuint _NumColorDrawBuffers; + GLint _ColorDrawBufferIndexes[MAX_DRAW_BUFFERS]; /**< BUFFER_x or -1 */ + GLint _ColorReadBufferIndex; /* -1 = None */ + struct gl_renderbuffer *_ColorDrawBuffers[MAX_DRAW_BUFFERS]; + struct gl_renderbuffer *_ColorReadBuffer; + + /** The Actual depth/stencil buffers to use. May be wrappers around the + * depth/stencil buffers attached above. */ + struct gl_renderbuffer *_DepthBuffer; + struct gl_renderbuffer *_StencilBuffer; + + /** Delete this framebuffer */ + void (*Delete)(struct gl_framebuffer *fb); +}; + + +/** + * Precision info for shader datatypes. See glGetShaderPrecisionFormat(). + */ +struct gl_precision +{ + GLushort RangeMin; /**< min value exponent */ + GLushort RangeMax; /**< max value exponent */ + GLushort Precision; /**< number of mantissa bits */ +}; + + +/** + * Limits for vertex and fragment programs/shaders. + */ +struct gl_program_constants +{ + /* logical limits */ + GLuint MaxInstructions; + GLuint MaxAluInstructions; + GLuint MaxTexInstructions; + GLuint MaxTexIndirections; + GLuint MaxAttribs; + GLuint MaxTemps; + GLuint MaxAddressRegs; + GLuint MaxParameters; + GLuint MaxLocalParams; + GLuint MaxEnvParams; + /* native/hardware limits */ + GLuint MaxNativeInstructions; + GLuint MaxNativeAluInstructions; + GLuint MaxNativeTexInstructions; + GLuint MaxNativeTexIndirections; + GLuint MaxNativeAttribs; + GLuint MaxNativeTemps; + GLuint MaxNativeAddressRegs; + GLuint MaxNativeParameters; + /* For shaders */ + GLuint MaxUniformComponents; + /* GL_ARB_geometry_shader4 */ + GLuint MaxGeometryTextureImageUnits; + GLuint MaxGeometryVaryingComponents; + GLuint MaxVertexVaryingComponents; + GLuint MaxGeometryUniformComponents; + GLuint MaxGeometryOutputVertices; + GLuint MaxGeometryTotalOutputComponents; + /* ES 2.0 and GL_ARB_ES2_compatibility */ + struct gl_precision LowFloat, MediumFloat, HighFloat; + struct gl_precision LowInt, MediumInt, HighInt; +}; + + +/** + * Constants which may be overridden by device driver during context creation + * but are never changed after that. + */ +struct gl_constants +{ + GLint MaxTextureMbytes; /**< Max memory per image, in MB */ + GLint MaxTextureLevels; /**< Max mipmap levels. */ + GLint Max3DTextureLevels; /**< Max mipmap levels for 3D textures */ + GLint MaxCubeTextureLevels; /**< Max mipmap levels for cube textures */ + GLint MaxArrayTextureLayers; /**< Max layers in array textures */ + GLint MaxTextureRectSize; /**< Max rectangle texture size, in pixes */ + GLuint MaxTextureCoordUnits; + GLuint MaxTextureImageUnits; + GLuint MaxVertexTextureImageUnits; + GLuint MaxCombinedTextureImageUnits; + GLuint MaxTextureUnits; /**< = MIN(CoordUnits, ImageUnits) */ + GLfloat MaxTextureMaxAnisotropy; /**< GL_EXT_texture_filter_anisotropic */ + GLfloat MaxTextureLodBias; /**< GL_EXT_texture_lod_bias */ + + GLuint MaxArrayLockSize; + + GLint SubPixelBits; + + GLfloat MinPointSize, MaxPointSize; /**< aliased */ + GLfloat MinPointSizeAA, MaxPointSizeAA; /**< antialiased */ + GLfloat PointSizeGranularity; + GLfloat MinLineWidth, MaxLineWidth; /**< aliased */ + GLfloat MinLineWidthAA, MaxLineWidthAA; /**< antialiased */ + GLfloat LineWidthGranularity; + + GLuint MaxColorTableSize; + + GLuint MaxClipPlanes; + GLuint MaxLights; + GLfloat MaxShininess; /**< GL_NV_light_max_exponent */ + GLfloat MaxSpotExponent; /**< GL_NV_light_max_exponent */ + + GLuint MaxViewportWidth, MaxViewportHeight; + + struct gl_program_constants VertexProgram; /**< GL_ARB_vertex_program */ + struct gl_program_constants FragmentProgram; /**< GL_ARB_fragment_program */ + struct gl_program_constants GeometryProgram; /**< GL_ARB_geometry_shader4 */ + GLuint MaxProgramMatrices; + GLuint MaxProgramMatrixStackDepth; + + /** vertex array / buffer object bounds checking */ + GLboolean CheckArrayBounds; + + GLuint MaxDrawBuffers; /**< GL_ARB_draw_buffers */ + + GLuint MaxColorAttachments; /**< GL_EXT_framebuffer_object */ + GLuint MaxRenderbufferSize; /**< GL_EXT_framebuffer_object */ + GLuint MaxSamples; /**< GL_ARB_framebuffer_object */ + + GLuint MaxVarying; /**< Number of float[4] varying parameters */ + + GLuint GLSLVersion; /**< GLSL version supported (ex: 120 = 1.20) */ + + /** Which texture units support GL_ATI_envmap_bumpmap as targets */ + GLbitfield SupportedBumpUnits; + + /** + * Maximum amount of time, measured in nanseconds, that the server can wait. + */ + GLuint64 MaxServerWaitTimeout; + + /** GL_EXT_provoking_vertex */ + GLboolean QuadsFollowProvokingVertexConvention; + + /** OpenGL version 3.0 */ + GLbitfield ContextFlags; /**< Ex: GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT */ + + /** OpenGL version 3.2 */ + GLbitfield ProfileMask; /**< Mask of CONTEXT_x_PROFILE_BIT */ + + /** GL_EXT_transform_feedback */ + GLuint MaxTransformFeedbackSeparateAttribs; + GLuint MaxTransformFeedbackSeparateComponents; + GLuint MaxTransformFeedbackInterleavedComponents; + + /** GL_EXT_gpu_shader4 */ + GLint MinProgramTexelOffset, MaxProgramTexelOffset; + + /* GL_EXT_framebuffer_sRGB */ + GLboolean sRGBCapable; /* can enable sRGB blend/update on FBOs */ +}; + + +/** + * Enable flag for each OpenGL extension. Different device drivers will + * enable different extensions at runtime. + */ +struct gl_extensions +{ + GLboolean dummy; /* don't remove this! */ + GLboolean dummy_true; /* Set true by _mesa_init_extensions(). */ + GLboolean dummy_false; /* Set false by _mesa_init_extensions(). */ + GLboolean ARB_ES2_compatibility; + GLboolean ARB_blend_func_extended; + GLboolean ARB_copy_buffer; + GLboolean ARB_depth_buffer_float; + GLboolean ARB_depth_clamp; + GLboolean ARB_depth_texture; + GLboolean ARB_draw_buffers; + GLboolean ARB_draw_buffers_blend; + GLboolean ARB_draw_elements_base_vertex; + GLboolean ARB_draw_instanced; + GLboolean ARB_fragment_coord_conventions; + GLboolean ARB_fragment_program; + GLboolean ARB_fragment_program_shadow; + GLboolean ARB_fragment_shader; + GLboolean ARB_framebuffer_object; + GLboolean ARB_explicit_attrib_location; + GLboolean ARB_geometry_shader4; + GLboolean ARB_half_float_pixel; + GLboolean ARB_half_float_vertex; + GLboolean ARB_instanced_arrays; + GLboolean ARB_map_buffer_range; + GLboolean ARB_multisample; + GLboolean ARB_multitexture; + GLboolean ARB_occlusion_query; + GLboolean ARB_occlusion_query2; + GLboolean ARB_point_sprite; + GLboolean ARB_sampler_objects; + GLboolean ARB_seamless_cube_map; + GLboolean ARB_shader_objects; + GLboolean ARB_shader_stencil_export; + GLboolean ARB_shading_language_100; + GLboolean ARB_shadow; + GLboolean ARB_shadow_ambient; + GLboolean ARB_sync; + GLboolean ARB_texture_border_clamp; + GLboolean ARB_texture_buffer_object; + GLboolean ARB_texture_compression; + GLboolean ARB_texture_compression_rgtc; + GLboolean ARB_texture_cube_map; + GLboolean ARB_texture_env_combine; + GLboolean ARB_texture_env_crossbar; + GLboolean ARB_texture_env_dot3; + GLboolean ARB_texture_float; + GLboolean ARB_texture_mirrored_repeat; + GLboolean ARB_texture_multisample; + GLboolean ARB_texture_non_power_of_two; + GLboolean ARB_texture_rg; + GLboolean ARB_texture_rgb10_a2ui; + GLboolean ARB_timer_query; + GLboolean ARB_transform_feedback2; + GLboolean ARB_transpose_matrix; + GLboolean ARB_uniform_buffer_object; + GLboolean ARB_vertex_array_object; + GLboolean ARB_vertex_buffer_object; + GLboolean ARB_vertex_program; + GLboolean ARB_vertex_shader; + GLboolean ARB_vertex_type_2_10_10_10_rev; + GLboolean ARB_window_pos; + GLboolean EXT_abgr; + GLboolean EXT_bgra; + GLboolean EXT_blend_color; + GLboolean EXT_blend_equation_separate; + GLboolean EXT_blend_func_separate; + GLboolean EXT_blend_logic_op; + GLboolean EXT_blend_minmax; + GLboolean EXT_blend_subtract; + GLboolean EXT_clip_volume_hint; + GLboolean EXT_compiled_vertex_array; + GLboolean EXT_copy_texture; + GLboolean EXT_depth_bounds_test; + GLboolean EXT_draw_buffers2; + GLboolean EXT_draw_range_elements; + GLboolean EXT_fog_coord; + GLboolean EXT_framebuffer_blit; + GLboolean EXT_framebuffer_multisample; + GLboolean EXT_framebuffer_object; + GLboolean EXT_framebuffer_sRGB; + GLboolean EXT_gpu_program_parameters; + GLboolean EXT_gpu_shader4; + GLboolean EXT_multi_draw_arrays; + GLboolean EXT_paletted_texture; + GLboolean EXT_packed_depth_stencil; + GLboolean EXT_packed_float; + GLboolean EXT_packed_pixels; + GLboolean EXT_pixel_buffer_object; + GLboolean EXT_point_parameters; + GLboolean EXT_polygon_offset; + GLboolean EXT_provoking_vertex; + GLboolean EXT_rescale_normal; + GLboolean EXT_shadow_funcs; + GLboolean EXT_secondary_color; + GLboolean EXT_separate_shader_objects; + GLboolean EXT_separate_specular_color; + GLboolean EXT_shared_texture_palette; + GLboolean EXT_stencil_wrap; + GLboolean EXT_stencil_two_side; + GLboolean EXT_subtexture; + GLboolean EXT_texture; + GLboolean EXT_texture_object; + GLboolean EXT_texture3D; + GLboolean EXT_texture_array; + GLboolean EXT_texture_compression_s3tc; + GLboolean EXT_texture_env_add; + GLboolean EXT_texture_env_combine; + GLboolean EXT_texture_env_dot3; + GLboolean EXT_texture_filter_anisotropic; + GLboolean EXT_texture_integer; + GLboolean EXT_texture_lod_bias; + GLboolean EXT_texture_mirror_clamp; + GLboolean EXT_texture_shared_exponent; + GLboolean EXT_texture_sRGB; + GLboolean EXT_texture_sRGB_decode; + GLboolean EXT_texture_swizzle; + GLboolean EXT_transform_feedback; + GLboolean EXT_timer_query; + GLboolean EXT_vertex_array; + GLboolean EXT_vertex_array_bgra; + GLboolean EXT_vertex_array_set; + GLboolean OES_standard_derivatives; + /* vendor extensions */ + GLboolean AMD_conservative_depth; + GLboolean APPLE_client_storage; + GLboolean APPLE_packed_pixels; + GLboolean APPLE_vertex_array_object; + GLboolean APPLE_object_purgeable; + GLboolean ATI_envmap_bumpmap; + GLboolean ATI_texture_mirror_once; + GLboolean ATI_texture_env_combine3; + GLboolean ATI_fragment_shader; + GLboolean ATI_separate_stencil; + GLboolean IBM_rasterpos_clip; + GLboolean IBM_multimode_draw_arrays; + GLboolean MESA_pack_invert; + GLboolean MESA_resize_buffers; + GLboolean MESA_ycbcr_texture; + GLboolean MESA_texture_array; + GLboolean MESA_texture_signed_rgba; + GLboolean NV_blend_square; + GLboolean NV_conditional_render; + GLboolean NV_fragment_program; + GLboolean NV_fragment_program_option; + GLboolean NV_light_max_exponent; + GLboolean NV_point_sprite; + GLboolean NV_primitive_restart; + GLboolean NV_texgen_reflection; + GLboolean NV_texture_env_combine4; + GLboolean NV_texture_rectangle; + GLboolean NV_vertex_program; + GLboolean NV_vertex_program1_1; + GLboolean OES_read_format; + GLboolean SGIS_generate_mipmap; + GLboolean SGIS_texture_edge_clamp; + GLboolean SGIS_texture_lod; + GLboolean TDFX_texture_compression_FXT1; + GLboolean S3_s3tc; + GLboolean OES_EGL_image; + GLboolean OES_draw_texture; + GLboolean EXT_texture_format_BGRA8888; + GLboolean extension_sentinel; + /** The extension string */ + const GLubyte *String; + /** Number of supported extensions */ + GLuint Count; +}; + + +/** + * A stack of matrices (projection, modelview, color, texture, etc). + */ +struct gl_matrix_stack +{ + GLmatrix *Top; /**< points into Stack */ + GLmatrix *Stack; /**< array [MaxDepth] of GLmatrix */ + GLuint Depth; /**< 0 <= Depth < MaxDepth */ + GLuint MaxDepth; /**< size of Stack[] array */ + GLuint DirtyFlag; /**< _NEW_MODELVIEW or _NEW_PROJECTION, for example */ +}; + + +/** + * \name Bits for image transfer operations + * \sa __struct gl_contextRec::ImageTransferState. + */ +/*@{*/ +#define IMAGE_SCALE_BIAS_BIT 0x1 +#define IMAGE_SHIFT_OFFSET_BIT 0x2 +#define IMAGE_MAP_COLOR_BIT 0x4 +#define IMAGE_CLAMP_BIT 0x800 + + +/** Pixel Transfer ops */ +#define IMAGE_BITS (IMAGE_SCALE_BIAS_BIT | \ + IMAGE_SHIFT_OFFSET_BIT | \ + IMAGE_MAP_COLOR_BIT) + +/** + * \name Bits to indicate what state has changed. + */ +/*@{*/ +#define _NEW_MODELVIEW (1 << 0) /**< gl_context::ModelView */ +#define _NEW_PROJECTION (1 << 1) /**< gl_context::Projection */ +#define _NEW_TEXTURE_MATRIX (1 << 2) /**< gl_context::TextureMatrix */ +#define _NEW_COLOR (1 << 3) /**< gl_context::Color */ +#define _NEW_DEPTH (1 << 4) /**< gl_context::Depth */ +#define _NEW_EVAL (1 << 5) /**< gl_context::Eval, EvalMap */ +#define _NEW_FOG (1 << 6) /**< gl_context::Fog */ +#define _NEW_HINT (1 << 7) /**< gl_context::Hint */ +#define _NEW_LIGHT (1 << 8) /**< gl_context::Light */ +#define _NEW_LINE (1 << 9) /**< gl_context::Line */ +#define _NEW_PIXEL (1 << 10) /**< gl_context::Pixel */ +#define _NEW_POINT (1 << 11) /**< gl_context::Point */ +#define _NEW_POLYGON (1 << 12) /**< gl_context::Polygon */ +#define _NEW_POLYGONSTIPPLE (1 << 13) /**< gl_context::PolygonStipple */ +#define _NEW_SCISSOR (1 << 14) /**< gl_context::Scissor */ +#define _NEW_STENCIL (1 << 15) /**< gl_context::Stencil */ +#define _NEW_TEXTURE (1 << 16) /**< gl_context::Texture */ +#define _NEW_TRANSFORM (1 << 17) /**< gl_context::Transform */ +#define _NEW_VIEWPORT (1 << 18) /**< gl_context::Viewport */ +#define _NEW_PACKUNPACK (1 << 19) /**< gl_context::Pack, Unpack */ +#define _NEW_ARRAY (1 << 20) /**< gl_context::Array */ +#define _NEW_RENDERMODE (1 << 21) /**< gl_context::RenderMode, etc */ +#define _NEW_BUFFERS (1 << 22) /**< gl_context::Visual, DrawBuffer, */ +#define _NEW_CURRENT_ATTRIB (1 << 23) /**< gl_context::Current */ +#define _NEW_MULTISAMPLE (1 << 24) /**< gl_context::Multisample */ +#define _NEW_TRACK_MATRIX (1 << 25) /**< gl_context::VertexProgram */ +#define _NEW_PROGRAM (1 << 26) /**< New program/shader state */ +#define _NEW_PROGRAM_CONSTANTS (1 << 27) +#define _NEW_BUFFER_OBJECT (1 << 28) +#define _NEW_ALL ~0 +/*@}*/ + + +/** + * \name Bits to track array state changes + * + * Also used to summarize array enabled. + */ +/*@{*/ +#define _NEW_ARRAY_VERTEX VERT_BIT_POS +#define _NEW_ARRAY_WEIGHT VERT_BIT_WEIGHT +#define _NEW_ARRAY_NORMAL VERT_BIT_NORMAL +#define _NEW_ARRAY_COLOR0 VERT_BIT_COLOR0 +#define _NEW_ARRAY_COLOR1 VERT_BIT_COLOR1 +#define _NEW_ARRAY_FOGCOORD VERT_BIT_FOG +#define _NEW_ARRAY_INDEX VERT_BIT_COLOR_INDEX +#define _NEW_ARRAY_EDGEFLAG VERT_BIT_EDGEFLAG +#define _NEW_ARRAY_POINT_SIZE VERT_BIT_COLOR_INDEX /* aliased */ +#define _NEW_ARRAY_TEXCOORD_0 VERT_BIT_TEX0 +#define _NEW_ARRAY_TEXCOORD_1 VERT_BIT_TEX1 +#define _NEW_ARRAY_TEXCOORD_2 VERT_BIT_TEX2 +#define _NEW_ARRAY_TEXCOORD_3 VERT_BIT_TEX3 +#define _NEW_ARRAY_TEXCOORD_4 VERT_BIT_TEX4 +#define _NEW_ARRAY_TEXCOORD_5 VERT_BIT_TEX5 +#define _NEW_ARRAY_TEXCOORD_6 VERT_BIT_TEX6 +#define _NEW_ARRAY_TEXCOORD_7 VERT_BIT_TEX7 +#define _NEW_ARRAY_ATTRIB_0 VERT_BIT_GENERIC0 /* start at bit 16 */ +#define _NEW_ARRAY_ALL 0xffffffff + + +#define _NEW_ARRAY_TEXCOORD(i) (_NEW_ARRAY_TEXCOORD_0 << (i)) +#define _NEW_ARRAY_ATTRIB(i) (_NEW_ARRAY_ATTRIB_0 << (i)) +/*@}*/ + + + +/** + * \name A bunch of flags that we think might be useful to drivers. + * + * Set in the __struct gl_contextRec::_TriangleCaps bitfield. + */ +/*@{*/ +#define DD_FLATSHADE 0x1 +#define DD_SEPARATE_SPECULAR 0x2 +#define DD_TRI_CULL_FRONT_BACK 0x4 /* special case on some hw */ +#define DD_TRI_LIGHT_TWOSIDE 0x8 +#define DD_TRI_UNFILLED 0x10 +#define DD_TRI_SMOOTH 0x20 +#define DD_TRI_STIPPLE 0x40 +#define DD_TRI_OFFSET 0x80 +#define DD_LINE_SMOOTH 0x100 +#define DD_LINE_STIPPLE 0x200 +#define DD_POINT_SMOOTH 0x400 +#define DD_POINT_ATTEN 0x800 +#define DD_TRI_TWOSTENCIL 0x1000 +/*@}*/ + + +/** + * \name Define the state changes under which each of these bits might change + */ +/*@{*/ +#define _DD_NEW_FLATSHADE _NEW_LIGHT +#define _DD_NEW_SEPARATE_SPECULAR (_NEW_LIGHT | _NEW_FOG | _NEW_PROGRAM) +#define _DD_NEW_TRI_CULL_FRONT_BACK _NEW_POLYGON +#define _DD_NEW_TRI_LIGHT_TWOSIDE _NEW_LIGHT +#define _DD_NEW_TRI_UNFILLED _NEW_POLYGON +#define _DD_NEW_TRI_SMOOTH _NEW_POLYGON +#define _DD_NEW_TRI_STIPPLE _NEW_POLYGON +#define _DD_NEW_TRI_OFFSET _NEW_POLYGON +#define _DD_NEW_LINE_SMOOTH _NEW_LINE +#define _DD_NEW_LINE_STIPPLE _NEW_LINE +#define _DD_NEW_LINE_WIDTH _NEW_LINE +#define _DD_NEW_POINT_SMOOTH _NEW_POINT +#define _DD_NEW_POINT_SIZE _NEW_POINT +#define _DD_NEW_POINT_ATTEN _NEW_POINT +/*@}*/ + + +/** + * Composite state flags + */ +/*@{*/ +#define _MESA_NEW_NEED_EYE_COORDS (_NEW_LIGHT | \ + _NEW_TEXTURE | \ + _NEW_POINT | \ + _NEW_PROGRAM | \ + _NEW_MODELVIEW) + +#define _MESA_NEW_NEED_NORMALS (_NEW_LIGHT | \ + _NEW_TEXTURE) + +#define _MESA_NEW_TRANSFER_STATE (_NEW_PIXEL) +/*@}*/ + + + + +/* This has to be included here. */ +#include "dd.h" + + +/** + * Display list flags. + * Strictly this is a tnl-private concept, but it doesn't seem + * worthwhile adding a tnl private structure just to hold this one bit + * of information: + */ +#define DLIST_DANGLING_REFS 0x1 + + +/** Opaque declaration of display list payload data type */ +union gl_dlist_node; + + +/** + * Provide a location where information about a display list can be + * collected. Could be extended with driverPrivate structures, + * etc. in the future. + */ +struct gl_display_list +{ + GLuint Name; + GLbitfield Flags; /**< DLIST_x flags */ + /** The dlist commands are in a linked list of nodes */ + union gl_dlist_node *Head; +}; + + +/** + * State used during display list compilation and execution. + */ +struct gl_dlist_state +{ + GLuint CallDepth; /**< Current recursion calling depth */ + + struct gl_display_list *CurrentList; /**< List currently being compiled */ + union gl_dlist_node *CurrentBlock; /**< Pointer to current block of nodes */ + GLuint CurrentPos; /**< Index into current block of nodes */ + + GLvertexformat ListVtxfmt; + + GLubyte ActiveAttribSize[VERT_ATTRIB_MAX]; + GLfloat CurrentAttrib[VERT_ATTRIB_MAX][4]; + + GLubyte ActiveMaterialSize[MAT_ATTRIB_MAX]; + GLfloat CurrentMaterial[MAT_ATTRIB_MAX][4]; + + GLubyte ActiveIndex; + GLfloat CurrentIndex; + + GLubyte ActiveEdgeFlag; + GLboolean CurrentEdgeFlag; + + struct { + /* State known to have been set by the currently-compiling display + * list. Used to eliminate some redundant state changes. + */ + GLenum ShadeModel; + } Current; +}; + + +/** + * Enum for the OpenGL APIs we know about and may support. + */ +typedef enum +{ + API_OPENGL, + API_OPENGLES, + API_OPENGLES2 +} gl_api; + + +/** + * Mesa rendering context. + * + * This is the central context data structure for Mesa. Almost all + * OpenGL state is contained in this structure. + * Think of this as a base class from which device drivers will derive + * sub classes. + * + * The struct gl_context typedef names this structure. + */ +struct gl_context +{ + /** State possibly shared with other contexts in the address space */ + struct gl_shared_state *Shared; + + /** \name API function pointer tables */ + /*@{*/ + gl_api API; + struct _glapi_table *Save; /**< Display list save functions */ + struct _glapi_table *Exec; /**< Execute functions */ + struct _glapi_table *CurrentDispatch; /**< == Save or Exec !! */ + /*@}*/ + + struct gl_config Visual; + struct gl_framebuffer *DrawBuffer; /**< buffer for writing */ + struct gl_framebuffer *ReadBuffer; /**< buffer for reading */ + struct gl_framebuffer *WinSysDrawBuffer; /**< set with MakeCurrent */ + struct gl_framebuffer *WinSysReadBuffer; /**< set with MakeCurrent */ + + /** + * Device driver function pointer table + */ + struct dd_function_table Driver; + + void *DriverCtx; /**< Points to device driver context/state */ + + /** Core/Driver constants */ + struct gl_constants Const; + + /** \name The various 4x4 matrix stacks */ + /*@{*/ + struct gl_matrix_stack ModelviewMatrixStack; + struct gl_matrix_stack ProjectionMatrixStack; + struct gl_matrix_stack TextureMatrixStack[MAX_TEXTURE_UNITS]; + struct gl_matrix_stack ProgramMatrixStack[MAX_PROGRAM_MATRICES]; + struct gl_matrix_stack *CurrentStack; /**< Points to one of the above stacks */ + /*@}*/ + + /** Combined modelview and projection matrix */ + GLmatrix _ModelProjectMatrix; + + /** \name Display lists */ + struct gl_dlist_state ListState; + + GLboolean ExecuteFlag; /**< Execute GL commands? */ + GLboolean CompileFlag; /**< Compile GL commands into display list? */ + + /** Extension information */ + struct gl_extensions Extensions; + + /** Version info */ + GLuint VersionMajor, VersionMinor; + char *VersionString; + + /** \name State attribute stack (for glPush/PopAttrib) */ + /*@{*/ + GLuint AttribStackDepth; + struct gl_attrib_node *AttribStack[MAX_ATTRIB_STACK_DEPTH]; + /*@}*/ + + /** \name Renderer attribute groups + * + * We define a struct for each attribute group to make pushing and popping + * attributes easy. Also it's a good organization. + */ + /*@{*/ + struct gl_accum_attrib Accum; /**< Accum buffer attributes */ + struct gl_colorbuffer_attrib Color; /**< Color buffer attributes */ + struct gl_current_attrib Current; /**< Current attributes */ + struct gl_depthbuffer_attrib Depth; /**< Depth buffer attributes */ + struct gl_eval_attrib Eval; /**< Eval attributes */ + struct gl_fog_attrib Fog; /**< Fog attributes */ + struct gl_hint_attrib Hint; /**< Hint attributes */ + struct gl_light_attrib Light; /**< Light attributes */ + struct gl_line_attrib Line; /**< Line attributes */ + struct gl_list_attrib List; /**< List attributes */ + struct gl_multisample_attrib Multisample; + struct gl_pixel_attrib Pixel; /**< Pixel attributes */ + struct gl_point_attrib Point; /**< Point attributes */ + struct gl_polygon_attrib Polygon; /**< Polygon attributes */ + GLuint PolygonStipple[32]; /**< Polygon stipple */ + struct gl_scissor_attrib Scissor; /**< Scissor attributes */ + struct gl_stencil_attrib Stencil; /**< Stencil buffer attributes */ + struct gl_texture_attrib Texture; /**< Texture attributes */ + struct gl_transform_attrib Transform; /**< Transformation attributes */ + struct gl_viewport_attrib Viewport; /**< Viewport attributes */ + /*@}*/ + + /** \name Client attribute stack */ + /*@{*/ + GLuint ClientAttribStackDepth; + struct gl_attrib_node *ClientAttribStack[MAX_CLIENT_ATTRIB_STACK_DEPTH]; + /*@}*/ + + /** \name Client attribute groups */ + /*@{*/ + struct gl_array_attrib Array; /**< Vertex arrays */ + struct gl_pixelstore_attrib Pack; /**< Pixel packing */ + struct gl_pixelstore_attrib Unpack; /**< Pixel unpacking */ + struct gl_pixelstore_attrib DefaultPacking; /**< Default params */ + /*@}*/ + + /** \name Other assorted state (not pushed/popped on attribute stack) */ + /*@{*/ + struct gl_pixelmaps PixelMaps; + + struct gl_evaluators EvalMap; /**< All evaluators */ + struct gl_feedback Feedback; /**< Feedback */ + struct gl_selection Select; /**< Selection */ + + struct gl_program_state Program; /**< general program state */ + struct gl_vertex_program_state VertexProgram; + struct gl_fragment_program_state FragmentProgram; + struct gl_geometry_program_state GeometryProgram; + struct gl_ati_fragment_shader_state ATIFragmentShader; + + struct gl_shader_state Shader; /**< GLSL shader object state */ + struct gl_shader_compiler_options ShaderCompilerOptions[MESA_SHADER_TYPES]; + + struct gl_query_state Query; /**< occlusion, timer queries */ + + struct gl_transform_feedback TransformFeedback; + + struct gl_buffer_object *CopyReadBuffer; /**< GL_ARB_copy_buffer */ + struct gl_buffer_object *CopyWriteBuffer; /**< GL_ARB_copy_buffer */ + /*@}*/ + + struct gl_meta_state *Meta; /**< for "meta" operations */ + + /* GL_EXT_framebuffer_object */ + struct gl_renderbuffer *CurrentRenderbuffer; + + GLenum ErrorValue; /**< Last error code */ + + /** + * Recognize and silence repeated error debug messages in buggy apps. + */ + const char *ErrorDebugFmtString; + GLuint ErrorDebugCount; + + GLenum RenderMode; /**< either GL_RENDER, GL_SELECT, GL_FEEDBACK */ + GLbitfield NewState; /**< bitwise-or of _NEW_* flags */ + + GLboolean ViewportInitialized; /**< has viewport size been initialized? */ + + GLbitfield varying_vp_inputs; /**< mask of VERT_BIT_* flags */ + + /** \name Derived state */ + /*@{*/ + /** Bitwise-or of DD_* flags. Note that this bitfield may be used before + * state validation so they need to always be current. + */ + GLbitfield _TriangleCaps; + GLbitfield _ImageTransferState;/**< bitwise-or of IMAGE_*_BIT flags */ + GLfloat _EyeZDir[3]; + GLfloat _ModelViewInvScale; + GLboolean _NeedEyeCoords; + GLboolean _ForceEyeCoords; + + GLuint TextureStateTimestamp; /**< detect changes to shared state */ + + struct gl_shine_tab *_ShineTable[2]; /**< Active shine tables */ + struct gl_shine_tab *_ShineTabList; /**< MRU list of inactive shine tables */ + /**@}*/ + + struct gl_list_extensions *ListExt; /**< driver dlist extensions */ + + /** \name For debugging/development only */ + /*@{*/ + GLboolean FirstTimeCurrent; + /*@}*/ + + /** software compression/decompression supported or not */ + GLboolean Mesa_DXTn; + + GLboolean TextureFormatSupported[MESA_FORMAT_COUNT]; + + /** + * Use dp4 (rather than mul/mad) instructions for position + * transformation? + */ + GLboolean mvp_with_dp4; + + /** + * \name Hooks for module contexts. + * + * These will eventually live in the driver or elsewhere. + */ + /*@{*/ + void *swrast_context; + void *swsetup_context; + void *swtnl_context; + void *swtnl_im; + struct st_context *st; + void *aelt_context; + /*@}*/ +}; + + +#ifdef DEBUG +extern int MESA_VERBOSE; +extern int MESA_DEBUG_FLAGS; +# define MESA_FUNCTION __FUNCTION__ +#else +# define MESA_VERBOSE 0 +# define MESA_DEBUG_FLAGS 0 +# define MESA_FUNCTION "a function" +# ifndef NDEBUG +# define NDEBUG +# endif +#endif + + +/** The MESA_VERBOSE var is a bitmask of these flags */ +enum _verbose +{ + VERBOSE_VARRAY = 0x0001, + VERBOSE_TEXTURE = 0x0002, + VERBOSE_MATERIAL = 0x0004, + VERBOSE_PIPELINE = 0x0008, + VERBOSE_DRIVER = 0x0010, + VERBOSE_STATE = 0x0020, + VERBOSE_API = 0x0040, + VERBOSE_DISPLAY_LIST = 0x0100, + VERBOSE_LIGHTING = 0x0200, + VERBOSE_PRIMS = 0x0400, + VERBOSE_VERTS = 0x0800, + VERBOSE_DISASSEM = 0x1000, + VERBOSE_DRAW = 0x2000, + VERBOSE_SWAPBUFFERS = 0x4000 +}; + + +/** The MESA_DEBUG_FLAGS var is a bitmask of these flags */ +enum _debug +{ + DEBUG_ALWAYS_FLUSH = 0x1 +}; + + + +#endif /* MTYPES_H */ diff --git a/mesalib/src/mesa/main/pbo.c b/mesalib/src/mesa/main/pbo.c new file mode 100644 index 000000000..dc00d423b --- /dev/null +++ b/mesalib/src/mesa/main/pbo.c @@ -0,0 +1,372 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009-2011 VMware, Inc. 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 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. + */ + + +/** + * \file pbo.c + * \brief Functions related to Pixel Buffer Objects. + */ + + + +#include "glheader.h" +#include "bufferobj.h" +#include "image.h" +#include "imports.h" +#include "mtypes.h" +#include "pbo.h" + + + +/** + * When we're about to read pixel data out of a PBO (via glDrawPixels, + * glTexImage, etc) or write data into a PBO (via glReadPixels, + * glGetTexImage, etc) we call this function to check that we're not + * going to read out of bounds. + * + * XXX This would also be a convenient time to check that the PBO isn't + * currently mapped. Whoever calls this function should check for that. + * Remember, we can't use a PBO when it's mapped! + * + * If we're not using a PBO, this is a no-op. + * + * \param width width of image to read/write + * \param height height of image to read/write + * \param depth depth of image to read/write + * \param format format of image to read/write + * \param type datatype of image to read/write + * \param ptr the user-provided pointer/offset + * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would + * go out of bounds. + */ +GLboolean +_mesa_validate_pbo_access(GLuint dimensions, + const struct gl_pixelstore_attrib *pack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *ptr) +{ + GLvoid *start, *end; + const GLubyte *sizeAddr; /* buffer size, cast to a pointer */ + + if (!_mesa_is_bufferobj(pack->BufferObj)) + return GL_TRUE; /* no PBO, OK */ + + if (pack->BufferObj->Size == 0) + /* no buffer! */ + return GL_FALSE; + + /* get address of first pixel we'll read */ + start = _mesa_image_address(dimensions, pack, ptr, width, height, + format, type, 0, 0, 0); + + /* get address just past the last pixel we'll read */ + end = _mesa_image_address(dimensions, pack, ptr, width, height, + format, type, depth-1, height-1, width); + + + sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size; + + if ((const GLubyte *) start > sizeAddr) { + /* This will catch negative values / wrap-around */ + return GL_FALSE; + } + if ((const GLubyte *) end > sizeAddr) { + /* Image read goes beyond end of buffer */ + return GL_FALSE; + } + + /* OK! */ + return GL_TRUE; +} + + +/** + * For commands that read from a PBO (glDrawPixels, glTexImage, + * glPolygonStipple, etc), if we're reading from a PBO, map it read-only + * and return the pointer into the PBO. If we're not reading from a + * PBO, return \p src as-is. + * If non-null return, must call _mesa_unmap_pbo_source() when done. + * + * \return NULL if error, else pointer to start of data + */ +const GLvoid * +_mesa_map_pbo_source(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *src) +{ + const GLubyte *buf; + + if (_mesa_is_bufferobj(unpack->BufferObj)) { + /* unpack from PBO */ + buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + GL_READ_ONLY_ARB, + unpack->BufferObj); + if (!buf) + return NULL; + + buf = ADD_POINTERS(buf, src); + } + else { + /* unpack from normal memory */ + buf = src; + } + + return buf; +} + + +/** + * Combine PBO-read validation and mapping. + * If any GL errors are detected, they'll be recorded and NULL returned. + * \sa _mesa_validate_pbo_access + * \sa _mesa_map_pbo_source + * A call to this function should have a matching call to + * _mesa_unmap_pbo_source(). + */ +const GLvoid * +_mesa_map_validate_pbo_source(struct gl_context *ctx, + GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *ptr, + const char *where) +{ + ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); + + if (!_mesa_is_bufferobj(unpack->BufferObj)) { + /* non-PBO access: no validation to be done */ + return ptr; + } + + if (!_mesa_validate_pbo_access(dimensions, unpack, + width, height, depth, format, type, ptr)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(out of bounds PBO access)", where); + return NULL; + } + + if (_mesa_bufferobj_mapped(unpack->BufferObj)) { + /* buffer is already mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); + return NULL; + } + + ptr = _mesa_map_pbo_source(ctx, unpack, ptr); + return ptr; +} + + +/** + * Counterpart to _mesa_map_pbo_source() + */ +void +_mesa_unmap_pbo_source(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack) +{ + ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */ + if (_mesa_is_bufferobj(unpack->BufferObj)) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + unpack->BufferObj); + } +} + + +/** + * For commands that write to a PBO (glReadPixels, glGetColorTable, etc), + * if we're writing to a PBO, map it write-only and return the pointer + * into the PBO. If we're not writing to a PBO, return \p dst as-is. + * If non-null return, must call _mesa_unmap_pbo_dest() when done. + * + * \return NULL if error, else pointer to start of data + */ +void * +_mesa_map_pbo_dest(struct gl_context *ctx, + const struct gl_pixelstore_attrib *pack, + GLvoid *dest) +{ + void *buf; + + if (_mesa_is_bufferobj(pack->BufferObj)) { + /* pack into PBO */ + buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + GL_WRITE_ONLY_ARB, + pack->BufferObj); + if (!buf) + return NULL; + + buf = ADD_POINTERS(buf, dest); + } + else { + /* pack to normal memory */ + buf = dest; + } + + return buf; +} + + +/** + * Combine PBO-write validation and mapping. + * If any GL errors are detected, they'll be recorded and NULL returned. + * \sa _mesa_validate_pbo_access + * \sa _mesa_map_pbo_dest + * A call to this function should have a matching call to + * _mesa_unmap_pbo_dest(). + */ +GLvoid * +_mesa_map_validate_pbo_dest(struct gl_context *ctx, + GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, GLvoid *ptr, + const char *where) +{ + ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); + + if (!_mesa_is_bufferobj(unpack->BufferObj)) { + /* non-PBO access: no validation to be done */ + return ptr; + } + + if (!_mesa_validate_pbo_access(dimensions, unpack, + width, height, depth, format, type, ptr)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(out of bounds PBO access)", where); + return NULL; + } + + if (_mesa_bufferobj_mapped(unpack->BufferObj)) { + /* buffer is already mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); + return NULL; + } + + ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); + return ptr; +} + + +/** + * Counterpart to _mesa_map_pbo_dest() + */ +void +_mesa_unmap_pbo_dest(struct gl_context *ctx, + const struct gl_pixelstore_attrib *pack) +{ + ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */ + if (_mesa_is_bufferobj(pack->BufferObj)) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj); + } +} + + + +/** + * Check if an unpack PBO is active prior to fetching a texture image. + * If so, do bounds checking and map the buffer into main memory. + * Any errors detected will be recorded. + * The caller _must_ call _mesa_unmap_teximage_pbo() too! + */ +const GLvoid * +_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *unpack, + const char *funcName) +{ + GLubyte *buf; + + if (!_mesa_is_bufferobj(unpack->BufferObj)) { + /* no PBO */ + return pixels; + } + if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, + format, type, pixels)) { + _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)"); + return NULL; + } + + buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + GL_READ_ONLY_ARB, unpack->BufferObj); + if (!buf) { + _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped)"); + return NULL; + } + + return ADD_POINTERS(buf, pixels); +} + + +/** + * Check if an unpack PBO is active prior to fetching a compressed texture + * image. + * If so, do bounds checking and map the buffer into main memory. + * Any errors detected will be recorded. + * The caller _must_ call _mesa_unmap_teximage_pbo() too! + */ +const GLvoid * +_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx, + GLsizei imageSize, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + const char *funcName) +{ + GLubyte *buf; + + if (!_mesa_is_bufferobj(packing->BufferObj)) { + /* not using a PBO - return pointer unchanged */ + return pixels; + } + if ((const GLubyte *) pixels + imageSize > + ((const GLubyte *) 0) + packing->BufferObj->Size) { + /* out of bounds read! */ + _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)"); + return NULL; + } + + buf = (GLubyte*) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + GL_READ_ONLY_ARB, packing->BufferObj); + if (!buf) { + _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped"); + return NULL; + } + + return ADD_POINTERS(buf, pixels); +} + + +/** + * This function must be called after either of the validate_pbo_*_teximage() + * functions. It unmaps the PBO buffer if it was mapped earlier. + */ +void +_mesa_unmap_teximage_pbo(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack) +{ + if (_mesa_is_bufferobj(unpack->BufferObj)) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + unpack->BufferObj); + } +} + + diff --git a/mesalib/src/mesa/main/pbo.h b/mesalib/src/mesa/main/pbo.h new file mode 100644 index 000000000..0cddd72ba --- /dev/null +++ b/mesalib/src/mesa/main/pbo.h @@ -0,0 +1,92 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009-2011 VMware, Inc. 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 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. + */ + + +#ifndef PBO_H +#define PBO_H + + +#include "mtypes.h" + + +extern GLboolean +_mesa_validate_pbo_access(GLuint dimensions, + const struct gl_pixelstore_attrib *pack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *ptr); + +extern const GLvoid * +_mesa_map_pbo_source(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *src); + +extern const GLvoid * +_mesa_map_validate_pbo_source(struct gl_context *ctx, + GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *ptr, + const char *where); + +extern void +_mesa_unmap_pbo_source(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack); + +extern void * +_mesa_map_pbo_dest(struct gl_context *ctx, + const struct gl_pixelstore_attrib *pack, + GLvoid *dest); + +extern GLvoid * +_mesa_map_validate_pbo_dest(struct gl_context *ctx, + GLuint dimensions, + const struct gl_pixelstore_attrib *unpack, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, GLvoid *ptr, + const char *where); + +extern void +_mesa_unmap_pbo_dest(struct gl_context *ctx, + const struct gl_pixelstore_attrib *pack); + + +extern const GLvoid * +_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *unpack, + const char *funcName); + +extern const GLvoid * +_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx, + GLsizei imageSize, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + const char *funcName); + +extern void +_mesa_unmap_teximage_pbo(struct gl_context *ctx, + const struct gl_pixelstore_attrib *unpack); + + +#endif diff --git a/mesalib/src/mesa/main/pixel.c b/mesalib/src/mesa/main/pixel.c index 2b4934fd3..195fa234b 100644 --- a/mesalib/src/mesa/main/pixel.c +++ b/mesalib/src/mesa/main/pixel.c @@ -1,701 +1,699 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.1
- *
- * Copyright (C) 1999-2008 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.
- */
-
-
-/**
- * \file pixel.c
- * Pixel transfer functions (glPixelZoom, glPixelMap, glPixelTransfer)
- */
-
-#include "glheader.h"
-#include "bufferobj.h"
-#include "colormac.h"
-#include "context.h"
-#include "macros.h"
-#include "mfeatures.h"
-#include "pixel.h"
-#include "mtypes.h"
-#include "main/dispatch.h"
-
-
-#if FEATURE_pixel_transfer
-
-
-/**********************************************************************/
-/***** glPixelZoom *****/
-/**********************************************************************/
-
-static void GLAPIENTRY
-_mesa_PixelZoom( GLfloat xfactor, GLfloat yfactor )
-{
- GET_CURRENT_CONTEXT(ctx);
-
- if (ctx->Pixel.ZoomX == xfactor &&
- ctx->Pixel.ZoomY == yfactor)
- return;
-
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.ZoomX = xfactor;
- ctx->Pixel.ZoomY = yfactor;
-}
-
-
-
-/**********************************************************************/
-/***** glPixelMap *****/
-/**********************************************************************/
-
-/**
- * Return pointer to a pixelmap by name.
- */
-static struct gl_pixelmap *
-get_pixelmap(struct gl_context *ctx, GLenum map)
-{
- switch (map) {
- case GL_PIXEL_MAP_I_TO_I:
- return &ctx->PixelMaps.ItoI;
- case GL_PIXEL_MAP_S_TO_S:
- return &ctx->PixelMaps.StoS;
- case GL_PIXEL_MAP_I_TO_R:
- return &ctx->PixelMaps.ItoR;
- case GL_PIXEL_MAP_I_TO_G:
- return &ctx->PixelMaps.ItoG;
- case GL_PIXEL_MAP_I_TO_B:
- return &ctx->PixelMaps.ItoB;
- case GL_PIXEL_MAP_I_TO_A:
- return &ctx->PixelMaps.ItoA;
- case GL_PIXEL_MAP_R_TO_R:
- return &ctx->PixelMaps.RtoR;
- case GL_PIXEL_MAP_G_TO_G:
- return &ctx->PixelMaps.GtoG;
- case GL_PIXEL_MAP_B_TO_B:
- return &ctx->PixelMaps.BtoB;
- case GL_PIXEL_MAP_A_TO_A:
- return &ctx->PixelMaps.AtoA;
- default:
- return NULL;
- }
-}
-
-
-/**
- * Helper routine used by the other _mesa_PixelMap() functions.
- */
-static void
-store_pixelmap(struct gl_context *ctx, GLenum map, GLsizei mapsize,
- const GLfloat *values)
-{
- GLint i;
- struct gl_pixelmap *pm = get_pixelmap(ctx, map);
- if (!pm) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glPixelMap(map)");
- return;
- }
-
- switch (map) {
- case GL_PIXEL_MAP_S_TO_S:
- /* special case */
- ctx->PixelMaps.StoS.Size = mapsize;
- for (i = 0; i < mapsize; i++) {
- ctx->PixelMaps.StoS.Map[i] = (GLfloat)IROUND(values[i]);
- }
- break;
- case GL_PIXEL_MAP_I_TO_I:
- /* special case */
- ctx->PixelMaps.ItoI.Size = mapsize;
- for (i = 0; i < mapsize; i++) {
- ctx->PixelMaps.ItoI.Map[i] = values[i];
- }
- break;
- default:
- /* general case */
- pm->Size = mapsize;
- for (i = 0; i < mapsize; i++) {
- GLfloat val = CLAMP(values[i], 0.0F, 1.0F);
- pm->Map[i] = val;
- pm->Map8[i] = (GLint) (val * 255.0F);
- }
- }
-}
-
-
-/**
- * Convenience wrapper for _mesa_validate_pbo_access() for gl[Get]PixelMap().
- */
-static GLboolean
-validate_pbo_access(struct gl_context *ctx, struct gl_pixelstore_attrib *pack,
- GLsizei mapsize, GLenum format, GLenum type,
- const GLvoid *ptr)
-{
- GLboolean ok;
-
- /* Note, need to use DefaultPacking and Unpack's buffer object */
- _mesa_reference_buffer_object(ctx,
- &ctx->DefaultPacking.BufferObj,
- pack->BufferObj);
-
- ok = _mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1,
- format, type, ptr);
-
- /* restore */
- _mesa_reference_buffer_object(ctx,
- &ctx->DefaultPacking.BufferObj,
- ctx->Shared->NullBufferObj);
-
- if (!ok) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glPixelMap(invalid PBO access)");
- }
- return ok;
-}
-
-
-static void GLAPIENTRY
-_mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- /* XXX someday, test against ctx->Const.MaxPixelMapTableSize */
- if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" );
- return;
- }
-
- if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) {
- /* test that mapsize is a power of two */
- if (!_mesa_is_pow_two(mapsize)) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" );
- return;
- }
- }
-
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
-
- if (!validate_pbo_access(ctx, &ctx->Unpack, mapsize,
- GL_INTENSITY, GL_FLOAT, values)) {
- return;
- }
-
- values = (const GLfloat *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values);
- if (!values) {
- if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glPixelMapfv(PBO is mapped)");
- }
- return;
- }
-
- store_pixelmap(ctx, map, mapsize, values);
-
- _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
-}
-
-
-static void GLAPIENTRY
-_mesa_PixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values )
-{
- GLfloat fvalues[MAX_PIXEL_MAP_TABLE];
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" );
- return;
- }
-
- if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) {
- /* test that mapsize is a power of two */
- if (!_mesa_is_pow_two(mapsize)) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" );
- return;
- }
- }
-
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
-
- if (!validate_pbo_access(ctx, &ctx->Unpack, mapsize,
- GL_INTENSITY, GL_UNSIGNED_INT, values)) {
- return;
- }
-
- values = (const GLuint *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values);
- if (!values) {
- if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glPixelMapuiv(PBO is mapped)");
- }
- return;
- }
-
- /* convert to floats */
- if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) {
- GLint i;
- for (i = 0; i < mapsize; i++) {
- fvalues[i] = (GLfloat) values[i];
- }
- }
- else {
- GLint i;
- for (i = 0; i < mapsize; i++) {
- fvalues[i] = UINT_TO_FLOAT( values[i] );
- }
- }
-
- _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
-
- store_pixelmap(ctx, map, mapsize, fvalues);
-}
-
-
-static void GLAPIENTRY
-_mesa_PixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values )
-{
- GLfloat fvalues[MAX_PIXEL_MAP_TABLE];
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapusv(mapsize)" );
- return;
- }
-
- if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) {
- /* test that mapsize is a power of two */
- if (!_mesa_is_pow_two(mapsize)) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" );
- return;
- }
- }
-
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
-
- if (!validate_pbo_access(ctx, &ctx->Unpack, mapsize,
- GL_INTENSITY, GL_UNSIGNED_SHORT, values)) {
- return;
- }
-
- values = (const GLushort *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values);
- if (!values) {
- if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glPixelMapusv(PBO is mapped)");
- }
- return;
- }
-
- /* convert to floats */
- if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) {
- GLint i;
- for (i = 0; i < mapsize; i++) {
- fvalues[i] = (GLfloat) values[i];
- }
- }
- else {
- GLint i;
- for (i = 0; i < mapsize; i++) {
- fvalues[i] = USHORT_TO_FLOAT( values[i] );
- }
- }
-
- _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
-
- store_pixelmap(ctx, map, mapsize, fvalues);
-}
-
-
-static void GLAPIENTRY
-_mesa_GetPixelMapfv( GLenum map, GLfloat *values )
-{
- GET_CURRENT_CONTEXT(ctx);
- GLuint mapsize, i;
- const struct gl_pixelmap *pm;
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- pm = get_pixelmap(ctx, map);
- if (!pm) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapfv(map)");
- return;
- }
-
- mapsize = pm->Size;
-
- if (!validate_pbo_access(ctx, &ctx->Pack, mapsize,
- GL_INTENSITY, GL_FLOAT, values)) {
- return;
- }
-
- values = (GLfloat *) _mesa_map_pbo_dest(ctx, &ctx->Pack, values);
- if (!values) {
- if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetPixelMapfv(PBO is mapped)");
- }
- return;
- }
-
- if (map == GL_PIXEL_MAP_S_TO_S) {
- /* special case */
- for (i = 0; i < mapsize; i++) {
- values[i] = (GLfloat) ctx->PixelMaps.StoS.Map[i];
- }
- }
- else {
- memcpy(values, pm->Map, mapsize * sizeof(GLfloat));
- }
-
- _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
-}
-
-
-static void GLAPIENTRY
-_mesa_GetPixelMapuiv( GLenum map, GLuint *values )
-{
- GET_CURRENT_CONTEXT(ctx);
- GLint mapsize, i;
- const struct gl_pixelmap *pm;
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- pm = get_pixelmap(ctx, map);
- if (!pm) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapuiv(map)");
- return;
- }
- mapsize = pm->Size;
-
- if (!validate_pbo_access(ctx, &ctx->Pack, mapsize,
- GL_INTENSITY, GL_UNSIGNED_INT, values)) {
- return;
- }
-
- values = (GLuint *) _mesa_map_pbo_dest(ctx, &ctx->Pack, values);
- if (!values) {
- if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetPixelMapuiv(PBO is mapped)");
- }
- return;
- }
-
- if (map == GL_PIXEL_MAP_S_TO_S) {
- /* special case */
- memcpy(values, ctx->PixelMaps.StoS.Map, mapsize * sizeof(GLint));
- }
- else {
- for (i = 0; i < mapsize; i++) {
- values[i] = FLOAT_TO_UINT( pm->Map[i] );
- }
- }
-
- _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
-}
-
-
-static void GLAPIENTRY
-_mesa_GetPixelMapusv( GLenum map, GLushort *values )
-{
- GET_CURRENT_CONTEXT(ctx);
- GLint mapsize, i;
- const struct gl_pixelmap *pm;
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- pm = get_pixelmap(ctx, map);
- if (!pm) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapusv(map)");
- return;
- }
- mapsize = pm->Size;
-
- if (!validate_pbo_access(ctx, &ctx->Pack, mapsize,
- GL_INTENSITY, GL_UNSIGNED_SHORT, values)) {
- return;
- }
-
- values = (GLushort *) _mesa_map_pbo_dest(ctx, &ctx->Pack, values);
- if (!values) {
- if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetPixelMapusv(PBO is mapped)");
- }
- return;
- }
-
- switch (map) {
- /* special cases */
- case GL_PIXEL_MAP_I_TO_I:
- for (i = 0; i < mapsize; i++) {
- values[i] = (GLushort) CLAMP(ctx->PixelMaps.ItoI.Map[i], 0.0, 65535.);
- }
- break;
- case GL_PIXEL_MAP_S_TO_S:
- for (i = 0; i < mapsize; i++) {
- values[i] = (GLushort) CLAMP(ctx->PixelMaps.StoS.Map[i], 0.0, 65535.);
- }
- break;
- default:
- for (i = 0; i < mapsize; i++) {
- CLAMPED_FLOAT_TO_USHORT(values[i], pm->Map[i] );
- }
- }
-
- _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
-}
-
-
-
-/**********************************************************************/
-/***** glPixelTransfer *****/
-/**********************************************************************/
-
-
-/*
- * Implements glPixelTransfer[fi] whether called immediately or from a
- * display list.
- */
-static void GLAPIENTRY
-_mesa_PixelTransferf( GLenum pname, GLfloat param )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- switch (pname) {
- case GL_MAP_COLOR:
- if (ctx->Pixel.MapColorFlag == (param ? GL_TRUE : GL_FALSE))
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.MapColorFlag = param ? GL_TRUE : GL_FALSE;
- break;
- case GL_MAP_STENCIL:
- if (ctx->Pixel.MapStencilFlag == (param ? GL_TRUE : GL_FALSE))
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.MapStencilFlag = param ? GL_TRUE : GL_FALSE;
- break;
- case GL_INDEX_SHIFT:
- if (ctx->Pixel.IndexShift == (GLint) param)
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.IndexShift = (GLint) param;
- break;
- case GL_INDEX_OFFSET:
- if (ctx->Pixel.IndexOffset == (GLint) param)
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.IndexOffset = (GLint) param;
- break;
- case GL_RED_SCALE:
- if (ctx->Pixel.RedScale == param)
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.RedScale = param;
- break;
- case GL_RED_BIAS:
- if (ctx->Pixel.RedBias == param)
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.RedBias = param;
- break;
- case GL_GREEN_SCALE:
- if (ctx->Pixel.GreenScale == param)
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.GreenScale = param;
- break;
- case GL_GREEN_BIAS:
- if (ctx->Pixel.GreenBias == param)
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.GreenBias = param;
- break;
- case GL_BLUE_SCALE:
- if (ctx->Pixel.BlueScale == param)
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.BlueScale = param;
- break;
- case GL_BLUE_BIAS:
- if (ctx->Pixel.BlueBias == param)
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.BlueBias = param;
- break;
- case GL_ALPHA_SCALE:
- if (ctx->Pixel.AlphaScale == param)
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.AlphaScale = param;
- break;
- case GL_ALPHA_BIAS:
- if (ctx->Pixel.AlphaBias == param)
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.AlphaBias = param;
- break;
- case GL_DEPTH_SCALE:
- if (ctx->Pixel.DepthScale == param)
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.DepthScale = param;
- break;
- case GL_DEPTH_BIAS:
- if (ctx->Pixel.DepthBias == param)
- return;
- FLUSH_VERTICES(ctx, _NEW_PIXEL);
- ctx->Pixel.DepthBias = param;
- break;
- default:
- _mesa_error( ctx, GL_INVALID_ENUM, "glPixelTransfer(pname)" );
- return;
- }
-}
-
-
-static void GLAPIENTRY
-_mesa_PixelTransferi( GLenum pname, GLint param )
-{
- _mesa_PixelTransferf( pname, (GLfloat) param );
-}
-
-
-
-/**********************************************************************/
-/***** State Management *****/
-/**********************************************************************/
-
-/*
- * Return a bitmask of IMAGE_*_BIT flags which to indicate which
- * pixel transfer operations are enabled.
- */
-static void
-update_image_transfer_state(struct gl_context *ctx)
-{
- GLuint mask = 0;
-
- if (ctx->Pixel.RedScale != 1.0F || ctx->Pixel.RedBias != 0.0F ||
- ctx->Pixel.GreenScale != 1.0F || ctx->Pixel.GreenBias != 0.0F ||
- ctx->Pixel.BlueScale != 1.0F || ctx->Pixel.BlueBias != 0.0F ||
- ctx->Pixel.AlphaScale != 1.0F || ctx->Pixel.AlphaBias != 0.0F)
- mask |= IMAGE_SCALE_BIAS_BIT;
-
- if (ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset)
- mask |= IMAGE_SHIFT_OFFSET_BIT;
-
- if (ctx->Pixel.MapColorFlag)
- mask |= IMAGE_MAP_COLOR_BIT;
-
- ctx->_ImageTransferState = mask;
-}
-
-
-/**
- * Update mesa pixel transfer derived state.
- */
-void _mesa_update_pixel( struct gl_context *ctx, GLuint new_state )
-{
- if (new_state & _MESA_NEW_TRANSFER_STATE)
- update_image_transfer_state(ctx);
-}
-
-
-void
-_mesa_init_pixel_dispatch(struct _glapi_table *disp)
-{
- SET_GetPixelMapfv(disp, _mesa_GetPixelMapfv);
- SET_GetPixelMapuiv(disp, _mesa_GetPixelMapuiv);
- SET_GetPixelMapusv(disp, _mesa_GetPixelMapusv);
- SET_PixelMapfv(disp, _mesa_PixelMapfv);
- SET_PixelMapuiv(disp, _mesa_PixelMapuiv);
- SET_PixelMapusv(disp, _mesa_PixelMapusv);
- SET_PixelTransferf(disp, _mesa_PixelTransferf);
- SET_PixelTransferi(disp, _mesa_PixelTransferi);
- SET_PixelZoom(disp, _mesa_PixelZoom);
-}
-
-
-#endif /* FEATURE_pixel_transfer */
-
-
-/**********************************************************************/
-/***** Initialization *****/
-/**********************************************************************/
-
-static void
-init_pixelmap(struct gl_pixelmap *map)
-{
- map->Size = 1;
- map->Map[0] = 0.0;
- map->Map8[0] = 0;
-}
-
-
-/**
- * Initialize the context's PIXEL attribute group.
- */
-void
-_mesa_init_pixel( struct gl_context *ctx )
-{
- /* Pixel group */
- ctx->Pixel.RedBias = 0.0;
- ctx->Pixel.RedScale = 1.0;
- ctx->Pixel.GreenBias = 0.0;
- ctx->Pixel.GreenScale = 1.0;
- ctx->Pixel.BlueBias = 0.0;
- ctx->Pixel.BlueScale = 1.0;
- ctx->Pixel.AlphaBias = 0.0;
- ctx->Pixel.AlphaScale = 1.0;
- ctx->Pixel.DepthBias = 0.0;
- ctx->Pixel.DepthScale = 1.0;
- ctx->Pixel.IndexOffset = 0;
- ctx->Pixel.IndexShift = 0;
- ctx->Pixel.ZoomX = 1.0;
- ctx->Pixel.ZoomY = 1.0;
- ctx->Pixel.MapColorFlag = GL_FALSE;
- ctx->Pixel.MapStencilFlag = GL_FALSE;
- init_pixelmap(&ctx->PixelMaps.StoS);
- init_pixelmap(&ctx->PixelMaps.ItoI);
- init_pixelmap(&ctx->PixelMaps.ItoR);
- init_pixelmap(&ctx->PixelMaps.ItoG);
- init_pixelmap(&ctx->PixelMaps.ItoB);
- init_pixelmap(&ctx->PixelMaps.ItoA);
- init_pixelmap(&ctx->PixelMaps.RtoR);
- init_pixelmap(&ctx->PixelMaps.GtoG);
- init_pixelmap(&ctx->PixelMaps.BtoB);
- init_pixelmap(&ctx->PixelMaps.AtoA);
- /* GL_SGI_texture_color_table */
- ASSIGN_4V(ctx->Pixel.TextureColorTableScale, 1.0, 1.0, 1.0, 1.0);
- ASSIGN_4V(ctx->Pixel.TextureColorTableBias, 0.0, 0.0, 0.0, 0.0);
-
- if (ctx->Visual.doubleBufferMode) {
- ctx->Pixel.ReadBuffer = GL_BACK;
- }
- else {
- ctx->Pixel.ReadBuffer = GL_FRONT;
- }
-
- /* Miscellaneous */
- ctx->_ImageTransferState = 0;
-}
+/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2008 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. + */ + + +/** + * \file pixel.c + * Pixel transfer functions (glPixelZoom, glPixelMap, glPixelTransfer) + */ + +#include "glheader.h" +#include "bufferobj.h" +#include "colormac.h" +#include "context.h" +#include "macros.h" +#include "mfeatures.h" +#include "pixel.h" +#include "pbo.h" +#include "mtypes.h" +#include "main/dispatch.h" + + +#if FEATURE_pixel_transfer + + +/**********************************************************************/ +/***** glPixelZoom *****/ +/**********************************************************************/ + +static void GLAPIENTRY +_mesa_PixelZoom( GLfloat xfactor, GLfloat yfactor ) +{ + GET_CURRENT_CONTEXT(ctx); + + if (ctx->Pixel.ZoomX == xfactor && + ctx->Pixel.ZoomY == yfactor) + return; + + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.ZoomX = xfactor; + ctx->Pixel.ZoomY = yfactor; +} + + + +/**********************************************************************/ +/***** glPixelMap *****/ +/**********************************************************************/ + +/** + * Return pointer to a pixelmap by name. + */ +static struct gl_pixelmap * +get_pixelmap(struct gl_context *ctx, GLenum map) +{ + switch (map) { + case GL_PIXEL_MAP_I_TO_I: + return &ctx->PixelMaps.ItoI; + case GL_PIXEL_MAP_S_TO_S: + return &ctx->PixelMaps.StoS; + case GL_PIXEL_MAP_I_TO_R: + return &ctx->PixelMaps.ItoR; + case GL_PIXEL_MAP_I_TO_G: + return &ctx->PixelMaps.ItoG; + case GL_PIXEL_MAP_I_TO_B: + return &ctx->PixelMaps.ItoB; + case GL_PIXEL_MAP_I_TO_A: + return &ctx->PixelMaps.ItoA; + case GL_PIXEL_MAP_R_TO_R: + return &ctx->PixelMaps.RtoR; + case GL_PIXEL_MAP_G_TO_G: + return &ctx->PixelMaps.GtoG; + case GL_PIXEL_MAP_B_TO_B: + return &ctx->PixelMaps.BtoB; + case GL_PIXEL_MAP_A_TO_A: + return &ctx->PixelMaps.AtoA; + default: + return NULL; + } +} + + +/** + * Helper routine used by the other _mesa_PixelMap() functions. + */ +static void +store_pixelmap(struct gl_context *ctx, GLenum map, GLsizei mapsize, + const GLfloat *values) +{ + GLint i; + struct gl_pixelmap *pm = get_pixelmap(ctx, map); + if (!pm) { + _mesa_error(ctx, GL_INVALID_ENUM, "glPixelMap(map)"); + return; + } + + switch (map) { + case GL_PIXEL_MAP_S_TO_S: + /* special case */ + ctx->PixelMaps.StoS.Size = mapsize; + for (i = 0; i < mapsize; i++) { + ctx->PixelMaps.StoS.Map[i] = (GLfloat)IROUND(values[i]); + } + break; + case GL_PIXEL_MAP_I_TO_I: + /* special case */ + ctx->PixelMaps.ItoI.Size = mapsize; + for (i = 0; i < mapsize; i++) { + ctx->PixelMaps.ItoI.Map[i] = values[i]; + } + break; + default: + /* general case */ + pm->Size = mapsize; + for (i = 0; i < mapsize; i++) { + GLfloat val = CLAMP(values[i], 0.0F, 1.0F); + pm->Map[i] = val; + pm->Map8[i] = (GLint) (val * 255.0F); + } + } +} + + +/** + * Convenience wrapper for _mesa_validate_pbo_access() for gl[Get]PixelMap(). + */ +static GLboolean +validate_pbo_access(struct gl_context *ctx, struct gl_pixelstore_attrib *pack, + GLsizei mapsize, GLenum format, GLenum type, + const GLvoid *ptr) +{ + GLboolean ok; + + /* Note, need to use DefaultPacking and Unpack's buffer object */ + _mesa_reference_buffer_object(ctx, + &ctx->DefaultPacking.BufferObj, + pack->BufferObj); + + ok = _mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1, + format, type, ptr); + + /* restore */ + _mesa_reference_buffer_object(ctx, + &ctx->DefaultPacking.BufferObj, + ctx->Shared->NullBufferObj); + + if (!ok) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glPixelMap(invalid PBO access)"); + } + return ok; +} + + +static void GLAPIENTRY +_mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* XXX someday, test against ctx->Const.MaxPixelMapTableSize */ + if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) { + _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" ); + return; + } + + if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) { + /* test that mapsize is a power of two */ + if (!_mesa_is_pow_two(mapsize)) { + _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" ); + return; + } + } + + FLUSH_VERTICES(ctx, _NEW_PIXEL); + + if (!validate_pbo_access(ctx, &ctx->Unpack, mapsize, + GL_INTENSITY, GL_FLOAT, values)) { + return; + } + + values = (const GLfloat *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values); + if (!values) { + if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glPixelMapfv(PBO is mapped)"); + } + return; + } + + store_pixelmap(ctx, map, mapsize, values); + + _mesa_unmap_pbo_source(ctx, &ctx->Unpack); +} + + +static void GLAPIENTRY +_mesa_PixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values ) +{ + GLfloat fvalues[MAX_PIXEL_MAP_TABLE]; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) { + _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" ); + return; + } + + if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) { + /* test that mapsize is a power of two */ + if (!_mesa_is_pow_two(mapsize)) { + _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" ); + return; + } + } + + FLUSH_VERTICES(ctx, _NEW_PIXEL); + + if (!validate_pbo_access(ctx, &ctx->Unpack, mapsize, + GL_INTENSITY, GL_UNSIGNED_INT, values)) { + return; + } + + values = (const GLuint *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values); + if (!values) { + if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glPixelMapuiv(PBO is mapped)"); + } + return; + } + + /* convert to floats */ + if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) { + GLint i; + for (i = 0; i < mapsize; i++) { + fvalues[i] = (GLfloat) values[i]; + } + } + else { + GLint i; + for (i = 0; i < mapsize; i++) { + fvalues[i] = UINT_TO_FLOAT( values[i] ); + } + } + + _mesa_unmap_pbo_source(ctx, &ctx->Unpack); + + store_pixelmap(ctx, map, mapsize, fvalues); +} + + +static void GLAPIENTRY +_mesa_PixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values ) +{ + GLfloat fvalues[MAX_PIXEL_MAP_TABLE]; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) { + _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapusv(mapsize)" ); + return; + } + + if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) { + /* test that mapsize is a power of two */ + if (!_mesa_is_pow_two(mapsize)) { + _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" ); + return; + } + } + + FLUSH_VERTICES(ctx, _NEW_PIXEL); + + if (!validate_pbo_access(ctx, &ctx->Unpack, mapsize, + GL_INTENSITY, GL_UNSIGNED_SHORT, values)) { + return; + } + + values = (const GLushort *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values); + if (!values) { + if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glPixelMapusv(PBO is mapped)"); + } + return; + } + + /* convert to floats */ + if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) { + GLint i; + for (i = 0; i < mapsize; i++) { + fvalues[i] = (GLfloat) values[i]; + } + } + else { + GLint i; + for (i = 0; i < mapsize; i++) { + fvalues[i] = USHORT_TO_FLOAT( values[i] ); + } + } + + _mesa_unmap_pbo_source(ctx, &ctx->Unpack); + + store_pixelmap(ctx, map, mapsize, fvalues); +} + + +static void GLAPIENTRY +_mesa_GetPixelMapfv( GLenum map, GLfloat *values ) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint mapsize, i; + const struct gl_pixelmap *pm; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + pm = get_pixelmap(ctx, map); + if (!pm) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapfv(map)"); + return; + } + + mapsize = pm->Size; + + if (!validate_pbo_access(ctx, &ctx->Pack, mapsize, + GL_INTENSITY, GL_FLOAT, values)) { + return; + } + + values = (GLfloat *) _mesa_map_pbo_dest(ctx, &ctx->Pack, values); + if (!values) { + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetPixelMapfv(PBO is mapped)"); + } + return; + } + + if (map == GL_PIXEL_MAP_S_TO_S) { + /* special case */ + for (i = 0; i < mapsize; i++) { + values[i] = (GLfloat) ctx->PixelMaps.StoS.Map[i]; + } + } + else { + memcpy(values, pm->Map, mapsize * sizeof(GLfloat)); + } + + _mesa_unmap_pbo_dest(ctx, &ctx->Pack); +} + + +static void GLAPIENTRY +_mesa_GetPixelMapuiv( GLenum map, GLuint *values ) +{ + GET_CURRENT_CONTEXT(ctx); + GLint mapsize, i; + const struct gl_pixelmap *pm; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + pm = get_pixelmap(ctx, map); + if (!pm) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapuiv(map)"); + return; + } + mapsize = pm->Size; + + if (!validate_pbo_access(ctx, &ctx->Pack, mapsize, + GL_INTENSITY, GL_UNSIGNED_INT, values)) { + return; + } + + values = (GLuint *) _mesa_map_pbo_dest(ctx, &ctx->Pack, values); + if (!values) { + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetPixelMapuiv(PBO is mapped)"); + } + return; + } + + if (map == GL_PIXEL_MAP_S_TO_S) { + /* special case */ + memcpy(values, ctx->PixelMaps.StoS.Map, mapsize * sizeof(GLint)); + } + else { + for (i = 0; i < mapsize; i++) { + values[i] = FLOAT_TO_UINT( pm->Map[i] ); + } + } + + _mesa_unmap_pbo_dest(ctx, &ctx->Pack); +} + + +static void GLAPIENTRY +_mesa_GetPixelMapusv( GLenum map, GLushort *values ) +{ + GET_CURRENT_CONTEXT(ctx); + GLint mapsize, i; + const struct gl_pixelmap *pm; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + pm = get_pixelmap(ctx, map); + if (!pm) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapusv(map)"); + return; + } + mapsize = pm->Size; + + if (!validate_pbo_access(ctx, &ctx->Pack, mapsize, + GL_INTENSITY, GL_UNSIGNED_SHORT, values)) { + return; + } + + values = (GLushort *) _mesa_map_pbo_dest(ctx, &ctx->Pack, values); + if (!values) { + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetPixelMapusv(PBO is mapped)"); + } + return; + } + + switch (map) { + /* special cases */ + case GL_PIXEL_MAP_I_TO_I: + for (i = 0; i < mapsize; i++) { + values[i] = (GLushort) CLAMP(ctx->PixelMaps.ItoI.Map[i], 0.0, 65535.); + } + break; + case GL_PIXEL_MAP_S_TO_S: + for (i = 0; i < mapsize; i++) { + values[i] = (GLushort) CLAMP(ctx->PixelMaps.StoS.Map[i], 0.0, 65535.); + } + break; + default: + for (i = 0; i < mapsize; i++) { + CLAMPED_FLOAT_TO_USHORT(values[i], pm->Map[i] ); + } + } + + _mesa_unmap_pbo_dest(ctx, &ctx->Pack); +} + + + +/**********************************************************************/ +/***** glPixelTransfer *****/ +/**********************************************************************/ + + +/* + * Implements glPixelTransfer[fi] whether called immediately or from a + * display list. + */ +static void GLAPIENTRY +_mesa_PixelTransferf( GLenum pname, GLfloat param ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + switch (pname) { + case GL_MAP_COLOR: + if (ctx->Pixel.MapColorFlag == (param ? GL_TRUE : GL_FALSE)) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.MapColorFlag = param ? GL_TRUE : GL_FALSE; + break; + case GL_MAP_STENCIL: + if (ctx->Pixel.MapStencilFlag == (param ? GL_TRUE : GL_FALSE)) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.MapStencilFlag = param ? GL_TRUE : GL_FALSE; + break; + case GL_INDEX_SHIFT: + if (ctx->Pixel.IndexShift == (GLint) param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.IndexShift = (GLint) param; + break; + case GL_INDEX_OFFSET: + if (ctx->Pixel.IndexOffset == (GLint) param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.IndexOffset = (GLint) param; + break; + case GL_RED_SCALE: + if (ctx->Pixel.RedScale == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.RedScale = param; + break; + case GL_RED_BIAS: + if (ctx->Pixel.RedBias == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.RedBias = param; + break; + case GL_GREEN_SCALE: + if (ctx->Pixel.GreenScale == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.GreenScale = param; + break; + case GL_GREEN_BIAS: + if (ctx->Pixel.GreenBias == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.GreenBias = param; + break; + case GL_BLUE_SCALE: + if (ctx->Pixel.BlueScale == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.BlueScale = param; + break; + case GL_BLUE_BIAS: + if (ctx->Pixel.BlueBias == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.BlueBias = param; + break; + case GL_ALPHA_SCALE: + if (ctx->Pixel.AlphaScale == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.AlphaScale = param; + break; + case GL_ALPHA_BIAS: + if (ctx->Pixel.AlphaBias == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.AlphaBias = param; + break; + case GL_DEPTH_SCALE: + if (ctx->Pixel.DepthScale == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.DepthScale = param; + break; + case GL_DEPTH_BIAS: + if (ctx->Pixel.DepthBias == param) + return; + FLUSH_VERTICES(ctx, _NEW_PIXEL); + ctx->Pixel.DepthBias = param; + break; + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glPixelTransfer(pname)" ); + return; + } +} + + +static void GLAPIENTRY +_mesa_PixelTransferi( GLenum pname, GLint param ) +{ + _mesa_PixelTransferf( pname, (GLfloat) param ); +} + + + +/**********************************************************************/ +/***** State Management *****/ +/**********************************************************************/ + +/* + * Return a bitmask of IMAGE_*_BIT flags which to indicate which + * pixel transfer operations are enabled. + */ +static void +update_image_transfer_state(struct gl_context *ctx) +{ + GLuint mask = 0; + + if (ctx->Pixel.RedScale != 1.0F || ctx->Pixel.RedBias != 0.0F || + ctx->Pixel.GreenScale != 1.0F || ctx->Pixel.GreenBias != 0.0F || + ctx->Pixel.BlueScale != 1.0F || ctx->Pixel.BlueBias != 0.0F || + ctx->Pixel.AlphaScale != 1.0F || ctx->Pixel.AlphaBias != 0.0F) + mask |= IMAGE_SCALE_BIAS_BIT; + + if (ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset) + mask |= IMAGE_SHIFT_OFFSET_BIT; + + if (ctx->Pixel.MapColorFlag) + mask |= IMAGE_MAP_COLOR_BIT; + + ctx->_ImageTransferState = mask; +} + + +/** + * Update mesa pixel transfer derived state. + */ +void _mesa_update_pixel( struct gl_context *ctx, GLuint new_state ) +{ + if (new_state & _MESA_NEW_TRANSFER_STATE) + update_image_transfer_state(ctx); +} + + +void +_mesa_init_pixel_dispatch(struct _glapi_table *disp) +{ + SET_GetPixelMapfv(disp, _mesa_GetPixelMapfv); + SET_GetPixelMapuiv(disp, _mesa_GetPixelMapuiv); + SET_GetPixelMapusv(disp, _mesa_GetPixelMapusv); + SET_PixelMapfv(disp, _mesa_PixelMapfv); + SET_PixelMapuiv(disp, _mesa_PixelMapuiv); + SET_PixelMapusv(disp, _mesa_PixelMapusv); + SET_PixelTransferf(disp, _mesa_PixelTransferf); + SET_PixelTransferi(disp, _mesa_PixelTransferi); + SET_PixelZoom(disp, _mesa_PixelZoom); +} + + +#endif /* FEATURE_pixel_transfer */ + + +/**********************************************************************/ +/***** Initialization *****/ +/**********************************************************************/ + +static void +init_pixelmap(struct gl_pixelmap *map) +{ + map->Size = 1; + map->Map[0] = 0.0; + map->Map8[0] = 0; +} + + +/** + * Initialize the context's PIXEL attribute group. + */ +void +_mesa_init_pixel( struct gl_context *ctx ) +{ + /* Pixel group */ + ctx->Pixel.RedBias = 0.0; + ctx->Pixel.RedScale = 1.0; + ctx->Pixel.GreenBias = 0.0; + ctx->Pixel.GreenScale = 1.0; + ctx->Pixel.BlueBias = 0.0; + ctx->Pixel.BlueScale = 1.0; + ctx->Pixel.AlphaBias = 0.0; + ctx->Pixel.AlphaScale = 1.0; + ctx->Pixel.DepthBias = 0.0; + ctx->Pixel.DepthScale = 1.0; + ctx->Pixel.IndexOffset = 0; + ctx->Pixel.IndexShift = 0; + ctx->Pixel.ZoomX = 1.0; + ctx->Pixel.ZoomY = 1.0; + ctx->Pixel.MapColorFlag = GL_FALSE; + ctx->Pixel.MapStencilFlag = GL_FALSE; + init_pixelmap(&ctx->PixelMaps.StoS); + init_pixelmap(&ctx->PixelMaps.ItoI); + init_pixelmap(&ctx->PixelMaps.ItoR); + init_pixelmap(&ctx->PixelMaps.ItoG); + init_pixelmap(&ctx->PixelMaps.ItoB); + init_pixelmap(&ctx->PixelMaps.ItoA); + init_pixelmap(&ctx->PixelMaps.RtoR); + init_pixelmap(&ctx->PixelMaps.GtoG); + init_pixelmap(&ctx->PixelMaps.BtoB); + init_pixelmap(&ctx->PixelMaps.AtoA); + + if (ctx->Visual.doubleBufferMode) { + ctx->Pixel.ReadBuffer = GL_BACK; + } + else { + ctx->Pixel.ReadBuffer = GL_FRONT; + } + + /* Miscellaneous */ + ctx->_ImageTransferState = 0; +} diff --git a/mesalib/src/mesa/main/polygon.c b/mesalib/src/mesa/main/polygon.c index 71ef929fc..ff4232ecc 100644 --- a/mesalib/src/mesa/main/polygon.c +++ b/mesalib/src/mesa/main/polygon.c @@ -1,322 +1,322 @@ -/**
- * \file polygon.c
- * Polygon operations.
- */
-
-/*
- * Mesa 3-D graphics library
- * Version: 6.5.1
- *
- * Copyright (C) 1999-2006 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.
- */
-
-
-#include "glheader.h"
-#include "imports.h"
-#include "bufferobj.h"
-#include "context.h"
-#include "image.h"
-#include "enums.h"
-#include "pack.h"
-#include "polygon.h"
-#include "mtypes.h"
-
-
-/**
- * Specify whether to cull front- or back-facing facets.
- *
- * \param mode culling mode.
- *
- * \sa glCullFace().
- *
- * Verifies the parameter and updates gl_polygon_attrib::CullFaceMode. On
- * change, flushes the vertices and notifies the driver via
- * the dd_function_table::CullFace callback.
- */
-void GLAPIENTRY
-_mesa_CullFace( GLenum mode )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (MESA_VERBOSE&VERBOSE_API)
- _mesa_debug(ctx, "glCullFace %s\n", _mesa_lookup_enum_by_nr(mode));
-
- if (mode!=GL_FRONT && mode!=GL_BACK && mode!=GL_FRONT_AND_BACK) {
- _mesa_error( ctx, GL_INVALID_ENUM, "glCullFace" );
- return;
- }
-
- if (ctx->Polygon.CullFaceMode == mode)
- return;
-
- FLUSH_VERTICES(ctx, _NEW_POLYGON);
- ctx->Polygon.CullFaceMode = mode;
-
- if (ctx->Driver.CullFace)
- ctx->Driver.CullFace( ctx, mode );
-}
-
-
-/**
- * Define front- and back-facing
- *
- * \param mode orientation of front-facing polygons.
- *
- * \sa glFrontFace().
- *
- * Verifies the parameter and updates gl_polygon_attrib::FrontFace. On change
- * flushes the vertices and notifies the driver via
- * the dd_function_table::FrontFace callback.
- */
-void GLAPIENTRY
-_mesa_FrontFace( GLenum mode )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (MESA_VERBOSE&VERBOSE_API)
- _mesa_debug(ctx, "glFrontFace %s\n", _mesa_lookup_enum_by_nr(mode));
-
- if (mode!=GL_CW && mode!=GL_CCW) {
- _mesa_error( ctx, GL_INVALID_ENUM, "glFrontFace" );
- return;
- }
-
- if (ctx->Polygon.FrontFace == mode)
- return;
-
- FLUSH_VERTICES(ctx, _NEW_POLYGON);
- ctx->Polygon.FrontFace = mode;
-
- ctx->Polygon._FrontBit = (GLboolean) (mode == GL_CW);
-
- if (ctx->Driver.FrontFace)
- ctx->Driver.FrontFace( ctx, mode );
-}
-
-
-/**
- * Set the polygon rasterization mode.
- *
- * \param face the polygons which \p mode applies to.
- * \param mode how polygons should be rasterized.
- *
- * \sa glPolygonMode().
- *
- * Verifies the parameters and updates gl_polygon_attrib::FrontMode and
- * gl_polygon_attrib::BackMode. On change flushes the vertices and notifies the
- * driver via the dd_function_table::PolygonMode callback.
- */
-void GLAPIENTRY
-_mesa_PolygonMode( GLenum face, GLenum mode )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (MESA_VERBOSE&VERBOSE_API)
- _mesa_debug(ctx, "glPolygonMode %s %s\n",
- _mesa_lookup_enum_by_nr(face),
- _mesa_lookup_enum_by_nr(mode));
-
- if (mode!=GL_POINT && mode!=GL_LINE && mode!=GL_FILL) {
- _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(mode)" );
- return;
- }
-
- switch (face) {
- case GL_FRONT:
- if (ctx->Polygon.FrontMode == mode)
- return;
- FLUSH_VERTICES(ctx, _NEW_POLYGON);
- ctx->Polygon.FrontMode = mode;
- break;
- case GL_FRONT_AND_BACK:
- if (ctx->Polygon.FrontMode == mode &&
- ctx->Polygon.BackMode == mode)
- return;
- FLUSH_VERTICES(ctx, _NEW_POLYGON);
- ctx->Polygon.FrontMode = mode;
- ctx->Polygon.BackMode = mode;
- break;
- case GL_BACK:
- if (ctx->Polygon.BackMode == mode)
- return;
- FLUSH_VERTICES(ctx, _NEW_POLYGON);
- ctx->Polygon.BackMode = mode;
- break;
- default:
- _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" );
- return;
- }
-
- if (ctx->Polygon.FrontMode == GL_FILL && ctx->Polygon.BackMode == GL_FILL)
- ctx->_TriangleCaps &= ~DD_TRI_UNFILLED;
- else
- ctx->_TriangleCaps |= DD_TRI_UNFILLED;
-
- if (ctx->Driver.PolygonMode)
- ctx->Driver.PolygonMode(ctx, face, mode);
-}
-
-#if _HAVE_FULL_GL
-
-
-/**
- * This routine updates the ctx->Polygon.Stipple state.
- * If we're getting the stipple data from a PBO, we map the buffer
- * in order to access the data.
- * In any case, we obey the current pixel unpacking parameters when fetching
- * the stipple data.
- *
- * In the future, this routine should be used as a fallback, called via
- * ctx->Driver.PolygonStipple(). We'll have to update all the DRI drivers
- * too.
- */
-void
-_mesa_polygon_stipple(struct gl_context *ctx, const GLubyte *pattern)
-{
- pattern = _mesa_map_validate_pbo_source(ctx, 2,
- &ctx->Unpack, 32, 32, 1,
- GL_COLOR_INDEX, GL_BITMAP, pattern,
- "glPolygonStipple");
- if (!pattern)
- return;
-
- _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack);
-
- _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
-}
-
-
-/**
- * Called by glPolygonStipple.
- */
-void GLAPIENTRY
-_mesa_PolygonStipple( const GLubyte *pattern )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (MESA_VERBOSE&VERBOSE_API)
- _mesa_debug(ctx, "glPolygonStipple\n");
-
- FLUSH_VERTICES(ctx, _NEW_POLYGONSTIPPLE);
-
- _mesa_polygon_stipple(ctx, pattern);
-
- if (ctx->Driver.PolygonStipple)
- ctx->Driver.PolygonStipple(ctx, pattern);
-}
-
-
-/**
- * Called by glPolygonStipple.
- */
-void GLAPIENTRY
-_mesa_GetPolygonStipple( GLubyte *dest )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (MESA_VERBOSE&VERBOSE_API)
- _mesa_debug(ctx, "glGetPolygonStipple\n");
-
- dest = _mesa_map_validate_pbo_dest(ctx, 2,
- &ctx->Pack, 32, 32, 1,
- GL_COLOR_INDEX, GL_BITMAP, dest,
- "glGetPolygonStipple");
- if (!dest)
- return;
-
- _mesa_pack_polygon_stipple(ctx->PolygonStipple, dest, &ctx->Pack);
-
- _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
-}
-
-
-void GLAPIENTRY
-_mesa_PolygonOffset( GLfloat factor, GLfloat units )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (MESA_VERBOSE&VERBOSE_API)
- _mesa_debug(ctx, "glPolygonOffset %f %f\n", factor, units);
-
- if (ctx->Polygon.OffsetFactor == factor &&
- ctx->Polygon.OffsetUnits == units)
- return;
-
- FLUSH_VERTICES(ctx, _NEW_POLYGON);
- ctx->Polygon.OffsetFactor = factor;
- ctx->Polygon.OffsetUnits = units;
-
- if (ctx->Driver.PolygonOffset)
- ctx->Driver.PolygonOffset( ctx, factor, units );
-}
-
-
-void GLAPIENTRY
-_mesa_PolygonOffsetEXT( GLfloat factor, GLfloat bias )
-{
- GET_CURRENT_CONTEXT(ctx);
- /* XXX mult by DepthMaxF here??? */
- _mesa_PolygonOffset(factor, bias * ctx->DrawBuffer->_DepthMaxF );
-}
-
-#endif
-
-
-/**********************************************************************/
-/** \name Initialization */
-/*@{*/
-
-/**
- * Initialize the context polygon state.
- *
- * \param ctx GL context.
- *
- * Initializes __struct gl_contextRec::Polygon and __struct gl_contextRec::PolygonStipple
- * attribute groups.
- */
-void _mesa_init_polygon( struct gl_context * ctx )
-{
- /* Polygon group */
- ctx->Polygon.CullFlag = GL_FALSE;
- ctx->Polygon.CullFaceMode = GL_BACK;
- ctx->Polygon.FrontFace = GL_CCW;
- ctx->Polygon._FrontBit = 0;
- ctx->Polygon.FrontMode = GL_FILL;
- ctx->Polygon.BackMode = GL_FILL;
- ctx->Polygon.SmoothFlag = GL_FALSE;
- ctx->Polygon.StippleFlag = GL_FALSE;
- ctx->Polygon.OffsetFactor = 0.0F;
- ctx->Polygon.OffsetUnits = 0.0F;
- ctx->Polygon.OffsetPoint = GL_FALSE;
- ctx->Polygon.OffsetLine = GL_FALSE;
- ctx->Polygon.OffsetFill = GL_FALSE;
-
-
- /* Polygon Stipple group */
- memset( ctx->PolygonStipple, 0xff, 32*sizeof(GLuint) );
-}
-
-/*@}*/
+/** + * \file polygon.c + * Polygon operations. + */ + +/* + * Mesa 3-D graphics library + * Version: 6.5.1 + * + * Copyright (C) 1999-2006 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. + */ + + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "image.h" +#include "enums.h" +#include "pack.h" +#include "pbo.h" +#include "polygon.h" +#include "mtypes.h" + + +/** + * Specify whether to cull front- or back-facing facets. + * + * \param mode culling mode. + * + * \sa glCullFace(). + * + * Verifies the parameter and updates gl_polygon_attrib::CullFaceMode. On + * change, flushes the vertices and notifies the driver via + * the dd_function_table::CullFace callback. + */ +void GLAPIENTRY +_mesa_CullFace( GLenum mode ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE&VERBOSE_API) + _mesa_debug(ctx, "glCullFace %s\n", _mesa_lookup_enum_by_nr(mode)); + + if (mode!=GL_FRONT && mode!=GL_BACK && mode!=GL_FRONT_AND_BACK) { + _mesa_error( ctx, GL_INVALID_ENUM, "glCullFace" ); + return; + } + + if (ctx->Polygon.CullFaceMode == mode) + return; + + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.CullFaceMode = mode; + + if (ctx->Driver.CullFace) + ctx->Driver.CullFace( ctx, mode ); +} + + +/** + * Define front- and back-facing + * + * \param mode orientation of front-facing polygons. + * + * \sa glFrontFace(). + * + * Verifies the parameter and updates gl_polygon_attrib::FrontFace. On change + * flushes the vertices and notifies the driver via + * the dd_function_table::FrontFace callback. + */ +void GLAPIENTRY +_mesa_FrontFace( GLenum mode ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE&VERBOSE_API) + _mesa_debug(ctx, "glFrontFace %s\n", _mesa_lookup_enum_by_nr(mode)); + + if (mode!=GL_CW && mode!=GL_CCW) { + _mesa_error( ctx, GL_INVALID_ENUM, "glFrontFace" ); + return; + } + + if (ctx->Polygon.FrontFace == mode) + return; + + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.FrontFace = mode; + + ctx->Polygon._FrontBit = (GLboolean) (mode == GL_CW); + + if (ctx->Driver.FrontFace) + ctx->Driver.FrontFace( ctx, mode ); +} + + +/** + * Set the polygon rasterization mode. + * + * \param face the polygons which \p mode applies to. + * \param mode how polygons should be rasterized. + * + * \sa glPolygonMode(). + * + * Verifies the parameters and updates gl_polygon_attrib::FrontMode and + * gl_polygon_attrib::BackMode. On change flushes the vertices and notifies the + * driver via the dd_function_table::PolygonMode callback. + */ +void GLAPIENTRY +_mesa_PolygonMode( GLenum face, GLenum mode ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE&VERBOSE_API) + _mesa_debug(ctx, "glPolygonMode %s %s\n", + _mesa_lookup_enum_by_nr(face), + _mesa_lookup_enum_by_nr(mode)); + + if (mode!=GL_POINT && mode!=GL_LINE && mode!=GL_FILL) { + _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(mode)" ); + return; + } + + switch (face) { + case GL_FRONT: + if (ctx->Polygon.FrontMode == mode) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.FrontMode = mode; + break; + case GL_FRONT_AND_BACK: + if (ctx->Polygon.FrontMode == mode && + ctx->Polygon.BackMode == mode) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.FrontMode = mode; + ctx->Polygon.BackMode = mode; + break; + case GL_BACK: + if (ctx->Polygon.BackMode == mode) + return; + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.BackMode = mode; + break; + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glPolygonMode(face)" ); + return; + } + + if (ctx->Polygon.FrontMode == GL_FILL && ctx->Polygon.BackMode == GL_FILL) + ctx->_TriangleCaps &= ~DD_TRI_UNFILLED; + else + ctx->_TriangleCaps |= DD_TRI_UNFILLED; + + if (ctx->Driver.PolygonMode) + ctx->Driver.PolygonMode(ctx, face, mode); +} + +#if _HAVE_FULL_GL + + +/** + * This routine updates the ctx->Polygon.Stipple state. + * If we're getting the stipple data from a PBO, we map the buffer + * in order to access the data. + * In any case, we obey the current pixel unpacking parameters when fetching + * the stipple data. + * + * In the future, this routine should be used as a fallback, called via + * ctx->Driver.PolygonStipple(). We'll have to update all the DRI drivers + * too. + */ +void +_mesa_polygon_stipple(struct gl_context *ctx, const GLubyte *pattern) +{ + pattern = _mesa_map_validate_pbo_source(ctx, 2, + &ctx->Unpack, 32, 32, 1, + GL_COLOR_INDEX, GL_BITMAP, pattern, + "glPolygonStipple"); + if (!pattern) + return; + + _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack); + + _mesa_unmap_pbo_source(ctx, &ctx->Unpack); +} + + +/** + * Called by glPolygonStipple. + */ +void GLAPIENTRY +_mesa_PolygonStipple( const GLubyte *pattern ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE&VERBOSE_API) + _mesa_debug(ctx, "glPolygonStipple\n"); + + FLUSH_VERTICES(ctx, _NEW_POLYGONSTIPPLE); + + _mesa_polygon_stipple(ctx, pattern); + + if (ctx->Driver.PolygonStipple) + ctx->Driver.PolygonStipple(ctx, pattern); +} + + +/** + * Called by glPolygonStipple. + */ +void GLAPIENTRY +_mesa_GetPolygonStipple( GLubyte *dest ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE&VERBOSE_API) + _mesa_debug(ctx, "glGetPolygonStipple\n"); + + dest = _mesa_map_validate_pbo_dest(ctx, 2, + &ctx->Pack, 32, 32, 1, + GL_COLOR_INDEX, GL_BITMAP, dest, + "glGetPolygonStipple"); + if (!dest) + return; + + _mesa_pack_polygon_stipple(ctx->PolygonStipple, dest, &ctx->Pack); + + _mesa_unmap_pbo_dest(ctx, &ctx->Pack); +} + + +void GLAPIENTRY +_mesa_PolygonOffset( GLfloat factor, GLfloat units ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE&VERBOSE_API) + _mesa_debug(ctx, "glPolygonOffset %f %f\n", factor, units); + + if (ctx->Polygon.OffsetFactor == factor && + ctx->Polygon.OffsetUnits == units) + return; + + FLUSH_VERTICES(ctx, _NEW_POLYGON); + ctx->Polygon.OffsetFactor = factor; + ctx->Polygon.OffsetUnits = units; + + if (ctx->Driver.PolygonOffset) + ctx->Driver.PolygonOffset( ctx, factor, units ); +} + + +void GLAPIENTRY +_mesa_PolygonOffsetEXT( GLfloat factor, GLfloat bias ) +{ + GET_CURRENT_CONTEXT(ctx); + /* XXX mult by DepthMaxF here??? */ + _mesa_PolygonOffset(factor, bias * ctx->DrawBuffer->_DepthMaxF ); +} + +#endif + + +/**********************************************************************/ +/** \name Initialization */ +/*@{*/ + +/** + * Initialize the context polygon state. + * + * \param ctx GL context. + * + * Initializes __struct gl_contextRec::Polygon and __struct gl_contextRec::PolygonStipple + * attribute groups. + */ +void _mesa_init_polygon( struct gl_context * ctx ) +{ + /* Polygon group */ + ctx->Polygon.CullFlag = GL_FALSE; + ctx->Polygon.CullFaceMode = GL_BACK; + ctx->Polygon.FrontFace = GL_CCW; + ctx->Polygon._FrontBit = 0; + ctx->Polygon.FrontMode = GL_FILL; + ctx->Polygon.BackMode = GL_FILL; + ctx->Polygon.SmoothFlag = GL_FALSE; + ctx->Polygon.StippleFlag = GL_FALSE; + ctx->Polygon.OffsetFactor = 0.0F; + ctx->Polygon.OffsetUnits = 0.0F; + ctx->Polygon.OffsetPoint = GL_FALSE; + ctx->Polygon.OffsetLine = GL_FALSE; + ctx->Polygon.OffsetFill = GL_FALSE; + + + /* Polygon Stipple group */ + memset( ctx->PolygonStipple, 0xff, 32*sizeof(GLuint) ); +} + +/*@}*/ diff --git a/mesalib/src/mesa/main/readpix.c b/mesalib/src/mesa/main/readpix.c index 3f424600c..6e09a52c8 100644 --- a/mesalib/src/mesa/main/readpix.c +++ b/mesalib/src/mesa/main/readpix.c @@ -1,243 +1,244 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.1
- *
- * Copyright (C) 1999-2008 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.
- */
-
-#include "glheader.h"
-#include "imports.h"
-#include "bufferobj.h"
-#include "context.h"
-#include "enums.h"
-#include "readpix.h"
-#include "framebuffer.h"
-#include "formats.h"
-#include "image.h"
-#include "mtypes.h"
-#include "state.h"
-
-
-/**
- * Do error checking of the format/type parameters to glReadPixels and
- * glDrawPixels.
- * \param drawing if GL_TRUE do checking for DrawPixels, else do checking
- * for ReadPixels.
- * \return GL_TRUE if error detected, GL_FALSE if no errors
- */
-GLboolean
-_mesa_error_check_format_type(struct gl_context *ctx, GLenum format, GLenum type,
- GLboolean drawing)
-{
- const char *readDraw = drawing ? "Draw" : "Read";
- const GLboolean reading = !drawing;
-
- /* state validation should have already been done */
- ASSERT(ctx->NewState == 0x0);
-
- if (ctx->Extensions.EXT_packed_depth_stencil
- && type == GL_UNSIGNED_INT_24_8_EXT
- && format != GL_DEPTH_STENCIL_EXT) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "gl%sPixels(format is not GL_DEPTH_STENCIL_EXT)", readDraw);
- return GL_TRUE;
- }
-
- /* basic combinations test */
- if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "gl%sPixels(format or type)", readDraw);
- return GL_TRUE;
- }
-
- /* additional checks */
- switch (format) {
- case GL_RG:
- case GL_RED:
- case GL_GREEN:
- case GL_BLUE:
- case GL_ALPHA:
- case GL_LUMINANCE:
- case GL_LUMINANCE_ALPHA:
- case GL_RGB:
- case GL_BGR:
- case GL_RGBA:
- case GL_BGRA:
- case GL_ABGR_EXT:
- case GL_RED_INTEGER_EXT:
- case GL_GREEN_INTEGER_EXT:
- case GL_BLUE_INTEGER_EXT:
- case GL_ALPHA_INTEGER_EXT:
- case GL_RGB_INTEGER_EXT:
- case GL_RGBA_INTEGER_EXT:
- case GL_BGR_INTEGER_EXT:
- case GL_BGRA_INTEGER_EXT:
- case GL_LUMINANCE_INTEGER_EXT:
- case GL_LUMINANCE_ALPHA_INTEGER_EXT:
- if (!drawing) {
- /* reading */
- if (!_mesa_source_buffer_exists(ctx, GL_COLOR)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glReadPixels(no color buffer)");
- return GL_TRUE;
- }
- }
- break;
- case GL_COLOR_INDEX:
- if (drawing) {
- if (ctx->PixelMaps.ItoR.Size == 0 ||
- ctx->PixelMaps.ItoG.Size == 0 ||
- ctx->PixelMaps.ItoB.Size == 0) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glDrawPixels(drawing color index pixels into RGB buffer)");
- return GL_TRUE;
- }
- }
- else {
- /* reading */
- if (!_mesa_source_buffer_exists(ctx, GL_COLOR)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glReadPixels(no color buffer)");
- return GL_TRUE;
- }
- /* We no longer support CI-mode color buffers so trying to read
- * GL_COLOR_INDEX pixels is always an error.
- */
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glReadPixels(color buffer is RGB)");
- return GL_TRUE;
- }
- break;
- case GL_STENCIL_INDEX:
- if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) ||
- (reading && !_mesa_source_buffer_exists(ctx, format))) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "gl%sPixels(no stencil buffer)", readDraw);
- return GL_TRUE;
- }
- break;
- case GL_DEPTH_COMPONENT:
- if ((drawing && !_mesa_dest_buffer_exists(ctx, format))) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "gl%sPixels(no depth buffer)", readDraw);
- return GL_TRUE;
- }
- break;
- case GL_DEPTH_STENCIL_EXT:
- if (!ctx->Extensions.EXT_packed_depth_stencil ||
- type != GL_UNSIGNED_INT_24_8_EXT) {
- _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw);
- return GL_TRUE;
- }
- if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) ||
- (reading && !_mesa_source_buffer_exists(ctx, format))) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "gl%sPixels(no depth or stencil buffer)", readDraw);
- return GL_TRUE;
- }
- break;
- default:
- /* this should have been caught in _mesa_is_legal_format_type() */
- _mesa_problem(ctx, "unexpected format in _mesa_%sPixels", readDraw);
- return GL_TRUE;
- }
-
- /* no errors */
- return GL_FALSE;
-}
-
-
-
-void GLAPIENTRY
-_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
- GLenum format, GLenum type, GLvoid *pixels )
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- FLUSH_CURRENT(ctx, 0);
-
- if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n",
- width, height,
- _mesa_lookup_enum_by_nr(format),
- _mesa_lookup_enum_by_nr(type),
- pixels);
-
- if (width < 0 || height < 0) {
- _mesa_error( ctx, GL_INVALID_VALUE,
- "glReadPixels(width=%d height=%d)", width, height );
- return;
- }
-
- if (ctx->NewState)
- _mesa_update_state(ctx);
-
- if (_mesa_error_check_format_type(ctx, format, type, GL_FALSE)) {
- /* found an error */
- return;
- }
-
- /* Check that the destination format and source buffer are both
- * integer-valued or both non-integer-valued.
- */
- if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) {
- const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
- const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format);
- const GLboolean dstInteger = _mesa_is_integer_format(format);
- if (dstInteger != srcInteger) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glReadPixels(integer / non-integer format mismatch");
- return;
- }
- }
-
- if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
- "glReadPixels(incomplete framebuffer)" );
- return;
- }
-
- if (!_mesa_source_buffer_exists(ctx, format)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)");
- return;
- }
-
- if (width == 0 || height == 0)
- return; /* nothing to do */
-
- if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
- if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1,
- format, type, pixels)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glReadPixels(invalid PBO access)");
- return;
- }
-
- if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
- /* buffer is mapped - that's an error */
- _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)");
- return;
- }
- }
-
- ctx->Driver.ReadPixels(ctx, x, y, width, height,
- format, type, &ctx->Pack, pixels);
-}
+/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2008 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. + */ + +#include "glheader.h" +#include "imports.h" +#include "bufferobj.h" +#include "context.h" +#include "enums.h" +#include "readpix.h" +#include "framebuffer.h" +#include "formats.h" +#include "image.h" +#include "mtypes.h" +#include "pbo.h" +#include "state.h" + + +/** + * Do error checking of the format/type parameters to glReadPixels and + * glDrawPixels. + * \param drawing if GL_TRUE do checking for DrawPixels, else do checking + * for ReadPixels. + * \return GL_TRUE if error detected, GL_FALSE if no errors + */ +GLboolean +_mesa_error_check_format_type(struct gl_context *ctx, GLenum format, GLenum type, + GLboolean drawing) +{ + const char *readDraw = drawing ? "Draw" : "Read"; + const GLboolean reading = !drawing; + + /* state validation should have already been done */ + ASSERT(ctx->NewState == 0x0); + + if (ctx->Extensions.EXT_packed_depth_stencil + && type == GL_UNSIGNED_INT_24_8_EXT + && format != GL_DEPTH_STENCIL_EXT) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "gl%sPixels(format is not GL_DEPTH_STENCIL_EXT)", readDraw); + return GL_TRUE; + } + + /* basic combinations test */ + if (!_mesa_is_legal_format_and_type(ctx, format, type)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "gl%sPixels(format or type)", readDraw); + return GL_TRUE; + } + + /* additional checks */ + switch (format) { + case GL_RG: + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_RGB: + case GL_BGR: + case GL_RGBA: + case GL_BGRA: + case GL_ABGR_EXT: + case GL_RED_INTEGER_EXT: + case GL_GREEN_INTEGER_EXT: + case GL_BLUE_INTEGER_EXT: + case GL_ALPHA_INTEGER_EXT: + case GL_RGB_INTEGER_EXT: + case GL_RGBA_INTEGER_EXT: + case GL_BGR_INTEGER_EXT: + case GL_BGRA_INTEGER_EXT: + case GL_LUMINANCE_INTEGER_EXT: + case GL_LUMINANCE_ALPHA_INTEGER_EXT: + if (!drawing) { + /* reading */ + if (!_mesa_source_buffer_exists(ctx, GL_COLOR)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glReadPixels(no color buffer)"); + return GL_TRUE; + } + } + break; + case GL_COLOR_INDEX: + if (drawing) { + if (ctx->PixelMaps.ItoR.Size == 0 || + ctx->PixelMaps.ItoG.Size == 0 || + ctx->PixelMaps.ItoB.Size == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDrawPixels(drawing color index pixels into RGB buffer)"); + return GL_TRUE; + } + } + else { + /* reading */ + if (!_mesa_source_buffer_exists(ctx, GL_COLOR)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glReadPixels(no color buffer)"); + return GL_TRUE; + } + /* We no longer support CI-mode color buffers so trying to read + * GL_COLOR_INDEX pixels is always an error. + */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glReadPixels(color buffer is RGB)"); + return GL_TRUE; + } + break; + case GL_STENCIL_INDEX: + if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) || + (reading && !_mesa_source_buffer_exists(ctx, format))) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "gl%sPixels(no stencil buffer)", readDraw); + return GL_TRUE; + } + break; + case GL_DEPTH_COMPONENT: + if ((drawing && !_mesa_dest_buffer_exists(ctx, format))) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "gl%sPixels(no depth buffer)", readDraw); + return GL_TRUE; + } + break; + case GL_DEPTH_STENCIL_EXT: + if (!ctx->Extensions.EXT_packed_depth_stencil || + type != GL_UNSIGNED_INT_24_8_EXT) { + _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw); + return GL_TRUE; + } + if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) || + (reading && !_mesa_source_buffer_exists(ctx, format))) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "gl%sPixels(no depth or stencil buffer)", readDraw); + return GL_TRUE; + } + break; + default: + /* this should have been caught in _mesa_is_legal_format_type() */ + _mesa_problem(ctx, "unexpected format in _mesa_%sPixels", readDraw); + return GL_TRUE; + } + + /* no errors */ + return GL_FALSE; +} + + + +void GLAPIENTRY +_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + FLUSH_CURRENT(ctx, 0); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n", + width, height, + _mesa_lookup_enum_by_nr(format), + _mesa_lookup_enum_by_nr(type), + pixels); + + if (width < 0 || height < 0) { + _mesa_error( ctx, GL_INVALID_VALUE, + "glReadPixels(width=%d height=%d)", width, height ); + return; + } + + if (ctx->NewState) + _mesa_update_state(ctx); + + if (_mesa_error_check_format_type(ctx, format, type, GL_FALSE)) { + /* found an error */ + return; + } + + /* Check that the destination format and source buffer are both + * integer-valued or both non-integer-valued. + */ + if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) { + const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; + const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format); + const GLboolean dstInteger = _mesa_is_integer_format(format); + if (dstInteger != srcInteger) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glReadPixels(integer / non-integer format mismatch"); + return; + } + } + + if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "glReadPixels(incomplete framebuffer)" ); + return; + } + + if (!_mesa_source_buffer_exists(ctx, format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)"); + return; + } + + if (width == 0 || height == 0) + return; /* nothing to do */ + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1, + format, type, pixels)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glReadPixels(invalid PBO access)"); + return; + } + + if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { + /* buffer is mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)"); + return; + } + } + + ctx->Driver.ReadPixels(ctx, x, y, width, height, + format, type, &ctx->Pack, pixels); +} diff --git a/mesalib/src/mesa/main/texcompress_rgtc.c b/mesalib/src/mesa/main/texcompress_rgtc.c index b7725f4a9..2f3a0f214 100644 --- a/mesalib/src/mesa/main/texcompress_rgtc.c +++ b/mesalib/src/mesa/main/texcompress_rgtc.c @@ -46,9 +46,9 @@ #define RGTC_DEBUG 0 -static void encode_rgtc_chan_u(GLubyte *blkaddr, GLubyte srccolors[4][4], - GLint numxpixels, GLint numypixels); -static void encode_rgtc_chan_s(GLbyte *blkaddr, GLbyte srccolors[4][4], +static void unsigned_encode_rgtc_chan(GLubyte *blkaddr, GLubyte srccolors[4][4], + GLint numxpixels, GLint numypixels); +static void signed_encode_rgtc_chan(GLbyte *blkaddr, GLbyte srccolors[4][4], GLint numxpixels, GLint numypixels); static void extractsrc_u( GLubyte srcpixels[4][4], const GLchan *srcaddr, @@ -88,7 +88,7 @@ _mesa_texstore_red_rgtc1(TEXSTORE_PARAMS) const GLchan *tempImage = NULL; int i, j; int numxpixels, numypixels; - const void *srcaddr; + const GLchan *srcaddr; GLubyte srcpixels[4][4]; GLubyte *blkaddr; GLint dstRowDiff; @@ -123,7 +123,7 @@ _mesa_texstore_red_rgtc1(TEXSTORE_PARAMS) if (srcWidth > i + 3) numxpixels = 4; else numxpixels = srcWidth - i; extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1); - encode_rgtc_chan_u(blkaddr, srcpixels, numxpixels, numypixels); + unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); srcaddr += numxpixels; blkaddr += 8; } @@ -177,7 +177,7 @@ _mesa_texstore_signed_red_rgtc1(TEXSTORE_PARAMS) if (srcWidth > i + 3) numxpixels = 4; else numxpixels = srcWidth - i; extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1); - encode_rgtc_chan_s(blkaddr, srcpixels, numxpixels, numypixels); + signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); srcaddr += numxpixels; blkaddr += 8; } @@ -197,7 +197,7 @@ _mesa_texstore_rg_rgtc2(TEXSTORE_PARAMS) const GLchan *tempImage = NULL; int i, j; int numxpixels, numypixels; - const void *srcaddr; + const GLchan *srcaddr; GLubyte srcpixels[4][4]; GLubyte *blkaddr; GLint dstRowDiff; @@ -232,11 +232,11 @@ _mesa_texstore_rg_rgtc2(TEXSTORE_PARAMS) if (srcWidth > i + 3) numxpixels = 4; else numxpixels = srcWidth - i; extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2); - encode_rgtc_chan_u(blkaddr, srcpixels, numxpixels, numypixels); + unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; extractsrc_u(srcpixels, (GLchan *)srcaddr + 1, srcWidth, numxpixels, numypixels, 2); - encode_rgtc_chan_u(blkaddr, srcpixels, numxpixels, numypixels); + unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; @@ -294,11 +294,11 @@ _mesa_texstore_signed_rg_rgtc2(TEXSTORE_PARAMS) else numxpixels = srcWidth - i; extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2); - encode_rgtc_chan_s(blkaddr, srcpixels, numxpixels, numypixels); + signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; extractsrc_s(srcpixels, srcaddr + 1, srcWidth, numxpixels, numypixels, 2); - encode_rgtc_chan_s(blkaddr, srcpixels, numxpixels, numypixels); + signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; srcaddr += numxpixels * 2; @@ -427,696 +427,27 @@ _mesa_fetch_texel_2d_f_signed_rg_rgtc2(const struct gl_texture_image *texImage, texel[ACOMP] = 1.0; } -static void write_rgtc_encoded_channel(GLubyte *blkaddr, - GLubyte alphabase1, - GLubyte alphabase2, - GLubyte alphaenc[16]) -{ - *blkaddr++ = alphabase1; - *blkaddr++ = alphabase2; - *blkaddr++ = alphaenc[0] | (alphaenc[1] << 3) | ((alphaenc[2] & 3) << 6); - *blkaddr++ = (alphaenc[2] >> 2) | (alphaenc[3] << 1) | (alphaenc[4] << 4) | ((alphaenc[5] & 1) << 7); - *blkaddr++ = (alphaenc[5] >> 1) | (alphaenc[6] << 2) | (alphaenc[7] << 5); - *blkaddr++ = alphaenc[8] | (alphaenc[9] << 3) | ((alphaenc[10] & 3) << 6); - *blkaddr++ = (alphaenc[10] >> 2) | (alphaenc[11] << 1) | (alphaenc[12] << 4) | ((alphaenc[13] & 1) << 7); - *blkaddr++ = (alphaenc[13] >> 1) | (alphaenc[14] << 2) | (alphaenc[15] << 5); -} - -static void encode_rgtc_chan_u(GLubyte *blkaddr, GLubyte srccolors[4][4], - GLint numxpixels, GLint numypixels) -{ - GLubyte alphabase[2], alphause[2]; - GLshort alphatest[2] = { 0 }; - GLuint alphablockerror1, alphablockerror2, alphablockerror3; - GLubyte i, j, aindex, acutValues[7]; - GLubyte alphaenc1[16], alphaenc2[16], alphaenc3[16]; - GLboolean alphaabsmin = GL_FALSE; - GLboolean alphaabsmax = GL_FALSE; - GLshort alphadist; - - /* find lowest and highest alpha value in block, alphabase[0] lowest, alphabase[1] highest */ - alphabase[0] = 0xff; alphabase[1] = 0x0; - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if (srccolors[j][i] == 0) - alphaabsmin = GL_TRUE; - else if (srccolors[j][i] == 255) - alphaabsmax = GL_TRUE; - else { - if (srccolors[j][i] > alphabase[1]) - alphabase[1] = srccolors[j][i]; - if (srccolors[j][i] < alphabase[0]) - alphabase[0] = srccolors[j][i]; - } - } - } - - - if ((alphabase[0] > alphabase[1]) && !(alphaabsmin && alphaabsmax)) { /* one color, either max or min */ - /* shortcut here since it is a very common case (and also avoids later problems) */ - /* || (alphabase[0] == alphabase[1] && !alphaabsmin && !alphaabsmax) */ - /* could also thest for alpha0 == alpha1 (and not min/max), but probably not common, so don't bother */ - - *blkaddr++ = srccolors[0][0]; - blkaddr++; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; -#if RGTC_DEBUG - fprintf(stderr, "enc0 used\n"); -#endif - return; - } - - /* find best encoding for alpha0 > alpha1 */ - /* it's possible this encoding is better even if both alphaabsmin and alphaabsmax are true */ - alphablockerror1 = 0x0; - alphablockerror2 = 0xffffffff; - alphablockerror3 = 0xffffffff; - if (alphaabsmin) alphause[0] = 0; - else alphause[0] = alphabase[0]; - if (alphaabsmax) alphause[1] = 255; - else alphause[1] = alphabase[1]; - /* calculate the 7 cut values, just the middle between 2 of the computed alpha values */ - for (aindex = 0; aindex < 7; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphause[0] * (2*aindex + 1) + alphause[1] * (14 - (2*aindex + 1))) / 14; - } - - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i] > acutValues[0]) { - alphaenc1[4*j + i] = 0; - alphadist = srccolors[j][i] - alphause[1]; - } - else if (srccolors[j][i] > acutValues[1]) { - alphaenc1[4*j + i] = 2; - alphadist = srccolors[j][i] - (alphause[1] * 6 + alphause[0] * 1) / 7; - } - else if (srccolors[j][i] > acutValues[2]) { - alphaenc1[4*j + i] = 3; - alphadist = srccolors[j][i] - (alphause[1] * 5 + alphause[0] * 2) / 7; - } - else if (srccolors[j][i] > acutValues[3]) { - alphaenc1[4*j + i] = 4; - alphadist = srccolors[j][i] - (alphause[1] * 4 + alphause[0] * 3) / 7; - } - else if (srccolors[j][i] > acutValues[4]) { - alphaenc1[4*j + i] = 5; - alphadist = srccolors[j][i] - (alphause[1] * 3 + alphause[0] * 4) / 7; - } - else if (srccolors[j][i] > acutValues[5]) { - alphaenc1[4*j + i] = 6; - alphadist = srccolors[j][i] - (alphause[1] * 2 + alphause[0] * 5) / 7; - } - else if (srccolors[j][i] > acutValues[6]) { - alphaenc1[4*j + i] = 7; - alphadist = srccolors[j][i] - (alphause[1] * 1 + alphause[0] * 6) / 7; - } - else { - alphaenc1[4*j + i] = 1; - alphadist = srccolors[j][i] - alphause[0]; - } - alphablockerror1 += alphadist * alphadist; - } - } - -#if RGTC_DEBUG - for (i = 0; i < 16; i++) { - fprintf(stderr, "%d ", alphaenc1[i]); - } - fprintf(stderr, "cutVals "); - for (i = 0; i < 8; i++) { - fprintf(stderr, "%d ", acutValues[i]); - } - fprintf(stderr, "srcVals "); - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - fprintf(stderr, "%d ", srccolors[j][i]); - } - } - fprintf(stderr, "\n"); -#endif - - /* it's not very likely this encoding is better if both alphaabsmin and alphaabsmax - are false but try it anyway */ - if (alphablockerror1 >= 32) { - - /* don't bother if encoding is already very good, this condition should also imply - we have valid alphabase colors which we absolutely need (alphabase[0] <= alphabase[1]) */ - alphablockerror2 = 0; - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphabase[0] * (10 - (2*aindex + 1)) + alphabase[1] * (2*aindex + 1)) / 10; - } - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i] == 0) { - alphaenc2[4*j + i] = 6; - alphadist = 0; - } - else if (srccolors[j][i] == 255) { - alphaenc2[4*j + i] = 7; - alphadist = 0; - } - else if (srccolors[j][i] <= acutValues[0]) { - alphaenc2[4*j + i] = 0; - alphadist = srccolors[j][i] - alphabase[0]; - } - else if (srccolors[j][i] <= acutValues[1]) { - alphaenc2[4*j + i] = 2; - alphadist = srccolors[j][i] - (alphabase[0] * 4 + alphabase[1] * 1) / 5; - } - else if (srccolors[j][i] <= acutValues[2]) { - alphaenc2[4*j + i] = 3; - alphadist = srccolors[j][i] - (alphabase[0] * 3 + alphabase[1] * 2) / 5; - } - else if (srccolors[j][i] <= acutValues[3]) { - alphaenc2[4*j + i] = 4; - alphadist = srccolors[j][i] - (alphabase[0] * 2 + alphabase[1] * 3) / 5; - } - else if (srccolors[j][i] <= acutValues[4]) { - alphaenc2[4*j + i] = 5; - alphadist = srccolors[j][i] - (alphabase[0] * 1 + alphabase[1] * 4) / 5; - } - else { - alphaenc2[4*j + i] = 1; - alphadist = srccolors[j][i] - alphabase[1]; - } - alphablockerror2 += alphadist * alphadist; - } - } - - - /* skip this if the error is already very small - this encoding is MUCH better on average than #2 though, but expensive! */ - if ((alphablockerror2 > 96) && (alphablockerror1 > 96)) { - GLshort blockerrlin1 = 0; - GLshort blockerrlin2 = 0; - GLubyte nralphainrangelow = 0; - GLubyte nralphainrangehigh = 0; - alphatest[0] = 0xff; - alphatest[1] = 0x0; - /* if we have large range it's likely there are values close to 0/255, try to map them to 0/255 */ - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if ((srccolors[j][i] > alphatest[1]) && (srccolors[j][i] < (255 -(alphabase[1] - alphabase[0]) / 28))) - alphatest[1] = srccolors[j][i]; - if ((srccolors[j][i] < alphatest[0]) && (srccolors[j][i] > (alphabase[1] - alphabase[0]) / 28)) - alphatest[0] = srccolors[j][i]; - } - } - /* shouldn't happen too often, don't really care about those degenerated cases */ - if (alphatest[1] <= alphatest[0]) { - alphatest[0] = 1; - alphatest[1] = 254; - } - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; - } - - /* find the "average" difference between the alpha values and the next encoded value. - This is then used to calculate new base values. - Should there be some weighting, i.e. those values closer to alphatest[x] have more weight, - since they will see more improvement, and also because the values in the middle are somewhat - likely to get no improvement at all (because the base values might move in different directions)? - OTOH it would mean the values in the middle are even less likely to get an improvement - */ - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if (srccolors[j][i] <= alphatest[0] / 2) { - } - else if (srccolors[j][i] > ((255 + alphatest[1]) / 2)) { - } - else if (srccolors[j][i] <= acutValues[0]) { - blockerrlin1 += (srccolors[j][i] - alphatest[0]); - nralphainrangelow += 1; - } - else if (srccolors[j][i] <= acutValues[1]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i] <= acutValues[2]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i] <= acutValues[3]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i] <= acutValues[4]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else { - blockerrlin2 += (srccolors[j][i] - alphatest[1]); - nralphainrangehigh += 1; - } - } - } - /* shouldn't happen often, needed to avoid div by zero */ - if (nralphainrangelow == 0) nralphainrangelow = 1; - if (nralphainrangehigh == 0) nralphainrangehigh = 1; - alphatest[0] = alphatest[0] + (blockerrlin1 / nralphainrangelow); -#if RGTC_DEBUG - fprintf(stderr, "block err lin low %d, nr %d\n", blockerrlin1, nralphainrangelow); - fprintf(stderr, "block err lin high %d, nr %d\n", blockerrlin2, nralphainrangehigh); -#endif - /* again shouldn't really happen often... */ - if (alphatest[0] < 0) { - alphatest[0] = 0; - } - alphatest[1] = alphatest[1] + (blockerrlin2 / nralphainrangehigh); - if (alphatest[1] > 255) { - alphatest[1] = 255; - } - - alphablockerror3 = 0; - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; - } - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i] <= alphatest[0] / 2) { - alphaenc3[4*j + i] = 6; - alphadist = srccolors[j][i]; - } - else if (srccolors[j][i] > ((255 + alphatest[1]) / 2)) { - alphaenc3[4*j + i] = 7; - alphadist = 255 - srccolors[j][i]; - } - else if (srccolors[j][i] <= acutValues[0]) { - alphaenc3[4*j + i] = 0; - alphadist = srccolors[j][i] - alphatest[0]; - } - else if (srccolors[j][i] <= acutValues[1]) { - alphaenc3[4*j + i] = 2; - alphadist = srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5; - } - else if (srccolors[j][i] <= acutValues[2]) { - alphaenc3[4*j + i] = 3; - alphadist = srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5; - } - else if (srccolors[j][i] <= acutValues[3]) { - alphaenc3[4*j + i] = 4; - alphadist = srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5; - } - else if (srccolors[j][i] <= acutValues[4]) { - alphaenc3[4*j + i] = 5; - alphadist = srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5; - } - else { - alphaenc3[4*j + i] = 1; - alphadist = srccolors[j][i] - alphatest[1]; - } - alphablockerror3 += alphadist * alphadist; - } - } - } - } - /* write the alpha values and encoding back. */ - if ((alphablockerror1 <= alphablockerror2) && (alphablockerror1 <= alphablockerror3)) { -#if RGTC_DEBUG - if (alphablockerror1 > 96) fprintf(stderr, "enc1 used, error %d\n", alphablockerror1); -#endif - write_rgtc_encoded_channel( blkaddr, alphause[1], alphause[0], alphaenc1 ); - } - else if (alphablockerror2 <= alphablockerror3) { -#if RGTC_DEBUG - if (alphablockerror2 > 96) fprintf(stderr, "enc2 used, error %d\n", alphablockerror2); -#endif - write_rgtc_encoded_channel( blkaddr, alphabase[0], alphabase[1], alphaenc2 ); - } - else { -#if RGTC_DEBUG - fprintf(stderr, "enc3 used, error %d\n", alphablockerror3); -#endif - write_rgtc_encoded_channel( blkaddr, (GLubyte)alphatest[0], (GLubyte)alphatest[1], alphaenc3 ); - } -} - - -static void write_rgtc_encoded_channel_s(GLbyte *blkaddr, - GLbyte alphabase1, - GLbyte alphabase2, - GLbyte alphaenc[16]) -{ - *blkaddr++ = alphabase1; - *blkaddr++ = alphabase2; - *blkaddr++ = alphaenc[0] | (alphaenc[1] << 3) | ((alphaenc[2] & 3) << 6); - *blkaddr++ = (alphaenc[2] >> 2) | (alphaenc[3] << 1) | (alphaenc[4] << 4) | ((alphaenc[5] & 1) << 7); - *blkaddr++ = (alphaenc[5] >> 1) | (alphaenc[6] << 2) | (alphaenc[7] << 5); - *blkaddr++ = alphaenc[8] | (alphaenc[9] << 3) | ((alphaenc[10] & 3) << 6); - *blkaddr++ = (alphaenc[10] >> 2) | (alphaenc[11] << 1) | (alphaenc[12] << 4) | ((alphaenc[13] & 1) << 7); - *blkaddr++ = (alphaenc[13] >> 1) | (alphaenc[14] << 2) | (alphaenc[15] << 5); -} - -static void encode_rgtc_chan_s(GLbyte *blkaddr, GLbyte srccolors[4][4], - GLint numxpixels, GLint numypixels) -{ - GLbyte alphabase[2], alphause[2]; - GLshort alphatest[2] = { 0 }; - GLuint alphablockerror1, alphablockerror2, alphablockerror3; - GLbyte i, j, aindex, acutValues[7]; - GLbyte alphaenc1[16], alphaenc2[16], alphaenc3[16]; - GLboolean alphaabsmin = GL_FALSE; - GLboolean alphaabsmax = GL_FALSE; - GLshort alphadist; - - /* find lowest and highest alpha value in block, alphabase[0] lowest, alphabase[1] highest */ - alphabase[0] = 0xff; alphabase[1] = 0x0; - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if (srccolors[j][i] == 0) - alphaabsmin = GL_TRUE; - else if (srccolors[j][i] == 255) - alphaabsmax = GL_TRUE; - else { - if (srccolors[j][i] > alphabase[1]) - alphabase[1] = srccolors[j][i]; - if (srccolors[j][i] < alphabase[0]) - alphabase[0] = srccolors[j][i]; - } - } - } - - - if ((alphabase[0] > alphabase[1]) && !(alphaabsmin && alphaabsmax)) { /* one color, either max or min */ - /* shortcut here since it is a very common case (and also avoids later problems) */ - /* || (alphabase[0] == alphabase[1] && !alphaabsmin && !alphaabsmax) */ - /* could also thest for alpha0 == alpha1 (and not min/max), but probably not common, so don't bother */ - - *blkaddr++ = srccolors[0][0]; - blkaddr++; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; -#if RGTC_DEBUG - fprintf(stderr, "enc0 used\n"); -#endif - return; - } - - /* find best encoding for alpha0 > alpha1 */ - /* it's possible this encoding is better even if both alphaabsmin and alphaabsmax are true */ - alphablockerror1 = 0x0; - alphablockerror2 = 0xffffffff; - alphablockerror3 = 0xffffffff; - if (alphaabsmin) alphause[0] = 0; - else alphause[0] = alphabase[0]; - if (alphaabsmax) alphause[1] = 255; - else alphause[1] = alphabase[1]; - /* calculate the 7 cut values, just the middle between 2 of the computed alpha values */ - for (aindex = 0; aindex < 7; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphause[0] * (2*aindex + 1) + alphause[1] * (14 - (2*aindex + 1))) / 14; - } +#define TAG(x) unsigned_##x - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i] > acutValues[0]) { - alphaenc1[4*j + i] = 0; - alphadist = srccolors[j][i] - alphause[1]; - } - else if (srccolors[j][i] > acutValues[1]) { - alphaenc1[4*j + i] = 2; - alphadist = srccolors[j][i] - (alphause[1] * 6 + alphause[0] * 1) / 7; - } - else if (srccolors[j][i] > acutValues[2]) { - alphaenc1[4*j + i] = 3; - alphadist = srccolors[j][i] - (alphause[1] * 5 + alphause[0] * 2) / 7; - } - else if (srccolors[j][i] > acutValues[3]) { - alphaenc1[4*j + i] = 4; - alphadist = srccolors[j][i] - (alphause[1] * 4 + alphause[0] * 3) / 7; - } - else if (srccolors[j][i] > acutValues[4]) { - alphaenc1[4*j + i] = 5; - alphadist = srccolors[j][i] - (alphause[1] * 3 + alphause[0] * 4) / 7; - } - else if (srccolors[j][i] > acutValues[5]) { - alphaenc1[4*j + i] = 6; - alphadist = srccolors[j][i] - (alphause[1] * 2 + alphause[0] * 5) / 7; - } - else if (srccolors[j][i] > acutValues[6]) { - alphaenc1[4*j + i] = 7; - alphadist = srccolors[j][i] - (alphause[1] * 1 + alphause[0] * 6) / 7; - } - else { - alphaenc1[4*j + i] = 1; - alphadist = srccolors[j][i] - alphause[0]; - } - alphablockerror1 += alphadist * alphadist; - } - } -#if RGTC_DEBUG - for (i = 0; i < 16; i++) { - fprintf(stderr, "%d ", alphaenc1[i]); - } - fprintf(stderr, "cutVals "); - for (i = 0; i < 8; i++) { - fprintf(stderr, "%d ", acutValues[i]); - } - fprintf(stderr, "srcVals "); - for (j = 0; j < numypixels; j++) - for (i = 0; i < numxpixels; i++) { - fprintf(stderr, "%d ", srccolors[j][i]); - } - - fprintf(stderr, "\n"); -#endif +#define TYPE GLubyte +#define T_MIN 0 +#define T_MAX 0xff - /* it's not very likely this encoding is better if both alphaabsmin and alphaabsmax - are false but try it anyway */ - if (alphablockerror1 >= 32) { - - /* don't bother if encoding is already very good, this condition should also imply - we have valid alphabase colors which we absolutely need (alphabase[0] <= alphabase[1]) */ - alphablockerror2 = 0; - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphabase[0] * (10 - (2*aindex + 1)) + alphabase[1] * (2*aindex + 1)) / 10; - } - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i] == 0) { - alphaenc2[4*j + i] = 6; - alphadist = 0; - } - else if (srccolors[j][i] == 255) { - alphaenc2[4*j + i] = 7; - alphadist = 0; - } - else if (srccolors[j][i] <= acutValues[0]) { - alphaenc2[4*j + i] = 0; - alphadist = srccolors[j][i] - alphabase[0]; - } - else if (srccolors[j][i] <= acutValues[1]) { - alphaenc2[4*j + i] = 2; - alphadist = srccolors[j][i] - (alphabase[0] * 4 + alphabase[1] * 1) / 5; - } - else if (srccolors[j][i] <= acutValues[2]) { - alphaenc2[4*j + i] = 3; - alphadist = srccolors[j][i] - (alphabase[0] * 3 + alphabase[1] * 2) / 5; - } - else if (srccolors[j][i] <= acutValues[3]) { - alphaenc2[4*j + i] = 4; - alphadist = srccolors[j][i] - (alphabase[0] * 2 + alphabase[1] * 3) / 5; - } - else if (srccolors[j][i] <= acutValues[4]) { - alphaenc2[4*j + i] = 5; - alphadist = srccolors[j][i] - (alphabase[0] * 1 + alphabase[1] * 4) / 5; - } - else { - alphaenc2[4*j + i] = 1; - alphadist = srccolors[j][i] - alphabase[1]; - } - alphablockerror2 += alphadist * alphadist; - } - } +#include "texcompress_rgtc_tmp.h" +#undef TAG +#undef TYPE +#undef T_MIN +#undef T_MAX - /* skip this if the error is already very small - this encoding is MUCH better on average than #2 though, but expensive! */ - if ((alphablockerror2 > 96) && (alphablockerror1 > 96)) { - GLshort blockerrlin1 = 0; - GLshort blockerrlin2 = 0; - GLubyte nralphainrangelow = 0; - GLubyte nralphainrangehigh = 0; - alphatest[0] = 0xff; - alphatest[1] = 0x0; - /* if we have large range it's likely there are values close to 0/255, try to map them to 0/255 */ - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if ((srccolors[j][i] > alphatest[1]) && (srccolors[j][i] < (255 -(alphabase[1] - alphabase[0]) / 28))) - alphatest[1] = srccolors[j][i]; - if ((srccolors[j][i] < alphatest[0]) && (srccolors[j][i] > (alphabase[1] - alphabase[0]) / 28)) - alphatest[0] = srccolors[j][i]; - } - } - /* shouldn't happen too often, don't really care about those degenerated cases */ - if (alphatest[1] <= alphatest[0]) { - alphatest[0] = 1; - alphatest[1] = 254; - } - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; - } +#define TAG(x) signed_##x +#define TYPE GLbyte +#define T_MIN (GLbyte)-127 +#define T_MAX (GLbyte)127 - /* find the "average" difference between the alpha values and the next encoded value. - This is then used to calculate new base values. - Should there be some weighting, i.e. those values closer to alphatest[x] have more weight, - since they will see more improvement, and also because the values in the middle are somewhat - likely to get no improvement at all (because the base values might move in different directions)? - OTOH it would mean the values in the middle are even less likely to get an improvement - */ - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if (srccolors[j][i] <= alphatest[0] / 2) { - } - else if (srccolors[j][i] > ((255 + alphatest[1]) / 2)) { - } - else if (srccolors[j][i] <= acutValues[0]) { - blockerrlin1 += (srccolors[j][i] - alphatest[0]); - nralphainrangelow += 1; - } - else if (srccolors[j][i] <= acutValues[1]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i] <= acutValues[2]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i] <= acutValues[3]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i] <= acutValues[4]) { - blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); - blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else { - blockerrlin2 += (srccolors[j][i] - alphatest[1]); - nralphainrangehigh += 1; - } - } - } - /* shouldn't happen often, needed to avoid div by zero */ - if (nralphainrangelow == 0) nralphainrangelow = 1; - if (nralphainrangehigh == 0) nralphainrangehigh = 1; - alphatest[0] = alphatest[0] + (blockerrlin1 / nralphainrangelow); -#if RGTC_DEBUG - fprintf(stderr, "block err lin low %d, nr %d\n", blockerrlin1, nralphainrangelow); - fprintf(stderr, "block err lin high %d, nr %d\n", blockerrlin2, nralphainrangehigh); -#endif - /* again shouldn't really happen often... */ - if (alphatest[0] < 0) { - alphatest[0] = 0; - } - alphatest[1] = alphatest[1] + (blockerrlin2 / nralphainrangehigh); - if (alphatest[1] > 255) { - alphatest[1] = 255; - } +#include "texcompress_rgtc_tmp.h" - alphablockerror3 = 0; - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; - } - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i] <= alphatest[0] / 2) { - alphaenc3[4*j + i] = 6; - alphadist = srccolors[j][i]; - } - else if (srccolors[j][i] > ((255 + alphatest[1]) / 2)) { - alphaenc3[4*j + i] = 7; - alphadist = 255 - srccolors[j][i]; - } - else if (srccolors[j][i] <= acutValues[0]) { - alphaenc3[4*j + i] = 0; - alphadist = srccolors[j][i] - alphatest[0]; - } - else if (srccolors[j][i] <= acutValues[1]) { - alphaenc3[4*j + i] = 2; - alphadist = srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5; - } - else if (srccolors[j][i] <= acutValues[2]) { - alphaenc3[4*j + i] = 3; - alphadist = srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5; - } - else if (srccolors[j][i] <= acutValues[3]) { - alphaenc3[4*j + i] = 4; - alphadist = srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5; - } - else if (srccolors[j][i] <= acutValues[4]) { - alphaenc3[4*j + i] = 5; - alphadist = srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5; - } - else { - alphaenc3[4*j + i] = 1; - alphadist = srccolors[j][i] - alphatest[1]; - } - alphablockerror3 += alphadist * alphadist; - } - } - } - } - /* write the alpha values and encoding back. */ - if ((alphablockerror1 <= alphablockerror2) && (alphablockerror1 <= alphablockerror3)) { -#if RGTC_DEBUG - if (alphablockerror1 > 96) fprintf(stderr, "enc1 used, error %d\n", alphablockerror1); -#endif - write_rgtc_encoded_channel_s( blkaddr, alphause[1], alphause[0], alphaenc1 ); - } - else if (alphablockerror2 <= alphablockerror3) { -#if RGTC_DEBUG - if (alphablockerror2 > 96) fprintf(stderr, "enc2 used, error %d\n", alphablockerror2); -#endif - write_rgtc_encoded_channel_s( blkaddr, alphabase[0], alphabase[1], alphaenc2 ); - } - else { -#if RGTC_DEBUG - fprintf(stderr, "enc3 used, error %d\n", alphablockerror3); -#endif - write_rgtc_encoded_channel_s( blkaddr, (GLubyte)alphatest[0], (GLubyte)alphatest[1], alphaenc3 ); - } -} +#undef TAG +#undef TYPE +#undef T_MIN +#undef T_MAX diff --git a/mesalib/src/mesa/main/texcompress_rgtc_tmp.h b/mesalib/src/mesa/main/texcompress_rgtc_tmp.h new file mode 100644 index 000000000..0f830a5d9 --- /dev/null +++ b/mesalib/src/mesa/main/texcompress_rgtc_tmp.h @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2011 Red Hat Inc. + * + * block compression parts are: + * Copyright (C) 2004 Roland Scheidegger 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 (including the next + * paragraph) 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. + * + * Author: + * Dave Airlie + */ + +/* included by texcompress_rgtc to define byte/ubyte compressors */ + +static void TAG(write_rgtc_encoded_channel)(TYPE *blkaddr, + TYPE alphabase1, + TYPE alphabase2, + TYPE alphaenc[16]) +{ + *blkaddr++ = alphabase1; + *blkaddr++ = alphabase2; + *blkaddr++ = alphaenc[0] | (alphaenc[1] << 3) | ((alphaenc[2] & 3) << 6); + *blkaddr++ = (alphaenc[2] >> 2) | (alphaenc[3] << 1) | (alphaenc[4] << 4) | ((alphaenc[5] & 1) << 7); + *blkaddr++ = (alphaenc[5] >> 1) | (alphaenc[6] << 2) | (alphaenc[7] << 5); + *blkaddr++ = alphaenc[8] | (alphaenc[9] << 3) | ((alphaenc[10] & 3) << 6); + *blkaddr++ = (alphaenc[10] >> 2) | (alphaenc[11] << 1) | (alphaenc[12] << 4) | ((alphaenc[13] & 1) << 7); + *blkaddr++ = (alphaenc[13] >> 1) | (alphaenc[14] << 2) | (alphaenc[15] << 5); +} +static void TAG(encode_rgtc_chan)(TYPE *blkaddr, TYPE srccolors[4][4], + GLint numxpixels, GLint numypixels) +{ + TYPE alphabase[2], alphause[2]; + GLshort alphatest[2] = { 0 }; + GLuint alphablockerror1, alphablockerror2, alphablockerror3; + TYPE i, j, aindex, acutValues[7]; + TYPE alphaenc1[16], alphaenc2[16], alphaenc3[16]; + GLboolean alphaabsmin = GL_FALSE; + GLboolean alphaabsmax = GL_FALSE; + GLshort alphadist; + + /* find lowest and highest alpha value in block, alphabase[0] lowest, alphabase[1] highest */ + alphabase[0] = T_MAX; alphabase[1] = T_MIN; + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + if (srccolors[j][i] == T_MIN) + alphaabsmin = GL_TRUE; + else if (srccolors[j][i] == T_MAX) + alphaabsmax = GL_TRUE; + else { + if (srccolors[j][i] > alphabase[1]) + alphabase[1] = srccolors[j][i]; + if (srccolors[j][i] < alphabase[0]) + alphabase[0] = srccolors[j][i]; + } + } + } + + + if ((alphabase[0] > alphabase[1]) && !(alphaabsmin && alphaabsmax)) { /* one color, either max or min */ + /* shortcut here since it is a very common case (and also avoids later problems) */ + /* || (alphabase[0] == alphabase[1] && !alphaabsmin && !alphaabsmax) */ + /* could also thest for alpha0 == alpha1 (and not min/max), but probably not common, so don't bother */ + + *blkaddr++ = srccolors[0][0]; + blkaddr++; + *blkaddr++ = 0; + *blkaddr++ = 0; + *blkaddr++ = 0; + *blkaddr++ = 0; + *blkaddr++ = 0; + *blkaddr++ = 0; +#if RGTC_DEBUG + fprintf(stderr, "enc0 used\n"); +#endif + return; + } + + /* find best encoding for alpha0 > alpha1 */ + /* it's possible this encoding is better even if both alphaabsmin and alphaabsmax are true */ + alphablockerror1 = 0x0; + alphablockerror2 = 0xffffffff; + alphablockerror3 = 0xffffffff; + if (alphaabsmin) alphause[0] = T_MIN; + else alphause[0] = alphabase[0]; + if (alphaabsmax) alphause[1] = T_MAX; + else alphause[1] = alphabase[1]; + /* calculate the 7 cut values, just the middle between 2 of the computed alpha values */ + for (aindex = 0; aindex < 7; aindex++) { + /* don't forget here is always rounded down */ + acutValues[aindex] = (alphause[0] * (2*aindex + 1) + alphause[1] * (14 - (2*aindex + 1))) / 14; + } + + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + /* maybe it's overkill to have the most complicated calculation just for the error + calculation which we only need to figure out if encoding1 or encoding2 is better... */ + if (srccolors[j][i] > acutValues[0]) { + alphaenc1[4*j + i] = 0; + alphadist = srccolors[j][i] - alphause[1]; + } + else if (srccolors[j][i] > acutValues[1]) { + alphaenc1[4*j + i] = 2; + alphadist = srccolors[j][i] - (alphause[1] * 6 + alphause[0] * 1) / 7; + } + else if (srccolors[j][i] > acutValues[2]) { + alphaenc1[4*j + i] = 3; + alphadist = srccolors[j][i] - (alphause[1] * 5 + alphause[0] * 2) / 7; + } + else if (srccolors[j][i] > acutValues[3]) { + alphaenc1[4*j + i] = 4; + alphadist = srccolors[j][i] - (alphause[1] * 4 + alphause[0] * 3) / 7; + } + else if (srccolors[j][i] > acutValues[4]) { + alphaenc1[4*j + i] = 5; + alphadist = srccolors[j][i] - (alphause[1] * 3 + alphause[0] * 4) / 7; + } + else if (srccolors[j][i] > acutValues[5]) { + alphaenc1[4*j + i] = 6; + alphadist = srccolors[j][i] - (alphause[1] * 2 + alphause[0] * 5) / 7; + } + else if (srccolors[j][i] > acutValues[6]) { + alphaenc1[4*j + i] = 7; + alphadist = srccolors[j][i] - (alphause[1] * 1 + alphause[0] * 6) / 7; + } + else { + alphaenc1[4*j + i] = 1; + alphadist = srccolors[j][i] - alphause[0]; + } + alphablockerror1 += alphadist * alphadist; + } + } + +#if RGTC_DEBUG + for (i = 0; i < 16; i++) { + fprintf(stderr, "%d ", alphaenc1[i]); + } + fprintf(stderr, "cutVals "); + for (i = 0; i < 8; i++) { + fprintf(stderr, "%d ", acutValues[i]); + } + fprintf(stderr, "srcVals "); + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + fprintf(stderr, "%d ", srccolors[j][i]); + } + } + fprintf(stderr, "\n"); +#endif + + /* it's not very likely this encoding is better if both alphaabsmin and alphaabsmax + are false but try it anyway */ + if (alphablockerror1 >= 32) { + + /* don't bother if encoding is already very good, this condition should also imply + we have valid alphabase colors which we absolutely need (alphabase[0] <= alphabase[1]) */ + alphablockerror2 = 0; + for (aindex = 0; aindex < 5; aindex++) { + /* don't forget here is always rounded down */ + acutValues[aindex] = (alphabase[0] * (10 - (2*aindex + 1)) + alphabase[1] * (2*aindex + 1)) / 10; + } + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + /* maybe it's overkill to have the most complicated calculation just for the error + calculation which we only need to figure out if encoding1 or encoding2 is better... */ + if (srccolors[j][i] == T_MIN) { + alphaenc2[4*j + i] = 6; + alphadist = 0; + } + else if (srccolors[j][i] == T_MAX) { + alphaenc2[4*j + i] = 7; + alphadist = 0; + } + else if (srccolors[j][i] <= acutValues[0]) { + alphaenc2[4*j + i] = 0; + alphadist = srccolors[j][i] - alphabase[0]; + } + else if (srccolors[j][i] <= acutValues[1]) { + alphaenc2[4*j + i] = 2; + alphadist = srccolors[j][i] - (alphabase[0] * 4 + alphabase[1] * 1) / 5; + } + else if (srccolors[j][i] <= acutValues[2]) { + alphaenc2[4*j + i] = 3; + alphadist = srccolors[j][i] - (alphabase[0] * 3 + alphabase[1] * 2) / 5; + } + else if (srccolors[j][i] <= acutValues[3]) { + alphaenc2[4*j + i] = 4; + alphadist = srccolors[j][i] - (alphabase[0] * 2 + alphabase[1] * 3) / 5; + } + else if (srccolors[j][i] <= acutValues[4]) { + alphaenc2[4*j + i] = 5; + alphadist = srccolors[j][i] - (alphabase[0] * 1 + alphabase[1] * 4) / 5; + } + else { + alphaenc2[4*j + i] = 1; + alphadist = srccolors[j][i] - alphabase[1]; + } + alphablockerror2 += alphadist * alphadist; + } + } + + + /* skip this if the error is already very small + this encoding is MUCH better on average than #2 though, but expensive! */ + if ((alphablockerror2 > 96) && (alphablockerror1 > 96)) { + GLshort blockerrlin1 = 0; + GLshort blockerrlin2 = 0; + TYPE nralphainrangelow = 0; + TYPE nralphainrangehigh = 0; + alphatest[0] = 0xff; + alphatest[1] = 0x0; + /* if we have large range it's likely there are values close to 0/255, try to map them to 0/255 */ + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + if ((srccolors[j][i] > alphatest[1]) && (srccolors[j][i] < (T_MAX -(alphabase[1] - alphabase[0]) / 28))) + alphatest[1] = srccolors[j][i]; + if ((srccolors[j][i] < alphatest[0]) && (srccolors[j][i] > (alphabase[1] - alphabase[0]) / 28)) + alphatest[0] = srccolors[j][i]; + } + } + /* shouldn't happen too often, don't really care about those degenerated cases */ + if (alphatest[1] <= alphatest[0]) { + alphatest[0] = 1; + alphatest[1] = 254; + } + for (aindex = 0; aindex < 5; aindex++) { + /* don't forget here is always rounded down */ + acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; + } + + /* find the "average" difference between the alpha values and the next encoded value. + This is then used to calculate new base values. + Should there be some weighting, i.e. those values closer to alphatest[x] have more weight, + since they will see more improvement, and also because the values in the middle are somewhat + likely to get no improvement at all (because the base values might move in different directions)? + OTOH it would mean the values in the middle are even less likely to get an improvement + */ + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + if (srccolors[j][i] <= alphatest[0] / 2) { + } + else if (srccolors[j][i] > ((T_MAX + alphatest[1]) / 2)) { + } + else if (srccolors[j][i] <= acutValues[0]) { + blockerrlin1 += (srccolors[j][i] - alphatest[0]); + nralphainrangelow += 1; + } + else if (srccolors[j][i] <= acutValues[1]) { + blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); + blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); + nralphainrangelow += 1; + nralphainrangehigh += 1; + } + else if (srccolors[j][i] <= acutValues[2]) { + blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); + blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); + nralphainrangelow += 1; + nralphainrangehigh += 1; + } + else if (srccolors[j][i] <= acutValues[3]) { + blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); + blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); + nralphainrangelow += 1; + nralphainrangehigh += 1; + } + else if (srccolors[j][i] <= acutValues[4]) { + blockerrlin1 += (srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); + blockerrlin2 += (srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); + nralphainrangelow += 1; + nralphainrangehigh += 1; + } + else { + blockerrlin2 += (srccolors[j][i] - alphatest[1]); + nralphainrangehigh += 1; + } + } + } + /* shouldn't happen often, needed to avoid div by zero */ + if (nralphainrangelow == 0) nralphainrangelow = 1; + if (nralphainrangehigh == 0) nralphainrangehigh = 1; + alphatest[0] = alphatest[0] + (blockerrlin1 / nralphainrangelow); +#if RGTC_DEBUG + fprintf(stderr, "block err lin low %d, nr %d\n", blockerrlin1, nralphainrangelow); + fprintf(stderr, "block err lin high %d, nr %d\n", blockerrlin2, nralphainrangehigh); +#endif + /* again shouldn't really happen often... */ + if (alphatest[0] < T_MIN) { + alphatest[0] = T_MIN; + } + alphatest[1] = alphatest[1] + (blockerrlin2 / nralphainrangehigh); + if (alphatest[1] > T_MAX) { + alphatest[1] = T_MIN; + } + + alphablockerror3 = 0; + for (aindex = 0; aindex < 5; aindex++) { + /* don't forget here is always rounded down */ + acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; + } + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + /* maybe it's overkill to have the most complicated calculation just for the error + calculation which we only need to figure out if encoding1 or encoding2 is better... */ + if (srccolors[j][i] <= alphatest[0] / 2) { + alphaenc3[4*j + i] = 6; + alphadist = srccolors[j][i]; + } + else if (srccolors[j][i] > ((T_MAX + alphatest[1]) / 2)) { + alphaenc3[4*j + i] = 7; + alphadist = T_MAX - srccolors[j][i]; + } + else if (srccolors[j][i] <= acutValues[0]) { + alphaenc3[4*j + i] = 0; + alphadist = srccolors[j][i] - alphatest[0]; + } + else if (srccolors[j][i] <= acutValues[1]) { + alphaenc3[4*j + i] = 2; + alphadist = srccolors[j][i] - (alphatest[0] * 4 + alphatest[1] * 1) / 5; + } + else if (srccolors[j][i] <= acutValues[2]) { + alphaenc3[4*j + i] = 3; + alphadist = srccolors[j][i] - (alphatest[0] * 3 + alphatest[1] * 2) / 5; + } + else if (srccolors[j][i] <= acutValues[3]) { + alphaenc3[4*j + i] = 4; + alphadist = srccolors[j][i] - (alphatest[0] * 2 + alphatest[1] * 3) / 5; + } + else if (srccolors[j][i] <= acutValues[4]) { + alphaenc3[4*j + i] = 5; + alphadist = srccolors[j][i] - (alphatest[0] * 1 + alphatest[1] * 4) / 5; + } + else { + alphaenc3[4*j + i] = 1; + alphadist = srccolors[j][i] - alphatest[1]; + } + alphablockerror3 += alphadist * alphadist; + } + } + } + } + /* write the alpha values and encoding back. */ + if ((alphablockerror1 <= alphablockerror2) && (alphablockerror1 <= alphablockerror3)) { +#if RGTC_DEBUG + if (alphablockerror1 > 96) fprintf(stderr, "enc1 used, error %d\n", alphablockerror1); +#endif + TAG(write_rgtc_encoded_channel)( blkaddr, alphause[1], alphause[0], alphaenc1 ); + } + else if (alphablockerror2 <= alphablockerror3) { +#if RGTC_DEBUG + if (alphablockerror2 > 96) fprintf(stderr, "enc2 used, error %d\n", alphablockerror2); +#endif + TAG(write_rgtc_encoded_channel)( blkaddr, alphabase[0], alphabase[1], alphaenc2 ); + } + else { +#if RGTC_DEBUG + fprintf(stderr, "enc3 used, error %d\n", alphablockerror3); +#endif + TAG(write_rgtc_encoded_channel)( blkaddr, (TYPE)alphatest[0], (TYPE)alphatest[1], alphaenc3 ); + } +} diff --git a/mesalib/src/mesa/main/texgetimage.c b/mesalib/src/mesa/main/texgetimage.c index c3f7d3c32..21d9140c5 100644 --- a/mesalib/src/mesa/main/texgetimage.c +++ b/mesalib/src/mesa/main/texgetimage.c @@ -1,917 +1,918 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.7
- *
- * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- * Copyright (c) 2009 VMware, Inc.
- *
- * 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.
- */
-
-
-/**
- * Code for glGetTexImage() and glGetCompressedTexImage().
- */
-
-
-#include "glheader.h"
-#include "bufferobj.h"
-#include "enums.h"
-#include "context.h"
-#include "formats.h"
-#include "image.h"
-#include "mfeatures.h"
-#include "mtypes.h"
-#include "pack.h"
-#include "texgetimage.h"
-#include "teximage.h"
-
-
-
-/**
- * Can the given type represent negative values?
- */
-static INLINE GLboolean
-type_with_negative_values(GLenum type)
-{
- switch (type) {
- case GL_BYTE:
- case GL_SHORT:
- case GL_INT:
- case GL_FLOAT:
- case GL_HALF_FLOAT_ARB:
- return GL_TRUE;
- default:
- return GL_FALSE;
- }
-}
-
-
-/**
- * glGetTexImage for color index pixels.
- */
-static void
-get_tex_color_index(struct gl_context *ctx, GLuint dimensions,
- GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_image *texImage)
-{
- const GLint width = texImage->Width;
- const GLint height = texImage->Height;
- const GLint depth = texImage->Depth;
- const GLuint indexBits =
- _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT);
- const GLbitfield transferOps = 0x0;
- GLint img, row, col;
-
- for (img = 0; img < depth; img++) {
- for (row = 0; row < height; row++) {
- GLuint indexRow[MAX_WIDTH] = { 0 };
- void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
- width, height, format, type,
- img, row, 0);
- assert(dest);
-
- if (indexBits == 8) {
- const GLubyte *src = (const GLubyte *) texImage->Data;
- src += width * (img * texImage->Height + row);
- for (col = 0; col < width; col++) {
- indexRow[col] = src[col];
- }
- }
- else if (indexBits == 16) {
- const GLushort *src = (const GLushort *) texImage->Data;
- src += width * (img * texImage->Height + row);
- for (col = 0; col < width; col++) {
- indexRow[col] = src[col];
- }
- }
- else {
- _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage");
- }
- _mesa_pack_index_span(ctx, width, type, dest,
- indexRow, &ctx->Pack, transferOps);
- }
- }
-}
-
-
-/**
- * glGetTexImage for depth/Z pixels.
- */
-static void
-get_tex_depth(struct gl_context *ctx, GLuint dimensions,
- GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_image *texImage)
-{
- const GLint width = texImage->Width;
- const GLint height = texImage->Height;
- const GLint depth = texImage->Depth;
- GLint img, row, col;
- GLfloat *depthRow = (GLfloat *) malloc(width * sizeof(GLfloat));
-
- if (!depthRow) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
- return;
- }
-
- for (img = 0; img < depth; img++) {
- for (row = 0; row < height; row++) {
- void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
- width, height, format, type,
- img, row, 0);
- assert(dest);
-
- for (col = 0; col < width; col++) {
- texImage->FetchTexelf(texImage, col, row, img, depthRow + col);
- }
- _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack);
- }
- }
-
- free(depthRow);
-}
-
-
-/**
- * glGetTexImage for depth/stencil pixels.
- */
-static void
-get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions,
- GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_image *texImage)
-{
- const GLint width = texImage->Width;
- const GLint height = texImage->Height;
- const GLint depth = texImage->Depth;
- const GLuint *src = (const GLuint *) texImage->Data;
- GLint img, row;
-
- for (img = 0; img < depth; img++) {
- for (row = 0; row < height; row++) {
- void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
- width, height, format, type,
- img, row, 0);
- memcpy(dest, src, width * sizeof(GLuint));
- if (ctx->Pack.SwapBytes) {
- _mesa_swap4((GLuint *) dest, width);
- }
-
- src += width * row + width * height * img;
- }
- }
-}
-
-
-/**
- * glGetTexImage for YCbCr pixels.
- */
-static void
-get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions,
- GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_image *texImage)
-{
- const GLint width = texImage->Width;
- const GLint height = texImage->Height;
- const GLint depth = texImage->Depth;
- const GLint rowstride = texImage->RowStride;
- const GLushort *src = (const GLushort *) texImage->Data;
- GLint img, row;
-
- for (img = 0; img < depth; img++) {
- for (row = 0; row < height; row++) {
- void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
- width, height, format, type,
- img, row, 0);
- memcpy(dest, src, width * sizeof(GLushort));
-
- /* check for byte swapping */
- if ((texImage->TexFormat == MESA_FORMAT_YCBCR
- && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
- (texImage->TexFormat == MESA_FORMAT_YCBCR_REV
- && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
- if (!ctx->Pack.SwapBytes)
- _mesa_swap2((GLushort *) dest, width);
- }
- else if (ctx->Pack.SwapBytes) {
- _mesa_swap2((GLushort *) dest, width);
- }
-
- src += rowstride;
- }
- }
-}
-
-
-#if FEATURE_EXT_texture_sRGB
-
-
-/**
- * Convert a float value from linear space to a
- * non-linear sRGB value in [0, 255].
- * Not terribly efficient.
- */
-static INLINE GLfloat
-linear_to_nonlinear(GLfloat cl)
-{
- /* can't have values outside [0, 1] */
- GLfloat cs;
- if (cl < 0.0031308f) {
- cs = 12.92f * cl;
- }
- else {
- cs = (GLfloat)(1.055 * pow(cl, 0.41666) - 0.055);
- }
- return cs;
-}
-
-
-/**
- * glGetTexImagefor sRGB pixels;
- */
-static void
-get_tex_srgb(struct gl_context *ctx, GLuint dimensions,
- GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_image *texImage)
-{
- const GLint width = texImage->Width;
- const GLint height = texImage->Height;
- const GLint depth = texImage->Depth;
- const GLbitfield transferOps = 0x0;
- GLint img, row;
- GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
-
- if (!rgba) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
- return;
- }
-
- for (img = 0; img < depth; img++) {
- for (row = 0; row < height; row++) {
- void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
- width, height, format, type,
- img, row, 0);
-
- GLint col;
-
- /* convert row to RGBA format */
- for (col = 0; col < width; col++) {
- texImage->FetchTexelf(texImage, col, row, img, rgba[col]);
- if (texImage->_BaseFormat == GL_LUMINANCE) {
- rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
- rgba[col][GCOMP] = 0.0;
- rgba[col][BCOMP] = 0.0;
- }
- else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
- rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
- rgba[col][GCOMP] = 0.0;
- rgba[col][BCOMP] = 0.0;
- }
- else if (texImage->_BaseFormat == GL_RGB ||
- texImage->_BaseFormat == GL_RGBA) {
- rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
- rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]);
- rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]);
- }
- }
- _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
- format, type, dest,
- &ctx->Pack, transferOps);
- }
- }
-
- free(rgba);
-}
-
-
-#else /* FEATURE_EXT_texture_sRGB */
-
-
-static INLINE void
-get_tex_srgb(struct gl_context *ctx, GLuint dimensions,
- GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_image *texImage)
-{
- ASSERT_NO_FEATURE();
-}
-
-
-#endif /* FEATURE_EXT_texture_sRGB */
-
-
-/**
- * glGetTexImagefor RGBA, Luminance, etc. pixels.
- * This is the slow way since we use texture sampling.
- */
-static void
-get_tex_rgba(struct gl_context *ctx, GLuint dimensions,
- GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_image *texImage)
-{
- const GLint width = texImage->Width;
- const GLint height = texImage->Height;
- const GLint depth = texImage->Depth;
- /* Normally, no pixel transfer ops are performed during glGetTexImage.
- * The only possible exception is component clamping to [0,1].
- */
- GLbitfield transferOps = 0x0;
- GLint img, row;
- GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
-
- if (!rgba) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
- return;
- }
-
- for (img = 0; img < depth; img++) {
- for (row = 0; row < height; row++) {
- void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
- width, height, format, type,
- img, row, 0);
- GLint col;
- GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
-
- /* clamp does not apply to GetTexImage (final conversion)?
- * Looks like we need clamp though when going from format
- * containing negative values to unsigned format.
- */
- if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) {
- transferOps |= IMAGE_CLAMP_BIT;
- }
- else if (!type_with_negative_values(type) &&
- (dataType == GL_FLOAT ||
- dataType == GL_SIGNED_NORMALIZED)) {
- transferOps |= IMAGE_CLAMP_BIT;
- }
-
- for (col = 0; col < width; col++) {
- texImage->FetchTexelf(texImage, col, row, img, rgba[col]);
- if (texImage->_BaseFormat == GL_ALPHA) {
- rgba[col][RCOMP] = 0.0F;
- rgba[col][GCOMP] = 0.0F;
- rgba[col][BCOMP] = 0.0F;
- }
- else if (texImage->_BaseFormat == GL_LUMINANCE) {
- rgba[col][GCOMP] = 0.0F;
- rgba[col][BCOMP] = 0.0F;
- rgba[col][ACOMP] = 1.0F;
- }
- else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
- rgba[col][GCOMP] = 0.0F;
- rgba[col][BCOMP] = 0.0F;
- }
- else if (texImage->_BaseFormat == GL_INTENSITY) {
- rgba[col][GCOMP] = 0.0F;
- rgba[col][BCOMP] = 0.0F;
- rgba[col][ACOMP] = 1.0F;
- }
- }
- _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
- format, type, dest,
- &ctx->Pack, transferOps);
- }
- }
-
- free(rgba);
-}
-
-
-/**
- * Try to do glGetTexImage() with simple memcpy().
- * \return GL_TRUE if done, GL_FALSE otherwise
- */
-static GLboolean
-get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, GLvoid *pixels,
- const struct gl_texture_object *texObj,
- const struct gl_texture_image *texImage)
-{
- GLboolean memCopy = GL_FALSE;
-
- /* Texture image should have been mapped already */
- assert(texImage->Data);
-
- /*
- * Check if the src/dst formats are compatible.
- * Also note that GL's pixel transfer ops don't apply to glGetTexImage()
- * so we don't have to worry about those.
- * XXX more format combinations could be supported here.
- */
- if ((texObj->Target == GL_TEXTURE_1D ||
- texObj->Target == GL_TEXTURE_2D ||
- texObj->Target == GL_TEXTURE_RECTANGLE ||
- (texObj->Target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
- texObj->Target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) {
- if (texImage->TexFormat == MESA_FORMAT_ARGB8888 &&
- format == GL_BGRA &&
- type == GL_UNSIGNED_BYTE &&
- !ctx->Pack.SwapBytes &&
- _mesa_little_endian()) {
- memCopy = GL_TRUE;
- }
- else if (texImage->TexFormat == MESA_FORMAT_AL88 &&
- format == GL_LUMINANCE_ALPHA &&
- type == GL_UNSIGNED_BYTE &&
- !ctx->Pack.SwapBytes &&
- _mesa_little_endian()) {
- memCopy = GL_TRUE;
- }
- else if (texImage->TexFormat == MESA_FORMAT_L8 &&
- format == GL_LUMINANCE &&
- type == GL_UNSIGNED_BYTE) {
- memCopy = GL_TRUE;
- }
- else if (texImage->TexFormat == MESA_FORMAT_L16 &&
- format == GL_LUMINANCE &&
- type == GL_UNSIGNED_SHORT) {
- memCopy = GL_TRUE;
- }
- else if (texImage->TexFormat == MESA_FORMAT_A8 &&
- format == GL_ALPHA &&
- type == GL_UNSIGNED_BYTE) {
- memCopy = GL_TRUE;
- }
- else if (texImage->TexFormat == MESA_FORMAT_A16 &&
- format == GL_ALPHA &&
- type == GL_UNSIGNED_SHORT) {
- memCopy = GL_TRUE;
- }
- }
-
- if (memCopy) {
- const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat);
- const GLuint bytesPerRow = texImage->Width * bpp;
- GLubyte *dst =
- _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width,
- texImage->Height, format, type, 0, 0);
- const GLint dstRowStride =
- _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type);
- const GLubyte *src = texImage->Data;
- const GLint srcRowStride = texImage->RowStride * bpp;
- GLuint row;
-
- if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
- memcpy(dst, src, bytesPerRow * texImage->Height);
- }
- else {
- for (row = 0; row < texImage->Height; row++) {
- memcpy(dst, src, bytesPerRow);
- dst += dstRowStride;
- src += srcRowStride;
- }
- }
- }
-
- return memCopy;
-}
-
-
-/**
- * This is the software fallback for Driver.GetTexImage().
- * All error checking will have been done before this routine is called.
- * The texture image must be mapped.
- */
-void
-_mesa_get_teximage(struct gl_context *ctx, GLenum target, GLint level,
- GLenum format, GLenum type, GLvoid *pixels,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- GLuint dimensions;
-
- /* If we get here, the texture image should be mapped */
- assert(texImage->Data);
-
- switch (target) {
- case GL_TEXTURE_1D:
- dimensions = 1;
- break;
- case GL_TEXTURE_3D:
- dimensions = 3;
- break;
- default:
- dimensions = 2;
- }
-
- if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
- /* Packing texture image into a PBO.
- * Map the (potentially) VRAM-based buffer into our process space so
- * we can write into it with the code below.
- * A hardware driver might use a sophisticated blit to move the
- * texture data to the PBO if the PBO is in VRAM along with the texture.
- */
- GLubyte *buf = (GLubyte *)
- ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
- GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
- if (!buf) {
- /* out of memory or other unexpected error */
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");
- return;
- }
- /* <pixels> was an offset into the PBO.
- * Now make it a real, client-side pointer inside the mapped region.
- */
- pixels = ADD_POINTERS(buf, pixels);
- }
-
- if (get_tex_memcpy(ctx, format, type, pixels, texObj, texImage)) {
- /* all done */
- }
- else if (format == GL_COLOR_INDEX) {
- get_tex_color_index(ctx, dimensions, format, type, pixels, texImage);
- }
- else if (format == GL_DEPTH_COMPONENT) {
- get_tex_depth(ctx, dimensions, format, type, pixels, texImage);
- }
- else if (format == GL_DEPTH_STENCIL_EXT) {
- get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage);
- }
- else if (format == GL_YCBCR_MESA) {
- get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage);
- }
- else if (_mesa_get_format_color_encoding(texImage->TexFormat) == GL_SRGB) {
- get_tex_srgb(ctx, dimensions, format, type, pixels, texImage);
- }
- else {
- get_tex_rgba(ctx, dimensions, format, type, pixels, texImage);
- }
-
- if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
- ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
- ctx->Pack.BufferObj);
- }
-}
-
-
-
-/**
- * This is the software fallback for Driver.GetCompressedTexImage().
- * All error checking will have been done before this routine is called.
- */
-void
-_mesa_get_compressed_teximage(struct gl_context *ctx, GLenum target, GLint level,
- GLvoid *img,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat,
- texImage->Width);
- const GLuint row_stride_stored = _mesa_format_row_stride(texImage->TexFormat,
- texImage->RowStride);
- GLuint i;
-
- if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
- /* pack texture image into a PBO */
- GLubyte *buf = (GLubyte *)
- ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
- GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
- if (!buf) {
- /* out of memory or other unexpected error */
- _mesa_error(ctx, GL_OUT_OF_MEMORY,
- "glGetCompresssedTexImage(map PBO failed)");
- return;
- }
- img = ADD_POINTERS(buf, img);
- }
-
- /* no pixelstore or pixel transfer, but respect stride */
-
- if (row_stride == row_stride_stored) {
- const GLuint size = _mesa_format_image_size(texImage->TexFormat,
- texImage->Width,
- texImage->Height,
- texImage->Depth);
- memcpy(img, texImage->Data, size);
- }
- else {
- GLuint bw, bh;
- _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
- for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) {
- memcpy((GLubyte *)img + i * row_stride,
- (GLubyte *)texImage->Data + i * row_stride_stored,
- row_stride);
- }
- }
-
- if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
- ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
- ctx->Pack.BufferObj);
- }
-}
-
-
-
-/**
- * Do error checking for a glGetTexImage() call.
- * \return GL_TRUE if any error, GL_FALSE if no errors.
- */
-static GLboolean
-getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
- GLenum format, GLenum type, GLvoid *pixels )
-{
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
- const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
- GLenum baseFormat;
-
- if (maxLevels == 0) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
- return GL_TRUE;
- }
-
- if (level < 0 || level >= maxLevels) {
- _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
- return GL_TRUE;
- }
-
- if (_mesa_sizeof_packed_type(type) <= 0) {
- _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" );
- return GL_TRUE;
- }
-
- if (_mesa_components_in_format(format) <= 0 ||
- format == GL_STENCIL_INDEX) {
- _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" );
- return GL_TRUE;
- }
-
- if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
- return GL_TRUE;
- }
-
- if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
- return GL_TRUE;
- }
-
- if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
- return GL_TRUE;
- }
-
- if (!ctx->Extensions.EXT_packed_depth_stencil
- && _mesa_is_depthstencil_format(format)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
- return GL_TRUE;
- }
-
- if (!ctx->Extensions.ATI_envmap_bumpmap
- && _mesa_is_dudv_format(format)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
- return GL_TRUE;
- }
-
- texObj = _mesa_get_current_tex_object(ctx, target);
-
- if (!texObj || _mesa_is_proxy_texture(target)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
- return GL_TRUE;
- }
-
- texImage = _mesa_select_tex_image(ctx, texObj, target, level);
- if (!texImage) {
- /* out of memory */
- return GL_TRUE;
- }
-
- baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
-
- /* Make sure the requested image format is compatible with the
- * texture's format. Note that a color index texture can be converted
- * to RGBA so that combo is allowed.
- */
- if (_mesa_is_color_format(format)
- && !_mesa_is_color_format(baseFormat)
- && !_mesa_is_index_format(baseFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
- return GL_TRUE;
- }
- else if (_mesa_is_index_format(format)
- && !_mesa_is_index_format(baseFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
- return GL_TRUE;
- }
- else if (_mesa_is_depth_format(format)
- && !_mesa_is_depth_format(baseFormat)
- && !_mesa_is_depthstencil_format(baseFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
- return GL_TRUE;
- }
- else if (_mesa_is_ycbcr_format(format)
- && !_mesa_is_ycbcr_format(baseFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
- return GL_TRUE;
- }
- else if (_mesa_is_depthstencil_format(format)
- && !_mesa_is_depthstencil_format(baseFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
- return GL_TRUE;
- }
- else if (_mesa_is_dudv_format(format)
- && !_mesa_is_dudv_format(baseFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
- return GL_TRUE;
- }
-
- if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
- /* packing texture image into a PBO */
- const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
- if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
- texImage->Height, texImage->Depth,
- format, type, pixels)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetTexImage(out of bounds PBO write)");
- return GL_TRUE;
- }
-
- /* PBO should not be mapped */
- if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetTexImage(PBO is mapped)");
- return GL_TRUE;
- }
- }
-
- return GL_FALSE;
-}
-
-
-
-/**
- * Get texture image. Called by glGetTexImage.
- *
- * \param target texture target.
- * \param level image level.
- * \param format pixel data format for returned image.
- * \param type pixel data type for returned image.
- * \param pixels returned pixel data.
- */
-void GLAPIENTRY
-_mesa_GetTexImage( GLenum target, GLint level, GLenum format,
- GLenum type, GLvoid *pixels )
-{
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (getteximage_error_check(ctx, target, level, format, type, pixels)) {
- return;
- }
-
- if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
- /* not an error, do nothing */
- return;
- }
-
- texObj = _mesa_get_current_tex_object(ctx, target);
- texImage = _mesa_select_tex_image(ctx, texObj, target, level);
-
- if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
- _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
- " dstFmt=0x%x, dstType=0x%x\n",
- texObj->Name,
- _mesa_get_format_name(texImage->TexFormat),
- texImage->Width, texImage->Height,
- format, type);
- }
-
- _mesa_lock_texture(ctx, texObj);
- {
- ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
- texObj, texImage);
- }
- _mesa_unlock_texture(ctx, texObj);
-}
-
-
-
-/**
- * Do error checking for a glGetCompressedTexImage() call.
- * \return GL_TRUE if any error, GL_FALSE if no errors.
- */
-static GLboolean
-getcompressedteximage_error_check(struct gl_context *ctx, GLenum target,
- GLint level, GLvoid *img)
-{
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
- const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
-
- if (maxLevels == 0) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
- target);
- return GL_TRUE;
- }
-
- if (level < 0 || level >= maxLevels) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glGetCompressedTexImageARB(bad level = %d)", level);
- return GL_TRUE;
- }
-
- if (_mesa_is_proxy_texture(target)) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetCompressedTexImageARB(bad target = %s)",
- _mesa_lookup_enum_by_nr(target));
- return GL_TRUE;
- }
-
- texObj = _mesa_get_current_tex_object(ctx, target);
- if (!texObj) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
- return GL_TRUE;
- }
-
- texImage = _mesa_select_tex_image(ctx, texObj, target, level);
-
- if (!texImage) {
- /* probably invalid mipmap level */
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glGetCompressedTexImageARB(level)");
- return GL_TRUE;
- }
-
- if (!_mesa_is_format_compressed(texImage->TexFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetCompressedTexImageARB(texture is not compressed)");
- return GL_TRUE;
- }
-
- if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
- GLuint compressedSize;
-
- /* make sure PBO is not mapped */
- if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetCompressedTexImage(PBO is mapped)");
- return GL_TRUE;
- }
-
- compressedSize = _mesa_format_image_size(texImage->TexFormat,
- texImage->Width,
- texImage->Height,
- texImage->Depth);
-
- /* do bounds checking on PBO write */
- if ((const GLubyte *) img + compressedSize >
- (const GLubyte *) ctx->Pack.BufferObj->Size) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetCompressedTexImage(out of bounds PBO write)");
- return GL_TRUE;
- }
- }
-
- return GL_FALSE;
-}
-
-
-void GLAPIENTRY
-_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
-{
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (getcompressedteximage_error_check(ctx, target, level, img)) {
- return;
- }
-
- if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
- /* not an error, do nothing */
- return;
- }
-
- texObj = _mesa_get_current_tex_object(ctx, target);
- texImage = _mesa_select_tex_image(ctx, texObj, target, level);
-
- if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
- _mesa_debug(ctx,
- "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
- texObj->Name,
- _mesa_get_format_name(texImage->TexFormat),
- texImage->Width, texImage->Height);
- }
-
- _mesa_lock_texture(ctx, texObj);
- {
- ctx->Driver.GetCompressedTexImage(ctx, target, level, img,
- texObj, texImage);
- }
- _mesa_unlock_texture(ctx, texObj);
-}
+/* + * Mesa 3-D graphics library + * Version: 7.7 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (c) 2009 VMware, Inc. + * + * 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. + */ + + +/** + * Code for glGetTexImage() and glGetCompressedTexImage(). + */ + + +#include "glheader.h" +#include "bufferobj.h" +#include "enums.h" +#include "context.h" +#include "formats.h" +#include "image.h" +#include "mfeatures.h" +#include "mtypes.h" +#include "pack.h" +#include "pbo.h" +#include "texgetimage.h" +#include "teximage.h" + + + +/** + * Can the given type represent negative values? + */ +static INLINE GLboolean +type_with_negative_values(GLenum type) +{ + switch (type) { + case GL_BYTE: + case GL_SHORT: + case GL_INT: + case GL_FLOAT: + case GL_HALF_FLOAT_ARB: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * glGetTexImage for color index pixels. + */ +static void +get_tex_color_index(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + const GLint width = texImage->Width; + const GLint height = texImage->Height; + const GLint depth = texImage->Depth; + const GLuint indexBits = + _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT); + const GLbitfield transferOps = 0x0; + GLint img, row, col; + + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + GLuint indexRow[MAX_WIDTH] = { 0 }; + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + assert(dest); + + if (indexBits == 8) { + const GLubyte *src = (const GLubyte *) texImage->Data; + src += width * (img * texImage->Height + row); + for (col = 0; col < width; col++) { + indexRow[col] = src[col]; + } + } + else if (indexBits == 16) { + const GLushort *src = (const GLushort *) texImage->Data; + src += width * (img * texImage->Height + row); + for (col = 0; col < width; col++) { + indexRow[col] = src[col]; + } + } + else { + _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage"); + } + _mesa_pack_index_span(ctx, width, type, dest, + indexRow, &ctx->Pack, transferOps); + } + } +} + + +/** + * glGetTexImage for depth/Z pixels. + */ +static void +get_tex_depth(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + const GLint width = texImage->Width; + const GLint height = texImage->Height; + const GLint depth = texImage->Depth; + GLint img, row, col; + GLfloat *depthRow = (GLfloat *) malloc(width * sizeof(GLfloat)); + + if (!depthRow) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); + return; + } + + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + assert(dest); + + for (col = 0; col < width; col++) { + texImage->FetchTexelf(texImage, col, row, img, depthRow + col); + } + _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack); + } + } + + free(depthRow); +} + + +/** + * glGetTexImage for depth/stencil pixels. + */ +static void +get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + const GLint width = texImage->Width; + const GLint height = texImage->Height; + const GLint depth = texImage->Depth; + const GLuint *src = (const GLuint *) texImage->Data; + GLint img, row; + + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + memcpy(dest, src, width * sizeof(GLuint)); + if (ctx->Pack.SwapBytes) { + _mesa_swap4((GLuint *) dest, width); + } + + src += width * row + width * height * img; + } + } +} + + +/** + * glGetTexImage for YCbCr pixels. + */ +static void +get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + const GLint width = texImage->Width; + const GLint height = texImage->Height; + const GLint depth = texImage->Depth; + const GLint rowstride = texImage->RowStride; + const GLushort *src = (const GLushort *) texImage->Data; + GLint img, row; + + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + memcpy(dest, src, width * sizeof(GLushort)); + + /* check for byte swapping */ + if ((texImage->TexFormat == MESA_FORMAT_YCBCR + && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || + (texImage->TexFormat == MESA_FORMAT_YCBCR_REV + && type == GL_UNSIGNED_SHORT_8_8_MESA)) { + if (!ctx->Pack.SwapBytes) + _mesa_swap2((GLushort *) dest, width); + } + else if (ctx->Pack.SwapBytes) { + _mesa_swap2((GLushort *) dest, width); + } + + src += rowstride; + } + } +} + + +#if FEATURE_EXT_texture_sRGB + + +/** + * Convert a float value from linear space to a + * non-linear sRGB value in [0, 255]. + * Not terribly efficient. + */ +static INLINE GLfloat +linear_to_nonlinear(GLfloat cl) +{ + /* can't have values outside [0, 1] */ + GLfloat cs; + if (cl < 0.0031308f) { + cs = 12.92f * cl; + } + else { + cs = (GLfloat)(1.055 * pow(cl, 0.41666) - 0.055); + } + return cs; +} + + +/** + * glGetTexImagefor sRGB pixels; + */ +static void +get_tex_srgb(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + const GLint width = texImage->Width; + const GLint height = texImage->Height; + const GLint depth = texImage->Depth; + const GLbitfield transferOps = 0x0; + GLint img, row; + GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); + + if (!rgba) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); + return; + } + + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + + GLint col; + + /* convert row to RGBA format */ + for (col = 0; col < width; col++) { + texImage->FetchTexelf(texImage, col, row, img, rgba[col]); + if (texImage->_BaseFormat == GL_LUMINANCE) { + rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); + rgba[col][GCOMP] = 0.0; + rgba[col][BCOMP] = 0.0; + } + else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { + rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); + rgba[col][GCOMP] = 0.0; + rgba[col][BCOMP] = 0.0; + } + else if (texImage->_BaseFormat == GL_RGB || + texImage->_BaseFormat == GL_RGBA) { + rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); + rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]); + rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]); + } + } + _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, + format, type, dest, + &ctx->Pack, transferOps); + } + } + + free(rgba); +} + + +#else /* FEATURE_EXT_texture_sRGB */ + + +static INLINE void +get_tex_srgb(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + ASSERT_NO_FEATURE(); +} + + +#endif /* FEATURE_EXT_texture_sRGB */ + + +/** + * glGetTexImagefor RGBA, Luminance, etc. pixels. + * This is the slow way since we use texture sampling. + */ +static void +get_tex_rgba(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_image *texImage) +{ + const GLint width = texImage->Width; + const GLint height = texImage->Height; + const GLint depth = texImage->Depth; + /* Normally, no pixel transfer ops are performed during glGetTexImage. + * The only possible exception is component clamping to [0,1]. + */ + GLbitfield transferOps = 0x0; + GLint img, row; + GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); + + if (!rgba) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); + return; + } + + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + GLint col; + GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); + + /* clamp does not apply to GetTexImage (final conversion)? + * Looks like we need clamp though when going from format + * containing negative values to unsigned format. + */ + if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) { + transferOps |= IMAGE_CLAMP_BIT; + } + else if (!type_with_negative_values(type) && + (dataType == GL_FLOAT || + dataType == GL_SIGNED_NORMALIZED)) { + transferOps |= IMAGE_CLAMP_BIT; + } + + for (col = 0; col < width; col++) { + texImage->FetchTexelf(texImage, col, row, img, rgba[col]); + if (texImage->_BaseFormat == GL_ALPHA) { + rgba[col][RCOMP] = 0.0F; + rgba[col][GCOMP] = 0.0F; + rgba[col][BCOMP] = 0.0F; + } + else if (texImage->_BaseFormat == GL_LUMINANCE) { + rgba[col][GCOMP] = 0.0F; + rgba[col][BCOMP] = 0.0F; + rgba[col][ACOMP] = 1.0F; + } + else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { + rgba[col][GCOMP] = 0.0F; + rgba[col][BCOMP] = 0.0F; + } + else if (texImage->_BaseFormat == GL_INTENSITY) { + rgba[col][GCOMP] = 0.0F; + rgba[col][BCOMP] = 0.0F; + rgba[col][ACOMP] = 1.0F; + } + } + _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, + format, type, dest, + &ctx->Pack, transferOps); + } + } + + free(rgba); +} + + +/** + * Try to do glGetTexImage() with simple memcpy(). + * \return GL_TRUE if done, GL_FALSE otherwise + */ +static GLboolean +get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_object *texObj, + const struct gl_texture_image *texImage) +{ + GLboolean memCopy = GL_FALSE; + + /* Texture image should have been mapped already */ + assert(texImage->Data); + + /* + * Check if the src/dst formats are compatible. + * Also note that GL's pixel transfer ops don't apply to glGetTexImage() + * so we don't have to worry about those. + * XXX more format combinations could be supported here. + */ + if ((texObj->Target == GL_TEXTURE_1D || + texObj->Target == GL_TEXTURE_2D || + texObj->Target == GL_TEXTURE_RECTANGLE || + (texObj->Target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && + texObj->Target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) { + if (texImage->TexFormat == MESA_FORMAT_ARGB8888 && + format == GL_BGRA && + type == GL_UNSIGNED_BYTE && + !ctx->Pack.SwapBytes && + _mesa_little_endian()) { + memCopy = GL_TRUE; + } + else if (texImage->TexFormat == MESA_FORMAT_AL88 && + format == GL_LUMINANCE_ALPHA && + type == GL_UNSIGNED_BYTE && + !ctx->Pack.SwapBytes && + _mesa_little_endian()) { + memCopy = GL_TRUE; + } + else if (texImage->TexFormat == MESA_FORMAT_L8 && + format == GL_LUMINANCE && + type == GL_UNSIGNED_BYTE) { + memCopy = GL_TRUE; + } + else if (texImage->TexFormat == MESA_FORMAT_L16 && + format == GL_LUMINANCE && + type == GL_UNSIGNED_SHORT) { + memCopy = GL_TRUE; + } + else if (texImage->TexFormat == MESA_FORMAT_A8 && + format == GL_ALPHA && + type == GL_UNSIGNED_BYTE) { + memCopy = GL_TRUE; + } + else if (texImage->TexFormat == MESA_FORMAT_A16 && + format == GL_ALPHA && + type == GL_UNSIGNED_SHORT) { + memCopy = GL_TRUE; + } + } + + if (memCopy) { + const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat); + const GLuint bytesPerRow = texImage->Width * bpp; + GLubyte *dst = + _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width, + texImage->Height, format, type, 0, 0); + const GLint dstRowStride = + _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type); + const GLubyte *src = texImage->Data; + const GLint srcRowStride = texImage->RowStride * bpp; + GLuint row; + + if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { + memcpy(dst, src, bytesPerRow * texImage->Height); + } + else { + for (row = 0; row < texImage->Height; row++) { + memcpy(dst, src, bytesPerRow); + dst += dstRowStride; + src += srcRowStride; + } + } + } + + return memCopy; +} + + +/** + * This is the software fallback for Driver.GetTexImage(). + * All error checking will have been done before this routine is called. + * The texture image must be mapped. + */ +void +_mesa_get_teximage(struct gl_context *ctx, GLenum target, GLint level, + GLenum format, GLenum type, GLvoid *pixels, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + GLuint dimensions; + + /* If we get here, the texture image should be mapped */ + assert(texImage->Data); + + switch (target) { + case GL_TEXTURE_1D: + dimensions = 1; + break; + case GL_TEXTURE_3D: + dimensions = 3; + break; + default: + dimensions = 2; + } + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + /* Packing texture image into a PBO. + * Map the (potentially) VRAM-based buffer into our process space so + * we can write into it with the code below. + * A hardware driver might use a sophisticated blit to move the + * texture data to the PBO if the PBO is in VRAM along with the texture. + */ + GLubyte *buf = (GLubyte *) + ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); + if (!buf) { + /* out of memory or other unexpected error */ + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)"); + return; + } + /* <pixels> was an offset into the PBO. + * Now make it a real, client-side pointer inside the mapped region. + */ + pixels = ADD_POINTERS(buf, pixels); + } + + if (get_tex_memcpy(ctx, format, type, pixels, texObj, texImage)) { + /* all done */ + } + else if (format == GL_COLOR_INDEX) { + get_tex_color_index(ctx, dimensions, format, type, pixels, texImage); + } + else if (format == GL_DEPTH_COMPONENT) { + get_tex_depth(ctx, dimensions, format, type, pixels, texImage); + } + else if (format == GL_DEPTH_STENCIL_EXT) { + get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage); + } + else if (format == GL_YCBCR_MESA) { + get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage); + } + else if (_mesa_get_format_color_encoding(texImage->TexFormat) == GL_SRGB) { + get_tex_srgb(ctx, dimensions, format, type, pixels, texImage); + } + else { + get_tex_rgba(ctx, dimensions, format, type, pixels, texImage); + } + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + ctx->Pack.BufferObj); + } +} + + + +/** + * This is the software fallback for Driver.GetCompressedTexImage(). + * All error checking will have been done before this routine is called. + */ +void +_mesa_get_compressed_teximage(struct gl_context *ctx, GLenum target, GLint level, + GLvoid *img, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat, + texImage->Width); + const GLuint row_stride_stored = _mesa_format_row_stride(texImage->TexFormat, + texImage->RowStride); + GLuint i; + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + /* pack texture image into a PBO */ + GLubyte *buf = (GLubyte *) + ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); + if (!buf) { + /* out of memory or other unexpected error */ + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "glGetCompresssedTexImage(map PBO failed)"); + return; + } + img = ADD_POINTERS(buf, img); + } + + /* no pixelstore or pixel transfer, but respect stride */ + + if (row_stride == row_stride_stored) { + const GLuint size = _mesa_format_image_size(texImage->TexFormat, + texImage->Width, + texImage->Height, + texImage->Depth); + memcpy(img, texImage->Data, size); + } + else { + GLuint bw, bh; + _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); + for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) { + memcpy((GLubyte *)img + i * row_stride, + (GLubyte *)texImage->Data + i * row_stride_stored, + row_stride); + } + } + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + ctx->Pack.BufferObj); + } +} + + + +/** + * Do error checking for a glGetTexImage() call. + * \return GL_TRUE if any error, GL_FALSE if no errors. + */ +static GLboolean +getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, + GLenum format, GLenum type, GLvoid *pixels ) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + const GLint maxLevels = _mesa_max_texture_levels(ctx, target); + GLenum baseFormat; + + if (maxLevels == 0) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); + return GL_TRUE; + } + + if (level < 0 || level >= maxLevels) { + _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" ); + return GL_TRUE; + } + + if (_mesa_sizeof_packed_type(type) <= 0) { + _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" ); + return GL_TRUE; + } + + if (_mesa_components_in_format(format) <= 0 || + format == GL_STENCIL_INDEX) { + _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" ); + return GL_TRUE; + } + + if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); + return GL_TRUE; + } + + if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); + return GL_TRUE; + } + + if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); + return GL_TRUE; + } + + if (!ctx->Extensions.EXT_packed_depth_stencil + && _mesa_is_depthstencil_format(format)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); + return GL_TRUE; + } + + if (!ctx->Extensions.ATI_envmap_bumpmap + && _mesa_is_dudv_format(format)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); + return GL_TRUE; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + + if (!texObj || _mesa_is_proxy_texture(target)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); + return GL_TRUE; + } + + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + if (!texImage) { + /* out of memory */ + return GL_TRUE; + } + + baseFormat = _mesa_get_format_base_format(texImage->TexFormat); + + /* Make sure the requested image format is compatible with the + * texture's format. Note that a color index texture can be converted + * to RGBA so that combo is allowed. + */ + if (_mesa_is_color_format(format) + && !_mesa_is_color_format(baseFormat) + && !_mesa_is_index_format(baseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + return GL_TRUE; + } + else if (_mesa_is_index_format(format) + && !_mesa_is_index_format(baseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + return GL_TRUE; + } + else if (_mesa_is_depth_format(format) + && !_mesa_is_depth_format(baseFormat) + && !_mesa_is_depthstencil_format(baseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + return GL_TRUE; + } + else if (_mesa_is_ycbcr_format(format) + && !_mesa_is_ycbcr_format(baseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + return GL_TRUE; + } + else if (_mesa_is_depthstencil_format(format) + && !_mesa_is_depthstencil_format(baseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + return GL_TRUE; + } + else if (_mesa_is_dudv_format(format) + && !_mesa_is_dudv_format(baseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + return GL_TRUE; + } + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + /* packing texture image into a PBO */ + const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; + if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, + texImage->Height, texImage->Depth, + format, type, pixels)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTexImage(out of bounds PBO write)"); + return GL_TRUE; + } + + /* PBO should not be mapped */ + if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTexImage(PBO is mapped)"); + return GL_TRUE; + } + } + + return GL_FALSE; +} + + + +/** + * Get texture image. Called by glGetTexImage. + * + * \param target texture target. + * \param level image level. + * \param format pixel data format for returned image. + * \param type pixel data type for returned image. + * \param pixels returned pixel data. + */ +void GLAPIENTRY +_mesa_GetTexImage( GLenum target, GLint level, GLenum format, + GLenum type, GLvoid *pixels ) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (getteximage_error_check(ctx, target, level, format, type, pixels)) { + return; + } + + if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) { + /* not an error, do nothing */ + return; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { + _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d," + " dstFmt=0x%x, dstType=0x%x\n", + texObj->Name, + _mesa_get_format_name(texImage->TexFormat), + texImage->Width, texImage->Height, + format, type); + } + + _mesa_lock_texture(ctx, texObj); + { + ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels, + texObj, texImage); + } + _mesa_unlock_texture(ctx, texObj); +} + + + +/** + * Do error checking for a glGetCompressedTexImage() call. + * \return GL_TRUE if any error, GL_FALSE if no errors. + */ +static GLboolean +getcompressedteximage_error_check(struct gl_context *ctx, GLenum target, + GLint level, GLvoid *img) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + const GLint maxLevels = _mesa_max_texture_levels(ctx, target); + + if (maxLevels == 0) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)", + target); + return GL_TRUE; + } + + if (level < 0 || level >= maxLevels) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetCompressedTexImageARB(bad level = %d)", level); + return GL_TRUE; + } + + if (_mesa_is_proxy_texture(target)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetCompressedTexImageARB(bad target = %s)", + _mesa_lookup_enum_by_nr(target)); + return GL_TRUE; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + if (!texObj) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); + return GL_TRUE; + } + + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (!texImage) { + /* probably invalid mipmap level */ + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetCompressedTexImageARB(level)"); + return GL_TRUE; + } + + if (!_mesa_is_format_compressed(texImage->TexFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetCompressedTexImageARB(texture is not compressed)"); + return GL_TRUE; + } + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { + GLuint compressedSize; + + /* make sure PBO is not mapped */ + if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetCompressedTexImage(PBO is mapped)"); + return GL_TRUE; + } + + compressedSize = _mesa_format_image_size(texImage->TexFormat, + texImage->Width, + texImage->Height, + texImage->Depth); + + /* do bounds checking on PBO write */ + if ((const GLubyte *) img + compressedSize > + (const GLubyte *) ctx->Pack.BufferObj->Size) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetCompressedTexImage(out of bounds PBO write)"); + return GL_TRUE; + } + } + + return GL_FALSE; +} + + +void GLAPIENTRY +_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (getcompressedteximage_error_check(ctx, target, level, img)) { + return; + } + + if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) { + /* not an error, do nothing */ + return; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { + _mesa_debug(ctx, + "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n", + texObj->Name, + _mesa_get_format_name(texImage->TexFormat), + texImage->Width, texImage->Height); + } + + _mesa_lock_texture(ctx, texObj); + { + ctx->Driver.GetCompressedTexImage(ctx, target, level, img, + texObj, texImage); + } + _mesa_unlock_texture(ctx, texObj); +} diff --git a/mesalib/src/mesa/main/teximage.c b/mesalib/src/mesa/main/teximage.c index ddad16a8e..d4ae6dd69 100644 --- a/mesalib/src/mesa/main/teximage.c +++ b/mesalib/src/mesa/main/teximage.c @@ -1,3500 +1,3504 @@ -/*
- * mesa 3-D graphics library
- * Version: 7.6
- *
- * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- * Copyright (C) 2009 VMware, Inc. 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.
- */
-
-
-/**
- * \file teximage.c
- * Texture image-related functions.
- */
-
-
-#include "glheader.h"
-#include "bufferobj.h"
-#include "context.h"
-#include "enums.h"
-#include "fbobject.h"
-#include "framebuffer.h"
-#include "hash.h"
-#include "image.h"
-#include "imports.h"
-#include "macros.h"
-#include "mfeatures.h"
-#include "state.h"
-#include "texcompress.h"
-#include "texfetch.h"
-#include "teximage.h"
-#include "texstate.h"
-#include "texpal.h"
-#include "mtypes.h"
-
-
-/**
- * State changes which we care about for glCopyTex[Sub]Image() calls.
- * In particular, we care about pixel transfer state and buffer state
- * (such as glReadBuffer to make sure we read from the right renderbuffer).
- */
-#define NEW_COPY_TEX_STATE (_MESA_NEW_TRANSFER_STATE | \
- _NEW_BUFFERS | \
- _NEW_PIXEL)
-
-
-
-/**
- * We allocate texture memory on 512-byte boundaries so we can use MMX/SSE
- * elsewhere.
- */
-void *
-_mesa_alloc_texmemory(GLsizei bytes)
-{
- return _mesa_align_malloc(bytes, 512);
-}
-
-
-/**
- * Free texture memory allocated with _mesa_alloc_texmemory()
- */
-void
-_mesa_free_texmemory(void *m)
-{
- _mesa_align_free(m);
-}
-
-
-/*
- * Compute floor(log_base_2(n)).
- * If n < 0 return -1.
- */
-static int
-logbase2( int n )
-{
- GLint i = 1;
- GLint log2 = 0;
-
- if (n < 0)
- return -1;
-
- if (n == 0)
- return 0;
-
- while ( n > i ) {
- i *= 2;
- log2++;
- }
- if (i != n) {
- return log2 - 1;
- }
- else {
- return log2;
- }
-}
-
-
-
-/**
- * Return the simple base format for a given internal texture format.
- * For example, given GL_LUMINANCE12_ALPHA4, return GL_LUMINANCE_ALPHA.
- *
- * \param ctx GL context.
- * \param internalFormat the internal texture format token or 1, 2, 3, or 4.
- *
- * \return the corresponding \u base internal format (GL_ALPHA, GL_LUMINANCE,
- * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA), or -1 if invalid enum.
- *
- * This is the format which is used during texture application (i.e. the
- * texture format and env mode determine the arithmetic used.
- *
- * XXX this could be static
- */
-GLint
-_mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
-{
- switch (internalFormat) {
- case GL_ALPHA:
- case GL_ALPHA4:
- case GL_ALPHA8:
- case GL_ALPHA12:
- case GL_ALPHA16:
- return GL_ALPHA;
- case 1:
- case GL_LUMINANCE:
- case GL_LUMINANCE4:
- case GL_LUMINANCE8:
- case GL_LUMINANCE12:
- case GL_LUMINANCE16:
- return GL_LUMINANCE;
- case 2:
- case GL_LUMINANCE_ALPHA:
- case GL_LUMINANCE4_ALPHA4:
- case GL_LUMINANCE6_ALPHA2:
- case GL_LUMINANCE8_ALPHA8:
- case GL_LUMINANCE12_ALPHA4:
- case GL_LUMINANCE12_ALPHA12:
- case GL_LUMINANCE16_ALPHA16:
- return GL_LUMINANCE_ALPHA;
- case GL_INTENSITY:
- case GL_INTENSITY4:
- case GL_INTENSITY8:
- case GL_INTENSITY12:
- case GL_INTENSITY16:
- return GL_INTENSITY;
- case 3:
- case GL_RGB:
- case GL_R3_G3_B2:
- case GL_RGB4:
- case GL_RGB5:
- case GL_RGB8:
- case GL_RGB10:
- case GL_RGB12:
- case GL_RGB16:
- return GL_RGB;
- case 4:
- case GL_RGBA:
- case GL_RGBA2:
- case GL_RGBA4:
- case GL_RGB5_A1:
- case GL_RGBA8:
- case GL_RGB10_A2:
- case GL_RGBA12:
- case GL_RGBA16:
- return GL_RGBA;
- default:
- ; /* fallthrough */
- }
-
- if (ctx->Extensions.EXT_texture_format_BGRA8888) {
- switch (internalFormat) {
- case GL_BGRA_EXT:
- return GL_RGBA;
- default:
- ; /* fallthrough */
- }
- }
-
- if (ctx->Extensions.EXT_paletted_texture) {
- switch (internalFormat) {
- case GL_COLOR_INDEX:
- case GL_COLOR_INDEX1_EXT:
- case GL_COLOR_INDEX2_EXT:
- case GL_COLOR_INDEX4_EXT:
- case GL_COLOR_INDEX8_EXT:
- case GL_COLOR_INDEX12_EXT:
- case GL_COLOR_INDEX16_EXT:
- return GL_COLOR_INDEX;
- default:
- ; /* fallthrough */
- }
- }
-
- if (ctx->Extensions.ARB_depth_texture) {
- switch (internalFormat) {
- case GL_DEPTH_COMPONENT:
- case GL_DEPTH_COMPONENT16:
- case GL_DEPTH_COMPONENT24:
- case GL_DEPTH_COMPONENT32:
- return GL_DEPTH_COMPONENT;
- default:
- ; /* fallthrough */
- }
- }
-
- switch (internalFormat) {
- case GL_COMPRESSED_ALPHA:
- return GL_ALPHA;
- case GL_COMPRESSED_LUMINANCE:
- return GL_LUMINANCE;
- case GL_COMPRESSED_LUMINANCE_ALPHA:
- return GL_LUMINANCE_ALPHA;
- case GL_COMPRESSED_INTENSITY:
- return GL_INTENSITY;
- case GL_COMPRESSED_RGB:
- return GL_RGB;
- case GL_COMPRESSED_RGBA:
- return GL_RGBA;
- default:
- ; /* fallthrough */
- }
-
- if (ctx->Extensions.TDFX_texture_compression_FXT1) {
- switch (internalFormat) {
- case GL_COMPRESSED_RGB_FXT1_3DFX:
- return GL_RGB;
- case GL_COMPRESSED_RGBA_FXT1_3DFX:
- return GL_RGBA;
- default:
- ; /* fallthrough */
- }
- }
-
- if (ctx->Extensions.EXT_texture_compression_s3tc) {
- switch (internalFormat) {
- case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- return GL_RGB;
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
- case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
- return GL_RGBA;
- default:
- ; /* fallthrough */
- }
- }
-
- if (ctx->Extensions.S3_s3tc) {
- switch (internalFormat) {
- case GL_RGB_S3TC:
- case GL_RGB4_S3TC:
- return GL_RGB;
- case GL_RGBA_S3TC:
- case GL_RGBA4_S3TC:
- return GL_RGBA;
- default:
- ; /* fallthrough */
- }
- }
-
- if (ctx->Extensions.MESA_ycbcr_texture) {
- if (internalFormat == GL_YCBCR_MESA)
- return GL_YCBCR_MESA;
- }
-
- if (ctx->Extensions.ARB_texture_float) {
- switch (internalFormat) {
- case GL_ALPHA16F_ARB:
- case GL_ALPHA32F_ARB:
- return GL_ALPHA;
- case GL_RGBA16F_ARB:
- case GL_RGBA32F_ARB:
- return GL_RGBA;
- case GL_RGB16F_ARB:
- case GL_RGB32F_ARB:
- return GL_RGB;
- case GL_INTENSITY16F_ARB:
- case GL_INTENSITY32F_ARB:
- return GL_INTENSITY;
- case GL_LUMINANCE16F_ARB:
- case GL_LUMINANCE32F_ARB:
- return GL_LUMINANCE;
- case GL_LUMINANCE_ALPHA16F_ARB:
- case GL_LUMINANCE_ALPHA32F_ARB:
- return GL_LUMINANCE_ALPHA;
- default:
- ; /* fallthrough */
- }
- }
-
- if (ctx->Extensions.ATI_envmap_bumpmap) {
- switch (internalFormat) {
- case GL_DUDV_ATI:
- case GL_DU8DV8_ATI:
- return GL_DUDV_ATI;
- default:
- ; /* fallthrough */
- }
- }
-
- if (ctx->Extensions.MESA_texture_signed_rgba) {
- switch (internalFormat) {
- case GL_RGBA_SNORM:
- case GL_RGBA8_SNORM:
- return GL_RGBA;
- default:
- ; /* fallthrough */
- }
- }
-
- if (ctx->Extensions.EXT_packed_depth_stencil) {
- switch (internalFormat) {
- case GL_DEPTH_STENCIL_EXT:
- case GL_DEPTH24_STENCIL8_EXT:
- return GL_DEPTH_STENCIL_EXT;
- default:
- ; /* fallthrough */
- }
- }
-
-#if FEATURE_EXT_texture_sRGB
- if (ctx->Extensions.EXT_texture_sRGB) {
- switch (internalFormat) {
- case GL_SRGB_EXT:
- case GL_SRGB8_EXT:
- case GL_COMPRESSED_SRGB_EXT:
- case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
- return GL_RGB;
- case GL_SRGB_ALPHA_EXT:
- case GL_SRGB8_ALPHA8_EXT:
- case GL_COMPRESSED_SRGB_ALPHA_EXT:
- case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
- case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
- case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
- return GL_RGBA;
- case GL_SLUMINANCE_ALPHA_EXT:
- case GL_SLUMINANCE8_ALPHA8_EXT:
- case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT:
- return GL_LUMINANCE_ALPHA;
- case GL_SLUMINANCE_EXT:
- case GL_SLUMINANCE8_EXT:
- case GL_COMPRESSED_SLUMINANCE_EXT:
- return GL_LUMINANCE;
- default:
- ; /* fallthrough */
- }
- }
-#endif /* FEATURE_EXT_texture_sRGB */
-
- if (ctx->Extensions.EXT_texture_integer) {
- switch (internalFormat) {
- case GL_RGBA8UI_EXT:
- case GL_RGBA16UI_EXT:
- case GL_RGBA32UI_EXT:
- case GL_RGBA8I_EXT:
- case GL_RGBA16I_EXT:
- case GL_RGBA32I_EXT:
- return GL_RGBA;
- case GL_RGB8UI_EXT:
- case GL_RGB16UI_EXT:
- case GL_RGB32UI_EXT:
- case GL_RGB8I_EXT:
- case GL_RGB16I_EXT:
- case GL_RGB32I_EXT:
- return GL_RGB;
- case GL_ALPHA8UI_EXT:
- case GL_ALPHA16UI_EXT:
- case GL_ALPHA32UI_EXT:
- case GL_ALPHA8I_EXT:
- case GL_ALPHA16I_EXT:
- case GL_ALPHA32I_EXT:
- return GL_ALPHA;
- case GL_INTENSITY8UI_EXT:
- case GL_INTENSITY16UI_EXT:
- case GL_INTENSITY32UI_EXT:
- case GL_INTENSITY8I_EXT:
- case GL_INTENSITY16I_EXT:
- case GL_INTENSITY32I_EXT:
- return GL_INTENSITY;
- case GL_LUMINANCE8UI_EXT:
- case GL_LUMINANCE16UI_EXT:
- case GL_LUMINANCE32UI_EXT:
- case GL_LUMINANCE8I_EXT:
- case GL_LUMINANCE16I_EXT:
- case GL_LUMINANCE32I_EXT:
- return GL_LUMINANCE;
- case GL_LUMINANCE_ALPHA8UI_EXT:
- case GL_LUMINANCE_ALPHA16UI_EXT:
- case GL_LUMINANCE_ALPHA32UI_EXT:
- case GL_LUMINANCE_ALPHA8I_EXT:
- case GL_LUMINANCE_ALPHA16I_EXT:
- case GL_LUMINANCE_ALPHA32I_EXT:
- return GL_LUMINANCE_ALPHA;
- default:
- ; /* fallthrough */
- }
- }
-
- if (ctx->Extensions.ARB_texture_rg) {
- switch (internalFormat) {
- case GL_R16F:
- /* R16F depends on both ARB_half_float_pixel and ARB_texture_float.
- */
- if (!ctx->Extensions.ARB_half_float_pixel)
- break;
- /* FALLTHROUGH */
- case GL_R32F:
- if (!ctx->Extensions.ARB_texture_float)
- break;
- return GL_RED;
- case GL_R8I:
- case GL_R8UI:
- case GL_R16I:
- case GL_R16UI:
- case GL_R32I:
- case GL_R32UI:
- if (!ctx->Extensions.EXT_texture_integer)
- break;
- /* FALLTHROUGH */
- case GL_R8:
- case GL_R16:
- case GL_RED:
- case GL_COMPRESSED_RED:
- return GL_RED;
-
- case GL_RG16F:
- /* RG16F depends on both ARB_half_float_pixel and ARB_texture_float.
- */
- if (!ctx->Extensions.ARB_half_float_pixel)
- break;
- /* FALLTHROUGH */
- case GL_RG32F:
- if (!ctx->Extensions.ARB_texture_float)
- break;
- return GL_RG;
- case GL_RG8I:
- case GL_RG8UI:
- case GL_RG16I:
- case GL_RG16UI:
- case GL_RG32I:
- case GL_RG32UI:
- if (!ctx->Extensions.EXT_texture_integer)
- break;
- /* FALLTHROUGH */
- case GL_RG:
- case GL_RG8:
- case GL_RG16:
- case GL_COMPRESSED_RG:
- return GL_RG;
- default:
- ; /* fallthrough */
- }
- }
-
- if (ctx->Extensions.EXT_texture_shared_exponent) {
- switch (internalFormat) {
- case GL_RGB9_E5_EXT:
- return GL_RGB;
- default:
- ; /* fallthrough */
- }
- }
-
- if (ctx->Extensions.EXT_packed_float) {
- switch (internalFormat) {
- case GL_R11F_G11F_B10F_EXT:
- return GL_RGB;
- default:
- ; /* fallthrough */
- }
- }
-
- if (ctx->Extensions.ARB_depth_buffer_float) {
- switch (internalFormat) {
- case GL_DEPTH_COMPONENT32F:
- return GL_DEPTH_COMPONENT;
- case GL_DEPTH32F_STENCIL8:
- return GL_DEPTH_STENCIL;
- default:
- ; /* fallthrough */
- }
- }
-
- if (ctx->Extensions.ARB_texture_compression_rgtc) {
- switch (internalFormat) {
- case GL_COMPRESSED_RED_RGTC1:
- case GL_COMPRESSED_SIGNED_RED_RGTC1:
- return GL_RED;
- case GL_COMPRESSED_RG_RGTC2:
- case GL_COMPRESSED_SIGNED_RG_RGTC2:
- return GL_RG;
- default:
- ; /* fallthrough */
- }
- }
-
- return -1; /* error */
-}
-
-
-/**
- * For cube map faces, return a face index in [0,5].
- * For other targets return 0;
- */
-GLuint
-_mesa_tex_target_to_face(GLenum target)
-{
- if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
- target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)
- return (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
- else
- return 0;
-}
-
-
-
-/**
- * Store a gl_texture_image pointer in a gl_texture_object structure
- * according to the target and level parameters.
- *
- * \param tObj texture object.
- * \param target texture target.
- * \param level image level.
- * \param texImage texture image.
- *
- * This was basically prompted by the introduction of cube maps.
- */
-void
-_mesa_set_tex_image(struct gl_texture_object *tObj,
- GLenum target, GLint level,
- struct gl_texture_image *texImage)
-{
- const GLuint face = _mesa_tex_target_to_face(target);
-
- ASSERT(tObj);
- ASSERT(texImage);
- ASSERT(target != GL_TEXTURE_RECTANGLE_NV || level == 0);
-
- tObj->Image[face][level] = texImage;
-
- /* Set the 'back' pointer */
- texImage->TexObject = tObj;
-}
-
-
-/**
- * Allocate a texture image structure.
- *
- * Called via ctx->Driver.NewTextureImage() unless overriden by a device
- * driver.
- *
- * \return a pointer to gl_texture_image struct with all fields initialized to
- * zero.
- */
-struct gl_texture_image *
-_mesa_new_texture_image( struct gl_context *ctx )
-{
- (void) ctx;
- return CALLOC_STRUCT(gl_texture_image);
-}
-
-
-/**
- * Free texture image data.
- * This function is a fallback called via ctx->Driver.FreeTexImageData().
- *
- * \param texImage texture image.
- *
- * Free the texture image data if it's not marked as client data.
- */
-void
-_mesa_free_texture_image_data(struct gl_context *ctx,
- struct gl_texture_image *texImage)
-{
- (void) ctx;
-
- if (texImage->Data && !texImage->IsClientData) {
- /* free the old texture data */
- _mesa_free_texmemory(texImage->Data);
- }
-
- texImage->Data = NULL;
-}
-
-
-/**
- * Free texture image.
- *
- * \param texImage texture image.
- *
- * Free the texture image structure and the associated image data.
- */
-void
-_mesa_delete_texture_image(struct gl_context *ctx,
- struct gl_texture_image *texImage)
-{
- /* Free texImage->Data and/or any other driver-specific texture
- * image storage.
- */
- ASSERT(ctx->Driver.FreeTexImageData);
- ctx->Driver.FreeTexImageData( ctx, texImage );
-
- ASSERT(texImage->Data == NULL);
- if (texImage->ImageOffsets)
- free(texImage->ImageOffsets);
- free(texImage);
-}
-
-
-/**
- * Test if a target is a proxy target.
- *
- * \param target texture target.
- *
- * \return GL_TRUE if the target is a proxy target, GL_FALSE otherwise.
- */
-GLboolean
-_mesa_is_proxy_texture(GLenum target)
-{
- /* NUM_TEXTURE_TARGETS should match number of terms below */
- assert(NUM_TEXTURE_TARGETS == 7);
-
- return (target == GL_PROXY_TEXTURE_1D ||
- target == GL_PROXY_TEXTURE_2D ||
- target == GL_PROXY_TEXTURE_3D ||
- target == GL_PROXY_TEXTURE_CUBE_MAP_ARB ||
- target == GL_PROXY_TEXTURE_RECTANGLE_NV ||
- target == GL_PROXY_TEXTURE_1D_ARRAY_EXT ||
- target == GL_PROXY_TEXTURE_2D_ARRAY_EXT);
-}
-
-
-/**
- * Return the proxy target which corresponds to the given texture target
- */
-static GLenum
-get_proxy_target(GLenum target)
-{
- switch (target) {
- case GL_TEXTURE_1D:
- case GL_PROXY_TEXTURE_1D:
- return GL_PROXY_TEXTURE_1D;
- case GL_TEXTURE_2D:
- case GL_PROXY_TEXTURE_2D:
- return GL_PROXY_TEXTURE_2D;
- case GL_TEXTURE_3D:
- case GL_PROXY_TEXTURE_3D:
- return GL_PROXY_TEXTURE_3D;
- case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
- case GL_TEXTURE_CUBE_MAP_ARB:
- case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
- return GL_PROXY_TEXTURE_CUBE_MAP_ARB;
- case GL_TEXTURE_RECTANGLE_NV:
- case GL_PROXY_TEXTURE_RECTANGLE_NV:
- return GL_PROXY_TEXTURE_RECTANGLE_NV;
- case GL_TEXTURE_1D_ARRAY_EXT:
- case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
- return GL_PROXY_TEXTURE_1D_ARRAY_EXT;
- case GL_TEXTURE_2D_ARRAY_EXT:
- case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
- return GL_PROXY_TEXTURE_2D_ARRAY_EXT;
- default:
- _mesa_problem(NULL, "unexpected target in get_proxy_target()");
- return 0;
- }
-}
-
-
-/**
- * Get the texture object that corresponds to the target of the given
- * texture unit.
- *
- * \param ctx GL context.
- * \param texUnit texture unit.
- * \param target texture target.
- *
- * \return pointer to the texture object on success, or NULL on failure.
- *
- * \sa gl_texture_unit.
- */
-struct gl_texture_object *
-_mesa_select_tex_object(struct gl_context *ctx,
- const struct gl_texture_unit *texUnit,
- GLenum target)
-{
- const GLboolean arrayTex = (ctx->Extensions.MESA_texture_array ||
- ctx->Extensions.EXT_texture_array);
-
- switch (target) {
- case GL_TEXTURE_1D:
- return texUnit->CurrentTex[TEXTURE_1D_INDEX];
- case GL_PROXY_TEXTURE_1D:
- return ctx->Texture.ProxyTex[TEXTURE_1D_INDEX];
- case GL_TEXTURE_2D:
- return texUnit->CurrentTex[TEXTURE_2D_INDEX];
- case GL_PROXY_TEXTURE_2D:
- return ctx->Texture.ProxyTex[TEXTURE_2D_INDEX];
- case GL_TEXTURE_3D:
- return texUnit->CurrentTex[TEXTURE_3D_INDEX];
- case GL_PROXY_TEXTURE_3D:
- return ctx->Texture.ProxyTex[TEXTURE_3D_INDEX];
- case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
- case GL_TEXTURE_CUBE_MAP_ARB:
- return ctx->Extensions.ARB_texture_cube_map
- ? texUnit->CurrentTex[TEXTURE_CUBE_INDEX] : NULL;
- case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
- return ctx->Extensions.ARB_texture_cube_map
- ? ctx->Texture.ProxyTex[TEXTURE_CUBE_INDEX] : NULL;
- case GL_TEXTURE_RECTANGLE_NV:
- return ctx->Extensions.NV_texture_rectangle
- ? texUnit->CurrentTex[TEXTURE_RECT_INDEX] : NULL;
- case GL_PROXY_TEXTURE_RECTANGLE_NV:
- return ctx->Extensions.NV_texture_rectangle
- ? ctx->Texture.ProxyTex[TEXTURE_RECT_INDEX] : NULL;
- case GL_TEXTURE_1D_ARRAY_EXT:
- return arrayTex ? texUnit->CurrentTex[TEXTURE_1D_ARRAY_INDEX] : NULL;
- case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
- return arrayTex ? ctx->Texture.ProxyTex[TEXTURE_1D_ARRAY_INDEX] : NULL;
- case GL_TEXTURE_2D_ARRAY_EXT:
- return arrayTex ? texUnit->CurrentTex[TEXTURE_2D_ARRAY_INDEX] : NULL;
- case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
- return arrayTex ? ctx->Texture.ProxyTex[TEXTURE_2D_ARRAY_INDEX] : NULL;
- default:
- _mesa_problem(NULL, "bad target in _mesa_select_tex_object()");
- return NULL;
- }
-}
-
-
-/**
- * Return pointer to texture object for given target on current texture unit.
- */
-struct gl_texture_object *
-_mesa_get_current_tex_object(struct gl_context *ctx, GLenum target)
-{
- struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
- return _mesa_select_tex_object(ctx, texUnit, target);
-}
-
-
-/**
- * Get a texture image pointer from a texture object, given a texture
- * target and mipmap level. The target and level parameters should
- * have already been error-checked.
- *
- * \param ctx GL context.
- * \param texObj texture unit.
- * \param target texture target.
- * \param level image level.
- *
- * \return pointer to the texture image structure, or NULL on failure.
- */
-struct gl_texture_image *
-_mesa_select_tex_image(struct gl_context *ctx,
- const struct gl_texture_object *texObj,
- GLenum target, GLint level)
-{
- const GLuint face = _mesa_tex_target_to_face(target);
-
- ASSERT(texObj);
- ASSERT(level >= 0);
- ASSERT(level < MAX_TEXTURE_LEVELS);
-
- return texObj->Image[face][level];
-}
-
-
-/**
- * Like _mesa_select_tex_image() but if the image doesn't exist, allocate
- * it and install it. Only return NULL if passed a bad parameter or run
- * out of memory.
- */
-struct gl_texture_image *
-_mesa_get_tex_image(struct gl_context *ctx, struct gl_texture_object *texObj,
- GLenum target, GLint level)
-{
- struct gl_texture_image *texImage;
-
- if (!texObj)
- return NULL;
-
- texImage = _mesa_select_tex_image(ctx, texObj, target, level);
- if (!texImage) {
- texImage = ctx->Driver.NewTextureImage(ctx);
- if (!texImage) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture image allocation");
- return NULL;
- }
-
- _mesa_set_tex_image(texObj, target, level, texImage);
- }
-
- return texImage;
-}
-
-
-/**
- * Return pointer to the specified proxy texture image.
- * Note that proxy textures are per-context, not per-texture unit.
- * \return pointer to texture image or NULL if invalid target, invalid
- * level, or out of memory.
- */
-struct gl_texture_image *
-_mesa_get_proxy_tex_image(struct gl_context *ctx, GLenum target, GLint level)
-{
- struct gl_texture_image *texImage;
- GLuint texIndex;
-
- if (level < 0 )
- return NULL;
-
- switch (target) {
- case GL_PROXY_TEXTURE_1D:
- if (level >= ctx->Const.MaxTextureLevels)
- return NULL;
- texIndex = TEXTURE_1D_INDEX;
- break;
- case GL_PROXY_TEXTURE_2D:
- if (level >= ctx->Const.MaxTextureLevels)
- return NULL;
- texIndex = TEXTURE_2D_INDEX;
- break;
- case GL_PROXY_TEXTURE_3D:
- if (level >= ctx->Const.Max3DTextureLevels)
- return NULL;
- texIndex = TEXTURE_3D_INDEX;
- break;
- case GL_PROXY_TEXTURE_CUBE_MAP:
- if (level >= ctx->Const.MaxCubeTextureLevels)
- return NULL;
- texIndex = TEXTURE_CUBE_INDEX;
- break;
- case GL_PROXY_TEXTURE_RECTANGLE_NV:
- if (level > 0)
- return NULL;
- texIndex = TEXTURE_RECT_INDEX;
- break;
- case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
- if (level >= ctx->Const.MaxTextureLevels)
- return NULL;
- texIndex = TEXTURE_1D_ARRAY_INDEX;
- break;
- case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
- if (level >= ctx->Const.MaxTextureLevels)
- return NULL;
- texIndex = TEXTURE_2D_ARRAY_INDEX;
- break;
- default:
- return NULL;
- }
-
- texImage = ctx->Texture.ProxyTex[texIndex]->Image[0][level];
- if (!texImage) {
- texImage = ctx->Driver.NewTextureImage(ctx);
- if (!texImage) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation");
- return NULL;
- }
- ctx->Texture.ProxyTex[texIndex]->Image[0][level] = texImage;
- /* Set the 'back' pointer */
- texImage->TexObject = ctx->Texture.ProxyTex[texIndex];
- }
- return texImage;
-}
-
-
-/**
- * Get the maximum number of allowed mipmap levels.
- *
- * \param ctx GL context.
- * \param target texture target.
- *
- * \return the maximum number of allowed mipmap levels for the given
- * texture target, or zero if passed a bad target.
- *
- * \sa gl_constants.
- */
-GLint
-_mesa_max_texture_levels(struct gl_context *ctx, GLenum target)
-{
- switch (target) {
- case GL_TEXTURE_1D:
- case GL_PROXY_TEXTURE_1D:
- case GL_TEXTURE_2D:
- case GL_PROXY_TEXTURE_2D:
- return ctx->Const.MaxTextureLevels;
- case GL_TEXTURE_3D:
- case GL_PROXY_TEXTURE_3D:
- return ctx->Const.Max3DTextureLevels;
- case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
- case GL_TEXTURE_CUBE_MAP_ARB:
- case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
- return ctx->Extensions.ARB_texture_cube_map
- ? ctx->Const.MaxCubeTextureLevels : 0;
- case GL_TEXTURE_RECTANGLE_NV:
- case GL_PROXY_TEXTURE_RECTANGLE_NV:
- return ctx->Extensions.NV_texture_rectangle ? 1 : 0;
- case GL_TEXTURE_1D_ARRAY_EXT:
- case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
- case GL_TEXTURE_2D_ARRAY_EXT:
- case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
- return (ctx->Extensions.MESA_texture_array ||
- ctx->Extensions.EXT_texture_array)
- ? ctx->Const.MaxTextureLevels : 0;
- default:
- return 0; /* bad target */
- }
-}
-
-
-/**
- * Return number of dimensions per mipmap level for the given texture target.
- */
-GLint
-_mesa_get_texture_dimensions(GLenum target)
-{
- switch (target) {
- case GL_TEXTURE_1D:
- case GL_PROXY_TEXTURE_1D:
- return 1;
- case GL_TEXTURE_2D:
- case GL_TEXTURE_RECTANGLE:
- case GL_TEXTURE_CUBE_MAP:
- case GL_PROXY_TEXTURE_2D:
- case GL_PROXY_TEXTURE_RECTANGLE:
- case GL_PROXY_TEXTURE_CUBE_MAP:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
- case GL_TEXTURE_1D_ARRAY:
- case GL_PROXY_TEXTURE_1D_ARRAY:
- return 2;
- case GL_TEXTURE_3D:
- case GL_PROXY_TEXTURE_3D:
- case GL_TEXTURE_2D_ARRAY:
- case GL_PROXY_TEXTURE_2D_ARRAY:
- return 3;
- default:
- _mesa_problem(NULL, "invalid target 0x%x in get_texture_dimensions()",
- target);
- return 2;
- }
-}
-
-
-
-
-#if 000 /* not used anymore */
-/*
- * glTexImage[123]D can accept a NULL image pointer. In this case we
- * create a texture image with unspecified image contents per the OpenGL
- * spec.
- */
-static GLubyte *
-make_null_texture(GLint width, GLint height, GLint depth, GLenum format)
-{
- const GLint components = _mesa_components_in_format(format);
- const GLint numPixels = width * height * depth;
- GLubyte *data = (GLubyte *) MALLOC(numPixels * components * sizeof(GLubyte));
-
-#ifdef DEBUG
- /*
- * Let's see if anyone finds this. If glTexImage2D() is called with
- * a NULL image pointer then load the texture image with something
- * interesting instead of leaving it indeterminate.
- */
- if (data) {
- static const char message[8][32] = {
- " X X XXXXX XXX X ",
- " XX XX X X X X X ",
- " X X X X X X X ",
- " X X XXXX XXX XXXXX ",
- " X X X X X X ",
- " X X X X X X X ",
- " X X XXXXX XXX X X ",
- " "
- };
-
- GLubyte *imgPtr = data;
- GLint h, i, j, k;
- for (h = 0; h < depth; h++) {
- for (i = 0; i < height; i++) {
- GLint srcRow = 7 - (i % 8);
- for (j = 0; j < width; j++) {
- GLint srcCol = j % 32;
- GLubyte texel = (message[srcRow][srcCol]=='X') ? 255 : 70;
- for (k = 0; k < components; k++) {
- *imgPtr++ = texel;
- }
- }
- }
- }
- }
-#endif
-
- return data;
-}
-#endif
-
-
-
-/**
- * Reset the fields of a gl_texture_image struct to zero.
- *
- * \param img texture image structure.
- *
- * This is called when a proxy texture test fails, we set all the
- * image members (except DriverData) to zero.
- * It's also used in glTexImage[123]D as a safeguard to be sure all
- * required fields get initialized properly by the Driver.TexImage[123]D
- * functions.
- */
-static void
-clear_teximage_fields(struct gl_texture_image *img)
-{
- ASSERT(img);
- img->_BaseFormat = 0;
- img->InternalFormat = 0;
- img->Border = 0;
- img->Width = 0;
- img->Height = 0;
- img->Depth = 0;
- img->RowStride = 0;
- if (img->ImageOffsets) {
- free(img->ImageOffsets);
- img->ImageOffsets = NULL;
- }
- img->Width2 = 0;
- img->Height2 = 0;
- img->Depth2 = 0;
- img->WidthLog2 = 0;
- img->HeightLog2 = 0;
- img->DepthLog2 = 0;
- img->Data = NULL;
- img->TexFormat = MESA_FORMAT_NONE;
- img->FetchTexelc = NULL;
- img->FetchTexelf = NULL;
-}
-
-
-/**
- * Initialize basic fields of the gl_texture_image struct.
- *
- * \param ctx GL context.
- * \param target texture target (GL_TEXTURE_1D, GL_TEXTURE_RECTANGLE, etc).
- * \param img texture image structure to be initialized.
- * \param width image width.
- * \param height image height.
- * \param depth image depth.
- * \param border image border.
- * \param internalFormat internal format.
- * \param format the actual hardware format (one of MESA_FORMAT_*)
- *
- * Fills in the fields of \p img with the given information.
- * Note: width, height and depth include the border.
- */
-void
-_mesa_init_teximage_fields(struct gl_context *ctx, GLenum target,
- struct gl_texture_image *img,
- GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLenum internalFormat,
- gl_format format)
-{
- GLint i, dims;
-
- ASSERT(img);
- ASSERT(width >= 0);
- ASSERT(height >= 0);
- ASSERT(depth >= 0);
-
- img->_BaseFormat = _mesa_base_tex_format( ctx, internalFormat );
- ASSERT(img->_BaseFormat > 0);
- img->InternalFormat = internalFormat;
- img->Border = border;
- img->Width = width;
- img->Height = height;
- img->Depth = depth;
-
- img->Width2 = width - 2 * border; /* == 1 << img->WidthLog2; */
- img->WidthLog2 = logbase2(img->Width2);
-
- if (height == 1) { /* 1-D texture */
- img->Height2 = 1;
- img->HeightLog2 = 0;
- }
- else {
- img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */
- img->HeightLog2 = logbase2(img->Height2);
- }
-
- if (depth == 1) { /* 2-D texture */
- img->Depth2 = 1;
- img->DepthLog2 = 0;
- }
- else {
- img->Depth2 = depth - 2 * border; /* == 1 << img->DepthLog2; */
- img->DepthLog2 = logbase2(img->Depth2);
- }
-
- img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2);
-
- if ((width == 1 || _mesa_is_pow_two(img->Width2)) &&
- (height == 1 || _mesa_is_pow_two(img->Height2)) &&
- (depth == 1 || _mesa_is_pow_two(img->Depth2)))
- img->_IsPowerOfTwo = GL_TRUE;
- else
- img->_IsPowerOfTwo = GL_FALSE;
-
- /* RowStride and ImageOffsets[] describe how to address texels in 'Data' */
- img->RowStride = width;
- /* Allocate the ImageOffsets array and initialize to typical values.
- * We allocate the array for 1D/2D textures too in order to avoid special-
- * case code in the texstore routines.
- */
- if (img->ImageOffsets)
- free(img->ImageOffsets);
- img->ImageOffsets = (GLuint *) malloc(depth * sizeof(GLuint));
- for (i = 0; i < depth; i++) {
- img->ImageOffsets[i] = i * width * height;
- }
-
- /* Compute Width/Height/DepthScale for mipmap lod computation */
- if (target == GL_TEXTURE_RECTANGLE_NV) {
- /* scale = 1.0 since texture coords directly map to texels */
- img->WidthScale = 1.0;
- img->HeightScale = 1.0;
- img->DepthScale = 1.0;
- }
- else {
- img->WidthScale = (GLfloat) img->Width;
- img->HeightScale = (GLfloat) img->Height;
- img->DepthScale = (GLfloat) img->Depth;
- }
-
- img->TexFormat = format;
-
- dims = _mesa_get_texture_dimensions(target);
-
- _mesa_set_fetch_functions(img, dims);
-}
-
-
-/**
- * Free and clear fields of the gl_texture_image struct.
- *
- * \param ctx GL context.
- * \param texImage texture image structure to be cleared.
- *
- * After the call, \p texImage will have no data associated with it. Its
- * fields are cleared so that its parent object will test incomplete.
- */
-void
-_mesa_clear_texture_image(struct gl_context *ctx,
- struct gl_texture_image *texImage)
-{
- ctx->Driver.FreeTexImageData(ctx, texImage);
- clear_teximage_fields(texImage);
-}
-
-
-/**
- * This is the fallback for Driver.TestProxyTexImage(). Test the texture
- * level, width, height and depth against the ctx->Const limits for textures.
- *
- * A hardware driver might override this function if, for example, the
- * max 3D texture size is 512x512x64 (i.e. not a cube).
- *
- * Note that width, height, depth == 0 is not an error. However, a
- * texture with zero width/height/depth will be considered "incomplete"
- * and texturing will effectively be disabled.
- *
- * \param target one of GL_PROXY_TEXTURE_1D, GL_PROXY_TEXTURE_2D,
- * GL_PROXY_TEXTURE_3D, GL_PROXY_TEXTURE_RECTANGLE_NV,
- * GL_PROXY_TEXTURE_CUBE_MAP_ARB.
- * \param level as passed to glTexImage
- * \param internalFormat as passed to glTexImage
- * \param format as passed to glTexImage
- * \param type as passed to glTexImage
- * \param width as passed to glTexImage
- * \param height as passed to glTexImage
- * \param depth as passed to glTexImage
- * \param border as passed to glTexImage
- * \return GL_TRUE if the image is acceptable, GL_FALSE if not acceptable.
- */
-GLboolean
-_mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level,
- GLint internalFormat, GLenum format, GLenum type,
- GLint width, GLint height, GLint depth, GLint border)
-{
- GLint maxSize;
-
- (void) internalFormat;
- (void) format;
- (void) type;
-
- switch (target) {
- case GL_PROXY_TEXTURE_1D:
- maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
- if (width < 2 * border || width > 2 + maxSize)
- return GL_FALSE;
- if (level >= ctx->Const.MaxTextureLevels)
- return GL_FALSE;
- if (!ctx->Extensions.ARB_texture_non_power_of_two) {
- if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
- return GL_FALSE;
- }
- return GL_TRUE;
-
- case GL_PROXY_TEXTURE_2D:
- maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
- if (width < 2 * border || width > 2 + maxSize)
- return GL_FALSE;
- if (height < 2 * border || height > 2 + maxSize)
- return GL_FALSE;
- if (level >= ctx->Const.MaxTextureLevels)
- return GL_FALSE;
- if (!ctx->Extensions.ARB_texture_non_power_of_two) {
- if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
- return GL_FALSE;
- if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
- return GL_FALSE;
- }
- return GL_TRUE;
-
- case GL_PROXY_TEXTURE_3D:
- maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
- if (width < 2 * border || width > 2 + maxSize)
- return GL_FALSE;
- if (height < 2 * border || height > 2 + maxSize)
- return GL_FALSE;
- if (depth < 2 * border || depth > 2 + maxSize)
- return GL_FALSE;
- if (level >= ctx->Const.Max3DTextureLevels)
- return GL_FALSE;
- if (!ctx->Extensions.ARB_texture_non_power_of_two) {
- if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
- return GL_FALSE;
- if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
- return GL_FALSE;
- if (depth > 0 && !_mesa_is_pow_two(depth - 2 * border))
- return GL_FALSE;
- }
- return GL_TRUE;
-
- case GL_PROXY_TEXTURE_RECTANGLE_NV:
- maxSize = ctx->Const.MaxTextureRectSize;
- if (width < 0 || width > maxSize)
- return GL_FALSE;
- if (height < 0 || height > maxSize)
- return GL_FALSE;
- if (level != 0)
- return GL_FALSE;
- return GL_TRUE;
-
- case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
- maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1);
- if (width < 2 * border || width > 2 + maxSize)
- return GL_FALSE;
- if (height < 2 * border || height > 2 + maxSize)
- return GL_FALSE;
- if (level >= ctx->Const.MaxCubeTextureLevels)
- return GL_FALSE;
- if (!ctx->Extensions.ARB_texture_non_power_of_two) {
- if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
- return GL_FALSE;
- if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
- return GL_FALSE;
- }
- return GL_TRUE;
-
- case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
- maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
- if (width < 2 * border || width > 2 + maxSize)
- return GL_FALSE;
- if (height < 1 || height > ctx->Const.MaxArrayTextureLayers)
- return GL_FALSE;
- if (level >= ctx->Const.MaxTextureLevels)
- return GL_FALSE;
- if (!ctx->Extensions.ARB_texture_non_power_of_two) {
- if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
- return GL_FALSE;
- }
- return GL_TRUE;
-
- case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
- maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
- if (width < 2 * border || width > 2 + maxSize)
- return GL_FALSE;
- if (height < 2 * border || height > 2 + maxSize)
- return GL_FALSE;
- if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers)
- return GL_FALSE;
- if (level >= ctx->Const.MaxTextureLevels)
- return GL_FALSE;
- if (!ctx->Extensions.ARB_texture_non_power_of_two) {
- if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
- return GL_FALSE;
- if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
- return GL_FALSE;
- }
- return GL_TRUE;
-
- default:
- _mesa_problem(ctx, "Invalid target in _mesa_test_proxy_teximage");
- return GL_FALSE;
- }
-}
-
-
-/**
- * Check if the memory used by the texture would exceed the driver's limit.
- * This lets us support a max 3D texture size of 8K (for example) but
- * prevents allocating a full 8K x 8K x 8K texture.
- * XXX this could be rolled into the proxy texture size test (above) but
- * we don't have the actual texture internal format at that point.
- */
-static GLboolean
-legal_texture_size(struct gl_context *ctx, gl_format format,
- GLint width, GLint height, GLint depth)
-{
- uint64_t bytes = _mesa_format_image_size64(format, width, height, depth);
- uint64_t mbytes = bytes / (1024 * 1024); /* convert to MB */
- return mbytes <= (uint64_t) ctx->Const.MaxTextureMbytes;
-}
-
-
-
-/**
- * Helper function to determine whether a target and specific compression
- * format are supported.
- */
-static GLboolean
-target_can_be_compressed(const struct gl_context *ctx, GLenum target,
- GLenum intFormat)
-{
- (void) intFormat; /* not used yet */
-
- switch (target) {
- case GL_TEXTURE_2D:
- case GL_PROXY_TEXTURE_2D:
- return GL_TRUE; /* true for any compressed format so far */
- case GL_PROXY_TEXTURE_CUBE_MAP:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
- return ctx->Extensions.ARB_texture_cube_map;
- case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
- case GL_TEXTURE_2D_ARRAY_EXT:
- return (ctx->Extensions.MESA_texture_array ||
- ctx->Extensions.EXT_texture_array);
- default:
- return GL_FALSE;
- }
-}
-
-
-/**
- * Check if the given texture target value is legal for a
- * glTexImage1/2/3D call.
- */
-static GLboolean
-legal_teximage_target(struct gl_context *ctx, GLuint dims, GLenum target)
-{
- switch (dims) {
- case 1:
- switch (target) {
- case GL_TEXTURE_1D:
- case GL_PROXY_TEXTURE_1D:
- return GL_TRUE;
- default:
- return GL_FALSE;
- }
- case 2:
- switch (target) {
- case GL_TEXTURE_2D:
- case GL_PROXY_TEXTURE_2D:
- return GL_TRUE;
- case GL_PROXY_TEXTURE_CUBE_MAP:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
- return ctx->Extensions.ARB_texture_cube_map;
- case GL_TEXTURE_RECTANGLE_NV:
- case GL_PROXY_TEXTURE_RECTANGLE_NV:
- return ctx->Extensions.NV_texture_rectangle;
- case GL_TEXTURE_1D_ARRAY_EXT:
- case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
- return (ctx->Extensions.MESA_texture_array ||
- ctx->Extensions.EXT_texture_array);
- default:
- return GL_FALSE;
- }
- case 3:
- switch (target) {
- case GL_TEXTURE_3D:
- case GL_PROXY_TEXTURE_3D:
- return GL_TRUE;
- case GL_TEXTURE_2D_ARRAY_EXT:
- case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
- return (ctx->Extensions.MESA_texture_array ||
- ctx->Extensions.EXT_texture_array);
- default:
- return GL_FALSE;
- }
- default:
- _mesa_problem(ctx, "invalid dims=%u in legal_teximage_target()", dims);
- return GL_FALSE;
- }
-}
-
-
-/**
- * Check if the given texture target value is legal for a
- * glTexSubImage, glCopyTexSubImage or glCopyTexImage call.
- * The difference compared to legal_teximage_target() above is that
- * proxy targets are not supported.
- */
-static GLboolean
-legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target)
-{
- switch (dims) {
- case 1:
- return target == GL_TEXTURE_1D;
- case 2:
- switch (target) {
- case GL_TEXTURE_2D:
- return GL_TRUE;
- case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
- return ctx->Extensions.ARB_texture_cube_map;
- case GL_TEXTURE_RECTANGLE_NV:
- return ctx->Extensions.NV_texture_rectangle;
- case GL_TEXTURE_1D_ARRAY_EXT:
- return (ctx->Extensions.MESA_texture_array ||
- ctx->Extensions.EXT_texture_array);
- default:
- return GL_FALSE;
- }
- case 3:
- switch (target) {
- case GL_TEXTURE_3D:
- return GL_TRUE;
- case GL_TEXTURE_2D_ARRAY_EXT:
- return (ctx->Extensions.MESA_texture_array ||
- ctx->Extensions.EXT_texture_array);
- default:
- return GL_FALSE;
- }
- default:
- _mesa_problem(ctx, "invalid dims=%u in legal_texsubimage_target()",
- dims);
- return GL_FALSE;
- }
-}
-
-
-/**
- * Test the glTexImage[123]D() parameters for errors.
- *
- * \param ctx GL context.
- * \param dimensions texture image dimensions (must be 1, 2 or 3).
- * \param target texture target given by the user.
- * \param level image level given by the user.
- * \param internalFormat internal format given by the user.
- * \param format pixel data format given by the user.
- * \param type pixel data type given by the user.
- * \param width image width given by the user.
- * \param height image height given by the user.
- * \param depth image depth given by the user.
- * \param border image border given by the user.
- *
- * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
- *
- * Verifies each of the parameters against the constants specified in
- * __struct gl_contextRec::Const and the supported extensions, and according
- * to the OpenGL specification.
- */
-static GLboolean
-texture_error_check( struct gl_context *ctx,
- GLuint dimensions, GLenum target,
- GLint level, GLint internalFormat,
- GLenum format, GLenum type,
- GLint width, GLint height,
- GLint depth, GLint border )
-{
- const GLenum proxyTarget = get_proxy_target(target);
- const GLboolean isProxy = target == proxyTarget;
- GLboolean sizeOK = GL_TRUE;
- GLboolean colorFormat, indexFormat;
-
- /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
- if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
- if (!isProxy) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glTexImage%dD(level=%d)", dimensions, level);
- }
- return GL_TRUE;
- }
-
- /* Check border */
- if (border < 0 || border > 1 ||
- ((target == GL_TEXTURE_RECTANGLE_NV ||
- target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) {
- if (!isProxy) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glTexImage%dD(border=%d)", dimensions, border);
- }
- return GL_TRUE;
- }
-
- if (width < 0 || height < 0 || depth < 0) {
- if (!isProxy) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glTexImage%dD(width, height or depth < 0)", dimensions);
- }
- return GL_TRUE;
- }
-
- /* Do this simple check before calling the TestProxyTexImage() function */
- if (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB) {
- sizeOK = (width == height);
- }
-
- /*
- * Use the proxy texture driver hook to see if the size/level/etc are
- * legal.
- */
- sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
- internalFormat, format,
- type, width, height,
- depth, border);
- if (!sizeOK) {
- if (!isProxy) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glTexImage%dD(level=%d, width=%d, height=%d, depth=%d)",
- dimensions, level, width, height, depth);
- }
- return GL_TRUE;
- }
-
- /* Check internalFormat */
- if (_mesa_base_tex_format(ctx, internalFormat) < 0) {
- if (!isProxy) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glTexImage%dD(internalFormat=%s)",
- dimensions, _mesa_lookup_enum_by_nr(internalFormat));
- }
- return GL_TRUE;
- }
-
- /* Check incoming image format and type */
- if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
- /* Normally, GL_INVALID_OPERATION is generated by a format/type
- * mismatch (see the 1.2 spec page 94, sec 3.6.4.). But with the
- * GL_EXT_texture_integer extension, some combinations should generate
- * GL_INVALID_ENUM instead (grr!).
- */
- if (!isProxy) {
- GLenum error = _mesa_is_integer_format(format)
- ? GL_INVALID_ENUM : GL_INVALID_OPERATION;
- _mesa_error(ctx, error,
- "glTexImage%dD(incompatible format 0x%x, type 0x%x)",
- dimensions, format, type);
- }
- return GL_TRUE;
- }
-
- /* make sure internal format and format basically agree */
- colorFormat = _mesa_is_color_format(format);
- indexFormat = _mesa_is_index_format(format);
- if ((_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat) ||
- (_mesa_is_index_format(internalFormat) && !indexFormat) ||
- (_mesa_is_depth_format(internalFormat) != _mesa_is_depth_format(format)) ||
- (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format)) ||
- (_mesa_is_depthstencil_format(internalFormat) != _mesa_is_depthstencil_format(format)) ||
- (_mesa_is_dudv_format(internalFormat) != _mesa_is_dudv_format(format))) {
- if (!isProxy)
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexImage%dD(incompatible internalFormat 0x%x, format 0x%x)",
- dimensions, internalFormat, format);
- return GL_TRUE;
- }
-
- /* additional checks for ycbcr textures */
- if (internalFormat == GL_YCBCR_MESA) {
- ASSERT(ctx->Extensions.MESA_ycbcr_texture);
- if (type != GL_UNSIGNED_SHORT_8_8_MESA &&
- type != GL_UNSIGNED_SHORT_8_8_REV_MESA) {
- char message[100];
- _mesa_snprintf(message, sizeof(message),
- "glTexImage%dD(format/type YCBCR mismatch", dimensions);
- _mesa_error(ctx, GL_INVALID_ENUM, "%s", message);
- return GL_TRUE; /* error */
- }
- if (target != GL_TEXTURE_2D &&
- target != GL_PROXY_TEXTURE_2D &&
- target != GL_TEXTURE_RECTANGLE_NV &&
- target != GL_PROXY_TEXTURE_RECTANGLE_NV) {
- if (!isProxy)
- _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage(target)");
- return GL_TRUE;
- }
- if (border != 0) {
- if (!isProxy) {
- char message[100];
- _mesa_snprintf(message, sizeof(message),
- "glTexImage%dD(format=GL_YCBCR_MESA and border=%d)",
- dimensions, border);
- _mesa_error(ctx, GL_INVALID_VALUE, "%s", message);
- }
- return GL_TRUE;
- }
- }
-
- /* additional checks for depth textures */
- if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT) {
- /* Only 1D, 2D and rectangular textures supported, not 3D or cubes */
- if (target != GL_TEXTURE_1D &&
- target != GL_PROXY_TEXTURE_1D &&
- target != GL_TEXTURE_2D &&
- target != GL_PROXY_TEXTURE_2D &&
- target != GL_TEXTURE_RECTANGLE_ARB &&
- target != GL_PROXY_TEXTURE_RECTANGLE_ARB) {
- if (!isProxy)
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glTexImage(target/internalFormat)");
- return GL_TRUE;
- }
- }
-
- /* additional checks for compressed textures */
- if (_mesa_is_compressed_format(ctx, internalFormat)) {
- if (!target_can_be_compressed(ctx, target, internalFormat)) {
- if (!isProxy)
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glTexImage%dD(target)", dimensions);
- return GL_TRUE;
- }
- if (border != 0) {
- if (!isProxy) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexImage%dD(border!=0)", dimensions);
- }
- return GL_TRUE;
- }
- }
-
- /* additional checks for integer textures */
- if (ctx->Extensions.EXT_texture_integer &&
- (_mesa_is_integer_format(format) !=
- _mesa_is_integer_format(internalFormat))) {
- if (!isProxy) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexImage%dD(integer/non-integer format mismatch)",
- dimensions);
- }
- return GL_TRUE;
- }
-
- /* if we get here, the parameters are OK */
- return GL_FALSE;
-}
-
-
-/**
- * Test glTexSubImage[123]D() parameters for errors.
- *
- * \param ctx GL context.
- * \param dimensions texture image dimensions (must be 1, 2 or 3).
- * \param target texture target given by the user.
- * \param level image level given by the user.
- * \param xoffset sub-image x offset given by the user.
- * \param yoffset sub-image y offset given by the user.
- * \param zoffset sub-image z offset given by the user.
- * \param format pixel data format given by the user.
- * \param type pixel data type given by the user.
- * \param width image width given by the user.
- * \param height image height given by the user.
- * \param depth image depth given by the user.
- *
- * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
- *
- * Verifies each of the parameters against the constants specified in
- * __struct gl_contextRec::Const and the supported extensions, and according
- * to the OpenGL specification.
- */
-static GLboolean
-subtexture_error_check( struct gl_context *ctx, GLuint dimensions,
- GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLint width, GLint height, GLint depth,
- GLenum format, GLenum type )
-{
- /* Basic level check */
- if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage2D(level=%d)", level);
- return GL_TRUE;
- }
-
- /* Check for negative sizes */
- if (width < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glTexSubImage%dD(width=%d)", dimensions, width);
- return GL_TRUE;
- }
- if (height < 0 && dimensions > 1) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glTexSubImage%dD(height=%d)", dimensions, height);
- return GL_TRUE;
- }
- if (depth < 0 && dimensions > 2) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glTexSubImage%dD(depth=%d)", dimensions, depth);
- return GL_TRUE;
- }
-
- if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
- /* As with the glTexImage2D check above, the error code here
- * depends on texture integer.
- */
- GLenum error = _mesa_is_integer_format(format)
- ? GL_INVALID_OPERATION : GL_INVALID_ENUM;
- _mesa_error(ctx, error,
- "glTexSubImage%dD(incompatible format 0x%x, type 0x%x)",
- dimensions, format, type);
- return GL_TRUE;
- }
-
- return GL_FALSE;
-}
-
-
-/**
- * Do second part of glTexSubImage which depends on the destination texture.
- * \return GL_TRUE if error recorded, GL_FALSE otherwise
- */
-static GLboolean
-subtexture_error_check2( struct gl_context *ctx, GLuint dimensions,
- GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLint width, GLint height, GLint depth,
- GLenum format, GLenum type,
- const struct gl_texture_image *destTex )
-{
- if (!destTex) {
- /* undefined image level */
- _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%dD", dimensions);
- return GL_TRUE;
- }
-
- if (xoffset < -((GLint)destTex->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset)",
- dimensions);
- return GL_TRUE;
- }
- if (xoffset + width > (GLint) (destTex->Width + destTex->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset+width)",
- dimensions);
- return GL_TRUE;
- }
- if (dimensions > 1) {
- if (yoffset < -((GLint)destTex->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset)",
- dimensions);
- return GL_TRUE;
- }
- if (yoffset + height > (GLint) (destTex->Height + destTex->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset+height)",
- dimensions);
- return GL_TRUE;
- }
- }
- if (dimensions > 2) {
- if (zoffset < -((GLint)destTex->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset)");
- return GL_TRUE;
- }
- if (zoffset + depth > (GLint) (destTex->Depth + destTex->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset+depth)");
- return GL_TRUE;
- }
- }
-
- if (_mesa_is_format_compressed(destTex->TexFormat)) {
- GLuint bw, bh;
-
- /* do tests which depend on compression block size */
- _mesa_get_format_block_size(destTex->TexFormat, &bw, &bh);
-
- /* offset must be multiple of block size */
- if ((xoffset % bw != 0) || (yoffset % bh != 0)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexSubImage%dD(xoffset = %d, yoffset = %d)",
- dimensions, xoffset, yoffset);
- return GL_TRUE;
- }
- /* size must be multiple of bw by bh or equal to whole texture size */
- if ((width % bw != 0) && (GLuint) width != destTex->Width) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexSubImage%dD(width = %d)", dimensions, width);
- return GL_TRUE;
- }
- if ((height % bh != 0) && (GLuint) height != destTex->Height) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexSubImage%dD(height = %d)", dimensions, height);
- return GL_TRUE;
- }
- }
-
- return GL_FALSE;
-}
-
-
-/**
- * Test glCopyTexImage[12]D() parameters for errors.
- *
- * \param ctx GL context.
- * \param dimensions texture image dimensions (must be 1, 2 or 3).
- * \param target texture target given by the user.
- * \param level image level given by the user.
- * \param internalFormat internal format given by the user.
- * \param width image width given by the user.
- * \param height image height given by the user.
- * \param border texture border.
- *
- * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
- *
- * Verifies each of the parameters against the constants specified in
- * __struct gl_contextRec::Const and the supported extensions, and according
- * to the OpenGL specification.
- */
-static GLboolean
-copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
- GLenum target, GLint level, GLint internalFormat,
- GLint width, GLint height, GLint border )
-{
- const GLenum proxyTarget = get_proxy_target(target);
- const GLenum type = GL_FLOAT;
- GLboolean sizeOK;
- GLint format;
-
- /* check target */
- if (!legal_texsubimage_target(ctx, dimensions, target)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage%uD(target=%s)",
- dimensions, _mesa_lookup_enum_by_nr(target));
- return GL_TRUE;
- }
-
- /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
- if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexImage%dD(level=%d)", dimensions, level);
- return GL_TRUE;
- }
-
- /* Check that the source buffer is complete */
- if (ctx->ReadBuffer->Name) {
- _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer);
- if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
- "glCopyTexImage%dD(invalid readbuffer)", dimensions);
- return GL_TRUE;
- }
- }
-
- /* Check border */
- if (border < 0 || border > 1 ||
- ((target == GL_TEXTURE_RECTANGLE_NV ||
- target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) {
- return GL_TRUE;
- }
-
- format = _mesa_base_tex_format(ctx, internalFormat);
- if (format < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexImage%dD(internalFormat)", dimensions);
- return GL_TRUE;
- }
-
- if (!_mesa_source_buffer_exists(ctx, format)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glCopyTexImage%dD(missing readbuffer)", dimensions);
- return GL_TRUE;
- }
-
- /* Do size, level checking */
- sizeOK = (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB)
- ? (width == height) : 1;
-
- sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
- internalFormat, format,
- type, width, height,
- 1, border);
-
- if (!sizeOK) {
- if (dimensions == 1) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexImage1D(width=%d)", width);
- }
- else {
- ASSERT(dimensions == 2);
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexImage2D(width=%d, height=%d)", width, height);
- }
- return GL_TRUE;
- }
-
- if (_mesa_is_compressed_format(ctx, internalFormat)) {
- if (!target_can_be_compressed(ctx, target, internalFormat)) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glCopyTexImage%dD(target)", dimensions);
- return GL_TRUE;
- }
- if (border != 0) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glCopyTexImage%dD(border!=0)", dimensions);
- return GL_TRUE;
- }
- }
- else if (_mesa_is_depth_format(internalFormat)) {
- /* make sure we have depth/stencil buffers */
- if (!ctx->ReadBuffer->_DepthBuffer) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glCopyTexImage%dD(no depth)", dimensions);
- return GL_TRUE;
- }
- }
- else if (_mesa_is_depthstencil_format(internalFormat)) {
- /* make sure we have depth/stencil buffers */
- if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glCopyTexImage%dD(no depth/stencil buffer)", dimensions);
- return GL_TRUE;
- }
- }
-
- /* if we get here, the parameters are OK */
- return GL_FALSE;
-}
-
-
-/**
- * Test glCopyTexSubImage[12]D() parameters for errors.
- * Note that this is the first part of error checking.
- * See also copytexsubimage_error_check2() below for the second part.
- *
- * \param ctx GL context.
- * \param dimensions texture image dimensions (must be 1, 2 or 3).
- * \param target texture target given by the user.
- * \param level image level given by the user.
- *
- * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
- */
-static GLboolean
-copytexsubimage_error_check1( struct gl_context *ctx, GLuint dimensions,
- GLenum target, GLint level)
-{
- /* Check that the source buffer is complete */
- if (ctx->ReadBuffer->Name) {
- _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer);
- if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
- "glCopyTexImage%dD(invalid readbuffer)", dimensions);
- return GL_TRUE;
- }
- }
-
- /* check target (proxies not allowed) */
- if (!legal_texsubimage_target(ctx, dimensions, target)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexSubImage%uD(target=%s)",
- dimensions, _mesa_lookup_enum_by_nr(target));
- return GL_TRUE;
- }
-
- /* Check level */
- if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(level=%d)", dimensions, level);
- return GL_TRUE;
- }
-
- return GL_FALSE;
-}
-
-
-/**
- * Second part of error checking for glCopyTexSubImage[12]D().
- * \param xoffset sub-image x offset given by the user.
- * \param yoffset sub-image y offset given by the user.
- * \param zoffset sub-image z offset given by the user.
- * \param width image width given by the user.
- * \param height image height given by the user.
- */
-static GLboolean
-copytexsubimage_error_check2( struct gl_context *ctx, GLuint dimensions,
- GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLsizei height,
- const struct gl_texture_image *teximage )
-{
- /* check that dest tex image exists */
- if (!teximage) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glCopyTexSubImage%dD(undefined texture level: %d)",
- dimensions, level);
- return GL_TRUE;
- }
-
- /* Check size */
- if (width < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(width=%d)", dimensions, width);
- return GL_TRUE;
- }
- if (dimensions > 1 && height < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(height=%d)", dimensions, height);
- return GL_TRUE;
- }
-
- /* check x/y offsets */
- if (xoffset < -((GLint)teximage->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(xoffset=%d)", dimensions, xoffset);
- return GL_TRUE;
- }
- if (xoffset + width > (GLint) (teximage->Width + teximage->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(xoffset+width)", dimensions);
- return GL_TRUE;
- }
- if (dimensions > 1) {
- if (yoffset < -((GLint)teximage->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(yoffset=%d)", dimensions, yoffset);
- return GL_TRUE;
- }
- /* NOTE: we're adding the border here, not subtracting! */
- if (yoffset + height > (GLint) (teximage->Height + teximage->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(yoffset+height)", dimensions);
- return GL_TRUE;
- }
- }
-
- /* check z offset */
- if (dimensions > 2) {
- if (zoffset < -((GLint)teximage->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(zoffset)", dimensions);
- return GL_TRUE;
- }
- if (zoffset > (GLint) (teximage->Depth + teximage->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(zoffset+depth)", dimensions);
- return GL_TRUE;
- }
- }
-
- if (_mesa_is_format_compressed(teximage->TexFormat)) {
- /* offset must be multiple of 4 */
- if ((xoffset & 3) || (yoffset & 3)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(xoffset or yoffset)", dimensions);
- return GL_TRUE;
- }
- /* size must be multiple of 4 */
- if ((width & 3) != 0 && (GLuint) width != teximage->Width) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(width)", dimensions);
- return GL_TRUE;
- }
- if ((height & 3) != 0 && (GLuint) height != teximage->Height) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(height)", dimensions);
- return GL_TRUE;
- }
- }
-
- if (teximage->InternalFormat == GL_YCBCR_MESA) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyTexSubImage2D");
- return GL_TRUE;
- }
-
- if (!_mesa_source_buffer_exists(ctx, teximage->_BaseFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glCopyTexSubImage%dD(missing readbuffer, format=0x%x)",
- dimensions, teximage->_BaseFormat);
- return GL_TRUE;
- }
-
- if (teximage->_BaseFormat == GL_DEPTH_COMPONENT) {
- if (!ctx->ReadBuffer->_DepthBuffer) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glCopyTexSubImage%dD(no depth buffer)",
- dimensions);
- return GL_TRUE;
- }
- }
- else if (teximage->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
- if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glCopyTexSubImage%dD(no depth/stencil buffer)",
- dimensions);
- return GL_TRUE;
- }
- }
-
- /* If copying into an integer texture, the source buffer must also be
- * integer-valued.
- */
- if (_mesa_is_format_integer_color(teximage->TexFormat)) {
- struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
- if (!_mesa_is_format_integer_color(rb->Format)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glCopyTexSubImage%dD(source buffer is not integer format)",
- dimensions);
- return GL_TRUE;
- }
- }
-
- /* if we get here, the parameters are OK */
- return GL_FALSE;
-}
-
-
-/** Callback info for walking over FBO hash table */
-struct cb_info
-{
- struct gl_context *ctx;
- struct gl_texture_object *texObj;
- GLuint level, face;
-};
-
-
-/**
- * Check render to texture callback. Called from _mesa_HashWalk().
- */
-static void
-check_rtt_cb(GLuint key, void *data, void *userData)
-{
- struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
- const struct cb_info *info = (struct cb_info *) userData;
- struct gl_context *ctx = info->ctx;
- const struct gl_texture_object *texObj = info->texObj;
- const GLuint level = info->level, face = info->face;
-
- /* If this is a user-created FBO */
- if (fb->Name) {
- GLuint i;
- /* check if any of the FBO's attachments point to 'texObj' */
- for (i = 0; i < BUFFER_COUNT; i++) {
- struct gl_renderbuffer_attachment *att = fb->Attachment + i;
- if (att->Type == GL_TEXTURE &&
- att->Texture == texObj &&
- att->TextureLevel == level &&
- att->CubeMapFace == face) {
- ASSERT(att->Texture->Image[att->CubeMapFace][att->TextureLevel]);
- /* Tell driver about the new renderbuffer texture */
- ctx->Driver.RenderTexture(ctx, ctx->DrawBuffer, att);
- /* Mark fb status as indeterminate to force re-validation */
- fb->_Status = 0;
- }
- }
- }
-}
-
-
-/**
- * When a texture image is specified we have to check if it's bound to
- * any framebuffer objects (render to texture) in order to detect changes
- * in size or format since that effects FBO completeness.
- * Any FBOs rendering into the texture must be re-validated.
- */
-static void
-update_fbo_texture(struct gl_context *ctx, struct gl_texture_object *texObj,
- GLuint face, GLuint level)
-{
- /* Only check this texture if it's been marked as RenderToTexture */
- if (texObj->_RenderToTexture) {
- struct cb_info info;
- info.ctx = ctx;
- info.texObj = texObj;
- info.level = level;
- info.face = face;
- _mesa_HashWalk(ctx->Shared->FrameBuffers, check_rtt_cb, &info);
- }
-}
-
-
-/**
- * If the texture object's GenerateMipmap flag is set and we've
- * changed the texture base level image, regenerate the rest of the
- * mipmap levels now.
- */
-static INLINE void
-check_gen_mipmap(struct gl_context *ctx, GLenum target,
- struct gl_texture_object *texObj, GLint level)
-{
- ASSERT(target != GL_TEXTURE_CUBE_MAP);
- if (texObj->GenerateMipmap &&
- level == texObj->BaseLevel &&
- level < texObj->MaxLevel) {
- ASSERT(ctx->Driver.GenerateMipmap);
- ctx->Driver.GenerateMipmap(ctx, target, texObj);
- }
-}
-
-
-/** Debug helper: override the user-requested internal format */
-static GLenum
-override_internal_format(GLenum internalFormat, GLint width, GLint height)
-{
-#if 0
- if (internalFormat == GL_RGBA16F_ARB ||
- internalFormat == GL_RGBA32F_ARB) {
- printf("Convert rgba float tex to int %d x %d\n", width, height);
- return GL_RGBA;
- }
- else if (internalFormat == GL_RGB16F_ARB ||
- internalFormat == GL_RGB32F_ARB) {
- printf("Convert rgb float tex to int %d x %d\n", width, height);
- return GL_RGB;
- }
- else if (internalFormat == GL_LUMINANCE_ALPHA16F_ARB ||
- internalFormat == GL_LUMINANCE_ALPHA32F_ARB) {
- printf("Convert luminance float tex to int %d x %d\n", width, height);
- return GL_LUMINANCE_ALPHA;
- }
- else if (internalFormat == GL_LUMINANCE16F_ARB ||
- internalFormat == GL_LUMINANCE32F_ARB) {
- printf("Convert luminance float tex to int %d x %d\n", width, height);
- return GL_LUMINANCE;
- }
- else if (internalFormat == GL_ALPHA16F_ARB ||
- internalFormat == GL_ALPHA32F_ARB) {
- printf("Convert luminance float tex to int %d x %d\n", width, height);
- return GL_ALPHA;
- }
- /*
- else if (internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) {
- internalFormat = GL_RGBA;
- }
- */
- else {
- return internalFormat;
- }
-#else
- return internalFormat;
-#endif
-}
-
-
-/**
- * Choose the actual hardware format for a texture image.
- * Try to use the same format as the previous image level when possible.
- * Otherwise, ask the driver for the best format.
- * It's important to try to choose a consistant format for all levels
- * for efficient texture memory layout/allocation. In particular, this
- * comes up during automatic mipmap generation.
- */
-gl_format
-_mesa_choose_texture_format(struct gl_context *ctx,
- struct gl_texture_object *texObj,
- GLenum target, GLint level,
- GLenum internalFormat, GLenum format, GLenum type)
-{
- gl_format f;
-
- /* see if we've already chosen a format for the previous level */
- if (level > 0) {
- struct gl_texture_image *prevImage =
- _mesa_select_tex_image(ctx, texObj, target, level - 1);
- /* See if the prev level is defined and has an internal format which
- * matches the new internal format.
- */
- if (prevImage &&
- prevImage->Width > 0 &&
- prevImage->InternalFormat == internalFormat) {
- /* use the same format */
- ASSERT(prevImage->TexFormat != MESA_FORMAT_NONE);
- return prevImage->TexFormat;
- }
- }
-
- /* choose format from scratch */
- f = ctx->Driver.ChooseTextureFormat(ctx, internalFormat, format, type);
- ASSERT(f != MESA_FORMAT_NONE);
- return f;
-}
-
-
-/**
- * Common code to implement all the glTexImage1D/2D/3D functions.
- */
-static void
-teximage(struct gl_context *ctx, GLuint dims,
- GLenum target, GLint level, GLint internalFormat,
- GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLenum format, GLenum type,
- const GLvoid *pixels)
-{
- GLboolean error;
-
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
- _mesa_debug(ctx, "glTexImage%uD %s %d %s %d %d %d %d %s %s %p\n",
- dims,
- _mesa_lookup_enum_by_nr(target), level,
- _mesa_lookup_enum_by_nr(internalFormat),
- width, height, depth, border,
- _mesa_lookup_enum_by_nr(format),
- _mesa_lookup_enum_by_nr(type), pixels);
-
- internalFormat = override_internal_format(internalFormat, width, height);
-
- /* target error checking */
- if (!legal_teximage_target(ctx, dims, target)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage%uD(target=%s)",
- dims, _mesa_lookup_enum_by_nr(target));
- return;
- }
-
- /* general error checking */
- error = texture_error_check(ctx, dims, target, level, internalFormat,
- format, type, width, height, depth, border);
-
- if (_mesa_is_proxy_texture(target)) {
- /* Proxy texture: just clear or set state depending on error checking */
- struct gl_texture_image *texImage =
- _mesa_get_proxy_tex_image(ctx, target, level);
-
- if (error) {
- /* when error, clear all proxy texture image parameters */
- if (texImage)
- clear_teximage_fields(texImage);
- }
- else {
- /* no error, set the tex image parameters */
- struct gl_texture_object *texObj =
- _mesa_get_current_tex_object(ctx, target);
- gl_format texFormat = _mesa_choose_texture_format(ctx, texObj,
- target, level,
- internalFormat,
- format, type);
-
- if (legal_texture_size(ctx, texFormat, width, height, depth)) {
- _mesa_init_teximage_fields(ctx, target, texImage, width, height,
- depth, border, internalFormat,
- texFormat);
- }
- else if (texImage) {
- clear_teximage_fields(texImage);
- }
- }
- }
- else {
- /* non-proxy target */
- const GLuint face = _mesa_tex_target_to_face(target);
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
-
- if (error) {
- return; /* error was recorded */
- }
-
- if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
- _mesa_update_state(ctx);
-
- texObj = _mesa_get_current_tex_object(ctx, target);
-
- _mesa_lock_texture(ctx, texObj);
- {
- texImage = _mesa_get_tex_image(ctx, texObj, target, level);
-
- if (!texImage) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims);
- }
- else {
- gl_format texFormat;
-
- if (texImage->Data) {
- ctx->Driver.FreeTexImageData( ctx, texImage );
- }
-
- ASSERT(texImage->Data == NULL);
- texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
- internalFormat, format,
- type);
-
- if (legal_texture_size(ctx, texFormat, width, height, depth)) {
- _mesa_init_teximage_fields(ctx, target, texImage,
- width, height, depth,
- border, internalFormat, texFormat);
-
- /* Give the texture to the driver. <pixels> may be null. */
- ASSERT(ctx->Driver.TexImage3D);
- switch (dims) {
- case 1:
- ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
- width, border, format,
- type, pixels, &ctx->Unpack, texObj,
- texImage);
- break;
- case 2:
- ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
- width, height, border, format,
- type, pixels, &ctx->Unpack, texObj,
- texImage);
- break;
- case 3:
- ctx->Driver.TexImage3D(ctx, target, level, internalFormat,
- width, height, depth, border, format,
- type, pixels, &ctx->Unpack, texObj,
- texImage);
- break;
- default:
- _mesa_problem(ctx, "invalid dims=%u in teximage()", dims);
- }
-
- check_gen_mipmap(ctx, target, texObj, level);
-
- update_fbo_texture(ctx, texObj, face, level);
-
- /* state update */
- texObj->_Complete = GL_FALSE;
- ctx->NewState |= _NEW_TEXTURE;
- }
- else {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims);
- }
- }
- }
- _mesa_unlock_texture(ctx, texObj);
- }
-}
-
-
-/*
- * Called from the API. Note that width includes the border.
- */
-void GLAPIENTRY
-_mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
- GLsizei width, GLint border, GLenum format,
- GLenum type, const GLvoid *pixels )
-{
- GET_CURRENT_CONTEXT(ctx);
- teximage(ctx, 1, target, level, internalFormat, width, 1, 1,
- border, format, type, pixels);
-}
-
-
-void GLAPIENTRY
-_mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
- GLsizei width, GLsizei height, GLint border,
- GLenum format, GLenum type,
- const GLvoid *pixels )
-{
- GET_CURRENT_CONTEXT(ctx);
- teximage(ctx, 2, target, level, internalFormat, width, height, 1,
- border, format, type, pixels);
-}
-
-
-/*
- * Called by the API or display list executor.
- * Note that width and height include the border.
- */
-void GLAPIENTRY
-_mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
- GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLenum format, GLenum type,
- const GLvoid *pixels )
-{
- GET_CURRENT_CONTEXT(ctx);
- teximage(ctx, 3, target, level, internalFormat, width, height, depth,
- border, format, type, pixels);
-}
-
-
-void GLAPIENTRY
-_mesa_TexImage3DEXT( GLenum target, GLint level, GLenum internalFormat,
- GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLenum format, GLenum type,
- const GLvoid *pixels )
-{
- _mesa_TexImage3D(target, level, (GLint) internalFormat, width, height,
- depth, border, format, type, pixels);
-}
-
-
-#if FEATURE_OES_EGL_image
-void GLAPIENTRY
-_mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
-{
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (!ctx->Extensions.OES_EGL_image) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glEGLImageTargetTexture2DOES(unsupported)");
- return;
- }
-
- if (target != GL_TEXTURE_2D) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glEGLImageTargetTexture2D(target=%d)", target);
- return;
- }
-
- if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
- _mesa_update_state(ctx);
-
- texObj = _mesa_get_current_tex_object(ctx, target);
- _mesa_lock_texture(ctx, texObj);
-
- texImage = _mesa_get_tex_image(ctx, texObj, target, 0);
- if (!texImage) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glEGLImageTargetTexture2D");
- } else {
- if (texImage->Data)
- ctx->Driver.FreeTexImageData( ctx, texImage );
-
- ASSERT(texImage->Data == NULL);
- ctx->Driver.EGLImageTargetTexture2D(ctx, target,
- texObj, texImage, image);
-
- /* state update */
- texObj->_Complete = GL_FALSE;
- ctx->NewState |= _NEW_TEXTURE;
- }
- _mesa_unlock_texture(ctx, texObj);
-
-}
-#endif
-
-
-
-/**
- * Implement all the glTexSubImage1/2/3D() functions.
- */
-static void
-texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLenum type, const GLvoid *pixels )
-{
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
-
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
- _mesa_debug(ctx, "glTexSubImage%uD %s %d %d %d %d %d %d %d %s %s %p\n",
- dims,
- _mesa_lookup_enum_by_nr(target), level,
- xoffset, yoffset, zoffset, width, height, depth,
- _mesa_lookup_enum_by_nr(format),
- _mesa_lookup_enum_by_nr(type), pixels);
-
- /* check target (proxies not allowed) */
- if (!legal_texsubimage_target(ctx, dims, target)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%uD(target=%s)",
- dims, _mesa_lookup_enum_by_nr(target));
- return;
- }
-
- if (ctx->NewState & _MESA_NEW_TRANSFER_STATE)
- _mesa_update_state(ctx);
-
- if (subtexture_error_check(ctx, dims, target, level, xoffset, yoffset, zoffset,
- width, height, depth, format, type)) {
- return; /* error was detected */
- }
-
- texObj = _mesa_get_current_tex_object(ctx, target);
-
- _mesa_lock_texture(ctx, texObj);
- {
- texImage = _mesa_select_tex_image(ctx, texObj, target, level);
-
- if (subtexture_error_check2(ctx, dims, target, level,
- xoffset, yoffset, zoffset,
- width, height, depth,
- format, type, texImage)) {
- /* error was recorded */
- }
- else if (width > 0 && height > 0 && height > 0) {
- /* If we have a border, offset=-1 is legal. Bias by border width. */
- switch (dims) {
- case 3:
- zoffset += texImage->Border;
- /* fall-through */
- case 2:
- yoffset += texImage->Border;
- /* fall-through */
- case 1:
- xoffset += texImage->Border;
- }
-
- switch (dims) {
- case 1:
- ctx->Driver.TexSubImage1D(ctx, target, level,
- xoffset, width,
- format, type, pixels,
- &ctx->Unpack, texObj, texImage );
- break;
- case 2:
- ctx->Driver.TexSubImage2D(ctx, target, level,
- xoffset, yoffset, width, height,
- format, type, pixels,
- &ctx->Unpack, texObj, texImage );
- break;
- case 3:
- ctx->Driver.TexSubImage3D(ctx, target, level,
- xoffset, yoffset, zoffset,
- width, height, depth,
- format, type, pixels,
- &ctx->Unpack, texObj, texImage );
- break;
- default:
- _mesa_problem(ctx, "unexpected dims in subteximage()");
- }
-
- check_gen_mipmap(ctx, target, texObj, level);
-
- ctx->NewState |= _NEW_TEXTURE;
- }
- }
- _mesa_unlock_texture(ctx, texObj);
-}
-
-
-void GLAPIENTRY
-_mesa_TexSubImage1D( GLenum target, GLint level,
- GLint xoffset, GLsizei width,
- GLenum format, GLenum type,
- const GLvoid *pixels )
-{
- GET_CURRENT_CONTEXT(ctx);
- texsubimage(ctx, 1, target, level,
- xoffset, 0, 0,
- width, 1, 1,
- format, type, pixels);
-}
-
-
-void GLAPIENTRY
-_mesa_TexSubImage2D( GLenum target, GLint level,
- GLint xoffset, GLint yoffset,
- GLsizei width, GLsizei height,
- GLenum format, GLenum type,
- const GLvoid *pixels )
-{
- GET_CURRENT_CONTEXT(ctx);
- texsubimage(ctx, 2, target, level,
- xoffset, yoffset, 0,
- width, height, 1,
- format, type, pixels);
-}
-
-
-
-void GLAPIENTRY
-_mesa_TexSubImage3D( GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLenum type,
- const GLvoid *pixels )
-{
- GET_CURRENT_CONTEXT(ctx);
- texsubimage(ctx, 3, target, level,
- xoffset, yoffset, zoffset,
- width, height, depth,
- format, type, pixels);
-}
-
-
-
-/**
- * Implement the glCopyTexImage1/2D() functions.
- */
-static void
-copyteximage(struct gl_context *ctx, GLuint dims,
- GLenum target, GLint level, GLenum internalFormat,
- GLint x, GLint y, GLsizei width, GLsizei height, GLint border )
-{
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
- const GLuint face = _mesa_tex_target_to_face(target);
-
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
- _mesa_debug(ctx, "glCopyTexImage%uD %s %d %s %d %d %d %d %d\n",
- dims,
- _mesa_lookup_enum_by_nr(target), level,
- _mesa_lookup_enum_by_nr(internalFormat),
- x, y, width, height, border);
-
- if (ctx->NewState & NEW_COPY_TEX_STATE)
- _mesa_update_state(ctx);
-
- if (copytexture_error_check(ctx, dims, target, level, internalFormat,
- width, height, border))
- return;
-
- texObj = _mesa_get_current_tex_object(ctx, target);
-
- _mesa_lock_texture(ctx, texObj);
- {
- texImage = _mesa_get_tex_image(ctx, texObj, target, level);
-
- if (!texImage) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
- }
- else {
- gl_format texFormat;
-
- if (texImage->Data) {
- ctx->Driver.FreeTexImageData( ctx, texImage );
- }
-
- ASSERT(texImage->Data == NULL);
-
- texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
- internalFormat, GL_NONE,
- GL_NONE);
-
- if (legal_texture_size(ctx, texFormat, width, height, 1)) {
- _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
- border, internalFormat, texFormat);
-
- ASSERT(ctx->Driver.CopyTexImage2D);
- if (dims == 1)
- ctx->Driver.CopyTexImage1D(ctx, target, level, internalFormat,
- x, y, width, border);
- else
- ctx->Driver.CopyTexImage2D(ctx, target, level, internalFormat,
- x, y, width, height, border);
-
- check_gen_mipmap(ctx, target, texObj, level);
-
- update_fbo_texture(ctx, texObj, face, level);
-
- /* state update */
- texObj->_Complete = GL_FALSE;
- ctx->NewState |= _NEW_TEXTURE;
- }
- else {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
- }
- }
- }
- _mesa_unlock_texture(ctx, texObj);
-}
-
-
-
-void GLAPIENTRY
-_mesa_CopyTexImage1D( GLenum target, GLint level,
- GLenum internalFormat,
- GLint x, GLint y,
- GLsizei width, GLint border )
-{
- GET_CURRENT_CONTEXT(ctx);
- copyteximage(ctx, 1, target, level, internalFormat, x, y, width, 1, border);
-}
-
-
-
-void GLAPIENTRY
-_mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
- GLint x, GLint y, GLsizei width, GLsizei height,
- GLint border )
-{
- GET_CURRENT_CONTEXT(ctx);
- copyteximage(ctx, 2, target, level, internalFormat,
- x, y, width, height, border);
-}
-
-
-
-/**
- * Implementation for glCopyTexSubImage1/2/3D() functions.
- */
-static void
-copytexsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLint x, GLint y, GLsizei width, GLsizei height)
-{
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
-
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
- _mesa_debug(ctx, "glCopyTexSubImage%uD %s %d %d %d %d %d %d %d %d\n",
- dims,
- _mesa_lookup_enum_by_nr(target),
- level, xoffset, yoffset, zoffset, x, y, width, height);
-
- if (ctx->NewState & NEW_COPY_TEX_STATE)
- _mesa_update_state(ctx);
-
- if (copytexsubimage_error_check1(ctx, dims, target, level))
- return;
-
- texObj = _mesa_get_current_tex_object(ctx, target);
-
- _mesa_lock_texture(ctx, texObj);
- {
- texImage = _mesa_select_tex_image(ctx, texObj, target, level);
-
- if (copytexsubimage_error_check2(ctx, dims, target, level, xoffset, yoffset,
- zoffset, width, height, texImage)) {
- /* error was recored */
- }
- else {
- /* If we have a border, offset=-1 is legal. Bias by border width. */
- switch (dims) {
- case 3:
- zoffset += texImage->Border;
- /* fall-through */
- case 2:
- yoffset += texImage->Border;
- /* fall-through */
- case 1:
- xoffset += texImage->Border;
- }
-
- if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
- &width, &height)) {
- switch (dims) {
- case 1:
- ctx->Driver.CopyTexSubImage1D(ctx, target, level,
- xoffset, x, y, width);
- break;
- case 2:
- ctx->Driver.CopyTexSubImage2D(ctx, target, level,
- xoffset, yoffset,
- x, y, width, height);
- break;
- case 3:
- ctx->Driver.CopyTexSubImage3D(ctx, target, level,
- xoffset, yoffset, zoffset,
- x, y, width, height);
- break;
- default:
- _mesa_problem(ctx, "bad dims in copytexsubimage()");
- }
-
- check_gen_mipmap(ctx, target, texObj, level);
-
- ctx->NewState |= _NEW_TEXTURE;
- }
- }
- }
- _mesa_unlock_texture(ctx, texObj);
-}
-
-
-void GLAPIENTRY
-_mesa_CopyTexSubImage1D( GLenum target, GLint level,
- GLint xoffset, GLint x, GLint y, GLsizei width )
-{
- GET_CURRENT_CONTEXT(ctx);
- copytexsubimage(ctx, 1, target, level, xoffset, 0, 0, x, y, width, 1);
-}
-
-
-
-void GLAPIENTRY
-_mesa_CopyTexSubImage2D( GLenum target, GLint level,
- GLint xoffset, GLint yoffset,
- GLint x, GLint y, GLsizei width, GLsizei height )
-{
- GET_CURRENT_CONTEXT(ctx);
- copytexsubimage(ctx, 2, target, level, xoffset, yoffset, 0, x, y,
- width, height);
-}
-
-
-
-void GLAPIENTRY
-_mesa_CopyTexSubImage3D( GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLint x, GLint y, GLsizei width, GLsizei height )
-{
- GET_CURRENT_CONTEXT(ctx);
- copytexsubimage(ctx, 3, target, level, xoffset, yoffset, zoffset,
- x, y, width, height);
-}
-
-
-
-
-/**********************************************************************/
-/****** Compressed Textures ******/
-/**********************************************************************/
-
-
-/**
- * Return expected size of a compressed texture.
- */
-static GLuint
-compressed_tex_size(GLsizei width, GLsizei height, GLsizei depth,
- GLenum glformat)
-{
- gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat);
- return _mesa_format_image_size(mesaFormat, width, height, depth);
-}
-
-
-/*
- * Return compressed texture block size, in pixels.
- */
-static void
-get_compressed_block_size(GLenum glformat, GLuint *bw, GLuint *bh)
-{
- gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat);
- _mesa_get_format_block_size(mesaFormat, bw, bh);
-}
-
-
-/**
- * Error checking for glCompressedTexImage[123]D().
- * \return error code or GL_NO_ERROR.
- */
-static GLenum
-compressed_texture_error_check(struct gl_context *ctx, GLint dimensions,
- GLenum target, GLint level,
- GLenum internalFormat, GLsizei width,
- GLsizei height, GLsizei depth, GLint border,
- GLsizei imageSize)
-{
- const GLenum proxyTarget = get_proxy_target(target);
- const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
- GLint expectedSize;
-
- /* check level */
- if (level < 0 || level >= maxLevels)
- return GL_INVALID_VALUE;
-
- if (!target_can_be_compressed(ctx, target, internalFormat)) {
- return GL_INVALID_ENUM;
- }
-
- /* This will detect any invalid internalFormat value */
- if (!_mesa_is_compressed_format(ctx, internalFormat))
- return GL_INVALID_ENUM;
-
- /* This should really never fail */
- if (_mesa_base_tex_format(ctx, internalFormat) < 0)
- return GL_INVALID_ENUM;
-
- /* No compressed formats support borders at this time */
- if (border != 0)
- return GL_INVALID_VALUE;
-
- /* For cube map, width must equal height */
- if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
- target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB && width != height)
- return GL_INVALID_VALUE;
-
- /* check image size against compression block size */
- {
- gl_format texFormat =
- ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
- GL_NONE, GL_NONE);
- GLuint bw, bh;
-
- _mesa_get_format_block_size(texFormat, &bw, &bh);
- if ((width > bw && width % bw > 0) ||
- (height > bh && height % bh > 0)) {
- /*
- * Per GL_ARB_texture_compression: GL_INVALID_OPERATION is
- * generated [...] if any parameter combinations are not
- * supported by the specific compressed internal format.
- */
- return GL_INVALID_OPERATION;
- }
- }
-
- /* check image sizes */
- if (!ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
- internalFormat, GL_NONE, GL_NONE,
- width, height, depth, border)) {
- /* See error comment above */
- return GL_INVALID_OPERATION;
- }
-
- /* check image size in bytes */
- expectedSize = compressed_tex_size(width, height, depth, internalFormat);
- if (expectedSize != imageSize) {
- /* Per GL_ARB_texture_compression: GL_INVALID_VALUE is generated [...]
- * if <imageSize> is not consistent with the format, dimensions, and
- * contents of the specified image.
- */
- return GL_INVALID_VALUE;
- }
-
- return GL_NO_ERROR;
-}
-
-
-/**
- * Error checking for glCompressedTexSubImage[123]D().
- * \warning There are some bad assumptions here about the size of compressed
- * texture tiles (multiple of 4) used to test the validity of the
- * offset and size parameters.
- * \return error code or GL_NO_ERROR.
- */
-static GLenum
-compressed_subtexture_error_check(struct gl_context *ctx, GLint dimensions,
- GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLsizei imageSize)
-{
- GLint expectedSize, maxLevels = 0, maxTextureSize;
- GLuint bw, bh;
- (void) zoffset;
-
- if (dimensions == 1) {
- /* 1D compressed textures not allowed */
- return GL_INVALID_ENUM;
- }
- else if (dimensions == 2) {
- if (target == GL_PROXY_TEXTURE_2D) {
- maxLevels = ctx->Const.MaxTextureLevels;
- }
- else if (target == GL_TEXTURE_2D) {
- maxLevels = ctx->Const.MaxTextureLevels;
- }
- else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB) {
- if (!ctx->Extensions.ARB_texture_cube_map)
- return GL_INVALID_ENUM; /*target*/
- maxLevels = ctx->Const.MaxCubeTextureLevels;
- }
- else if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
- target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) {
- if (!ctx->Extensions.ARB_texture_cube_map)
- return GL_INVALID_ENUM; /*target*/
- maxLevels = ctx->Const.MaxCubeTextureLevels;
- }
- else {
- return GL_INVALID_ENUM; /*target*/
- }
- }
- else if (dimensions == 3) {
- /* 3D compressed textures not allowed */
- return GL_INVALID_ENUM;
- }
-
- maxTextureSize = 1 << (maxLevels - 1);
-
- /* this will catch any invalid compressed format token */
- if (!_mesa_is_compressed_format(ctx, format))
- return GL_INVALID_ENUM;
-
- if (width < 1 || width > maxTextureSize)
- return GL_INVALID_VALUE;
-
- if ((height < 1 || height > maxTextureSize)
- && dimensions > 1)
- return GL_INVALID_VALUE;
-
- if (level < 0 || level >= maxLevels)
- return GL_INVALID_VALUE;
-
- /*
- * do checks which depend on compression block size
- */
- get_compressed_block_size(format, &bw, &bh);
-
- if ((xoffset % bw != 0) || (yoffset % bh != 0))
- return GL_INVALID_VALUE;
-
- if ((width % bw != 0) && width != 2 && width != 1)
- return GL_INVALID_VALUE;
-
- if ((height % bh != 0) && height != 2 && height != 1)
- return GL_INVALID_VALUE;
-
- expectedSize = compressed_tex_size(width, height, depth, format);
- if (expectedSize != imageSize)
- return GL_INVALID_VALUE;
-
- return GL_NO_ERROR;
-}
-
-
-/**
- * Do second part of glCompressedTexSubImage error checking.
- * \return GL_TRUE if error found, GL_FALSE otherwise.
- */
-static GLboolean
-compressed_subtexture_error_check2(struct gl_context *ctx, GLuint dims,
- GLsizei width, GLsizei height,
- GLsizei depth, GLenum format,
- struct gl_texture_image *texImage)
-{
-
- if ((GLint) format != texImage->InternalFormat) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glCompressedTexSubImage%uD(format=0x%x)", dims, format);
- return GL_TRUE;
- }
-
- if (((width == 1 || width == 2) &&
- width != (GLsizei) texImage->Width) ||
- (width > (GLsizei) texImage->Width)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCompressedTexSubImage%uD(width=%d)", dims, width);
- return GL_TRUE;
- }
-
- if (dims >= 2) {
- if (((height == 1 || height == 2) &&
- height != (GLsizei) texImage->Height) ||
- (height > (GLsizei) texImage->Height)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCompressedTexSubImage%uD(height=%d)", dims, height);
- return GL_TRUE;
- }
- }
-
- if (dims >= 3) {
- if (((depth == 1 || depth == 2) &&
- depth != (GLsizei) texImage->Depth) ||
- (depth > (GLsizei) texImage->Depth)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCompressedTexSubImage%uD(depth=%d)", dims, depth);
- return GL_TRUE;
- }
- }
-
- return GL_FALSE;
-}
-
-
-/**
- * Implementation of the glCompressedTexImage1/2/3D() functions.
- */
-static void
-compressedteximage(struct gl_context *ctx, GLuint dims,
- GLenum target, GLint level,
- GLenum internalFormat, GLsizei width,
- GLsizei height, GLsizei depth, GLint border,
- GLsizei imageSize, const GLvoid *data)
-{
- GLenum error;
-
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
- _mesa_debug(ctx,
- "glCompressedTexImage%uDARB %s %d %s %d %d %d %d %d %p\n",
- dims,
- _mesa_lookup_enum_by_nr(target), level,
- _mesa_lookup_enum_by_nr(internalFormat),
- width, height, depth, border, imageSize, data);
-
- /* check target */
- if (!legal_teximage_target(ctx, dims, target)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(target=%s)",
- dims, _mesa_lookup_enum_by_nr(target));
- return;
- }
-
- error = compressed_texture_error_check(ctx, dims, target, level,
- internalFormat, width, height, depth,
- border, imageSize);
-
-#if FEATURE_ES
- /* XXX this is kind of a hack */
- if (error) {
- _mesa_error(ctx, error, "glTexImage2D");
- return;
- }
-
- if (dims == 2) {
- switch (internalFormat) {
- case GL_PALETTE4_RGB8_OES:
- case GL_PALETTE4_RGBA8_OES:
- case GL_PALETTE4_R5_G6_B5_OES:
- case GL_PALETTE4_RGBA4_OES:
- case GL_PALETTE4_RGB5_A1_OES:
- case GL_PALETTE8_RGB8_OES:
- case GL_PALETTE8_RGBA8_OES:
- case GL_PALETTE8_R5_G6_B5_OES:
- case GL_PALETTE8_RGBA4_OES:
- case GL_PALETTE8_RGB5_A1_OES:
- _mesa_cpal_compressed_teximage2d(target, level, internalFormat,
- width, height, imageSize, data);
- return;
- }
- }
-#endif
-
- if (_mesa_is_proxy_texture(target)) {
- /* Proxy texture: just check for errors and update proxy state */
- struct gl_texture_image *texImage;
-
- if (!error) {
- struct gl_texture_object *texObj =
- _mesa_get_current_tex_object(ctx, target);
- gl_format texFormat =
- _mesa_choose_texture_format(ctx, texObj, target, level,
- internalFormat, GL_NONE, GL_NONE);
- if (!legal_texture_size(ctx, texFormat, width, height, depth)) {
- error = GL_OUT_OF_MEMORY;
- }
- }
-
- texImage = _mesa_get_proxy_tex_image(ctx, target, level);
- if (texImage) {
- if (error) {
- /* if error, clear all proxy texture image parameters */
- clear_teximage_fields(texImage);
- }
- else {
- /* no error: store the teximage parameters */
- _mesa_init_teximage_fields(ctx, target, texImage, width, height,
- depth, border, internalFormat,
- MESA_FORMAT_NONE);
- }
- }
- }
- else {
- /* non-proxy target */
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
-
- if (error) {
- _mesa_error(ctx, error, "glCompressedTexImage%uD", dims);
- return;
- }
-
- texObj = _mesa_get_current_tex_object(ctx, target);
-
- _mesa_lock_texture(ctx, texObj);
- {
- texImage = _mesa_get_tex_image(ctx, texObj, target, level);
- if (!texImage) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY,
- "glCompressedTexImage%uD", dims);
- }
- else {
- gl_format texFormat;
-
- if (texImage->Data) {
- ctx->Driver.FreeTexImageData( ctx, texImage );
- }
- ASSERT(texImage->Data == NULL);
-
- texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
- internalFormat, GL_NONE,
- GL_NONE);
-
- if (legal_texture_size(ctx, texFormat, width, height, depth)) {
- _mesa_init_teximage_fields(ctx, target, texImage,
- width, height, depth,
- border, internalFormat, texFormat);
-
- switch (dims) {
- case 1:
- ASSERT(ctx->Driver.CompressedTexImage1D);
- ctx->Driver.CompressedTexImage1D(ctx, target, level,
- internalFormat,
- width,
- border, imageSize, data,
- texObj, texImage);
- break;
- case 2:
- ASSERT(ctx->Driver.CompressedTexImage2D);
- ctx->Driver.CompressedTexImage2D(ctx, target, level,
- internalFormat,
- width, height,
- border, imageSize, data,
- texObj, texImage);
- break;
- case 3:
- ASSERT(ctx->Driver.CompressedTexImage3D);
- ctx->Driver.CompressedTexImage3D(ctx, target, level,
- internalFormat,
- width, height, depth,
- border, imageSize, data,
- texObj, texImage);
- break;
- default:
- _mesa_problem(ctx, "bad dims in compressedteximage");
- }
-
- check_gen_mipmap(ctx, target, texObj, level);
-
- /* state update */
- texObj->_Complete = GL_FALSE;
- ctx->NewState |= _NEW_TEXTURE;
- }
- else {
- _mesa_error(ctx, GL_OUT_OF_MEMORY,
- "glCompressedTexImage%uD", dims);
- }
- }
- }
- _mesa_unlock_texture(ctx, texObj);
- }
-}
-
-
-void GLAPIENTRY
-_mesa_CompressedTexImage1DARB(GLenum target, GLint level,
- GLenum internalFormat, GLsizei width,
- GLint border, GLsizei imageSize,
- const GLvoid *data)
-{
- GET_CURRENT_CONTEXT(ctx);
- compressedteximage(ctx, 1, target, level, internalFormat,
- width, 1, 1, border, imageSize, data);
-}
-
-
-void GLAPIENTRY
-_mesa_CompressedTexImage2DARB(GLenum target, GLint level,
- GLenum internalFormat, GLsizei width,
- GLsizei height, GLint border, GLsizei imageSize,
- const GLvoid *data)
-{
- GET_CURRENT_CONTEXT(ctx);
- compressedteximage(ctx, 2, target, level, internalFormat,
- width, height, 1, border, imageSize, data);
-}
-
-
-void GLAPIENTRY
-_mesa_CompressedTexImage3DARB(GLenum target, GLint level,
- GLenum internalFormat, GLsizei width,
- GLsizei height, GLsizei depth, GLint border,
- GLsizei imageSize, const GLvoid *data)
-{
- GET_CURRENT_CONTEXT(ctx);
- compressedteximage(ctx, 3, target, level, internalFormat,
- width, height, depth, border, imageSize, data);
-}
-
-
-/**
- * Common helper for glCompressedTexSubImage1/2/3D().
- */
-static void
-compressed_tex_sub_image(GLuint dims, GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLsizei imageSize, const GLvoid *data)
-{
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
- GLenum error;
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- error = compressed_subtexture_error_check(ctx, dims, target, level,
- xoffset, 0, 0, /* pos */
- width, height, depth, /* size */
- format, imageSize);
- if (error) {
- _mesa_error(ctx, error, "glCompressedTexSubImage%uD", dims);
- return;
- }
-
- texObj = _mesa_get_current_tex_object(ctx, target);
-
- _mesa_lock_texture(ctx, texObj);
- {
- texImage = _mesa_select_tex_image(ctx, texObj, target, level);
- assert(texImage);
-
- if (compressed_subtexture_error_check2(ctx, dims, width, height, depth,
- format, texImage)) {
- /* error was recorded */
- }
- else if (width > 0 && height > 0 && depth > 0) {
- switch (dims) {
- case 1:
- if (ctx->Driver.CompressedTexSubImage1D) {
- ctx->Driver.CompressedTexSubImage1D(ctx, target, level,
- xoffset, width,
- format, imageSize, data,
- texObj, texImage);
- }
- break;
- case 2:
- if (ctx->Driver.CompressedTexSubImage2D) {
- ctx->Driver.CompressedTexSubImage2D(ctx, target, level,
- xoffset, yoffset,
- width, height,
- format, imageSize, data,
- texObj, texImage);
- }
- break;
- case 3:
- if (ctx->Driver.CompressedTexSubImage3D) {
- ctx->Driver.CompressedTexSubImage3D(ctx, target, level,
- xoffset, yoffset, zoffset,
- width, height, depth,
- format, imageSize, data,
- texObj, texImage);
- }
- break;
- default:
- ;
- }
-
- check_gen_mipmap(ctx, target, texObj, level);
-
- ctx->NewState |= _NEW_TEXTURE;
- }
- }
- _mesa_unlock_texture(ctx, texObj);
-}
-
-
-void GLAPIENTRY
-_mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
- GLsizei width, GLenum format,
- GLsizei imageSize, const GLvoid *data)
-{
- compressed_tex_sub_image(1, target, level, xoffset, 0, 0, width, 1, 1,
- format, imageSize, data);
-}
-
-
-void GLAPIENTRY
-_mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset,
- GLint yoffset, GLsizei width, GLsizei height,
- GLenum format, GLsizei imageSize,
- const GLvoid *data)
-{
- compressed_tex_sub_image(2, target, level, xoffset, yoffset, 0,
- width, height, 1, format, imageSize, data);
-}
-
-
-void GLAPIENTRY
-_mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset,
- GLint yoffset, GLint zoffset, GLsizei width,
- GLsizei height, GLsizei depth, GLenum format,
- GLsizei imageSize, const GLvoid *data)
-{
- compressed_tex_sub_image(3, target, level, xoffset, yoffset, zoffset,
- width, height, depth, format, imageSize, data);
-}
+/* + * mesa 3-D graphics library + * Version: 7.6 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. 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. + */ + + +/** + * \file teximage.c + * Texture image-related functions. + */ + + +#include "glheader.h" +#include "bufferobj.h" +#include "context.h" +#include "enums.h" +#include "fbobject.h" +#include "framebuffer.h" +#include "hash.h" +#include "image.h" +#include "imports.h" +#include "macros.h" +#include "mfeatures.h" +#include "state.h" +#include "texcompress.h" +#include "texfetch.h" +#include "teximage.h" +#include "texstate.h" +#include "texpal.h" +#include "mtypes.h" + + +/** + * State changes which we care about for glCopyTex[Sub]Image() calls. + * In particular, we care about pixel transfer state and buffer state + * (such as glReadBuffer to make sure we read from the right renderbuffer). + */ +#define NEW_COPY_TEX_STATE (_MESA_NEW_TRANSFER_STATE | \ + _NEW_BUFFERS | \ + _NEW_PIXEL) + + + +/** + * We allocate texture memory on 512-byte boundaries so we can use MMX/SSE + * elsewhere. + */ +void * +_mesa_alloc_texmemory(GLsizei bytes) +{ + return _mesa_align_malloc(bytes, 512); +} + + +/** + * Free texture memory allocated with _mesa_alloc_texmemory() + */ +void +_mesa_free_texmemory(void *m) +{ + _mesa_align_free(m); +} + + +/* + * Compute floor(log_base_2(n)). + * If n < 0 return -1. + */ +static int +logbase2( int n ) +{ + GLint i = 1; + GLint log2 = 0; + + if (n < 0) + return -1; + + if (n == 0) + return 0; + + while ( n > i ) { + i *= 2; + log2++; + } + if (i != n) { + return log2 - 1; + } + else { + return log2; + } +} + + + +/** + * Return the simple base format for a given internal texture format. + * For example, given GL_LUMINANCE12_ALPHA4, return GL_LUMINANCE_ALPHA. + * + * \param ctx GL context. + * \param internalFormat the internal texture format token or 1, 2, 3, or 4. + * + * \return the corresponding \u base internal format (GL_ALPHA, GL_LUMINANCE, + * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA), or -1 if invalid enum. + * + * This is the format which is used during texture application (i.e. the + * texture format and env mode determine the arithmetic used. + * + * XXX this could be static + */ +GLint +_mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) +{ + switch (internalFormat) { + case GL_ALPHA: + case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + return GL_ALPHA; + case 1: + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + return GL_LUMINANCE; + case 2: + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE4_ALPHA4: + case GL_LUMINANCE6_ALPHA2: + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE12_ALPHA4: + case GL_LUMINANCE12_ALPHA12: + case GL_LUMINANCE16_ALPHA16: + return GL_LUMINANCE_ALPHA; + case GL_INTENSITY: + case GL_INTENSITY4: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + return GL_INTENSITY; + case 3: + case GL_RGB: + case GL_R3_G3_B2: + case GL_RGB4: + case GL_RGB5: + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + return GL_RGB; + case 4: + case GL_RGBA: + case GL_RGBA2: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: + return GL_RGBA; + default: + ; /* fallthrough */ + } + + if (ctx->Extensions.EXT_texture_format_BGRA8888) { + switch (internalFormat) { + case GL_BGRA_EXT: + return GL_RGBA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.EXT_paletted_texture) { + switch (internalFormat) { + case GL_COLOR_INDEX: + case GL_COLOR_INDEX1_EXT: + case GL_COLOR_INDEX2_EXT: + case GL_COLOR_INDEX4_EXT: + case GL_COLOR_INDEX8_EXT: + case GL_COLOR_INDEX12_EXT: + case GL_COLOR_INDEX16_EXT: + return GL_COLOR_INDEX; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.ARB_depth_texture) { + switch (internalFormat) { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT32: + return GL_DEPTH_COMPONENT; + default: + ; /* fallthrough */ + } + } + + switch (internalFormat) { + case GL_COMPRESSED_ALPHA: + return GL_ALPHA; + case GL_COMPRESSED_LUMINANCE: + return GL_LUMINANCE; + case GL_COMPRESSED_LUMINANCE_ALPHA: + return GL_LUMINANCE_ALPHA; + case GL_COMPRESSED_INTENSITY: + return GL_INTENSITY; + case GL_COMPRESSED_RGB: + return GL_RGB; + case GL_COMPRESSED_RGBA: + return GL_RGBA; + default: + ; /* fallthrough */ + } + + if (ctx->Extensions.TDFX_texture_compression_FXT1) { + switch (internalFormat) { + case GL_COMPRESSED_RGB_FXT1_3DFX: + return GL_RGB; + case GL_COMPRESSED_RGBA_FXT1_3DFX: + return GL_RGBA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.EXT_texture_compression_s3tc) { + switch (internalFormat) { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + return GL_RGB; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + return GL_RGBA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.S3_s3tc) { + switch (internalFormat) { + case GL_RGB_S3TC: + case GL_RGB4_S3TC: + return GL_RGB; + case GL_RGBA_S3TC: + case GL_RGBA4_S3TC: + return GL_RGBA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.MESA_ycbcr_texture) { + if (internalFormat == GL_YCBCR_MESA) + return GL_YCBCR_MESA; + } + + if (ctx->Extensions.ARB_texture_float) { + switch (internalFormat) { + case GL_ALPHA16F_ARB: + case GL_ALPHA32F_ARB: + return GL_ALPHA; + case GL_RGBA16F_ARB: + case GL_RGBA32F_ARB: + return GL_RGBA; + case GL_RGB16F_ARB: + case GL_RGB32F_ARB: + return GL_RGB; + case GL_INTENSITY16F_ARB: + case GL_INTENSITY32F_ARB: + return GL_INTENSITY; + case GL_LUMINANCE16F_ARB: + case GL_LUMINANCE32F_ARB: + return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA16F_ARB: + case GL_LUMINANCE_ALPHA32F_ARB: + return GL_LUMINANCE_ALPHA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.ATI_envmap_bumpmap) { + switch (internalFormat) { + case GL_DUDV_ATI: + case GL_DU8DV8_ATI: + return GL_DUDV_ATI; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.MESA_texture_signed_rgba) { + switch (internalFormat) { + case GL_RGBA_SNORM: + case GL_RGBA8_SNORM: + return GL_RGBA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.EXT_packed_depth_stencil) { + switch (internalFormat) { + case GL_DEPTH_STENCIL_EXT: + case GL_DEPTH24_STENCIL8_EXT: + return GL_DEPTH_STENCIL_EXT; + default: + ; /* fallthrough */ + } + } + +#if FEATURE_EXT_texture_sRGB + if (ctx->Extensions.EXT_texture_sRGB) { + switch (internalFormat) { + case GL_SRGB_EXT: + case GL_SRGB8_EXT: + case GL_COMPRESSED_SRGB_EXT: + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + return GL_RGB; + case GL_SRGB_ALPHA_EXT: + case GL_SRGB8_ALPHA8_EXT: + case GL_COMPRESSED_SRGB_ALPHA_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + return GL_RGBA; + case GL_SLUMINANCE_ALPHA_EXT: + case GL_SLUMINANCE8_ALPHA8_EXT: + case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT: + return GL_LUMINANCE_ALPHA; + case GL_SLUMINANCE_EXT: + case GL_SLUMINANCE8_EXT: + case GL_COMPRESSED_SLUMINANCE_EXT: + return GL_LUMINANCE; + default: + ; /* fallthrough */ + } + } +#endif /* FEATURE_EXT_texture_sRGB */ + + if (ctx->Extensions.EXT_texture_integer) { + switch (internalFormat) { + case GL_RGBA8UI_EXT: + case GL_RGBA16UI_EXT: + case GL_RGBA32UI_EXT: + case GL_RGBA8I_EXT: + case GL_RGBA16I_EXT: + case GL_RGBA32I_EXT: + return GL_RGBA; + case GL_RGB8UI_EXT: + case GL_RGB16UI_EXT: + case GL_RGB32UI_EXT: + case GL_RGB8I_EXT: + case GL_RGB16I_EXT: + case GL_RGB32I_EXT: + return GL_RGB; + case GL_ALPHA8UI_EXT: + case GL_ALPHA16UI_EXT: + case GL_ALPHA32UI_EXT: + case GL_ALPHA8I_EXT: + case GL_ALPHA16I_EXT: + case GL_ALPHA32I_EXT: + return GL_ALPHA; + case GL_INTENSITY8UI_EXT: + case GL_INTENSITY16UI_EXT: + case GL_INTENSITY32UI_EXT: + case GL_INTENSITY8I_EXT: + case GL_INTENSITY16I_EXT: + case GL_INTENSITY32I_EXT: + return GL_INTENSITY; + case GL_LUMINANCE8UI_EXT: + case GL_LUMINANCE16UI_EXT: + case GL_LUMINANCE32UI_EXT: + case GL_LUMINANCE8I_EXT: + case GL_LUMINANCE16I_EXT: + case GL_LUMINANCE32I_EXT: + return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA8UI_EXT: + case GL_LUMINANCE_ALPHA16UI_EXT: + case GL_LUMINANCE_ALPHA32UI_EXT: + case GL_LUMINANCE_ALPHA8I_EXT: + case GL_LUMINANCE_ALPHA16I_EXT: + case GL_LUMINANCE_ALPHA32I_EXT: + return GL_LUMINANCE_ALPHA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.ARB_texture_rg) { + switch (internalFormat) { + case GL_R16F: + /* R16F depends on both ARB_half_float_pixel and ARB_texture_float. + */ + if (!ctx->Extensions.ARB_half_float_pixel) + break; + /* FALLTHROUGH */ + case GL_R32F: + if (!ctx->Extensions.ARB_texture_float) + break; + return GL_RED; + case GL_R8I: + case GL_R8UI: + case GL_R16I: + case GL_R16UI: + case GL_R32I: + case GL_R32UI: + if (!ctx->Extensions.EXT_texture_integer) + break; + /* FALLTHROUGH */ + case GL_R8: + case GL_R16: + case GL_RED: + case GL_COMPRESSED_RED: + return GL_RED; + + case GL_RG16F: + /* RG16F depends on both ARB_half_float_pixel and ARB_texture_float. + */ + if (!ctx->Extensions.ARB_half_float_pixel) + break; + /* FALLTHROUGH */ + case GL_RG32F: + if (!ctx->Extensions.ARB_texture_float) + break; + return GL_RG; + case GL_RG8I: + case GL_RG8UI: + case GL_RG16I: + case GL_RG16UI: + case GL_RG32I: + case GL_RG32UI: + if (!ctx->Extensions.EXT_texture_integer) + break; + /* FALLTHROUGH */ + case GL_RG: + case GL_RG8: + case GL_RG16: + case GL_COMPRESSED_RG: + return GL_RG; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.EXT_texture_shared_exponent) { + switch (internalFormat) { + case GL_RGB9_E5_EXT: + return GL_RGB; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.EXT_packed_float) { + switch (internalFormat) { + case GL_R11F_G11F_B10F_EXT: + return GL_RGB; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.ARB_depth_buffer_float) { + switch (internalFormat) { + case GL_DEPTH_COMPONENT32F: + return GL_DEPTH_COMPONENT; + case GL_DEPTH32F_STENCIL8: + return GL_DEPTH_STENCIL; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.ARB_texture_compression_rgtc) { + switch (internalFormat) { + case GL_COMPRESSED_RED_RGTC1: + case GL_COMPRESSED_SIGNED_RED_RGTC1: + return GL_RED; + case GL_COMPRESSED_RG_RGTC2: + case GL_COMPRESSED_SIGNED_RG_RGTC2: + return GL_RG; + default: + ; /* fallthrough */ + } + } + + return -1; /* error */ +} + + +/** + * For cube map faces, return a face index in [0,5]. + * For other targets return 0; + */ +GLuint +_mesa_tex_target_to_face(GLenum target) +{ + if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) + return (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + else + return 0; +} + + + +/** + * Store a gl_texture_image pointer in a gl_texture_object structure + * according to the target and level parameters. + * + * \param tObj texture object. + * \param target texture target. + * \param level image level. + * \param texImage texture image. + * + * This was basically prompted by the introduction of cube maps. + */ +void +_mesa_set_tex_image(struct gl_texture_object *tObj, + GLenum target, GLint level, + struct gl_texture_image *texImage) +{ + const GLuint face = _mesa_tex_target_to_face(target); + + ASSERT(tObj); + ASSERT(texImage); + ASSERT(target != GL_TEXTURE_RECTANGLE_NV || level == 0); + + tObj->Image[face][level] = texImage; + + /* Set the 'back' pointer */ + texImage->TexObject = tObj; +} + + +/** + * Allocate a texture image structure. + * + * Called via ctx->Driver.NewTextureImage() unless overriden by a device + * driver. + * + * \return a pointer to gl_texture_image struct with all fields initialized to + * zero. + */ +struct gl_texture_image * +_mesa_new_texture_image( struct gl_context *ctx ) +{ + (void) ctx; + return CALLOC_STRUCT(gl_texture_image); +} + + +/** + * Free texture image data. + * This function is a fallback called via ctx->Driver.FreeTexImageData(). + * + * \param texImage texture image. + * + * Free the texture image data if it's not marked as client data. + */ +void +_mesa_free_texture_image_data(struct gl_context *ctx, + struct gl_texture_image *texImage) +{ + (void) ctx; + + if (texImage->Data && !texImage->IsClientData) { + /* free the old texture data */ + _mesa_free_texmemory(texImage->Data); + } + + texImage->Data = NULL; +} + + +/** + * Free texture image. + * + * \param texImage texture image. + * + * Free the texture image structure and the associated image data. + */ +void +_mesa_delete_texture_image(struct gl_context *ctx, + struct gl_texture_image *texImage) +{ + /* Free texImage->Data and/or any other driver-specific texture + * image storage. + */ + ASSERT(ctx->Driver.FreeTexImageData); + ctx->Driver.FreeTexImageData( ctx, texImage ); + + ASSERT(texImage->Data == NULL); + if (texImage->ImageOffsets) + free(texImage->ImageOffsets); + free(texImage); +} + + +/** + * Test if a target is a proxy target. + * + * \param target texture target. + * + * \return GL_TRUE if the target is a proxy target, GL_FALSE otherwise. + */ +GLboolean +_mesa_is_proxy_texture(GLenum target) +{ + /* NUM_TEXTURE_TARGETS should match number of terms below */ + assert(NUM_TEXTURE_TARGETS == 7); + + return (target == GL_PROXY_TEXTURE_1D || + target == GL_PROXY_TEXTURE_2D || + target == GL_PROXY_TEXTURE_3D || + target == GL_PROXY_TEXTURE_CUBE_MAP_ARB || + target == GL_PROXY_TEXTURE_RECTANGLE_NV || + target == GL_PROXY_TEXTURE_1D_ARRAY_EXT || + target == GL_PROXY_TEXTURE_2D_ARRAY_EXT); +} + + +/** + * Return the proxy target which corresponds to the given texture target + */ +static GLenum +get_proxy_target(GLenum target) +{ + switch (target) { + case GL_TEXTURE_1D: + case GL_PROXY_TEXTURE_1D: + return GL_PROXY_TEXTURE_1D; + case GL_TEXTURE_2D: + case GL_PROXY_TEXTURE_2D: + return GL_PROXY_TEXTURE_2D; + case GL_TEXTURE_3D: + case GL_PROXY_TEXTURE_3D: + return GL_PROXY_TEXTURE_3D; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_ARB: + case GL_PROXY_TEXTURE_CUBE_MAP_ARB: + return GL_PROXY_TEXTURE_CUBE_MAP_ARB; + case GL_TEXTURE_RECTANGLE_NV: + case GL_PROXY_TEXTURE_RECTANGLE_NV: + return GL_PROXY_TEXTURE_RECTANGLE_NV; + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + return GL_PROXY_TEXTURE_1D_ARRAY_EXT; + case GL_TEXTURE_2D_ARRAY_EXT: + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + return GL_PROXY_TEXTURE_2D_ARRAY_EXT; + default: + _mesa_problem(NULL, "unexpected target in get_proxy_target()"); + return 0; + } +} + + +/** + * Get the texture object that corresponds to the target of the given + * texture unit. + * + * \param ctx GL context. + * \param texUnit texture unit. + * \param target texture target. + * + * \return pointer to the texture object on success, or NULL on failure. + * + * \sa gl_texture_unit. + */ +struct gl_texture_object * +_mesa_select_tex_object(struct gl_context *ctx, + const struct gl_texture_unit *texUnit, + GLenum target) +{ + const GLboolean arrayTex = (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array); + + switch (target) { + case GL_TEXTURE_1D: + return texUnit->CurrentTex[TEXTURE_1D_INDEX]; + case GL_PROXY_TEXTURE_1D: + return ctx->Texture.ProxyTex[TEXTURE_1D_INDEX]; + case GL_TEXTURE_2D: + return texUnit->CurrentTex[TEXTURE_2D_INDEX]; + case GL_PROXY_TEXTURE_2D: + return ctx->Texture.ProxyTex[TEXTURE_2D_INDEX]; + case GL_TEXTURE_3D: + return texUnit->CurrentTex[TEXTURE_3D_INDEX]; + case GL_PROXY_TEXTURE_3D: + return ctx->Texture.ProxyTex[TEXTURE_3D_INDEX]; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_ARB: + return ctx->Extensions.ARB_texture_cube_map + ? texUnit->CurrentTex[TEXTURE_CUBE_INDEX] : NULL; + case GL_PROXY_TEXTURE_CUBE_MAP_ARB: + return ctx->Extensions.ARB_texture_cube_map + ? ctx->Texture.ProxyTex[TEXTURE_CUBE_INDEX] : NULL; + case GL_TEXTURE_RECTANGLE_NV: + return ctx->Extensions.NV_texture_rectangle + ? texUnit->CurrentTex[TEXTURE_RECT_INDEX] : NULL; + case GL_PROXY_TEXTURE_RECTANGLE_NV: + return ctx->Extensions.NV_texture_rectangle + ? ctx->Texture.ProxyTex[TEXTURE_RECT_INDEX] : NULL; + case GL_TEXTURE_1D_ARRAY_EXT: + return arrayTex ? texUnit->CurrentTex[TEXTURE_1D_ARRAY_INDEX] : NULL; + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + return arrayTex ? ctx->Texture.ProxyTex[TEXTURE_1D_ARRAY_INDEX] : NULL; + case GL_TEXTURE_2D_ARRAY_EXT: + return arrayTex ? texUnit->CurrentTex[TEXTURE_2D_ARRAY_INDEX] : NULL; + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + return arrayTex ? ctx->Texture.ProxyTex[TEXTURE_2D_ARRAY_INDEX] : NULL; + default: + _mesa_problem(NULL, "bad target in _mesa_select_tex_object()"); + return NULL; + } +} + + +/** + * Return pointer to texture object for given target on current texture unit. + */ +struct gl_texture_object * +_mesa_get_current_tex_object(struct gl_context *ctx, GLenum target) +{ + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + return _mesa_select_tex_object(ctx, texUnit, target); +} + + +/** + * Get a texture image pointer from a texture object, given a texture + * target and mipmap level. The target and level parameters should + * have already been error-checked. + * + * \param ctx GL context. + * \param texObj texture unit. + * \param target texture target. + * \param level image level. + * + * \return pointer to the texture image structure, or NULL on failure. + */ +struct gl_texture_image * +_mesa_select_tex_image(struct gl_context *ctx, + const struct gl_texture_object *texObj, + GLenum target, GLint level) +{ + const GLuint face = _mesa_tex_target_to_face(target); + + ASSERT(texObj); + ASSERT(level >= 0); + ASSERT(level < MAX_TEXTURE_LEVELS); + + return texObj->Image[face][level]; +} + + +/** + * Like _mesa_select_tex_image() but if the image doesn't exist, allocate + * it and install it. Only return NULL if passed a bad parameter or run + * out of memory. + */ +struct gl_texture_image * +_mesa_get_tex_image(struct gl_context *ctx, struct gl_texture_object *texObj, + GLenum target, GLint level) +{ + struct gl_texture_image *texImage; + + if (!texObj) + return NULL; + + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + if (!texImage) { + texImage = ctx->Driver.NewTextureImage(ctx); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture image allocation"); + return NULL; + } + + _mesa_set_tex_image(texObj, target, level, texImage); + } + + return texImage; +} + + +/** + * Return pointer to the specified proxy texture image. + * Note that proxy textures are per-context, not per-texture unit. + * \return pointer to texture image or NULL if invalid target, invalid + * level, or out of memory. + */ +struct gl_texture_image * +_mesa_get_proxy_tex_image(struct gl_context *ctx, GLenum target, GLint level) +{ + struct gl_texture_image *texImage; + GLuint texIndex; + + if (level < 0 ) + return NULL; + + switch (target) { + case GL_PROXY_TEXTURE_1D: + if (level >= ctx->Const.MaxTextureLevels) + return NULL; + texIndex = TEXTURE_1D_INDEX; + break; + case GL_PROXY_TEXTURE_2D: + if (level >= ctx->Const.MaxTextureLevels) + return NULL; + texIndex = TEXTURE_2D_INDEX; + break; + case GL_PROXY_TEXTURE_3D: + if (level >= ctx->Const.Max3DTextureLevels) + return NULL; + texIndex = TEXTURE_3D_INDEX; + break; + case GL_PROXY_TEXTURE_CUBE_MAP: + if (level >= ctx->Const.MaxCubeTextureLevels) + return NULL; + texIndex = TEXTURE_CUBE_INDEX; + break; + case GL_PROXY_TEXTURE_RECTANGLE_NV: + if (level > 0) + return NULL; + texIndex = TEXTURE_RECT_INDEX; + break; + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + if (level >= ctx->Const.MaxTextureLevels) + return NULL; + texIndex = TEXTURE_1D_ARRAY_INDEX; + break; + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + if (level >= ctx->Const.MaxTextureLevels) + return NULL; + texIndex = TEXTURE_2D_ARRAY_INDEX; + break; + default: + return NULL; + } + + texImage = ctx->Texture.ProxyTex[texIndex]->Image[0][level]; + if (!texImage) { + texImage = ctx->Driver.NewTextureImage(ctx); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation"); + return NULL; + } + ctx->Texture.ProxyTex[texIndex]->Image[0][level] = texImage; + /* Set the 'back' pointer */ + texImage->TexObject = ctx->Texture.ProxyTex[texIndex]; + } + return texImage; +} + + +/** + * Get the maximum number of allowed mipmap levels. + * + * \param ctx GL context. + * \param target texture target. + * + * \return the maximum number of allowed mipmap levels for the given + * texture target, or zero if passed a bad target. + * + * \sa gl_constants. + */ +GLint +_mesa_max_texture_levels(struct gl_context *ctx, GLenum target) +{ + switch (target) { + case GL_TEXTURE_1D: + case GL_PROXY_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_PROXY_TEXTURE_2D: + return ctx->Const.MaxTextureLevels; + case GL_TEXTURE_3D: + case GL_PROXY_TEXTURE_3D: + return ctx->Const.Max3DTextureLevels; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_ARB: + case GL_PROXY_TEXTURE_CUBE_MAP_ARB: + return ctx->Extensions.ARB_texture_cube_map + ? ctx->Const.MaxCubeTextureLevels : 0; + case GL_TEXTURE_RECTANGLE_NV: + case GL_PROXY_TEXTURE_RECTANGLE_NV: + return ctx->Extensions.NV_texture_rectangle ? 1 : 0; + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + case GL_TEXTURE_2D_ARRAY_EXT: + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + return (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array) + ? ctx->Const.MaxTextureLevels : 0; + default: + return 0; /* bad target */ + } +} + + +/** + * Return number of dimensions per mipmap level for the given texture target. + */ +GLint +_mesa_get_texture_dimensions(GLenum target) +{ + switch (target) { + case GL_TEXTURE_1D: + case GL_PROXY_TEXTURE_1D: + return 1; + case GL_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE: + case GL_TEXTURE_CUBE_MAP: + case GL_PROXY_TEXTURE_2D: + case GL_PROXY_TEXTURE_RECTANGLE: + case GL_PROXY_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + case GL_TEXTURE_1D_ARRAY: + case GL_PROXY_TEXTURE_1D_ARRAY: + return 2; + case GL_TEXTURE_3D: + case GL_PROXY_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + case GL_PROXY_TEXTURE_2D_ARRAY: + return 3; + default: + _mesa_problem(NULL, "invalid target 0x%x in get_texture_dimensions()", + target); + return 2; + } +} + + + + +#if 000 /* not used anymore */ +/* + * glTexImage[123]D can accept a NULL image pointer. In this case we + * create a texture image with unspecified image contents per the OpenGL + * spec. + */ +static GLubyte * +make_null_texture(GLint width, GLint height, GLint depth, GLenum format) +{ + const GLint components = _mesa_components_in_format(format); + const GLint numPixels = width * height * depth; + GLubyte *data = (GLubyte *) MALLOC(numPixels * components * sizeof(GLubyte)); + +#ifdef DEBUG + /* + * Let's see if anyone finds this. If glTexImage2D() is called with + * a NULL image pointer then load the texture image with something + * interesting instead of leaving it indeterminate. + */ + if (data) { + static const char message[8][32] = { + " X X XXXXX XXX X ", + " XX XX X X X X X ", + " X X X X X X X ", + " X X XXXX XXX XXXXX ", + " X X X X X X ", + " X X X X X X X ", + " X X XXXXX XXX X X ", + " " + }; + + GLubyte *imgPtr = data; + GLint h, i, j, k; + for (h = 0; h < depth; h++) { + for (i = 0; i < height; i++) { + GLint srcRow = 7 - (i % 8); + for (j = 0; j < width; j++) { + GLint srcCol = j % 32; + GLubyte texel = (message[srcRow][srcCol]=='X') ? 255 : 70; + for (k = 0; k < components; k++) { + *imgPtr++ = texel; + } + } + } + } + } +#endif + + return data; +} +#endif + + + +/** + * Reset the fields of a gl_texture_image struct to zero. + * + * \param img texture image structure. + * + * This is called when a proxy texture test fails, we set all the + * image members (except DriverData) to zero. + * It's also used in glTexImage[123]D as a safeguard to be sure all + * required fields get initialized properly by the Driver.TexImage[123]D + * functions. + */ +static void +clear_teximage_fields(struct gl_texture_image *img) +{ + ASSERT(img); + img->_BaseFormat = 0; + img->InternalFormat = 0; + img->Border = 0; + img->Width = 0; + img->Height = 0; + img->Depth = 0; + img->RowStride = 0; + if (img->ImageOffsets) { + free(img->ImageOffsets); + img->ImageOffsets = NULL; + } + img->Width2 = 0; + img->Height2 = 0; + img->Depth2 = 0; + img->WidthLog2 = 0; + img->HeightLog2 = 0; + img->DepthLog2 = 0; + img->Data = NULL; + img->TexFormat = MESA_FORMAT_NONE; + img->FetchTexelc = NULL; + img->FetchTexelf = NULL; +} + + +/** + * Initialize basic fields of the gl_texture_image struct. + * + * \param ctx GL context. + * \param target texture target (GL_TEXTURE_1D, GL_TEXTURE_RECTANGLE, etc). + * \param img texture image structure to be initialized. + * \param width image width. + * \param height image height. + * \param depth image depth. + * \param border image border. + * \param internalFormat internal format. + * \param format the actual hardware format (one of MESA_FORMAT_*) + * + * Fills in the fields of \p img with the given information. + * Note: width, height and depth include the border. + */ +void +_mesa_init_teximage_fields(struct gl_context *ctx, GLenum target, + struct gl_texture_image *img, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum internalFormat, + gl_format format) +{ + GLint i, dims; + + ASSERT(img); + ASSERT(width >= 0); + ASSERT(height >= 0); + ASSERT(depth >= 0); + + img->_BaseFormat = _mesa_base_tex_format( ctx, internalFormat ); + ASSERT(img->_BaseFormat > 0); + img->InternalFormat = internalFormat; + img->Border = border; + img->Width = width; + img->Height = height; + img->Depth = depth; + + img->Width2 = width - 2 * border; /* == 1 << img->WidthLog2; */ + img->WidthLog2 = logbase2(img->Width2); + + if (height == 1) { /* 1-D texture */ + img->Height2 = 1; + img->HeightLog2 = 0; + } + else { + img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */ + img->HeightLog2 = logbase2(img->Height2); + } + + if (depth == 1) { /* 2-D texture */ + img->Depth2 = 1; + img->DepthLog2 = 0; + } + else { + img->Depth2 = depth - 2 * border; /* == 1 << img->DepthLog2; */ + img->DepthLog2 = logbase2(img->Depth2); + } + + img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2); + + if ((width == 1 || _mesa_is_pow_two(img->Width2)) && + (height == 1 || _mesa_is_pow_two(img->Height2)) && + (depth == 1 || _mesa_is_pow_two(img->Depth2))) + img->_IsPowerOfTwo = GL_TRUE; + else + img->_IsPowerOfTwo = GL_FALSE; + + /* RowStride and ImageOffsets[] describe how to address texels in 'Data' */ + img->RowStride = width; + /* Allocate the ImageOffsets array and initialize to typical values. + * We allocate the array for 1D/2D textures too in order to avoid special- + * case code in the texstore routines. + */ + if (img->ImageOffsets) + free(img->ImageOffsets); + img->ImageOffsets = (GLuint *) malloc(depth * sizeof(GLuint)); + for (i = 0; i < depth; i++) { + img->ImageOffsets[i] = i * width * height; + } + + /* Compute Width/Height/DepthScale for mipmap lod computation */ + if (target == GL_TEXTURE_RECTANGLE_NV) { + /* scale = 1.0 since texture coords directly map to texels */ + img->WidthScale = 1.0; + img->HeightScale = 1.0; + img->DepthScale = 1.0; + } + else { + img->WidthScale = (GLfloat) img->Width; + img->HeightScale = (GLfloat) img->Height; + img->DepthScale = (GLfloat) img->Depth; + } + + img->TexFormat = format; + + dims = _mesa_get_texture_dimensions(target); + + _mesa_set_fetch_functions(img, dims); +} + + +/** + * Free and clear fields of the gl_texture_image struct. + * + * \param ctx GL context. + * \param texImage texture image structure to be cleared. + * + * After the call, \p texImage will have no data associated with it. Its + * fields are cleared so that its parent object will test incomplete. + */ +void +_mesa_clear_texture_image(struct gl_context *ctx, + struct gl_texture_image *texImage) +{ + ctx->Driver.FreeTexImageData(ctx, texImage); + clear_teximage_fields(texImage); +} + + +/** + * This is the fallback for Driver.TestProxyTexImage(). Test the texture + * level, width, height and depth against the ctx->Const limits for textures. + * + * A hardware driver might override this function if, for example, the + * max 3D texture size is 512x512x64 (i.e. not a cube). + * + * Note that width, height, depth == 0 is not an error. However, a + * texture with zero width/height/depth will be considered "incomplete" + * and texturing will effectively be disabled. + * + * \param target one of GL_PROXY_TEXTURE_1D, GL_PROXY_TEXTURE_2D, + * GL_PROXY_TEXTURE_3D, GL_PROXY_TEXTURE_RECTANGLE_NV, + * GL_PROXY_TEXTURE_CUBE_MAP_ARB. + * \param level as passed to glTexImage + * \param internalFormat as passed to glTexImage + * \param format as passed to glTexImage + * \param type as passed to glTexImage + * \param width as passed to glTexImage + * \param height as passed to glTexImage + * \param depth as passed to glTexImage + * \param border as passed to glTexImage + * \return GL_TRUE if the image is acceptable, GL_FALSE if not acceptable. + */ +GLboolean +_mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level, + GLint internalFormat, GLenum format, GLenum type, + GLint width, GLint height, GLint depth, GLint border) +{ + GLint maxSize; + + (void) internalFormat; + (void) format; + (void) type; + + switch (target) { + case GL_PROXY_TEXTURE_1D: + maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize) + return GL_FALSE; + if (level >= ctx->Const.MaxTextureLevels) + return GL_FALSE; + if (!ctx->Extensions.ARB_texture_non_power_of_two) { + if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) + return GL_FALSE; + } + return GL_TRUE; + + case GL_PROXY_TEXTURE_2D: + maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize) + return GL_FALSE; + if (height < 2 * border || height > 2 + maxSize) + return GL_FALSE; + if (level >= ctx->Const.MaxTextureLevels) + return GL_FALSE; + if (!ctx->Extensions.ARB_texture_non_power_of_two) { + if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) + return GL_FALSE; + if (height > 0 && !_mesa_is_pow_two(height - 2 * border)) + return GL_FALSE; + } + return GL_TRUE; + + case GL_PROXY_TEXTURE_3D: + maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize) + return GL_FALSE; + if (height < 2 * border || height > 2 + maxSize) + return GL_FALSE; + if (depth < 2 * border || depth > 2 + maxSize) + return GL_FALSE; + if (level >= ctx->Const.Max3DTextureLevels) + return GL_FALSE; + if (!ctx->Extensions.ARB_texture_non_power_of_two) { + if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) + return GL_FALSE; + if (height > 0 && !_mesa_is_pow_two(height - 2 * border)) + return GL_FALSE; + if (depth > 0 && !_mesa_is_pow_two(depth - 2 * border)) + return GL_FALSE; + } + return GL_TRUE; + + case GL_PROXY_TEXTURE_RECTANGLE_NV: + maxSize = ctx->Const.MaxTextureRectSize; + if (width < 0 || width > maxSize) + return GL_FALSE; + if (height < 0 || height > maxSize) + return GL_FALSE; + if (level != 0) + return GL_FALSE; + return GL_TRUE; + + case GL_PROXY_TEXTURE_CUBE_MAP_ARB: + maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize) + return GL_FALSE; + if (height < 2 * border || height > 2 + maxSize) + return GL_FALSE; + if (level >= ctx->Const.MaxCubeTextureLevels) + return GL_FALSE; + if (!ctx->Extensions.ARB_texture_non_power_of_two) { + if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) + return GL_FALSE; + if (height > 0 && !_mesa_is_pow_two(height - 2 * border)) + return GL_FALSE; + } + return GL_TRUE; + + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize) + return GL_FALSE; + if (height < 1 || height > ctx->Const.MaxArrayTextureLayers) + return GL_FALSE; + if (level >= ctx->Const.MaxTextureLevels) + return GL_FALSE; + if (!ctx->Extensions.ARB_texture_non_power_of_two) { + if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) + return GL_FALSE; + } + return GL_TRUE; + + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize) + return GL_FALSE; + if (height < 2 * border || height > 2 + maxSize) + return GL_FALSE; + if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers) + return GL_FALSE; + if (level >= ctx->Const.MaxTextureLevels) + return GL_FALSE; + if (!ctx->Extensions.ARB_texture_non_power_of_two) { + if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) + return GL_FALSE; + if (height > 0 && !_mesa_is_pow_two(height - 2 * border)) + return GL_FALSE; + } + return GL_TRUE; + + default: + _mesa_problem(ctx, "Invalid target in _mesa_test_proxy_teximage"); + return GL_FALSE; + } +} + + +/** + * Check if the memory used by the texture would exceed the driver's limit. + * This lets us support a max 3D texture size of 8K (for example) but + * prevents allocating a full 8K x 8K x 8K texture. + * XXX this could be rolled into the proxy texture size test (above) but + * we don't have the actual texture internal format at that point. + */ +static GLboolean +legal_texture_size(struct gl_context *ctx, gl_format format, + GLint width, GLint height, GLint depth) +{ + uint64_t bytes = _mesa_format_image_size64(format, width, height, depth); + uint64_t mbytes = bytes / (1024 * 1024); /* convert to MB */ + return mbytes <= (uint64_t) ctx->Const.MaxTextureMbytes; +} + + + +/** + * Helper function to determine whether a target and specific compression + * format are supported. + */ +static GLboolean +target_can_be_compressed(const struct gl_context *ctx, GLenum target, + GLenum intFormat) +{ + (void) intFormat; /* not used yet */ + + switch (target) { + case GL_TEXTURE_2D: + case GL_PROXY_TEXTURE_2D: + return GL_TRUE; /* true for any compressed format so far */ + case GL_PROXY_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + return ctx->Extensions.ARB_texture_cube_map; + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + case GL_TEXTURE_2D_ARRAY_EXT: + return (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array); + default: + return GL_FALSE; + } +} + + +/** + * Check if the given texture target value is legal for a + * glTexImage1/2/3D call. + */ +static GLboolean +legal_teximage_target(struct gl_context *ctx, GLuint dims, GLenum target) +{ + switch (dims) { + case 1: + switch (target) { + case GL_TEXTURE_1D: + case GL_PROXY_TEXTURE_1D: + return GL_TRUE; + default: + return GL_FALSE; + } + case 2: + switch (target) { + case GL_TEXTURE_2D: + case GL_PROXY_TEXTURE_2D: + return GL_TRUE; + case GL_PROXY_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + return ctx->Extensions.ARB_texture_cube_map; + case GL_TEXTURE_RECTANGLE_NV: + case GL_PROXY_TEXTURE_RECTANGLE_NV: + return ctx->Extensions.NV_texture_rectangle; + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + return (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array); + default: + return GL_FALSE; + } + case 3: + switch (target) { + case GL_TEXTURE_3D: + case GL_PROXY_TEXTURE_3D: + return GL_TRUE; + case GL_TEXTURE_2D_ARRAY_EXT: + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + return (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array); + default: + return GL_FALSE; + } + default: + _mesa_problem(ctx, "invalid dims=%u in legal_teximage_target()", dims); + return GL_FALSE; + } +} + + +/** + * Check if the given texture target value is legal for a + * glTexSubImage, glCopyTexSubImage or glCopyTexImage call. + * The difference compared to legal_teximage_target() above is that + * proxy targets are not supported. + */ +static GLboolean +legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target) +{ + switch (dims) { + case 1: + return target == GL_TEXTURE_1D; + case 2: + switch (target) { + case GL_TEXTURE_2D: + return GL_TRUE; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + return ctx->Extensions.ARB_texture_cube_map; + case GL_TEXTURE_RECTANGLE_NV: + return ctx->Extensions.NV_texture_rectangle; + case GL_TEXTURE_1D_ARRAY_EXT: + return (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array); + default: + return GL_FALSE; + } + case 3: + switch (target) { + case GL_TEXTURE_3D: + return GL_TRUE; + case GL_TEXTURE_2D_ARRAY_EXT: + return (ctx->Extensions.MESA_texture_array || + ctx->Extensions.EXT_texture_array); + default: + return GL_FALSE; + } + default: + _mesa_problem(ctx, "invalid dims=%u in legal_texsubimage_target()", + dims); + return GL_FALSE; + } +} + + +/** + * Test the glTexImage[123]D() parameters for errors. + * + * \param ctx GL context. + * \param dimensions texture image dimensions (must be 1, 2 or 3). + * \param target texture target given by the user. + * \param level image level given by the user. + * \param internalFormat internal format given by the user. + * \param format pixel data format given by the user. + * \param type pixel data type given by the user. + * \param width image width given by the user. + * \param height image height given by the user. + * \param depth image depth given by the user. + * \param border image border given by the user. + * + * \return GL_TRUE if an error was detected, or GL_FALSE if no errors. + * + * Verifies each of the parameters against the constants specified in + * __struct gl_contextRec::Const and the supported extensions, and according + * to the OpenGL specification. + */ +static GLboolean +texture_error_check( struct gl_context *ctx, + GLuint dimensions, GLenum target, + GLint level, GLint internalFormat, + GLenum format, GLenum type, + GLint width, GLint height, + GLint depth, GLint border ) +{ + const GLenum proxyTarget = get_proxy_target(target); + const GLboolean isProxy = target == proxyTarget; + GLboolean sizeOK = GL_TRUE; + GLboolean colorFormat, indexFormat; + + /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */ + if (level < 0 || level >= MAX_TEXTURE_LEVELS) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexImage%dD(level=%d)", dimensions, level); + } + return GL_TRUE; + } + + /* Check border */ + if (border < 0 || border > 1 || + ((target == GL_TEXTURE_RECTANGLE_NV || + target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexImage%dD(border=%d)", dimensions, border); + } + return GL_TRUE; + } + + if (width < 0 || height < 0 || depth < 0) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexImage%dD(width, height or depth < 0)", dimensions); + } + return GL_TRUE; + } + + /* Do this simple check before calling the TestProxyTexImage() function */ + if (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB) { + sizeOK = (width == height); + } + + /* + * Use the proxy texture driver hook to see if the size/level/etc are + * legal. + */ + sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level, + internalFormat, format, + type, width, height, + depth, border); + if (!sizeOK) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexImage%dD(level=%d, width=%d, height=%d, depth=%d)", + dimensions, level, width, height, depth); + } + return GL_TRUE; + } + + /* Check internalFormat */ + if (_mesa_base_tex_format(ctx, internalFormat) < 0) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexImage%dD(internalFormat=%s)", + dimensions, _mesa_lookup_enum_by_nr(internalFormat)); + } + return GL_TRUE; + } + + /* Check incoming image format and type */ + if (!_mesa_is_legal_format_and_type(ctx, format, type)) { + /* Normally, GL_INVALID_OPERATION is generated by a format/type + * mismatch (see the 1.2 spec page 94, sec 3.6.4.). But with the + * GL_EXT_texture_integer extension, some combinations should generate + * GL_INVALID_ENUM instead (grr!). + */ + if (!isProxy) { + GLenum error = _mesa_is_integer_format(format) + ? GL_INVALID_ENUM : GL_INVALID_OPERATION; + _mesa_error(ctx, error, + "glTexImage%dD(incompatible format 0x%x, type 0x%x)", + dimensions, format, type); + } + return GL_TRUE; + } + + /* make sure internal format and format basically agree */ + colorFormat = _mesa_is_color_format(format); + indexFormat = _mesa_is_index_format(format); + if ((_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat) || + (_mesa_is_index_format(internalFormat) && !indexFormat) || + (_mesa_is_depth_format(internalFormat) != _mesa_is_depth_format(format)) || + (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format)) || + (_mesa_is_depthstencil_format(internalFormat) != _mesa_is_depthstencil_format(format)) || + (_mesa_is_dudv_format(internalFormat) != _mesa_is_dudv_format(format))) { + if (!isProxy) + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexImage%dD(incompatible internalFormat 0x%x, format 0x%x)", + dimensions, internalFormat, format); + return GL_TRUE; + } + + /* additional checks for ycbcr textures */ + if (internalFormat == GL_YCBCR_MESA) { + ASSERT(ctx->Extensions.MESA_ycbcr_texture); + if (type != GL_UNSIGNED_SHORT_8_8_MESA && + type != GL_UNSIGNED_SHORT_8_8_REV_MESA) { + char message[100]; + _mesa_snprintf(message, sizeof(message), + "glTexImage%dD(format/type YCBCR mismatch", dimensions); + _mesa_error(ctx, GL_INVALID_ENUM, "%s", message); + return GL_TRUE; /* error */ + } + if (target != GL_TEXTURE_2D && + target != GL_PROXY_TEXTURE_2D && + target != GL_TEXTURE_RECTANGLE_NV && + target != GL_PROXY_TEXTURE_RECTANGLE_NV) { + if (!isProxy) + _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage(target)"); + return GL_TRUE; + } + if (border != 0) { + if (!isProxy) { + char message[100]; + _mesa_snprintf(message, sizeof(message), + "glTexImage%dD(format=GL_YCBCR_MESA and border=%d)", + dimensions, border); + _mesa_error(ctx, GL_INVALID_VALUE, "%s", message); + } + return GL_TRUE; + } + } + + /* additional checks for depth textures */ + if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT) { + /* Only 1D, 2D and rectangular textures supported, not 3D or cubes */ + if (target != GL_TEXTURE_1D && + target != GL_PROXY_TEXTURE_1D && + target != GL_TEXTURE_2D && + target != GL_PROXY_TEXTURE_2D && + target != GL_TEXTURE_RECTANGLE_ARB && + target != GL_PROXY_TEXTURE_RECTANGLE_ARB) { + if (!isProxy) + _mesa_error(ctx, GL_INVALID_ENUM, + "glTexImage(target/internalFormat)"); + return GL_TRUE; + } + } + + /* additional checks for compressed textures */ + if (_mesa_is_compressed_format(ctx, internalFormat)) { + if (!target_can_be_compressed(ctx, target, internalFormat)) { + if (!isProxy) + _mesa_error(ctx, GL_INVALID_ENUM, + "glTexImage%dD(target)", dimensions); + return GL_TRUE; + } + if (border != 0) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexImage%dD(border!=0)", dimensions); + } + return GL_TRUE; + } + } + + /* additional checks for integer textures */ + if (ctx->Extensions.EXT_texture_integer && + (_mesa_is_integer_format(format) != + _mesa_is_integer_format(internalFormat))) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexImage%dD(integer/non-integer format mismatch)", + dimensions); + } + return GL_TRUE; + } + + /* if we get here, the parameters are OK */ + return GL_FALSE; +} + + +/** + * Test glTexSubImage[123]D() parameters for errors. + * + * \param ctx GL context. + * \param dimensions texture image dimensions (must be 1, 2 or 3). + * \param target texture target given by the user. + * \param level image level given by the user. + * \param xoffset sub-image x offset given by the user. + * \param yoffset sub-image y offset given by the user. + * \param zoffset sub-image z offset given by the user. + * \param format pixel data format given by the user. + * \param type pixel data type given by the user. + * \param width image width given by the user. + * \param height image height given by the user. + * \param depth image depth given by the user. + * + * \return GL_TRUE if an error was detected, or GL_FALSE if no errors. + * + * Verifies each of the parameters against the constants specified in + * __struct gl_contextRec::Const and the supported extensions, and according + * to the OpenGL specification. + */ +static GLboolean +subtexture_error_check( struct gl_context *ctx, GLuint dimensions, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint width, GLint height, GLint depth, + GLenum format, GLenum type ) +{ + /* Basic level check */ + if (level < 0 || level >= MAX_TEXTURE_LEVELS) { + _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage2D(level=%d)", level); + return GL_TRUE; + } + + /* Check for negative sizes */ + if (width < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexSubImage%dD(width=%d)", dimensions, width); + return GL_TRUE; + } + if (height < 0 && dimensions > 1) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexSubImage%dD(height=%d)", dimensions, height); + return GL_TRUE; + } + if (depth < 0 && dimensions > 2) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glTexSubImage%dD(depth=%d)", dimensions, depth); + return GL_TRUE; + } + + if (!_mesa_is_legal_format_and_type(ctx, format, type)) { + /* As with the glTexImage2D check above, the error code here + * depends on texture integer. + */ + GLenum error = _mesa_is_integer_format(format) + ? GL_INVALID_OPERATION : GL_INVALID_ENUM; + _mesa_error(ctx, error, + "glTexSubImage%dD(incompatible format 0x%x, type 0x%x)", + dimensions, format, type); + return GL_TRUE; + } + + return GL_FALSE; +} + + +/** + * Do second part of glTexSubImage which depends on the destination texture. + * \return GL_TRUE if error recorded, GL_FALSE otherwise + */ +static GLboolean +subtexture_error_check2( struct gl_context *ctx, GLuint dimensions, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint width, GLint height, GLint depth, + GLenum format, GLenum type, + const struct gl_texture_image *destTex ) +{ + if (!destTex) { + /* undefined image level */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%dD", dimensions); + return GL_TRUE; + } + + if (xoffset < -((GLint)destTex->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset)", + dimensions); + return GL_TRUE; + } + if (xoffset + width > (GLint) (destTex->Width + destTex->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset+width)", + dimensions); + return GL_TRUE; + } + if (dimensions > 1) { + if (yoffset < -((GLint)destTex->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset)", + dimensions); + return GL_TRUE; + } + if (yoffset + height > (GLint) (destTex->Height + destTex->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset+height)", + dimensions); + return GL_TRUE; + } + } + if (dimensions > 2) { + if (zoffset < -((GLint)destTex->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset)"); + return GL_TRUE; + } + if (zoffset + depth > (GLint) (destTex->Depth + destTex->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset+depth)"); + return GL_TRUE; + } + } + + if (_mesa_is_format_compressed(destTex->TexFormat)) { + GLuint bw, bh; + + /* do tests which depend on compression block size */ + _mesa_get_format_block_size(destTex->TexFormat, &bw, &bh); + + /* offset must be multiple of block size */ + if ((xoffset % bw != 0) || (yoffset % bh != 0)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexSubImage%dD(xoffset = %d, yoffset = %d)", + dimensions, xoffset, yoffset); + return GL_TRUE; + } + /* size must be multiple of bw by bh or equal to whole texture size */ + if ((width % bw != 0) && (GLuint) width != destTex->Width) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexSubImage%dD(width = %d)", dimensions, width); + return GL_TRUE; + } + if ((height % bh != 0) && (GLuint) height != destTex->Height) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexSubImage%dD(height = %d)", dimensions, height); + return GL_TRUE; + } + } + + return GL_FALSE; +} + + +/** + * Test glCopyTexImage[12]D() parameters for errors. + * + * \param ctx GL context. + * \param dimensions texture image dimensions (must be 1, 2 or 3). + * \param target texture target given by the user. + * \param level image level given by the user. + * \param internalFormat internal format given by the user. + * \param width image width given by the user. + * \param height image height given by the user. + * \param border texture border. + * + * \return GL_TRUE if an error was detected, or GL_FALSE if no errors. + * + * Verifies each of the parameters against the constants specified in + * __struct gl_contextRec::Const and the supported extensions, and according + * to the OpenGL specification. + */ +static GLboolean +copytexture_error_check( struct gl_context *ctx, GLuint dimensions, + GLenum target, GLint level, GLint internalFormat, + GLint width, GLint height, GLint border ) +{ + const GLenum proxyTarget = get_proxy_target(target); + const GLenum type = GL_FLOAT; + GLboolean sizeOK; + GLint format; + + /* check target */ + if (!legal_texsubimage_target(ctx, dimensions, target)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage%uD(target=%s)", + dimensions, _mesa_lookup_enum_by_nr(target)); + return GL_TRUE; + } + + /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */ + if (level < 0 || level >= MAX_TEXTURE_LEVELS) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexImage%dD(level=%d)", dimensions, level); + return GL_TRUE; + } + + /* Check that the source buffer is complete */ + if (ctx->ReadBuffer->Name) { + if (ctx->ReadBuffer->_Status == 0) { + _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer); + } + if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "glCopyTexImage%dD(invalid readbuffer)", dimensions); + return GL_TRUE; + } + } + + /* Check border */ + if (border < 0 || border > 1 || + ((target == GL_TEXTURE_RECTANGLE_NV || + target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) { + return GL_TRUE; + } + + format = _mesa_base_tex_format(ctx, internalFormat); + if (format < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexImage%dD(internalFormat)", dimensions); + return GL_TRUE; + } + + if (!_mesa_source_buffer_exists(ctx, format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%dD(missing readbuffer)", dimensions); + return GL_TRUE; + } + + /* Do size, level checking */ + sizeOK = (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB) + ? (width == height) : 1; + + sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level, + internalFormat, format, + type, width, height, + 1, border); + + if (!sizeOK) { + if (dimensions == 1) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexImage1D(width=%d)", width); + } + else { + ASSERT(dimensions == 2); + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexImage2D(width=%d, height=%d)", width, height); + } + return GL_TRUE; + } + + if (_mesa_is_compressed_format(ctx, internalFormat)) { + if (!target_can_be_compressed(ctx, target, internalFormat)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glCopyTexImage%dD(target)", dimensions); + return GL_TRUE; + } + if (border != 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%dD(border!=0)", dimensions); + return GL_TRUE; + } + } + else if (_mesa_is_depth_format(internalFormat)) { + /* make sure we have depth/stencil buffers */ + if (!ctx->ReadBuffer->_DepthBuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%dD(no depth)", dimensions); + return GL_TRUE; + } + } + else if (_mesa_is_depthstencil_format(internalFormat)) { + /* make sure we have depth/stencil buffers */ + if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%dD(no depth/stencil buffer)", dimensions); + return GL_TRUE; + } + } + + /* if we get here, the parameters are OK */ + return GL_FALSE; +} + + +/** + * Test glCopyTexSubImage[12]D() parameters for errors. + * Note that this is the first part of error checking. + * See also copytexsubimage_error_check2() below for the second part. + * + * \param ctx GL context. + * \param dimensions texture image dimensions (must be 1, 2 or 3). + * \param target texture target given by the user. + * \param level image level given by the user. + * + * \return GL_TRUE if an error was detected, or GL_FALSE if no errors. + */ +static GLboolean +copytexsubimage_error_check1( struct gl_context *ctx, GLuint dimensions, + GLenum target, GLint level) +{ + /* Check that the source buffer is complete */ + if (ctx->ReadBuffer->Name) { + if (ctx->ReadBuffer->_Status == 0) { + _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer); + } + if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "glCopyTexImage%dD(invalid readbuffer)", dimensions); + return GL_TRUE; + } + } + + /* check target (proxies not allowed) */ + if (!legal_texsubimage_target(ctx, dimensions, target)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexSubImage%uD(target=%s)", + dimensions, _mesa_lookup_enum_by_nr(target)); + return GL_TRUE; + } + + /* Check level */ + if (level < 0 || level >= MAX_TEXTURE_LEVELS) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(level=%d)", dimensions, level); + return GL_TRUE; + } + + return GL_FALSE; +} + + +/** + * Second part of error checking for glCopyTexSubImage[12]D(). + * \param xoffset sub-image x offset given by the user. + * \param yoffset sub-image y offset given by the user. + * \param zoffset sub-image z offset given by the user. + * \param width image width given by the user. + * \param height image height given by the user. + */ +static GLboolean +copytexsubimage_error_check2( struct gl_context *ctx, GLuint dimensions, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, + const struct gl_texture_image *teximage ) +{ + /* check that dest tex image exists */ + if (!teximage) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexSubImage%dD(undefined texture level: %d)", + dimensions, level); + return GL_TRUE; + } + + /* Check size */ + if (width < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(width=%d)", dimensions, width); + return GL_TRUE; + } + if (dimensions > 1 && height < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(height=%d)", dimensions, height); + return GL_TRUE; + } + + /* check x/y offsets */ + if (xoffset < -((GLint)teximage->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(xoffset=%d)", dimensions, xoffset); + return GL_TRUE; + } + if (xoffset + width > (GLint) (teximage->Width + teximage->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(xoffset+width)", dimensions); + return GL_TRUE; + } + if (dimensions > 1) { + if (yoffset < -((GLint)teximage->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(yoffset=%d)", dimensions, yoffset); + return GL_TRUE; + } + /* NOTE: we're adding the border here, not subtracting! */ + if (yoffset + height > (GLint) (teximage->Height + teximage->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(yoffset+height)", dimensions); + return GL_TRUE; + } + } + + /* check z offset */ + if (dimensions > 2) { + if (zoffset < -((GLint)teximage->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(zoffset)", dimensions); + return GL_TRUE; + } + if (zoffset > (GLint) (teximage->Depth + teximage->Border)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(zoffset+depth)", dimensions); + return GL_TRUE; + } + } + + if (_mesa_is_format_compressed(teximage->TexFormat)) { + /* offset must be multiple of 4 */ + if ((xoffset & 3) || (yoffset & 3)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(xoffset or yoffset)", dimensions); + return GL_TRUE; + } + /* size must be multiple of 4 */ + if ((width & 3) != 0 && (GLuint) width != teximage->Width) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(width)", dimensions); + return GL_TRUE; + } + if ((height & 3) != 0 && (GLuint) height != teximage->Height) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%dD(height)", dimensions); + return GL_TRUE; + } + } + + if (teximage->InternalFormat == GL_YCBCR_MESA) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyTexSubImage2D"); + return GL_TRUE; + } + + if (!_mesa_source_buffer_exists(ctx, teximage->_BaseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexSubImage%dD(missing readbuffer, format=0x%x)", + dimensions, teximage->_BaseFormat); + return GL_TRUE; + } + + if (teximage->_BaseFormat == GL_DEPTH_COMPONENT) { + if (!ctx->ReadBuffer->_DepthBuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexSubImage%dD(no depth buffer)", + dimensions); + return GL_TRUE; + } + } + else if (teximage->_BaseFormat == GL_DEPTH_STENCIL_EXT) { + if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexSubImage%dD(no depth/stencil buffer)", + dimensions); + return GL_TRUE; + } + } + + /* If copying into an integer texture, the source buffer must also be + * integer-valued. + */ + if (_mesa_is_format_integer_color(teximage->TexFormat)) { + struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; + if (!_mesa_is_format_integer_color(rb->Format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexSubImage%dD(source buffer is not integer format)", + dimensions); + return GL_TRUE; + } + } + + /* if we get here, the parameters are OK */ + return GL_FALSE; +} + + +/** Callback info for walking over FBO hash table */ +struct cb_info +{ + struct gl_context *ctx; + struct gl_texture_object *texObj; + GLuint level, face; +}; + + +/** + * Check render to texture callback. Called from _mesa_HashWalk(). + */ +static void +check_rtt_cb(GLuint key, void *data, void *userData) +{ + struct gl_framebuffer *fb = (struct gl_framebuffer *) data; + const struct cb_info *info = (struct cb_info *) userData; + struct gl_context *ctx = info->ctx; + const struct gl_texture_object *texObj = info->texObj; + const GLuint level = info->level, face = info->face; + + /* If this is a user-created FBO */ + if (fb->Name) { + GLuint i; + /* check if any of the FBO's attachments point to 'texObj' */ + for (i = 0; i < BUFFER_COUNT; i++) { + struct gl_renderbuffer_attachment *att = fb->Attachment + i; + if (att->Type == GL_TEXTURE && + att->Texture == texObj && + att->TextureLevel == level && + att->CubeMapFace == face) { + ASSERT(att->Texture->Image[att->CubeMapFace][att->TextureLevel]); + /* Tell driver about the new renderbuffer texture */ + ctx->Driver.RenderTexture(ctx, ctx->DrawBuffer, att); + /* Mark fb status as indeterminate to force re-validation */ + fb->_Status = 0; + } + } + } +} + + +/** + * When a texture image is specified we have to check if it's bound to + * any framebuffer objects (render to texture) in order to detect changes + * in size or format since that effects FBO completeness. + * Any FBOs rendering into the texture must be re-validated. + */ +static void +update_fbo_texture(struct gl_context *ctx, struct gl_texture_object *texObj, + GLuint face, GLuint level) +{ + /* Only check this texture if it's been marked as RenderToTexture */ + if (texObj->_RenderToTexture) { + struct cb_info info; + info.ctx = ctx; + info.texObj = texObj; + info.level = level; + info.face = face; + _mesa_HashWalk(ctx->Shared->FrameBuffers, check_rtt_cb, &info); + } +} + + +/** + * If the texture object's GenerateMipmap flag is set and we've + * changed the texture base level image, regenerate the rest of the + * mipmap levels now. + */ +static INLINE void +check_gen_mipmap(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj, GLint level) +{ + ASSERT(target != GL_TEXTURE_CUBE_MAP); + if (texObj->GenerateMipmap && + level == texObj->BaseLevel && + level < texObj->MaxLevel) { + ASSERT(ctx->Driver.GenerateMipmap); + ctx->Driver.GenerateMipmap(ctx, target, texObj); + } +} + + +/** Debug helper: override the user-requested internal format */ +static GLenum +override_internal_format(GLenum internalFormat, GLint width, GLint height) +{ +#if 0 + if (internalFormat == GL_RGBA16F_ARB || + internalFormat == GL_RGBA32F_ARB) { + printf("Convert rgba float tex to int %d x %d\n", width, height); + return GL_RGBA; + } + else if (internalFormat == GL_RGB16F_ARB || + internalFormat == GL_RGB32F_ARB) { + printf("Convert rgb float tex to int %d x %d\n", width, height); + return GL_RGB; + } + else if (internalFormat == GL_LUMINANCE_ALPHA16F_ARB || + internalFormat == GL_LUMINANCE_ALPHA32F_ARB) { + printf("Convert luminance float tex to int %d x %d\n", width, height); + return GL_LUMINANCE_ALPHA; + } + else if (internalFormat == GL_LUMINANCE16F_ARB || + internalFormat == GL_LUMINANCE32F_ARB) { + printf("Convert luminance float tex to int %d x %d\n", width, height); + return GL_LUMINANCE; + } + else if (internalFormat == GL_ALPHA16F_ARB || + internalFormat == GL_ALPHA32F_ARB) { + printf("Convert luminance float tex to int %d x %d\n", width, height); + return GL_ALPHA; + } + /* + else if (internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) { + internalFormat = GL_RGBA; + } + */ + else { + return internalFormat; + } +#else + return internalFormat; +#endif +} + + +/** + * Choose the actual hardware format for a texture image. + * Try to use the same format as the previous image level when possible. + * Otherwise, ask the driver for the best format. + * It's important to try to choose a consistant format for all levels + * for efficient texture memory layout/allocation. In particular, this + * comes up during automatic mipmap generation. + */ +gl_format +_mesa_choose_texture_format(struct gl_context *ctx, + struct gl_texture_object *texObj, + GLenum target, GLint level, + GLenum internalFormat, GLenum format, GLenum type) +{ + gl_format f; + + /* see if we've already chosen a format for the previous level */ + if (level > 0) { + struct gl_texture_image *prevImage = + _mesa_select_tex_image(ctx, texObj, target, level - 1); + /* See if the prev level is defined and has an internal format which + * matches the new internal format. + */ + if (prevImage && + prevImage->Width > 0 && + prevImage->InternalFormat == internalFormat) { + /* use the same format */ + ASSERT(prevImage->TexFormat != MESA_FORMAT_NONE); + return prevImage->TexFormat; + } + } + + /* choose format from scratch */ + f = ctx->Driver.ChooseTextureFormat(ctx, internalFormat, format, type); + ASSERT(f != MESA_FORMAT_NONE); + return f; +} + + +/** + * Common code to implement all the glTexImage1D/2D/3D functions. + */ +static void +teximage(struct gl_context *ctx, GLuint dims, + GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, + const GLvoid *pixels) +{ + GLboolean error; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glTexImage%uD %s %d %s %d %d %d %d %s %s %p\n", + dims, + _mesa_lookup_enum_by_nr(target), level, + _mesa_lookup_enum_by_nr(internalFormat), + width, height, depth, border, + _mesa_lookup_enum_by_nr(format), + _mesa_lookup_enum_by_nr(type), pixels); + + internalFormat = override_internal_format(internalFormat, width, height); + + /* target error checking */ + if (!legal_teximage_target(ctx, dims, target)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage%uD(target=%s)", + dims, _mesa_lookup_enum_by_nr(target)); + return; + } + + /* general error checking */ + error = texture_error_check(ctx, dims, target, level, internalFormat, + format, type, width, height, depth, border); + + if (_mesa_is_proxy_texture(target)) { + /* Proxy texture: just clear or set state depending on error checking */ + struct gl_texture_image *texImage = + _mesa_get_proxy_tex_image(ctx, target, level); + + if (error) { + /* when error, clear all proxy texture image parameters */ + if (texImage) + clear_teximage_fields(texImage); + } + else { + /* no error, set the tex image parameters */ + struct gl_texture_object *texObj = + _mesa_get_current_tex_object(ctx, target); + gl_format texFormat = _mesa_choose_texture_format(ctx, texObj, + target, level, + internalFormat, + format, type); + + if (legal_texture_size(ctx, texFormat, width, height, depth)) { + _mesa_init_teximage_fields(ctx, target, texImage, width, height, + depth, border, internalFormat, + texFormat); + } + else if (texImage) { + clear_teximage_fields(texImage); + } + } + } + else { + /* non-proxy target */ + const GLuint face = _mesa_tex_target_to_face(target); + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + + if (error) { + return; /* error was recorded */ + } + + if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) + _mesa_update_state(ctx); + + texObj = _mesa_get_current_tex_object(ctx, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims); + } + else { + gl_format texFormat; + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + + ASSERT(texImage->Data == NULL); + texFormat = _mesa_choose_texture_format(ctx, texObj, target, level, + internalFormat, format, + type); + + if (legal_texture_size(ctx, texFormat, width, height, depth)) { + _mesa_init_teximage_fields(ctx, target, texImage, + width, height, depth, + border, internalFormat, texFormat); + + /* Give the texture to the driver. <pixels> may be null. */ + ASSERT(ctx->Driver.TexImage3D); + switch (dims) { + case 1: + ctx->Driver.TexImage1D(ctx, target, level, internalFormat, + width, border, format, + type, pixels, &ctx->Unpack, texObj, + texImage); + break; + case 2: + ctx->Driver.TexImage2D(ctx, target, level, internalFormat, + width, height, border, format, + type, pixels, &ctx->Unpack, texObj, + texImage); + break; + case 3: + ctx->Driver.TexImage3D(ctx, target, level, internalFormat, + width, height, depth, border, format, + type, pixels, &ctx->Unpack, texObj, + texImage); + break; + default: + _mesa_problem(ctx, "invalid dims=%u in teximage()", dims); + } + + check_gen_mipmap(ctx, target, texObj, level); + + update_fbo_texture(ctx, texObj, face, level); + + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims); + } + } + } + _mesa_unlock_texture(ctx, texObj); + } +} + + +/* + * Called from the API. Note that width includes the border. + */ +void GLAPIENTRY +_mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLint border, GLenum format, + GLenum type, const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + teximage(ctx, 1, target, level, internalFormat, width, 1, 1, + border, format, type, pixels); +} + + +void GLAPIENTRY +_mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, + const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + teximage(ctx, 2, target, level, internalFormat, width, height, 1, + border, format, type, pixels); +} + + +/* + * Called by the API or display list executor. + * Note that width and height include the border. + */ +void GLAPIENTRY +_mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, + const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + teximage(ctx, 3, target, level, internalFormat, width, height, depth, + border, format, type, pixels); +} + + +void GLAPIENTRY +_mesa_TexImage3DEXT( GLenum target, GLint level, GLenum internalFormat, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, + const GLvoid *pixels ) +{ + _mesa_TexImage3D(target, level, (GLint) internalFormat, width, height, + depth, border, format, type, pixels); +} + + +#if FEATURE_OES_EGL_image +void GLAPIENTRY +_mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (!ctx->Extensions.OES_EGL_image) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glEGLImageTargetTexture2DOES(unsupported)"); + return; + } + + if (target != GL_TEXTURE_2D) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glEGLImageTargetTexture2D(target=%d)", target); + return; + } + + if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) + _mesa_update_state(ctx); + + texObj = _mesa_get_current_tex_object(ctx, target); + _mesa_lock_texture(ctx, texObj); + + texImage = _mesa_get_tex_image(ctx, texObj, target, 0); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glEGLImageTargetTexture2D"); + } else { + if (texImage->Data) + ctx->Driver.FreeTexImageData( ctx, texImage ); + + ASSERT(texImage->Data == NULL); + ctx->Driver.EGLImageTargetTexture2D(ctx, target, + texObj, texImage, image); + + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + _mesa_unlock_texture(ctx, texObj); + +} +#endif + + + +/** + * Implement all the glTexSubImage1/2/3D() functions. + */ +static void +texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *pixels ) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glTexSubImage%uD %s %d %d %d %d %d %d %d %s %s %p\n", + dims, + _mesa_lookup_enum_by_nr(target), level, + xoffset, yoffset, zoffset, width, height, depth, + _mesa_lookup_enum_by_nr(format), + _mesa_lookup_enum_by_nr(type), pixels); + + /* check target (proxies not allowed) */ + if (!legal_texsubimage_target(ctx, dims, target)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%uD(target=%s)", + dims, _mesa_lookup_enum_by_nr(target)); + return; + } + + if (ctx->NewState & _MESA_NEW_TRANSFER_STATE) + _mesa_update_state(ctx); + + if (subtexture_error_check(ctx, dims, target, level, xoffset, yoffset, zoffset, + width, height, depth, format, type)) { + return; /* error was detected */ + } + + texObj = _mesa_get_current_tex_object(ctx, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (subtexture_error_check2(ctx, dims, target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, type, texImage)) { + /* error was recorded */ + } + else if (width > 0 && height > 0 && height > 0) { + /* If we have a border, offset=-1 is legal. Bias by border width. */ + switch (dims) { + case 3: + zoffset += texImage->Border; + /* fall-through */ + case 2: + yoffset += texImage->Border; + /* fall-through */ + case 1: + xoffset += texImage->Border; + } + + switch (dims) { + case 1: + ctx->Driver.TexSubImage1D(ctx, target, level, + xoffset, width, + format, type, pixels, + &ctx->Unpack, texObj, texImage ); + break; + case 2: + ctx->Driver.TexSubImage2D(ctx, target, level, + xoffset, yoffset, width, height, + format, type, pixels, + &ctx->Unpack, texObj, texImage ); + break; + case 3: + ctx->Driver.TexSubImage3D(ctx, target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, type, pixels, + &ctx->Unpack, texObj, texImage ); + break; + default: + _mesa_problem(ctx, "unexpected dims in subteximage()"); + } + + check_gen_mipmap(ctx, target, texObj, level); + + ctx->NewState |= _NEW_TEXTURE; + } + } + _mesa_unlock_texture(ctx, texObj); +} + + +void GLAPIENTRY +_mesa_TexSubImage1D( GLenum target, GLint level, + GLint xoffset, GLsizei width, + GLenum format, GLenum type, + const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + texsubimage(ctx, 1, target, level, + xoffset, 0, 0, + width, 1, 1, + format, type, pixels); +} + + +void GLAPIENTRY +_mesa_TexSubImage2D( GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + texsubimage(ctx, 2, target, level, + xoffset, yoffset, 0, + width, height, 1, + format, type, pixels); +} + + + +void GLAPIENTRY +_mesa_TexSubImage3D( GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + const GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + texsubimage(ctx, 3, target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, type, pixels); +} + + + +/** + * Implement the glCopyTexImage1/2D() functions. + */ +static void +copyteximage(struct gl_context *ctx, GLuint dims, + GLenum target, GLint level, GLenum internalFormat, + GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + const GLuint face = _mesa_tex_target_to_face(target); + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glCopyTexImage%uD %s %d %s %d %d %d %d %d\n", + dims, + _mesa_lookup_enum_by_nr(target), level, + _mesa_lookup_enum_by_nr(internalFormat), + x, y, width, height, border); + + if (ctx->NewState & NEW_COPY_TEX_STATE) + _mesa_update_state(ctx); + + if (copytexture_error_check(ctx, dims, target, level, internalFormat, + width, height, border)) + return; + + texObj = _mesa_get_current_tex_object(ctx, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims); + } + else { + gl_format texFormat; + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + + ASSERT(texImage->Data == NULL); + + texFormat = _mesa_choose_texture_format(ctx, texObj, target, level, + internalFormat, GL_NONE, + GL_NONE); + + if (legal_texture_size(ctx, texFormat, width, height, 1)) { + _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, + border, internalFormat, texFormat); + + ASSERT(ctx->Driver.CopyTexImage2D); + if (dims == 1) + ctx->Driver.CopyTexImage1D(ctx, target, level, internalFormat, + x, y, width, border); + else + ctx->Driver.CopyTexImage2D(ctx, target, level, internalFormat, + x, y, width, height, border); + + check_gen_mipmap(ctx, target, texObj, level); + + update_fbo_texture(ctx, texObj, face, level); + + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims); + } + } + } + _mesa_unlock_texture(ctx, texObj); +} + + + +void GLAPIENTRY +_mesa_CopyTexImage1D( GLenum target, GLint level, + GLenum internalFormat, + GLint x, GLint y, + GLsizei width, GLint border ) +{ + GET_CURRENT_CONTEXT(ctx); + copyteximage(ctx, 1, target, level, internalFormat, x, y, width, 1, border); +} + + + +void GLAPIENTRY +_mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint border ) +{ + GET_CURRENT_CONTEXT(ctx); + copyteximage(ctx, 2, target, level, internalFormat, + x, y, width, height, border); +} + + + +/** + * Implementation for glCopyTexSubImage1/2/3D() functions. + */ +static void +copytexsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glCopyTexSubImage%uD %s %d %d %d %d %d %d %d %d\n", + dims, + _mesa_lookup_enum_by_nr(target), + level, xoffset, yoffset, zoffset, x, y, width, height); + + if (ctx->NewState & NEW_COPY_TEX_STATE) + _mesa_update_state(ctx); + + if (copytexsubimage_error_check1(ctx, dims, target, level)) + return; + + texObj = _mesa_get_current_tex_object(ctx, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (copytexsubimage_error_check2(ctx, dims, target, level, xoffset, yoffset, + zoffset, width, height, texImage)) { + /* error was recored */ + } + else { + /* If we have a border, offset=-1 is legal. Bias by border width. */ + switch (dims) { + case 3: + zoffset += texImage->Border; + /* fall-through */ + case 2: + yoffset += texImage->Border; + /* fall-through */ + case 1: + xoffset += texImage->Border; + } + + if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y, + &width, &height)) { + switch (dims) { + case 1: + ctx->Driver.CopyTexSubImage1D(ctx, target, level, + xoffset, x, y, width); + break; + case 2: + ctx->Driver.CopyTexSubImage2D(ctx, target, level, + xoffset, yoffset, + x, y, width, height); + break; + case 3: + ctx->Driver.CopyTexSubImage3D(ctx, target, level, + xoffset, yoffset, zoffset, + x, y, width, height); + break; + default: + _mesa_problem(ctx, "bad dims in copytexsubimage()"); + } + + check_gen_mipmap(ctx, target, texObj, level); + + ctx->NewState |= _NEW_TEXTURE; + } + } + } + _mesa_unlock_texture(ctx, texObj); +} + + +void GLAPIENTRY +_mesa_CopyTexSubImage1D( GLenum target, GLint level, + GLint xoffset, GLint x, GLint y, GLsizei width ) +{ + GET_CURRENT_CONTEXT(ctx); + copytexsubimage(ctx, 1, target, level, xoffset, 0, 0, x, y, width, 1); +} + + + +void GLAPIENTRY +_mesa_CopyTexSubImage2D( GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLint x, GLint y, GLsizei width, GLsizei height ) +{ + GET_CURRENT_CONTEXT(ctx); + copytexsubimage(ctx, 2, target, level, xoffset, yoffset, 0, x, y, + width, height); +} + + + +void GLAPIENTRY +_mesa_CopyTexSubImage3D( GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height ) +{ + GET_CURRENT_CONTEXT(ctx); + copytexsubimage(ctx, 3, target, level, xoffset, yoffset, zoffset, + x, y, width, height); +} + + + + +/**********************************************************************/ +/****** Compressed Textures ******/ +/**********************************************************************/ + + +/** + * Return expected size of a compressed texture. + */ +static GLuint +compressed_tex_size(GLsizei width, GLsizei height, GLsizei depth, + GLenum glformat) +{ + gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat); + return _mesa_format_image_size(mesaFormat, width, height, depth); +} + + +/* + * Return compressed texture block size, in pixels. + */ +static void +get_compressed_block_size(GLenum glformat, GLuint *bw, GLuint *bh) +{ + gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat); + _mesa_get_format_block_size(mesaFormat, bw, bh); +} + + +/** + * Error checking for glCompressedTexImage[123]D(). + * \return error code or GL_NO_ERROR. + */ +static GLenum +compressed_texture_error_check(struct gl_context *ctx, GLint dimensions, + GLenum target, GLint level, + GLenum internalFormat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, + GLsizei imageSize) +{ + const GLenum proxyTarget = get_proxy_target(target); + const GLint maxLevels = _mesa_max_texture_levels(ctx, target); + GLint expectedSize; + + /* check level */ + if (level < 0 || level >= maxLevels) + return GL_INVALID_VALUE; + + if (!target_can_be_compressed(ctx, target, internalFormat)) { + return GL_INVALID_ENUM; + } + + /* This will detect any invalid internalFormat value */ + if (!_mesa_is_compressed_format(ctx, internalFormat)) + return GL_INVALID_ENUM; + + /* This should really never fail */ + if (_mesa_base_tex_format(ctx, internalFormat) < 0) + return GL_INVALID_ENUM; + + /* No compressed formats support borders at this time */ + if (border != 0) + return GL_INVALID_VALUE; + + /* For cube map, width must equal height */ + if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB && width != height) + return GL_INVALID_VALUE; + + /* check image size against compression block size */ + { + gl_format texFormat = + ctx->Driver.ChooseTextureFormat(ctx, internalFormat, + GL_NONE, GL_NONE); + GLuint bw, bh; + + _mesa_get_format_block_size(texFormat, &bw, &bh); + if ((width > bw && width % bw > 0) || + (height > bh && height % bh > 0)) { + /* + * Per GL_ARB_texture_compression: GL_INVALID_OPERATION is + * generated [...] if any parameter combinations are not + * supported by the specific compressed internal format. + */ + return GL_INVALID_OPERATION; + } + } + + /* check image sizes */ + if (!ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level, + internalFormat, GL_NONE, GL_NONE, + width, height, depth, border)) { + /* See error comment above */ + return GL_INVALID_OPERATION; + } + + /* check image size in bytes */ + expectedSize = compressed_tex_size(width, height, depth, internalFormat); + if (expectedSize != imageSize) { + /* Per GL_ARB_texture_compression: GL_INVALID_VALUE is generated [...] + * if <imageSize> is not consistent with the format, dimensions, and + * contents of the specified image. + */ + return GL_INVALID_VALUE; + } + + return GL_NO_ERROR; +} + + +/** + * Error checking for glCompressedTexSubImage[123]D(). + * \warning There are some bad assumptions here about the size of compressed + * texture tiles (multiple of 4) used to test the validity of the + * offset and size parameters. + * \return error code or GL_NO_ERROR. + */ +static GLenum +compressed_subtexture_error_check(struct gl_context *ctx, GLint dimensions, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLsizei imageSize) +{ + GLint expectedSize, maxLevels = 0, maxTextureSize; + GLuint bw, bh; + (void) zoffset; + + if (dimensions == 1) { + /* 1D compressed textures not allowed */ + return GL_INVALID_ENUM; + } + else if (dimensions == 2) { + if (target == GL_PROXY_TEXTURE_2D) { + maxLevels = ctx->Const.MaxTextureLevels; + } + else if (target == GL_TEXTURE_2D) { + maxLevels = ctx->Const.MaxTextureLevels; + } + else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB) { + if (!ctx->Extensions.ARB_texture_cube_map) + return GL_INVALID_ENUM; /*target*/ + maxLevels = ctx->Const.MaxCubeTextureLevels; + } + else if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) { + if (!ctx->Extensions.ARB_texture_cube_map) + return GL_INVALID_ENUM; /*target*/ + maxLevels = ctx->Const.MaxCubeTextureLevels; + } + else { + return GL_INVALID_ENUM; /*target*/ + } + } + else if (dimensions == 3) { + /* 3D compressed textures not allowed */ + return GL_INVALID_ENUM; + } + + maxTextureSize = 1 << (maxLevels - 1); + + /* this will catch any invalid compressed format token */ + if (!_mesa_is_compressed_format(ctx, format)) + return GL_INVALID_ENUM; + + if (width < 1 || width > maxTextureSize) + return GL_INVALID_VALUE; + + if ((height < 1 || height > maxTextureSize) + && dimensions > 1) + return GL_INVALID_VALUE; + + if (level < 0 || level >= maxLevels) + return GL_INVALID_VALUE; + + /* + * do checks which depend on compression block size + */ + get_compressed_block_size(format, &bw, &bh); + + if ((xoffset % bw != 0) || (yoffset % bh != 0)) + return GL_INVALID_VALUE; + + if ((width % bw != 0) && width != 2 && width != 1) + return GL_INVALID_VALUE; + + if ((height % bh != 0) && height != 2 && height != 1) + return GL_INVALID_VALUE; + + expectedSize = compressed_tex_size(width, height, depth, format); + if (expectedSize != imageSize) + return GL_INVALID_VALUE; + + return GL_NO_ERROR; +} + + +/** + * Do second part of glCompressedTexSubImage error checking. + * \return GL_TRUE if error found, GL_FALSE otherwise. + */ +static GLboolean +compressed_subtexture_error_check2(struct gl_context *ctx, GLuint dims, + GLsizei width, GLsizei height, + GLsizei depth, GLenum format, + struct gl_texture_image *texImage) +{ + + if ((GLint) format != texImage->InternalFormat) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTexSubImage%uD(format=0x%x)", dims, format); + return GL_TRUE; + } + + if (((width == 1 || width == 2) && + width != (GLsizei) texImage->Width) || + (width > (GLsizei) texImage->Width)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCompressedTexSubImage%uD(width=%d)", dims, width); + return GL_TRUE; + } + + if (dims >= 2) { + if (((height == 1 || height == 2) && + height != (GLsizei) texImage->Height) || + (height > (GLsizei) texImage->Height)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCompressedTexSubImage%uD(height=%d)", dims, height); + return GL_TRUE; + } + } + + if (dims >= 3) { + if (((depth == 1 || depth == 2) && + depth != (GLsizei) texImage->Depth) || + (depth > (GLsizei) texImage->Depth)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCompressedTexSubImage%uD(depth=%d)", dims, depth); + return GL_TRUE; + } + } + + return GL_FALSE; +} + + +/** + * Implementation of the glCompressedTexImage1/2/3D() functions. + */ +static void +compressedteximage(struct gl_context *ctx, GLuint dims, + GLenum target, GLint level, + GLenum internalFormat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, + GLsizei imageSize, const GLvoid *data) +{ + GLenum error; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, + "glCompressedTexImage%uDARB %s %d %s %d %d %d %d %d %p\n", + dims, + _mesa_lookup_enum_by_nr(target), level, + _mesa_lookup_enum_by_nr(internalFormat), + width, height, depth, border, imageSize, data); + + /* check target */ + if (!legal_teximage_target(ctx, dims, target)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(target=%s)", + dims, _mesa_lookup_enum_by_nr(target)); + return; + } + + error = compressed_texture_error_check(ctx, dims, target, level, + internalFormat, width, height, depth, + border, imageSize); + +#if FEATURE_ES + /* XXX this is kind of a hack */ + if (error) { + _mesa_error(ctx, error, "glTexImage2D"); + return; + } + + if (dims == 2) { + switch (internalFormat) { + case GL_PALETTE4_RGB8_OES: + case GL_PALETTE4_RGBA8_OES: + case GL_PALETTE4_R5_G6_B5_OES: + case GL_PALETTE4_RGBA4_OES: + case GL_PALETTE4_RGB5_A1_OES: + case GL_PALETTE8_RGB8_OES: + case GL_PALETTE8_RGBA8_OES: + case GL_PALETTE8_R5_G6_B5_OES: + case GL_PALETTE8_RGBA4_OES: + case GL_PALETTE8_RGB5_A1_OES: + _mesa_cpal_compressed_teximage2d(target, level, internalFormat, + width, height, imageSize, data); + return; + } + } +#endif + + if (_mesa_is_proxy_texture(target)) { + /* Proxy texture: just check for errors and update proxy state */ + struct gl_texture_image *texImage; + + if (!error) { + struct gl_texture_object *texObj = + _mesa_get_current_tex_object(ctx, target); + gl_format texFormat = + _mesa_choose_texture_format(ctx, texObj, target, level, + internalFormat, GL_NONE, GL_NONE); + if (!legal_texture_size(ctx, texFormat, width, height, depth)) { + error = GL_OUT_OF_MEMORY; + } + } + + texImage = _mesa_get_proxy_tex_image(ctx, target, level); + if (texImage) { + if (error) { + /* if error, clear all proxy texture image parameters */ + clear_teximage_fields(texImage); + } + else { + /* no error: store the teximage parameters */ + _mesa_init_teximage_fields(ctx, target, texImage, width, height, + depth, border, internalFormat, + MESA_FORMAT_NONE); + } + } + } + else { + /* non-proxy target */ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + + if (error) { + _mesa_error(ctx, error, "glCompressedTexImage%uD", dims); + return; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "glCompressedTexImage%uD", dims); + } + else { + gl_format texFormat; + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + ASSERT(texImage->Data == NULL); + + texFormat = _mesa_choose_texture_format(ctx, texObj, target, level, + internalFormat, GL_NONE, + GL_NONE); + + if (legal_texture_size(ctx, texFormat, width, height, depth)) { + _mesa_init_teximage_fields(ctx, target, texImage, + width, height, depth, + border, internalFormat, texFormat); + + switch (dims) { + case 1: + ASSERT(ctx->Driver.CompressedTexImage1D); + ctx->Driver.CompressedTexImage1D(ctx, target, level, + internalFormat, + width, + border, imageSize, data, + texObj, texImage); + break; + case 2: + ASSERT(ctx->Driver.CompressedTexImage2D); + ctx->Driver.CompressedTexImage2D(ctx, target, level, + internalFormat, + width, height, + border, imageSize, data, + texObj, texImage); + break; + case 3: + ASSERT(ctx->Driver.CompressedTexImage3D); + ctx->Driver.CompressedTexImage3D(ctx, target, level, + internalFormat, + width, height, depth, + border, imageSize, data, + texObj, texImage); + break; + default: + _mesa_problem(ctx, "bad dims in compressedteximage"); + } + + check_gen_mipmap(ctx, target, texObj, level); + + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "glCompressedTexImage%uD", dims); + } + } + } + _mesa_unlock_texture(ctx, texObj); + } +} + + +void GLAPIENTRY +_mesa_CompressedTexImage1DARB(GLenum target, GLint level, + GLenum internalFormat, GLsizei width, + GLint border, GLsizei imageSize, + const GLvoid *data) +{ + GET_CURRENT_CONTEXT(ctx); + compressedteximage(ctx, 1, target, level, internalFormat, + width, 1, 1, border, imageSize, data); +} + + +void GLAPIENTRY +_mesa_CompressedTexImage2DARB(GLenum target, GLint level, + GLenum internalFormat, GLsizei width, + GLsizei height, GLint border, GLsizei imageSize, + const GLvoid *data) +{ + GET_CURRENT_CONTEXT(ctx); + compressedteximage(ctx, 2, target, level, internalFormat, + width, height, 1, border, imageSize, data); +} + + +void GLAPIENTRY +_mesa_CompressedTexImage3DARB(GLenum target, GLint level, + GLenum internalFormat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, + GLsizei imageSize, const GLvoid *data) +{ + GET_CURRENT_CONTEXT(ctx); + compressedteximage(ctx, 3, target, level, internalFormat, + width, height, depth, border, imageSize, data); +} + + +/** + * Common helper for glCompressedTexSubImage1/2/3D(). + */ +static void +compressed_tex_sub_image(GLuint dims, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLsizei imageSize, const GLvoid *data) +{ + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + GLenum error; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + error = compressed_subtexture_error_check(ctx, dims, target, level, + xoffset, 0, 0, /* pos */ + width, height, depth, /* size */ + format, imageSize); + if (error) { + _mesa_error(ctx, error, "glCompressedTexSubImage%uD", dims); + return; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + assert(texImage); + + if (compressed_subtexture_error_check2(ctx, dims, width, height, depth, + format, texImage)) { + /* error was recorded */ + } + else if (width > 0 && height > 0 && depth > 0) { + switch (dims) { + case 1: + if (ctx->Driver.CompressedTexSubImage1D) { + ctx->Driver.CompressedTexSubImage1D(ctx, target, level, + xoffset, width, + format, imageSize, data, + texObj, texImage); + } + break; + case 2: + if (ctx->Driver.CompressedTexSubImage2D) { + ctx->Driver.CompressedTexSubImage2D(ctx, target, level, + xoffset, yoffset, + width, height, + format, imageSize, data, + texObj, texImage); + } + break; + case 3: + if (ctx->Driver.CompressedTexSubImage3D) { + ctx->Driver.CompressedTexSubImage3D(ctx, target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, imageSize, data, + texObj, texImage); + } + break; + default: + ; + } + + check_gen_mipmap(ctx, target, texObj, level); + + ctx->NewState |= _NEW_TEXTURE; + } + } + _mesa_unlock_texture(ctx, texObj); +} + + +void GLAPIENTRY +_mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset, + GLsizei width, GLenum format, + GLsizei imageSize, const GLvoid *data) +{ + compressed_tex_sub_image(1, target, level, xoffset, 0, 0, width, 1, 1, + format, imageSize, data); +} + + +void GLAPIENTRY +_mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, + const GLvoid *data) +{ + compressed_tex_sub_image(2, target, level, xoffset, yoffset, 0, + width, height, 1, format, imageSize, data); +} + + +void GLAPIENTRY +_mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, const GLvoid *data) +{ + compressed_tex_sub_image(3, target, level, xoffset, yoffset, zoffset, + width, height, depth, format, imageSize, data); +} diff --git a/mesalib/src/mesa/main/texstate.c b/mesalib/src/mesa/main/texstate.c index d86a5a5ec..41d531f59 100644 --- a/mesalib/src/mesa/main/texstate.c +++ b/mesalib/src/mesa/main/texstate.c @@ -1,844 +1,841 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.5
- *
- * 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.
- */
-
-/**
- * \file texstate.c
- *
- * Texture state handling.
- */
-
-#include "glheader.h"
-#include "mfeatures.h"
-#include "colormac.h"
-#include "colortab.h"
-#include "context.h"
-#include "enums.h"
-#include "macros.h"
-#include "texobj.h"
-#include "teximage.h"
-#include "texstate.h"
-#include "mtypes.h"
-
-
-
-/**
- * Default texture combine environment state. This is used to initialize
- * a context's texture units and as the basis for converting "classic"
- * texture environmnets to ARB_texture_env_combine style values.
- */
-static const struct gl_tex_env_combine_state default_combine_state = {
- GL_MODULATE, GL_MODULATE,
- { GL_TEXTURE, GL_PREVIOUS, GL_CONSTANT, GL_CONSTANT },
- { GL_TEXTURE, GL_PREVIOUS, GL_CONSTANT, GL_CONSTANT },
- { GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_ALPHA, GL_SRC_ALPHA },
- { GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA },
- 0, 0,
- 2, 2
-};
-
-
-
-/**
- * Used by glXCopyContext to copy texture state from one context to another.
- */
-void
-_mesa_copy_texture_state( const struct gl_context *src, struct gl_context *dst )
-{
- GLuint u, tex;
-
- ASSERT(src);
- ASSERT(dst);
-
- dst->Texture.CurrentUnit = src->Texture.CurrentUnit;
- dst->Texture._GenFlags = src->Texture._GenFlags;
- dst->Texture._TexGenEnabled = src->Texture._TexGenEnabled;
- dst->Texture._TexMatEnabled = src->Texture._TexMatEnabled;
- dst->Texture.SharedPalette = src->Texture.SharedPalette;
-
- /* per-unit state */
- for (u = 0; u < src->Const.MaxCombinedTextureImageUnits; u++) {
- dst->Texture.Unit[u].Enabled = src->Texture.Unit[u].Enabled;
- dst->Texture.Unit[u].EnvMode = src->Texture.Unit[u].EnvMode;
- COPY_4V(dst->Texture.Unit[u].EnvColor, src->Texture.Unit[u].EnvColor);
- dst->Texture.Unit[u].TexGenEnabled = src->Texture.Unit[u].TexGenEnabled;
- dst->Texture.Unit[u].GenS = src->Texture.Unit[u].GenS;
- dst->Texture.Unit[u].GenT = src->Texture.Unit[u].GenT;
- dst->Texture.Unit[u].GenR = src->Texture.Unit[u].GenR;
- dst->Texture.Unit[u].GenQ = src->Texture.Unit[u].GenQ;
- dst->Texture.Unit[u].LodBias = src->Texture.Unit[u].LodBias;
-
- /* GL_EXT_texture_env_combine */
- dst->Texture.Unit[u].Combine = src->Texture.Unit[u].Combine;
-
- /* GL_ATI_envmap_bumpmap - need this? */
- dst->Texture.Unit[u].BumpTarget = src->Texture.Unit[u].BumpTarget;
- COPY_4V(dst->Texture.Unit[u].RotMatrix, src->Texture.Unit[u].RotMatrix);
-
- /*
- * XXX strictly speaking, we should compare texture names/ids and
- * bind textures in the dest context according to id. For now, only
- * copy bindings if the contexts share the same pool of textures to
- * avoid refcounting bugs.
- */
- if (dst->Shared == src->Shared) {
- /* copy texture object bindings, not contents of texture objects */
- _mesa_lock_context_textures(dst);
-
- for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) {
- _mesa_reference_texobj(&dst->Texture.Unit[u].CurrentTex[tex],
- src->Texture.Unit[u].CurrentTex[tex]);
- }
- _mesa_unlock_context_textures(dst);
- }
- }
-}
-
-
-/*
- * For debugging
- */
-void
-_mesa_print_texunit_state( struct gl_context *ctx, GLuint unit )
-{
- const struct gl_texture_unit *texUnit = ctx->Texture.Unit + unit;
- printf("Texture Unit %d\n", unit);
- printf(" GL_TEXTURE_ENV_MODE = %s\n", _mesa_lookup_enum_by_nr(texUnit->EnvMode));
- printf(" GL_COMBINE_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.ModeRGB));
- printf(" GL_COMBINE_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.ModeA));
- printf(" GL_SOURCE0_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceRGB[0]));
- printf(" GL_SOURCE1_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceRGB[1]));
- printf(" GL_SOURCE2_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceRGB[2]));
- printf(" GL_SOURCE0_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceA[0]));
- printf(" GL_SOURCE1_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceA[1]));
- printf(" GL_SOURCE2_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceA[2]));
- printf(" GL_OPERAND0_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandRGB[0]));
- printf(" GL_OPERAND1_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandRGB[1]));
- printf(" GL_OPERAND2_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandRGB[2]));
- printf(" GL_OPERAND0_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandA[0]));
- printf(" GL_OPERAND1_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandA[1]));
- printf(" GL_OPERAND2_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandA[2]));
- printf(" GL_RGB_SCALE = %d\n", 1 << texUnit->Combine.ScaleShiftRGB);
- printf(" GL_ALPHA_SCALE = %d\n", 1 << texUnit->Combine.ScaleShiftA);
- printf(" GL_TEXTURE_ENV_COLOR = (%f, %f, %f, %f)\n", texUnit->EnvColor[0], texUnit->EnvColor[1], texUnit->EnvColor[2], texUnit->EnvColor[3]);
-}
-
-
-
-/**********************************************************************/
-/* Texture Environment */
-/**********************************************************************/
-
-/**
- * Convert "classic" texture environment to ARB_texture_env_combine style
- * environments.
- *
- * \param state texture_env_combine state vector to be filled-in.
- * \param mode Classic texture environment mode (i.e., \c GL_REPLACE,
- * \c GL_BLEND, \c GL_DECAL, etc.).
- * \param texBaseFormat Base format of the texture associated with the
- * texture unit.
- */
-static void
-calculate_derived_texenv( struct gl_tex_env_combine_state *state,
- GLenum mode, GLenum texBaseFormat )
-{
- GLenum mode_rgb;
- GLenum mode_a;
-
- *state = default_combine_state;
-
- switch (texBaseFormat) {
- case GL_ALPHA:
- state->SourceRGB[0] = GL_PREVIOUS;
- break;
-
- case GL_LUMINANCE_ALPHA:
- case GL_INTENSITY:
- case GL_RGBA:
- break;
-
- case GL_LUMINANCE:
- case GL_RED:
- case GL_RG:
- case GL_RGB:
- case GL_YCBCR_MESA:
- case GL_DUDV_ATI:
- state->SourceA[0] = GL_PREVIOUS;
- break;
-
- default:
- _mesa_problem(NULL,
- "Invalid texBaseFormat 0x%x in calculate_derived_texenv",
- texBaseFormat);
- return;
- }
-
- if (mode == GL_REPLACE_EXT)
- mode = GL_REPLACE;
-
- switch (mode) {
- case GL_REPLACE:
- case GL_MODULATE:
- mode_rgb = (texBaseFormat == GL_ALPHA) ? GL_REPLACE : mode;
- mode_a = mode;
- break;
-
- case GL_DECAL:
- mode_rgb = GL_INTERPOLATE;
- mode_a = GL_REPLACE;
-
- state->SourceA[0] = GL_PREVIOUS;
-
- /* Having alpha / luminance / intensity textures replace using the
- * incoming fragment color matches the definition in NV_texture_shader.
- * The 1.5 spec simply marks these as "undefined".
- */
- switch (texBaseFormat) {
- case GL_ALPHA:
- case GL_LUMINANCE:
- case GL_LUMINANCE_ALPHA:
- case GL_INTENSITY:
- state->SourceRGB[0] = GL_PREVIOUS;
- break;
- case GL_RED:
- case GL_RG:
- case GL_RGB:
- case GL_YCBCR_MESA:
- case GL_DUDV_ATI:
- mode_rgb = GL_REPLACE;
- break;
- case GL_RGBA:
- state->SourceRGB[2] = GL_TEXTURE;
- break;
- }
- break;
-
- case GL_BLEND:
- mode_rgb = GL_INTERPOLATE;
- mode_a = GL_MODULATE;
-
- switch (texBaseFormat) {
- case GL_ALPHA:
- mode_rgb = GL_REPLACE;
- break;
- case GL_INTENSITY:
- mode_a = GL_INTERPOLATE;
- state->SourceA[0] = GL_CONSTANT;
- state->OperandA[2] = GL_SRC_ALPHA;
- /* FALLTHROUGH */
- case GL_LUMINANCE:
- case GL_RED:
- case GL_RG:
- case GL_RGB:
- case GL_LUMINANCE_ALPHA:
- case GL_RGBA:
- case GL_YCBCR_MESA:
- case GL_DUDV_ATI:
- state->SourceRGB[2] = GL_TEXTURE;
- state->SourceA[2] = GL_TEXTURE;
- state->SourceRGB[0] = GL_CONSTANT;
- state->OperandRGB[2] = GL_SRC_COLOR;
- break;
- }
- break;
-
- case GL_ADD:
- mode_rgb = (texBaseFormat == GL_ALPHA) ? GL_REPLACE : GL_ADD;
- mode_a = (texBaseFormat == GL_INTENSITY) ? GL_ADD : GL_MODULATE;
- break;
-
- default:
- _mesa_problem(NULL,
- "Invalid texture env mode 0x%x in calculate_derived_texenv",
- mode);
- return;
- }
-
- state->ModeRGB = (state->SourceRGB[0] != GL_PREVIOUS)
- ? mode_rgb : GL_REPLACE;
- state->ModeA = (state->SourceA[0] != GL_PREVIOUS)
- ? mode_a : GL_REPLACE;
-}
-
-
-
-
-/* GL_ARB_multitexture */
-void GLAPIENTRY
-_mesa_ActiveTextureARB(GLenum texture)
-{
- const GLuint texUnit = texture - GL_TEXTURE0;
- GLuint k;
- GET_CURRENT_CONTEXT(ctx);
-
- /* See OpenGL spec for glActiveTexture: */
- k = MAX2(ctx->Const.MaxCombinedTextureImageUnits,
- ctx->Const.MaxTextureCoordUnits);
-
- ASSERT(k <= Elements(ctx->Texture.Unit));
-
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
- _mesa_debug(ctx, "glActiveTexture %s\n",
- _mesa_lookup_enum_by_nr(texture));
-
- if (texUnit >= k) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glActiveTexture(texture=%s)",
- _mesa_lookup_enum_by_nr(texture));
- return;
- }
-
- if (ctx->Texture.CurrentUnit == texUnit)
- return;
-
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-
- ctx->Texture.CurrentUnit = texUnit;
- if (ctx->Transform.MatrixMode == GL_TEXTURE) {
- /* update current stack pointer */
- ctx->CurrentStack = &ctx->TextureMatrixStack[texUnit];
- }
-}
-
-
-/* GL_ARB_multitexture */
-void GLAPIENTRY
-_mesa_ClientActiveTextureARB(GLenum texture)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLuint texUnit = texture - GL_TEXTURE0;
- ASSERT_OUTSIDE_BEGIN_END(ctx);
-
- if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE))
- _mesa_debug(ctx, "glClientActiveTexture %s\n",
- _mesa_lookup_enum_by_nr(texture));
-
- if (texUnit >= ctx->Const.MaxTextureCoordUnits) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glClientActiveTexture(texture)");
- return;
- }
-
- if (ctx->Array.ActiveTexture == texUnit)
- return;
-
- FLUSH_VERTICES(ctx, _NEW_ARRAY);
- ctx->Array.ActiveTexture = texUnit;
-}
-
-
-
-/**********************************************************************/
-/***** State management *****/
-/**********************************************************************/
-
-
-/**
- * \note This routine refers to derived texture attribute values to
- * compute the ENABLE_TEXMAT flags, but is only called on
- * _NEW_TEXTURE_MATRIX. On changes to _NEW_TEXTURE, the ENABLE_TEXMAT
- * flags are updated by _mesa_update_textures(), below.
- *
- * \param ctx GL context.
- */
-static void
-update_texture_matrices( struct gl_context *ctx )
-{
- GLuint u;
-
- ctx->Texture._TexMatEnabled = 0x0;
-
- for (u = 0; u < ctx->Const.MaxTextureCoordUnits; u++) {
- ASSERT(u < Elements(ctx->TextureMatrixStack));
- if (_math_matrix_is_dirty(ctx->TextureMatrixStack[u].Top)) {
- _math_matrix_analyse( ctx->TextureMatrixStack[u].Top );
-
- if (ctx->Texture.Unit[u]._ReallyEnabled &&
- ctx->TextureMatrixStack[u].Top->type != MATRIX_IDENTITY)
- ctx->Texture._TexMatEnabled |= ENABLE_TEXMAT(u);
- }
- }
-}
-
-
-/**
- * Examine texture unit's combine/env state to update derived state.
- */
-static void
-update_tex_combine(struct gl_context *ctx, struct gl_texture_unit *texUnit)
-{
- struct gl_tex_env_combine_state *combine;
-
- /* Set the texUnit->_CurrentCombine field to point to the user's combiner
- * state, or the combiner state which is derived from traditional texenv
- * mode.
- */
- if (texUnit->EnvMode == GL_COMBINE ||
- texUnit->EnvMode == GL_COMBINE4_NV) {
- texUnit->_CurrentCombine = & texUnit->Combine;
- }
- else {
- const struct gl_texture_object *texObj = texUnit->_Current;
- GLenum format = texObj->Image[0][texObj->BaseLevel]->_BaseFormat;
- if (format == GL_COLOR_INDEX) {
- format = GL_RGBA; /* a bit of a hack */
- }
- else if (format == GL_DEPTH_COMPONENT ||
- format == GL_DEPTH_STENCIL_EXT) {
- format = texObj->DepthMode;
- }
- calculate_derived_texenv(&texUnit->_EnvMode, texUnit->EnvMode, format);
- texUnit->_CurrentCombine = & texUnit->_EnvMode;
- }
-
- combine = texUnit->_CurrentCombine;
-
- /* Determine number of source RGB terms in the combiner function */
- switch (combine->ModeRGB) {
- case GL_REPLACE:
- combine->_NumArgsRGB = 1;
- break;
- case GL_ADD:
- case GL_ADD_SIGNED:
- if (texUnit->EnvMode == GL_COMBINE4_NV)
- combine->_NumArgsRGB = 4;
- else
- combine->_NumArgsRGB = 2;
- break;
- case GL_MODULATE:
- case GL_SUBTRACT:
- case GL_DOT3_RGB:
- case GL_DOT3_RGBA:
- case GL_DOT3_RGB_EXT:
- case GL_DOT3_RGBA_EXT:
- combine->_NumArgsRGB = 2;
- break;
- case GL_INTERPOLATE:
- case GL_MODULATE_ADD_ATI:
- case GL_MODULATE_SIGNED_ADD_ATI:
- case GL_MODULATE_SUBTRACT_ATI:
- combine->_NumArgsRGB = 3;
- break;
- case GL_BUMP_ENVMAP_ATI:
- /* no real arguments for this case */
- combine->_NumArgsRGB = 0;
- break;
- default:
- combine->_NumArgsRGB = 0;
- _mesa_problem(ctx, "invalid RGB combine mode in update_texture_state");
- return;
- }
-
- /* Determine number of source Alpha terms in the combiner function */
- switch (combine->ModeA) {
- case GL_REPLACE:
- combine->_NumArgsA = 1;
- break;
- case GL_ADD:
- case GL_ADD_SIGNED:
- if (texUnit->EnvMode == GL_COMBINE4_NV)
- combine->_NumArgsA = 4;
- else
- combine->_NumArgsA = 2;
- break;
- case GL_MODULATE:
- case GL_SUBTRACT:
- combine->_NumArgsA = 2;
- break;
- case GL_INTERPOLATE:
- case GL_MODULATE_ADD_ATI:
- case GL_MODULATE_SIGNED_ADD_ATI:
- case GL_MODULATE_SUBTRACT_ATI:
- combine->_NumArgsA = 3;
- break;
- default:
- combine->_NumArgsA = 0;
- _mesa_problem(ctx, "invalid Alpha combine mode in update_texture_state");
- break;
- }
-}
-
-
-/**
- * \note This routine refers to derived texture matrix values to
- * compute the ENABLE_TEXMAT flags, but is only called on
- * _NEW_TEXTURE. On changes to _NEW_TEXTURE_MATRIX, the ENABLE_TEXMAT
- * flags are updated by _mesa_update_texture_matrices, above.
- *
- * \param ctx GL context.
- */
-static void
-update_texture_state( struct gl_context *ctx )
-{
- GLuint unit;
- struct gl_fragment_program *fprog = NULL;
- struct gl_vertex_program *vprog = NULL;
- GLbitfield enabledFragUnits = 0x0;
-
- if (ctx->Shader.CurrentVertexProgram &&
- ctx->Shader.CurrentVertexProgram->LinkStatus) {
- vprog = ctx->Shader.CurrentVertexProgram->VertexProgram;
- } else if (ctx->VertexProgram._Enabled) {
- /* XXX enable this if/when non-shader vertex programs get
- * texture fetches:
- vprog = ctx->VertexProgram.Current;
- */
- }
-
- if (ctx->Shader.CurrentFragmentProgram &&
- ctx->Shader.CurrentFragmentProgram->LinkStatus) {
- fprog = ctx->Shader.CurrentFragmentProgram->FragmentProgram;
- }
- else if (ctx->FragmentProgram._Enabled) {
- fprog = ctx->FragmentProgram.Current;
- }
-
- /* FINISHME: Geometry shader texture accesses should also be considered
- * FINISHME: here.
- */
-
- /* TODO: only set this if there are actual changes */
- ctx->NewState |= _NEW_TEXTURE;
-
- ctx->Texture._EnabledUnits = 0x0;
- ctx->Texture._GenFlags = 0x0;
- ctx->Texture._TexMatEnabled = 0x0;
- ctx->Texture._TexGenEnabled = 0x0;
-
- /*
- * Update texture unit state.
- */
- for (unit = 0; unit < ctx->Const.MaxCombinedTextureImageUnits; unit++) {
- struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
- GLbitfield enabledVertTargets = 0x0;
- GLbitfield enabledFragTargets = 0x0;
- GLbitfield enabledTargets = 0x0;
- GLuint texIndex;
-
- /* Get the bitmask of texture target enables.
- * enableBits will be a mask of the TEXTURE_*_BIT flags indicating
- * which texture targets are enabled (fixed function) or referenced
- * by a fragment program/program. When multiple flags are set, we'll
- * settle on the one with highest priority (see below).
- */
- if (vprog) {
- enabledVertTargets |= vprog->Base.TexturesUsed[unit];
- }
-
- if (fprog) {
- enabledFragTargets |= fprog->Base.TexturesUsed[unit];
- }
- else {
- /* fixed-function fragment program */
- enabledFragTargets |= texUnit->Enabled;
- }
-
- enabledTargets = enabledVertTargets | enabledFragTargets;
-
- texUnit->_ReallyEnabled = 0x0;
-
- if (enabledTargets == 0x0) {
- /* neither vertex nor fragment processing uses this unit */
- continue;
- }
-
- /* Look for the highest priority texture target that's enabled (or used
- * by the vert/frag shaders) and "complete". That's the one we'll use
- * for texturing. If we're using vert/frag program we're guaranteed
- * that bitcount(enabledBits) <= 1.
- * Note that the TEXTURE_x_INDEX values are in high to low priority.
- */
- for (texIndex = 0; texIndex < NUM_TEXTURE_TARGETS; texIndex++) {
- if (enabledTargets & (1 << texIndex)) {
- struct gl_texture_object *texObj = texUnit->CurrentTex[texIndex];
- if (!texObj->_Complete) {
- _mesa_test_texobj_completeness(ctx, texObj);
- }
- if (texObj->_Complete) {
- texUnit->_ReallyEnabled = 1 << texIndex;
- _mesa_reference_texobj(&texUnit->_Current, texObj);
- break;
- }
- }
- }
-
- if (!texUnit->_ReallyEnabled) {
- if (fprog) {
- /* If we get here it means the shader is expecting a texture
- * object, but there isn't one (or it's incomplete). Use the
- * fallback texture.
- */
- struct gl_texture_object *texObj = _mesa_get_fallback_texture(ctx);
- texUnit->_ReallyEnabled = 1 << TEXTURE_2D_INDEX;
- _mesa_reference_texobj(&texUnit->_Current, texObj);
- }
- else {
- /* fixed-function: texture unit is really disabled */
- continue;
- }
- }
-
- /* if we get here, we know this texture unit is enabled */
-
- ctx->Texture._EnabledUnits |= (1 << unit);
-
- if (enabledFragTargets)
- enabledFragUnits |= (1 << unit);
-
- update_tex_combine(ctx, texUnit);
- }
-
-
- /* Determine which texture coordinate sets are actually needed */
- if (fprog) {
- const GLuint coordMask = (1 << MAX_TEXTURE_COORD_UNITS) - 1;
- ctx->Texture._EnabledCoordUnits
- = (fprog->Base.InputsRead >> FRAG_ATTRIB_TEX0) & coordMask;
- }
- else {
- ctx->Texture._EnabledCoordUnits = enabledFragUnits;
- }
-
- /* Setup texgen for those texture coordinate sets that are in use */
- for (unit = 0; unit < ctx->Const.MaxTextureCoordUnits; unit++) {
- struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
-
- texUnit->_GenFlags = 0x0;
-
- if (!(ctx->Texture._EnabledCoordUnits & (1 << unit)))
- continue;
-
- if (texUnit->TexGenEnabled) {
- if (texUnit->TexGenEnabled & S_BIT) {
- texUnit->_GenFlags |= texUnit->GenS._ModeBit;
- }
- if (texUnit->TexGenEnabled & T_BIT) {
- texUnit->_GenFlags |= texUnit->GenT._ModeBit;
- }
- if (texUnit->TexGenEnabled & R_BIT) {
- texUnit->_GenFlags |= texUnit->GenR._ModeBit;
- }
- if (texUnit->TexGenEnabled & Q_BIT) {
- texUnit->_GenFlags |= texUnit->GenQ._ModeBit;
- }
-
- ctx->Texture._TexGenEnabled |= ENABLE_TEXGEN(unit);
- ctx->Texture._GenFlags |= texUnit->_GenFlags;
- }
-
- ASSERT(unit < Elements(ctx->TextureMatrixStack));
- if (ctx->TextureMatrixStack[unit].Top->type != MATRIX_IDENTITY)
- ctx->Texture._TexMatEnabled |= ENABLE_TEXMAT(unit);
- }
-}
-
-
-/**
- * Update texture-related derived state.
- */
-void
-_mesa_update_texture( struct gl_context *ctx, GLuint new_state )
-{
- if (new_state & _NEW_TEXTURE_MATRIX)
- update_texture_matrices( ctx );
-
- if (new_state & (_NEW_TEXTURE | _NEW_PROGRAM))
- update_texture_state( ctx );
-}
-
-
-/**********************************************************************/
-/***** Initialization *****/
-/**********************************************************************/
-
-/**
- * Allocate the proxy textures for the given context.
- *
- * \param ctx the context to allocate proxies for.
- *
- * \return GL_TRUE on success, or GL_FALSE on failure
- *
- * If run out of memory part way through the allocations, clean up and return
- * GL_FALSE.
- */
-static GLboolean
-alloc_proxy_textures( struct gl_context *ctx )
-{
- static const GLenum targets[] = {
- GL_TEXTURE_1D,
- GL_TEXTURE_2D,
- GL_TEXTURE_3D,
- GL_TEXTURE_CUBE_MAP_ARB,
- GL_TEXTURE_RECTANGLE_NV,
- GL_TEXTURE_1D_ARRAY_EXT,
- GL_TEXTURE_2D_ARRAY_EXT
- };
- GLint tgt;
-
- ASSERT(Elements(targets) == NUM_TEXTURE_TARGETS);
-
- for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) {
- if (!(ctx->Texture.ProxyTex[tgt]
- = ctx->Driver.NewTextureObject(ctx, 0, targets[tgt]))) {
- /* out of memory, free what we did allocate */
- while (--tgt >= 0) {
- ctx->Driver.DeleteTexture(ctx, ctx->Texture.ProxyTex[tgt]);
- }
- return GL_FALSE;
- }
- }
-
- assert(ctx->Texture.ProxyTex[0]->RefCount == 1); /* sanity check */
- return GL_TRUE;
-}
-
-
-/**
- * Initialize a texture unit.
- *
- * \param ctx GL context.
- * \param unit texture unit number to be initialized.
- */
-static void
-init_texture_unit( struct gl_context *ctx, GLuint unit )
-{
- struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
- GLuint tex;
-
- texUnit->EnvMode = GL_MODULATE;
- ASSIGN_4V( texUnit->EnvColor, 0.0, 0.0, 0.0, 0.0 );
-
- texUnit->Combine = default_combine_state;
- texUnit->_EnvMode = default_combine_state;
- texUnit->_CurrentCombine = & texUnit->_EnvMode;
- texUnit->BumpTarget = GL_TEXTURE0;
-
- texUnit->TexGenEnabled = 0x0;
- texUnit->GenS.Mode = GL_EYE_LINEAR;
- texUnit->GenT.Mode = GL_EYE_LINEAR;
- texUnit->GenR.Mode = GL_EYE_LINEAR;
- texUnit->GenQ.Mode = GL_EYE_LINEAR;
- texUnit->GenS._ModeBit = TEXGEN_EYE_LINEAR;
- texUnit->GenT._ModeBit = TEXGEN_EYE_LINEAR;
- texUnit->GenR._ModeBit = TEXGEN_EYE_LINEAR;
- texUnit->GenQ._ModeBit = TEXGEN_EYE_LINEAR;
-
- /* Yes, these plane coefficients are correct! */
- ASSIGN_4V( texUnit->GenS.ObjectPlane, 1.0, 0.0, 0.0, 0.0 );
- ASSIGN_4V( texUnit->GenT.ObjectPlane, 0.0, 1.0, 0.0, 0.0 );
- ASSIGN_4V( texUnit->GenR.ObjectPlane, 0.0, 0.0, 0.0, 0.0 );
- ASSIGN_4V( texUnit->GenQ.ObjectPlane, 0.0, 0.0, 0.0, 0.0 );
- ASSIGN_4V( texUnit->GenS.EyePlane, 1.0, 0.0, 0.0, 0.0 );
- ASSIGN_4V( texUnit->GenT.EyePlane, 0.0, 1.0, 0.0, 0.0 );
- ASSIGN_4V( texUnit->GenR.EyePlane, 0.0, 0.0, 0.0, 0.0 );
- ASSIGN_4V( texUnit->GenQ.EyePlane, 0.0, 0.0, 0.0, 0.0 );
-
- /* no mention of this in spec, but maybe id matrix expected? */
- ASSIGN_4V( texUnit->RotMatrix, 1.0, 0.0, 0.0, 1.0 );
-
- /* initialize current texture object ptrs to the shared default objects */
- for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) {
- _mesa_reference_texobj(&texUnit->CurrentTex[tex],
- ctx->Shared->DefaultTex[tex]);
- }
-}
-
-
-/**
- * Initialize texture state for the given context.
- */
-GLboolean
-_mesa_init_texture(struct gl_context *ctx)
-{
- GLuint u;
-
- /* Texture group */
- ctx->Texture.CurrentUnit = 0; /* multitexture */
- ctx->Texture._EnabledUnits = 0x0;
- ctx->Texture.SharedPalette = GL_FALSE;
- _mesa_init_colortable(&ctx->Texture.Palette);
-
- for (u = 0; u < Elements(ctx->Texture.Unit); u++)
- init_texture_unit(ctx, u);
-
- /* After we're done initializing the context's texture state the default
- * texture objects' refcounts should be at least
- * MAX_COMBINED_TEXTURE_IMAGE_UNITS + 1.
- */
- assert(ctx->Shared->DefaultTex[TEXTURE_1D_INDEX]->RefCount
- >= MAX_COMBINED_TEXTURE_IMAGE_UNITS + 1);
-
- /* Allocate proxy textures */
- if (!alloc_proxy_textures( ctx ))
- return GL_FALSE;
-
- return GL_TRUE;
-}
-
-
-/**
- * Free dynamically-allocted texture data attached to the given context.
- */
-void
-_mesa_free_texture_data(struct gl_context *ctx)
-{
- GLuint u, tgt;
-
- /* unreference current textures */
- for (u = 0; u < Elements(ctx->Texture.Unit); u++) {
- /* The _Current texture could account for another reference */
- _mesa_reference_texobj(&ctx->Texture.Unit[u]._Current, NULL);
-
- for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) {
- _mesa_reference_texobj(&ctx->Texture.Unit[u].CurrentTex[tgt], NULL);
- }
- }
-
- /* Free proxy texture objects */
- for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++)
- ctx->Driver.DeleteTexture(ctx, ctx->Texture.ProxyTex[tgt]);
-
- for (u = 0; u < Elements(ctx->Texture.Unit); u++)
- _mesa_free_colortable_data(&ctx->Texture.Unit[u].ColorTable);
-}
-
-
-/**
- * Update the default texture objects in the given context to reference those
- * specified in the shared state and release those referencing the old
- * shared state.
- */
-void
-_mesa_update_default_objects_texture(struct gl_context *ctx)
-{
- GLuint u, tex;
-
- for (u = 0; u < Elements(ctx->Texture.Unit); u++) {
- struct gl_texture_unit *texUnit = &ctx->Texture.Unit[u];
- for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) {
- _mesa_reference_texobj(&texUnit->CurrentTex[tex],
- ctx->Shared->DefaultTex[tex]);
- }
- }
-}
+/* + * Mesa 3-D graphics library + * Version: 7.5 + * + * 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. + */ + +/** + * \file texstate.c + * + * Texture state handling. + */ + +#include "glheader.h" +#include "mfeatures.h" +#include "colormac.h" +#include "colortab.h" +#include "context.h" +#include "enums.h" +#include "macros.h" +#include "texobj.h" +#include "teximage.h" +#include "texstate.h" +#include "mtypes.h" + + + +/** + * Default texture combine environment state. This is used to initialize + * a context's texture units and as the basis for converting "classic" + * texture environmnets to ARB_texture_env_combine style values. + */ +static const struct gl_tex_env_combine_state default_combine_state = { + GL_MODULATE, GL_MODULATE, + { GL_TEXTURE, GL_PREVIOUS, GL_CONSTANT, GL_CONSTANT }, + { GL_TEXTURE, GL_PREVIOUS, GL_CONSTANT, GL_CONSTANT }, + { GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_ALPHA, GL_SRC_ALPHA }, + { GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA }, + 0, 0, + 2, 2 +}; + + + +/** + * Used by glXCopyContext to copy texture state from one context to another. + */ +void +_mesa_copy_texture_state( const struct gl_context *src, struct gl_context *dst ) +{ + GLuint u, tex; + + ASSERT(src); + ASSERT(dst); + + dst->Texture.CurrentUnit = src->Texture.CurrentUnit; + dst->Texture._GenFlags = src->Texture._GenFlags; + dst->Texture._TexGenEnabled = src->Texture._TexGenEnabled; + dst->Texture._TexMatEnabled = src->Texture._TexMatEnabled; + dst->Texture.SharedPalette = src->Texture.SharedPalette; + + /* per-unit state */ + for (u = 0; u < src->Const.MaxCombinedTextureImageUnits; u++) { + dst->Texture.Unit[u].Enabled = src->Texture.Unit[u].Enabled; + dst->Texture.Unit[u].EnvMode = src->Texture.Unit[u].EnvMode; + COPY_4V(dst->Texture.Unit[u].EnvColor, src->Texture.Unit[u].EnvColor); + dst->Texture.Unit[u].TexGenEnabled = src->Texture.Unit[u].TexGenEnabled; + dst->Texture.Unit[u].GenS = src->Texture.Unit[u].GenS; + dst->Texture.Unit[u].GenT = src->Texture.Unit[u].GenT; + dst->Texture.Unit[u].GenR = src->Texture.Unit[u].GenR; + dst->Texture.Unit[u].GenQ = src->Texture.Unit[u].GenQ; + dst->Texture.Unit[u].LodBias = src->Texture.Unit[u].LodBias; + + /* GL_EXT_texture_env_combine */ + dst->Texture.Unit[u].Combine = src->Texture.Unit[u].Combine; + + /* GL_ATI_envmap_bumpmap - need this? */ + dst->Texture.Unit[u].BumpTarget = src->Texture.Unit[u].BumpTarget; + COPY_4V(dst->Texture.Unit[u].RotMatrix, src->Texture.Unit[u].RotMatrix); + + /* + * XXX strictly speaking, we should compare texture names/ids and + * bind textures in the dest context according to id. For now, only + * copy bindings if the contexts share the same pool of textures to + * avoid refcounting bugs. + */ + if (dst->Shared == src->Shared) { + /* copy texture object bindings, not contents of texture objects */ + _mesa_lock_context_textures(dst); + + for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { + _mesa_reference_texobj(&dst->Texture.Unit[u].CurrentTex[tex], + src->Texture.Unit[u].CurrentTex[tex]); + } + _mesa_unlock_context_textures(dst); + } + } +} + + +/* + * For debugging + */ +void +_mesa_print_texunit_state( struct gl_context *ctx, GLuint unit ) +{ + const struct gl_texture_unit *texUnit = ctx->Texture.Unit + unit; + printf("Texture Unit %d\n", unit); + printf(" GL_TEXTURE_ENV_MODE = %s\n", _mesa_lookup_enum_by_nr(texUnit->EnvMode)); + printf(" GL_COMBINE_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.ModeRGB)); + printf(" GL_COMBINE_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.ModeA)); + printf(" GL_SOURCE0_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceRGB[0])); + printf(" GL_SOURCE1_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceRGB[1])); + printf(" GL_SOURCE2_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceRGB[2])); + printf(" GL_SOURCE0_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceA[0])); + printf(" GL_SOURCE1_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceA[1])); + printf(" GL_SOURCE2_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.SourceA[2])); + printf(" GL_OPERAND0_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandRGB[0])); + printf(" GL_OPERAND1_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandRGB[1])); + printf(" GL_OPERAND2_RGB = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandRGB[2])); + printf(" GL_OPERAND0_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandA[0])); + printf(" GL_OPERAND1_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandA[1])); + printf(" GL_OPERAND2_ALPHA = %s\n", _mesa_lookup_enum_by_nr(texUnit->Combine.OperandA[2])); + printf(" GL_RGB_SCALE = %d\n", 1 << texUnit->Combine.ScaleShiftRGB); + printf(" GL_ALPHA_SCALE = %d\n", 1 << texUnit->Combine.ScaleShiftA); + printf(" GL_TEXTURE_ENV_COLOR = (%f, %f, %f, %f)\n", texUnit->EnvColor[0], texUnit->EnvColor[1], texUnit->EnvColor[2], texUnit->EnvColor[3]); +} + + + +/**********************************************************************/ +/* Texture Environment */ +/**********************************************************************/ + +/** + * Convert "classic" texture environment to ARB_texture_env_combine style + * environments. + * + * \param state texture_env_combine state vector to be filled-in. + * \param mode Classic texture environment mode (i.e., \c GL_REPLACE, + * \c GL_BLEND, \c GL_DECAL, etc.). + * \param texBaseFormat Base format of the texture associated with the + * texture unit. + */ +static void +calculate_derived_texenv( struct gl_tex_env_combine_state *state, + GLenum mode, GLenum texBaseFormat ) +{ + GLenum mode_rgb; + GLenum mode_a; + + *state = default_combine_state; + + switch (texBaseFormat) { + case GL_ALPHA: + state->SourceRGB[0] = GL_PREVIOUS; + break; + + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + case GL_RGBA: + break; + + case GL_LUMINANCE: + case GL_RED: + case GL_RG: + case GL_RGB: + case GL_YCBCR_MESA: + case GL_DUDV_ATI: + state->SourceA[0] = GL_PREVIOUS; + break; + + default: + _mesa_problem(NULL, + "Invalid texBaseFormat 0x%x in calculate_derived_texenv", + texBaseFormat); + return; + } + + if (mode == GL_REPLACE_EXT) + mode = GL_REPLACE; + + switch (mode) { + case GL_REPLACE: + case GL_MODULATE: + mode_rgb = (texBaseFormat == GL_ALPHA) ? GL_REPLACE : mode; + mode_a = mode; + break; + + case GL_DECAL: + mode_rgb = GL_INTERPOLATE; + mode_a = GL_REPLACE; + + state->SourceA[0] = GL_PREVIOUS; + + /* Having alpha / luminance / intensity textures replace using the + * incoming fragment color matches the definition in NV_texture_shader. + * The 1.5 spec simply marks these as "undefined". + */ + switch (texBaseFormat) { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + state->SourceRGB[0] = GL_PREVIOUS; + break; + case GL_RED: + case GL_RG: + case GL_RGB: + case GL_YCBCR_MESA: + case GL_DUDV_ATI: + mode_rgb = GL_REPLACE; + break; + case GL_RGBA: + state->SourceRGB[2] = GL_TEXTURE; + break; + } + break; + + case GL_BLEND: + mode_rgb = GL_INTERPOLATE; + mode_a = GL_MODULATE; + + switch (texBaseFormat) { + case GL_ALPHA: + mode_rgb = GL_REPLACE; + break; + case GL_INTENSITY: + mode_a = GL_INTERPOLATE; + state->SourceA[0] = GL_CONSTANT; + state->OperandA[2] = GL_SRC_ALPHA; + /* FALLTHROUGH */ + case GL_LUMINANCE: + case GL_RED: + case GL_RG: + case GL_RGB: + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + case GL_YCBCR_MESA: + case GL_DUDV_ATI: + state->SourceRGB[2] = GL_TEXTURE; + state->SourceA[2] = GL_TEXTURE; + state->SourceRGB[0] = GL_CONSTANT; + state->OperandRGB[2] = GL_SRC_COLOR; + break; + } + break; + + case GL_ADD: + mode_rgb = (texBaseFormat == GL_ALPHA) ? GL_REPLACE : GL_ADD; + mode_a = (texBaseFormat == GL_INTENSITY) ? GL_ADD : GL_MODULATE; + break; + + default: + _mesa_problem(NULL, + "Invalid texture env mode 0x%x in calculate_derived_texenv", + mode); + return; + } + + state->ModeRGB = (state->SourceRGB[0] != GL_PREVIOUS) + ? mode_rgb : GL_REPLACE; + state->ModeA = (state->SourceA[0] != GL_PREVIOUS) + ? mode_a : GL_REPLACE; +} + + + + +/* GL_ARB_multitexture */ +void GLAPIENTRY +_mesa_ActiveTextureARB(GLenum texture) +{ + const GLuint texUnit = texture - GL_TEXTURE0; + GLuint k; + GET_CURRENT_CONTEXT(ctx); + + /* See OpenGL spec for glActiveTexture: */ + k = MAX2(ctx->Const.MaxCombinedTextureImageUnits, + ctx->Const.MaxTextureCoordUnits); + + ASSERT(k <= Elements(ctx->Texture.Unit)); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glActiveTexture %s\n", + _mesa_lookup_enum_by_nr(texture)); + + if (texUnit >= k) { + _mesa_error(ctx, GL_INVALID_ENUM, "glActiveTexture(texture=%s)", + _mesa_lookup_enum_by_nr(texture)); + return; + } + + if (ctx->Texture.CurrentUnit == texUnit) + return; + + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + + ctx->Texture.CurrentUnit = texUnit; + if (ctx->Transform.MatrixMode == GL_TEXTURE) { + /* update current stack pointer */ + ctx->CurrentStack = &ctx->TextureMatrixStack[texUnit]; + } +} + + +/* GL_ARB_multitexture */ +void GLAPIENTRY +_mesa_ClientActiveTextureARB(GLenum texture) +{ + GET_CURRENT_CONTEXT(ctx); + GLuint texUnit = texture - GL_TEXTURE0; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glClientActiveTexture %s\n", + _mesa_lookup_enum_by_nr(texture)); + + if (texUnit >= ctx->Const.MaxTextureCoordUnits) { + _mesa_error(ctx, GL_INVALID_ENUM, "glClientActiveTexture(texture)"); + return; + } + + if (ctx->Array.ActiveTexture == texUnit) + return; + + FLUSH_VERTICES(ctx, _NEW_ARRAY); + ctx->Array.ActiveTexture = texUnit; +} + + + +/**********************************************************************/ +/***** State management *****/ +/**********************************************************************/ + + +/** + * \note This routine refers to derived texture attribute values to + * compute the ENABLE_TEXMAT flags, but is only called on + * _NEW_TEXTURE_MATRIX. On changes to _NEW_TEXTURE, the ENABLE_TEXMAT + * flags are updated by _mesa_update_textures(), below. + * + * \param ctx GL context. + */ +static void +update_texture_matrices( struct gl_context *ctx ) +{ + GLuint u; + + ctx->Texture._TexMatEnabled = 0x0; + + for (u = 0; u < ctx->Const.MaxTextureCoordUnits; u++) { + ASSERT(u < Elements(ctx->TextureMatrixStack)); + if (_math_matrix_is_dirty(ctx->TextureMatrixStack[u].Top)) { + _math_matrix_analyse( ctx->TextureMatrixStack[u].Top ); + + if (ctx->Texture.Unit[u]._ReallyEnabled && + ctx->TextureMatrixStack[u].Top->type != MATRIX_IDENTITY) + ctx->Texture._TexMatEnabled |= ENABLE_TEXMAT(u); + } + } +} + + +/** + * Examine texture unit's combine/env state to update derived state. + */ +static void +update_tex_combine(struct gl_context *ctx, struct gl_texture_unit *texUnit) +{ + struct gl_tex_env_combine_state *combine; + + /* Set the texUnit->_CurrentCombine field to point to the user's combiner + * state, or the combiner state which is derived from traditional texenv + * mode. + */ + if (texUnit->EnvMode == GL_COMBINE || + texUnit->EnvMode == GL_COMBINE4_NV) { + texUnit->_CurrentCombine = & texUnit->Combine; + } + else { + const struct gl_texture_object *texObj = texUnit->_Current; + GLenum format = texObj->Image[0][texObj->BaseLevel]->_BaseFormat; + if (format == GL_COLOR_INDEX) { + format = GL_RGBA; /* a bit of a hack */ + } + else if (format == GL_DEPTH_COMPONENT || + format == GL_DEPTH_STENCIL_EXT) { + format = texObj->DepthMode; + } + calculate_derived_texenv(&texUnit->_EnvMode, texUnit->EnvMode, format); + texUnit->_CurrentCombine = & texUnit->_EnvMode; + } + + combine = texUnit->_CurrentCombine; + + /* Determine number of source RGB terms in the combiner function */ + switch (combine->ModeRGB) { + case GL_REPLACE: + combine->_NumArgsRGB = 1; + break; + case GL_ADD: + case GL_ADD_SIGNED: + if (texUnit->EnvMode == GL_COMBINE4_NV) + combine->_NumArgsRGB = 4; + else + combine->_NumArgsRGB = 2; + break; + case GL_MODULATE: + case GL_SUBTRACT: + case GL_DOT3_RGB: + case GL_DOT3_RGBA: + case GL_DOT3_RGB_EXT: + case GL_DOT3_RGBA_EXT: + combine->_NumArgsRGB = 2; + break; + case GL_INTERPOLATE: + case GL_MODULATE_ADD_ATI: + case GL_MODULATE_SIGNED_ADD_ATI: + case GL_MODULATE_SUBTRACT_ATI: + combine->_NumArgsRGB = 3; + break; + case GL_BUMP_ENVMAP_ATI: + /* no real arguments for this case */ + combine->_NumArgsRGB = 0; + break; + default: + combine->_NumArgsRGB = 0; + _mesa_problem(ctx, "invalid RGB combine mode in update_texture_state"); + return; + } + + /* Determine number of source Alpha terms in the combiner function */ + switch (combine->ModeA) { + case GL_REPLACE: + combine->_NumArgsA = 1; + break; + case GL_ADD: + case GL_ADD_SIGNED: + if (texUnit->EnvMode == GL_COMBINE4_NV) + combine->_NumArgsA = 4; + else + combine->_NumArgsA = 2; + break; + case GL_MODULATE: + case GL_SUBTRACT: + combine->_NumArgsA = 2; + break; + case GL_INTERPOLATE: + case GL_MODULATE_ADD_ATI: + case GL_MODULATE_SIGNED_ADD_ATI: + case GL_MODULATE_SUBTRACT_ATI: + combine->_NumArgsA = 3; + break; + default: + combine->_NumArgsA = 0; + _mesa_problem(ctx, "invalid Alpha combine mode in update_texture_state"); + break; + } +} + + +/** + * \note This routine refers to derived texture matrix values to + * compute the ENABLE_TEXMAT flags, but is only called on + * _NEW_TEXTURE. On changes to _NEW_TEXTURE_MATRIX, the ENABLE_TEXMAT + * flags are updated by _mesa_update_texture_matrices, above. + * + * \param ctx GL context. + */ +static void +update_texture_state( struct gl_context *ctx ) +{ + GLuint unit; + struct gl_fragment_program *fprog = NULL; + struct gl_vertex_program *vprog = NULL; + GLbitfield enabledFragUnits = 0x0; + + if (ctx->Shader.CurrentVertexProgram && + ctx->Shader.CurrentVertexProgram->LinkStatus) { + vprog = ctx->Shader.CurrentVertexProgram->VertexProgram; + } else if (ctx->VertexProgram._Enabled) { + /* XXX enable this if/when non-shader vertex programs get + * texture fetches: + vprog = ctx->VertexProgram.Current; + */ + } + + if (ctx->Shader.CurrentFragmentProgram && + ctx->Shader.CurrentFragmentProgram->LinkStatus) { + fprog = ctx->Shader.CurrentFragmentProgram->FragmentProgram; + } + else if (ctx->FragmentProgram._Enabled) { + fprog = ctx->FragmentProgram.Current; + } + + /* FINISHME: Geometry shader texture accesses should also be considered + * FINISHME: here. + */ + + /* TODO: only set this if there are actual changes */ + ctx->NewState |= _NEW_TEXTURE; + + ctx->Texture._EnabledUnits = 0x0; + ctx->Texture._GenFlags = 0x0; + ctx->Texture._TexMatEnabled = 0x0; + ctx->Texture._TexGenEnabled = 0x0; + + /* + * Update texture unit state. + */ + for (unit = 0; unit < ctx->Const.MaxCombinedTextureImageUnits; unit++) { + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + GLbitfield enabledVertTargets = 0x0; + GLbitfield enabledFragTargets = 0x0; + GLbitfield enabledTargets = 0x0; + GLuint texIndex; + + /* Get the bitmask of texture target enables. + * enableBits will be a mask of the TEXTURE_*_BIT flags indicating + * which texture targets are enabled (fixed function) or referenced + * by a fragment program/program. When multiple flags are set, we'll + * settle on the one with highest priority (see below). + */ + if (vprog) { + enabledVertTargets |= vprog->Base.TexturesUsed[unit]; + } + + if (fprog) { + enabledFragTargets |= fprog->Base.TexturesUsed[unit]; + } + else { + /* fixed-function fragment program */ + enabledFragTargets |= texUnit->Enabled; + } + + enabledTargets = enabledVertTargets | enabledFragTargets; + + texUnit->_ReallyEnabled = 0x0; + + if (enabledTargets == 0x0) { + /* neither vertex nor fragment processing uses this unit */ + continue; + } + + /* Look for the highest priority texture target that's enabled (or used + * by the vert/frag shaders) and "complete". That's the one we'll use + * for texturing. If we're using vert/frag program we're guaranteed + * that bitcount(enabledBits) <= 1. + * Note that the TEXTURE_x_INDEX values are in high to low priority. + */ + for (texIndex = 0; texIndex < NUM_TEXTURE_TARGETS; texIndex++) { + if (enabledTargets & (1 << texIndex)) { + struct gl_texture_object *texObj = texUnit->CurrentTex[texIndex]; + if (!texObj->_Complete) { + _mesa_test_texobj_completeness(ctx, texObj); + } + if (texObj->_Complete) { + texUnit->_ReallyEnabled = 1 << texIndex; + _mesa_reference_texobj(&texUnit->_Current, texObj); + break; + } + } + } + + if (!texUnit->_ReallyEnabled) { + if (fprog) { + /* If we get here it means the shader is expecting a texture + * object, but there isn't one (or it's incomplete). Use the + * fallback texture. + */ + struct gl_texture_object *texObj = _mesa_get_fallback_texture(ctx); + texUnit->_ReallyEnabled = 1 << TEXTURE_2D_INDEX; + _mesa_reference_texobj(&texUnit->_Current, texObj); + } + else { + /* fixed-function: texture unit is really disabled */ + continue; + } + } + + /* if we get here, we know this texture unit is enabled */ + + ctx->Texture._EnabledUnits |= (1 << unit); + + if (enabledFragTargets) + enabledFragUnits |= (1 << unit); + + update_tex_combine(ctx, texUnit); + } + + + /* Determine which texture coordinate sets are actually needed */ + if (fprog) { + const GLuint coordMask = (1 << MAX_TEXTURE_COORD_UNITS) - 1; + ctx->Texture._EnabledCoordUnits + = (fprog->Base.InputsRead >> FRAG_ATTRIB_TEX0) & coordMask; + } + else { + ctx->Texture._EnabledCoordUnits = enabledFragUnits; + } + + /* Setup texgen for those texture coordinate sets that are in use */ + for (unit = 0; unit < ctx->Const.MaxTextureCoordUnits; unit++) { + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + + texUnit->_GenFlags = 0x0; + + if (!(ctx->Texture._EnabledCoordUnits & (1 << unit))) + continue; + + if (texUnit->TexGenEnabled) { + if (texUnit->TexGenEnabled & S_BIT) { + texUnit->_GenFlags |= texUnit->GenS._ModeBit; + } + if (texUnit->TexGenEnabled & T_BIT) { + texUnit->_GenFlags |= texUnit->GenT._ModeBit; + } + if (texUnit->TexGenEnabled & R_BIT) { + texUnit->_GenFlags |= texUnit->GenR._ModeBit; + } + if (texUnit->TexGenEnabled & Q_BIT) { + texUnit->_GenFlags |= texUnit->GenQ._ModeBit; + } + + ctx->Texture._TexGenEnabled |= ENABLE_TEXGEN(unit); + ctx->Texture._GenFlags |= texUnit->_GenFlags; + } + + ASSERT(unit < Elements(ctx->TextureMatrixStack)); + if (ctx->TextureMatrixStack[unit].Top->type != MATRIX_IDENTITY) + ctx->Texture._TexMatEnabled |= ENABLE_TEXMAT(unit); + } +} + + +/** + * Update texture-related derived state. + */ +void +_mesa_update_texture( struct gl_context *ctx, GLuint new_state ) +{ + if (new_state & _NEW_TEXTURE_MATRIX) + update_texture_matrices( ctx ); + + if (new_state & (_NEW_TEXTURE | _NEW_PROGRAM)) + update_texture_state( ctx ); +} + + +/**********************************************************************/ +/***** Initialization *****/ +/**********************************************************************/ + +/** + * Allocate the proxy textures for the given context. + * + * \param ctx the context to allocate proxies for. + * + * \return GL_TRUE on success, or GL_FALSE on failure + * + * If run out of memory part way through the allocations, clean up and return + * GL_FALSE. + */ +static GLboolean +alloc_proxy_textures( struct gl_context *ctx ) +{ + static const GLenum targets[] = { + GL_TEXTURE_1D, + GL_TEXTURE_2D, + GL_TEXTURE_3D, + GL_TEXTURE_CUBE_MAP_ARB, + GL_TEXTURE_RECTANGLE_NV, + GL_TEXTURE_1D_ARRAY_EXT, + GL_TEXTURE_2D_ARRAY_EXT + }; + GLint tgt; + + ASSERT(Elements(targets) == NUM_TEXTURE_TARGETS); + + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + if (!(ctx->Texture.ProxyTex[tgt] + = ctx->Driver.NewTextureObject(ctx, 0, targets[tgt]))) { + /* out of memory, free what we did allocate */ + while (--tgt >= 0) { + ctx->Driver.DeleteTexture(ctx, ctx->Texture.ProxyTex[tgt]); + } + return GL_FALSE; + } + } + + assert(ctx->Texture.ProxyTex[0]->RefCount == 1); /* sanity check */ + return GL_TRUE; +} + + +/** + * Initialize a texture unit. + * + * \param ctx GL context. + * \param unit texture unit number to be initialized. + */ +static void +init_texture_unit( struct gl_context *ctx, GLuint unit ) +{ + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + GLuint tex; + + texUnit->EnvMode = GL_MODULATE; + ASSIGN_4V( texUnit->EnvColor, 0.0, 0.0, 0.0, 0.0 ); + + texUnit->Combine = default_combine_state; + texUnit->_EnvMode = default_combine_state; + texUnit->_CurrentCombine = & texUnit->_EnvMode; + texUnit->BumpTarget = GL_TEXTURE0; + + texUnit->TexGenEnabled = 0x0; + texUnit->GenS.Mode = GL_EYE_LINEAR; + texUnit->GenT.Mode = GL_EYE_LINEAR; + texUnit->GenR.Mode = GL_EYE_LINEAR; + texUnit->GenQ.Mode = GL_EYE_LINEAR; + texUnit->GenS._ModeBit = TEXGEN_EYE_LINEAR; + texUnit->GenT._ModeBit = TEXGEN_EYE_LINEAR; + texUnit->GenR._ModeBit = TEXGEN_EYE_LINEAR; + texUnit->GenQ._ModeBit = TEXGEN_EYE_LINEAR; + + /* Yes, these plane coefficients are correct! */ + ASSIGN_4V( texUnit->GenS.ObjectPlane, 1.0, 0.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenT.ObjectPlane, 0.0, 1.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenR.ObjectPlane, 0.0, 0.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenQ.ObjectPlane, 0.0, 0.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenS.EyePlane, 1.0, 0.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenT.EyePlane, 0.0, 1.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenR.EyePlane, 0.0, 0.0, 0.0, 0.0 ); + ASSIGN_4V( texUnit->GenQ.EyePlane, 0.0, 0.0, 0.0, 0.0 ); + + /* no mention of this in spec, but maybe id matrix expected? */ + ASSIGN_4V( texUnit->RotMatrix, 1.0, 0.0, 0.0, 1.0 ); + + /* initialize current texture object ptrs to the shared default objects */ + for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { + _mesa_reference_texobj(&texUnit->CurrentTex[tex], + ctx->Shared->DefaultTex[tex]); + } +} + + +/** + * Initialize texture state for the given context. + */ +GLboolean +_mesa_init_texture(struct gl_context *ctx) +{ + GLuint u; + + /* Texture group */ + ctx->Texture.CurrentUnit = 0; /* multitexture */ + ctx->Texture._EnabledUnits = 0x0; + ctx->Texture.SharedPalette = GL_FALSE; + _mesa_init_colortable(&ctx->Texture.Palette); + + for (u = 0; u < Elements(ctx->Texture.Unit); u++) + init_texture_unit(ctx, u); + + /* After we're done initializing the context's texture state the default + * texture objects' refcounts should be at least + * MAX_COMBINED_TEXTURE_IMAGE_UNITS + 1. + */ + assert(ctx->Shared->DefaultTex[TEXTURE_1D_INDEX]->RefCount + >= MAX_COMBINED_TEXTURE_IMAGE_UNITS + 1); + + /* Allocate proxy textures */ + if (!alloc_proxy_textures( ctx )) + return GL_FALSE; + + return GL_TRUE; +} + + +/** + * Free dynamically-allocted texture data attached to the given context. + */ +void +_mesa_free_texture_data(struct gl_context *ctx) +{ + GLuint u, tgt; + + /* unreference current textures */ + for (u = 0; u < Elements(ctx->Texture.Unit); u++) { + /* The _Current texture could account for another reference */ + _mesa_reference_texobj(&ctx->Texture.Unit[u]._Current, NULL); + + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + _mesa_reference_texobj(&ctx->Texture.Unit[u].CurrentTex[tgt], NULL); + } + } + + /* Free proxy texture objects */ + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) + ctx->Driver.DeleteTexture(ctx, ctx->Texture.ProxyTex[tgt]); +} + + +/** + * Update the default texture objects in the given context to reference those + * specified in the shared state and release those referencing the old + * shared state. + */ +void +_mesa_update_default_objects_texture(struct gl_context *ctx) +{ + GLuint u, tex; + + for (u = 0; u < Elements(ctx->Texture.Unit); u++) { + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[u]; + for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { + _mesa_reference_texobj(&texUnit->CurrentTex[tex], + ctx->Shared->DefaultTex[tex]); + } + } +} diff --git a/mesalib/src/mesa/main/texstore.c b/mesalib/src/mesa/main/texstore.c index 8a3e5f779..cd30fa021 100644 --- a/mesalib/src/mesa/main/texstore.c +++ b/mesalib/src/mesa/main/texstore.c @@ -61,6 +61,7 @@ #include "mfeatures.h" #include "mtypes.h" #include "pack.h" +#include "pbo.h" #include "imports.h" #include "pack.h" #include "texcompress.h" @@ -4200,94 +4201,6 @@ _mesa_texstore(TEXSTORE_PARAMS) } -/** - * Check if an unpack PBO is active prior to fetching a texture image. - * If so, do bounds checking and map the buffer into main memory. - * Any errors detected will be recorded. - * The caller _must_ call _mesa_unmap_teximage_pbo() too! - */ -const GLvoid * -_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *pixels, - const struct gl_pixelstore_attrib *unpack, - const char *funcName) -{ - GLubyte *buf; - - if (!_mesa_is_bufferobj(unpack->BufferObj)) { - /* no PBO */ - return pixels; - } - if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, - format, type, pixels)) { - _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)"); - return NULL; - } - - buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - GL_READ_ONLY_ARB, unpack->BufferObj); - if (!buf) { - _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped)"); - return NULL; - } - - return ADD_POINTERS(buf, pixels); -} - - -/** - * Check if an unpack PBO is active prior to fetching a compressed texture - * image. - * If so, do bounds checking and map the buffer into main memory. - * Any errors detected will be recorded. - * The caller _must_ call _mesa_unmap_teximage_pbo() too! - */ -const GLvoid * -_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx, - GLsizei imageSize, const GLvoid *pixels, - const struct gl_pixelstore_attrib *packing, - const char *funcName) -{ - GLubyte *buf; - - if (!_mesa_is_bufferobj(packing->BufferObj)) { - /* not using a PBO - return pointer unchanged */ - return pixels; - } - if ((const GLubyte *) pixels + imageSize > - ((const GLubyte *) 0) + packing->BufferObj->Size) { - /* out of bounds read! */ - _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access)"); - return NULL; - } - - buf = (GLubyte*) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - GL_READ_ONLY_ARB, packing->BufferObj); - if (!buf) { - _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped"); - return NULL; - } - - return ADD_POINTERS(buf, pixels); -} - - -/** - * This function must be called after either of the validate_pbo_*_teximage() - * functions. It unmaps the PBO buffer if it was mapped earlier. - */ -void -_mesa_unmap_teximage_pbo(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack) -{ - if (_mesa_is_bufferobj(unpack->BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, - unpack->BufferObj); - } -} - - /** Return texture size in bytes */ static GLuint texture_size(const struct gl_texture_image *texImage) diff --git a/mesalib/src/mesa/main/texstore.h b/mesalib/src/mesa/main/texstore.h index 2f3c4e821..d56318709 100644 --- a/mesalib/src/mesa/main/texstore.h +++ b/mesalib/src/mesa/main/texstore.h @@ -206,22 +206,4 @@ _mesa_store_compressed_texsubimage3d(struct gl_context *ctx, GLenum target, struct gl_texture_image *texImage); -extern const GLvoid * -_mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *pixels, - const struct gl_pixelstore_attrib *unpack, - const char *funcName); - -extern const GLvoid * -_mesa_validate_pbo_compressed_teximage(struct gl_context *ctx, - GLsizei imageSize, const GLvoid *pixels, - const struct gl_pixelstore_attrib *packing, - const char *funcName); - -extern void -_mesa_unmap_teximage_pbo(struct gl_context *ctx, - const struct gl_pixelstore_attrib *unpack); - - #endif |