/** * 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(GLcontext *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: if (ctx->Color.BlendEnabled == state) return; FLUSH_VERTICES(ctx, _NEW_COLOR); ctx->Color.BlendEnabled = state; 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_CULL_VERTEX_EXT: CHECK_EXTENSION(EXT_cull_vertex, cap); if (ctx->Transform.CullVertexFlag == state) return; FLUSH_VERTICES(ctx, _NEW_TRANSFORM); ctx->Transform.CullVertexFlag = 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->NoDither) { state = GL_FALSE; /* MESA_NO_DITHER env var */ } 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_HISTOGRAM: CHECK_EXTENSION(EXT_histogram, cap); if (ctx->Pixel.HistogramEnabled == state) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.HistogramEnabled = 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_MINMAX: if (ctx->Pixel.MinMaxEnabled == state) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.MinMaxEnabled = 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; /* * 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_color_table */ case GL_COLOR_TABLE_SGI: CHECK_EXTENSION(SGI_color_table, cap); if (ctx->Pixel.ColorTableEnabled[COLORTABLE_PRECONVOLUTION] == state) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.ColorTableEnabled[COLORTABLE_PRECONVOLUTION] = state; break; case GL_POST_CONVOLUTION_COLOR_TABLE_SGI: CHECK_EXTENSION(SGI_color_table, cap); if (ctx->Pixel.ColorTableEnabled[COLORTABLE_POSTCONVOLUTION] == state) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.ColorTableEnabled[COLORTABLE_POSTCONVOLUTION] = state; break; case GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI: CHECK_EXTENSION(SGI_color_table, cap); if (ctx->Pixel.ColorTableEnabled[COLORTABLE_POSTCOLORMATRIX] == state) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.ColorTableEnabled[COLORTABLE_POSTCOLORMATRIX] = state; break; 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_EXT_convolution */ case GL_CONVOLUTION_1D: CHECK_EXTENSION(EXT_convolution, cap); if (ctx->Pixel.Convolution1DEnabled == state) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.Convolution1DEnabled = state; break; case GL_CONVOLUTION_2D: CHECK_EXTENSION(EXT_convolution, cap); if (ctx->Pixel.Convolution2DEnabled == state) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.Convolution2DEnabled = state; break; case GL_SEPARABLE_2D: CHECK_EXTENSION(EXT_convolution, cap); if (ctx->Pixel.Separable2DEnabled == state) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.Separable2DEnabled = 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; default: _mesa_error(ctx, GL_INVALID_ENUM, "%s(0x%x)", state ? "glEnable" : "glDisable", cap); return; } if (ctx->Driver.Enable) { ctx->Driver.Enable( ctx, cap, state ); } }
void GLAPIENTRY _mesa_BeginQueryARB(GLenum target, GLuint id) { struct gl_query_object *q; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); FLUSH_VERTICES(ctx, _NEW_DEPTH); switch (target) { case GL_SAMPLES_PASSED_ARB: if (!ctx->Extensions.ARB_occlusion_query) { _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)"); return; } if (ctx->Query.CurrentOcclusionObject) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB"); return; } break; #if FEATURE_EXT_timer_query case GL_TIME_ELAPSED_EXT: if (!ctx->Extensions.EXT_timer_query) { _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)"); return; } if (ctx->Query.CurrentTimerObject) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB"); return; } break; #endif default: _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)"); return; } if (id == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(id==0)"); return; } q = lookup_query_object(ctx, id); if (!q) { /* create new object */ q = ctx->Driver.NewQueryObject(ctx, id); if (!q) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQueryARB"); return; } _mesa_HashInsert(ctx->Query.QueryObjects, id, q); } else { /* pre-existing object */ if (q->Active) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(query already active)"); return; } } q->Active = GL_TRUE; q->Result = 0; q->Ready = GL_FALSE; if (target == GL_SAMPLES_PASSED_ARB) { ctx->Query.CurrentOcclusionObject = q; } #if FEATURE_EXT_timer_query else if (target == GL_TIME_ELAPSED_EXT) { ctx->Query.CurrentTimerObject = q; } #endif if (ctx->Driver.BeginQuery) { ctx->Driver.BeginQuery(ctx, target, q); } }
/** * Called by glUniformMatrix*() functions. * Note: cols=2, rows=4 ==> array[2] of vec4 */ extern "C" void _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg, GLuint cols, GLuint rows, GLint location, GLsizei count, GLboolean transpose, const GLfloat *values) { unsigned loc, offset; unsigned vectors; unsigned components; unsigned elements; struct gl_uniform_storage *uni; ASSERT_OUTSIDE_BEGIN_END(ctx); if (!validate_uniform_parameters(ctx, shProg, location, count, &loc, &offset, "glUniformMatrix", false)) return; uni = &shProg->UniformStorage[loc]; if (!uni->type->is_matrix()) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(non-matrix uniform)"); return; } assert(!uni->type->is_sampler()); vectors = uni->type->matrix_columns; components = uni->type->vector_elements; /* Verify that the types are compatible. This is greatly simplified for * matrices because they can only have a float base type. */ if (vectors != cols || components != rows) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(matrix size mismatch)"); return; } if (ctx->Shader.Flags & GLSL_UNIFORMS) { log_uniform(values, GLSL_TYPE_FLOAT, components, vectors, count, bool(transpose), shProg, location, uni); } /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: * * "When loading N elements starting at an arbitrary position k in a * uniform declared as an array, elements k through k + N - 1 in the * array will be replaced with the new values. Values for any array * element that exceeds the highest array element index used, as * reported by GetActiveUniform, will be ignored by the GL." * * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 * will have already generated an error. */ if (uni->array_elements != 0) { if (offset >= uni->array_elements) return; count = MIN2(count, (int) (uni->array_elements - offset)); } FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); /* Store the data in the "actual type" backing storage for the uniform. */ elements = components * vectors; if (!transpose) { memcpy(&uni->storage[elements * offset], values, sizeof(uni->storage[0]) * elements * count); } else { /* Copy and transpose the matrix. */ const float *src = values; float *dst = &uni->storage[elements * offset].f; for (int i = 0; i < count; i++) { for (unsigned r = 0; r < rows; r++) { for (unsigned c = 0; c < cols; c++) { dst[(c * components) + r] = src[c + (r * vectors)]; } } dst += elements; src += elements; } } uni->initialized = true; _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); }
/** * Called via ctx->Driver.Uniform(). */ void _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, const GLvoid *values, GLenum type) { struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; GLint elems, i, k; GLenum uType; GLsizei maxCount; if (!shProg || !shProg->LinkStatus) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)"); return; } if (location == -1) return; /* The standard specifies this as a no-op */ /* The spec says this is GL_INVALID_OPERATION, although it seems like it * ought to be GL_INVALID_VALUE */ if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)"); return; } FLUSH_VERTICES(ctx, _NEW_PROGRAM); uType = shProg->Uniforms->Parameters[location].DataType; /* * If we're setting a sampler, we must use glUniformi1()! */ if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) { GLint unit; if (type != GL_INT || count != 1) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(only glUniform1i can be used " "to set sampler uniforms)"); return; } /* check that the sampler (tex unit index) is legal */ unit = ((GLint *) values)[0]; if (unit >= ctx->Const.MaxTextureImageUnits) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniform1(invalid sampler/tex unit index)"); return; } } if (count < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)"); return; } switch (type) { case GL_FLOAT: case GL_INT: elems = 1; break; case GL_FLOAT_VEC2: case GL_INT_VEC2: elems = 2; break; case GL_FLOAT_VEC3: case GL_INT_VEC3: elems = 3; break; case GL_FLOAT_VEC4: case GL_INT_VEC4: elems = 4; break; default: _mesa_problem(ctx, "Invalid type in _mesa_uniform"); return; } /* OpenGL requires types to match exactly, except that one can convert * float or int array to boolean array. */ switch (uType) { case GL_BOOL: case GL_BOOL_VEC2: case GL_BOOL_VEC3: case GL_BOOL_VEC4: if (elems != sizeof_glsl_type(uType)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count mismatch)"); } break; case PROGRAM_SAMPLER: break; default: if (shProg->Uniforms->Parameters[location].Type != PROGRAM_SAMPLER && uType != type) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)"); } break; } /* XXX if this is a base type, then count must equal 1. However, we * don't have enough information from the compiler to distinguish a * base type from a 1-element array of that type. The standard allows * count to overrun an array, in which case the overflow is ignored. */ maxCount = shProg->Uniforms->Parameters[location].Size / elems; if (count > maxCount) count = maxCount; for (k = 0; k < count; k++) { GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k]; if (type == GL_INT || type == GL_INT_VEC2 || type == GL_INT_VEC3 || type == GL_INT_VEC4) { const GLint *iValues = ((const GLint *) values) + k * elems; for (i = 0; i < elems; i++) { uniformVal[i] = (GLfloat) iValues[i]; } } else { const GLfloat *fValues = ((const GLfloat *) values) + k * elems; for (i = 0; i < elems; i++) { uniformVal[i] = fValues[i]; } } if (uType == GL_BOOL || uType == GL_BOOL_VEC2 || uType == GL_BOOL_VEC3 || uType == GL_BOOL_VEC4) { for (i = 0; i < elems; i++) uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f; } } if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) { if (shProg->VertexProgram) _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base); if (shProg->FragmentProgram) _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base); FLUSH_VERTICES(ctx, _NEW_TEXTURE); } }
void GLAPIENTRY _mesa_Fogfv( GLenum pname, const GLfloat *params ) { GET_CURRENT_CONTEXT(ctx); GLenum m; ASSERT_OUTSIDE_BEGIN_END(ctx); switch (pname) { case GL_FOG_MODE: m = (GLenum) (GLint) *params; switch (m) { case GL_LINEAR: case GL_EXP: case GL_EXP2: break; default: _mesa_error( ctx, GL_INVALID_ENUM, "glFog" ); return; } if (ctx->Fog.Mode == m) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.Mode = m; break; case GL_FOG_DENSITY: if (*params<0.0) { _mesa_error( ctx, GL_INVALID_VALUE, "glFog" ); return; } if (ctx->Fog.Density == *params) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.Density = *params; break; case GL_FOG_START: if (ctx->Fog.Start == *params) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.Start = *params; UPDATE_FOG_SCALE(ctx); break; case GL_FOG_END: if (ctx->Fog.End == *params) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.End = *params; UPDATE_FOG_SCALE(ctx); break; case GL_FOG_INDEX: if (ctx->Fog.Index == *params) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.Index = *params; break; case GL_FOG_COLOR: if (TEST_EQ_4V(ctx->Fog.Color, params)) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.Color[0] = CLAMP(params[0], 0.0F, 1.0F); ctx->Fog.Color[1] = CLAMP(params[1], 0.0F, 1.0F); ctx->Fog.Color[2] = CLAMP(params[2], 0.0F, 1.0F); ctx->Fog.Color[3] = CLAMP(params[3], 0.0F, 1.0F); break; case GL_FOG_COORDINATE_SOURCE_EXT: { GLenum p = (GLenum) (GLint) *params; if (!ctx->Extensions.EXT_fog_coord || (p != GL_FOG_COORDINATE_EXT && p != GL_FRAGMENT_DEPTH_EXT)) { _mesa_error(ctx, GL_INVALID_ENUM, "glFog"); return; } if (ctx->Fog.FogCoordinateSource == p) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.FogCoordinateSource = p; break; } default: _mesa_error( ctx, GL_INVALID_ENUM, "glFog" ); return; } if (ctx->Driver.Fogfv) { (*ctx->Driver.Fogfv)( ctx, pname, params ); } }
/* * Implements glPixelTransfer[fi] whether called immediately or from a * display list. */ 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; case GL_POST_COLOR_MATRIX_RED_SCALE: if (ctx->Pixel.PostColorMatrixScale[0] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostColorMatrixScale[0] = param; break; case GL_POST_COLOR_MATRIX_RED_BIAS: if (ctx->Pixel.PostColorMatrixBias[0] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostColorMatrixBias[0] = param; break; case GL_POST_COLOR_MATRIX_GREEN_SCALE: if (ctx->Pixel.PostColorMatrixScale[1] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostColorMatrixScale[1] = param; break; case GL_POST_COLOR_MATRIX_GREEN_BIAS: if (ctx->Pixel.PostColorMatrixBias[1] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostColorMatrixBias[1] = param; break; case GL_POST_COLOR_MATRIX_BLUE_SCALE: if (ctx->Pixel.PostColorMatrixScale[2] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostColorMatrixScale[2] = param; break; case GL_POST_COLOR_MATRIX_BLUE_BIAS: if (ctx->Pixel.PostColorMatrixBias[2] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostColorMatrixBias[2] = param; break; case GL_POST_COLOR_MATRIX_ALPHA_SCALE: if (ctx->Pixel.PostColorMatrixScale[3] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostColorMatrixScale[3] = param; break; case GL_POST_COLOR_MATRIX_ALPHA_BIAS: if (ctx->Pixel.PostColorMatrixBias[3] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostColorMatrixBias[3] = param; break; case GL_POST_CONVOLUTION_RED_SCALE: if (ctx->Pixel.PostConvolutionScale[0] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostConvolutionScale[0] = param; break; case GL_POST_CONVOLUTION_RED_BIAS: if (ctx->Pixel.PostConvolutionBias[0] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostConvolutionBias[0] = param; break; case GL_POST_CONVOLUTION_GREEN_SCALE: if (ctx->Pixel.PostConvolutionScale[1] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostConvolutionScale[1] = param; break; case GL_POST_CONVOLUTION_GREEN_BIAS: if (ctx->Pixel.PostConvolutionBias[1] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostConvolutionBias[1] = param; break; case GL_POST_CONVOLUTION_BLUE_SCALE: if (ctx->Pixel.PostConvolutionScale[2] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostConvolutionScale[2] = param; break; case GL_POST_CONVOLUTION_BLUE_BIAS: if (ctx->Pixel.PostConvolutionBias[2] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostConvolutionBias[2] = param; break; case GL_POST_CONVOLUTION_ALPHA_SCALE: if (ctx->Pixel.PostConvolutionScale[3] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostConvolutionScale[3] = param; break; case GL_POST_CONVOLUTION_ALPHA_BIAS: if (ctx->Pixel.PostConvolutionBias[3] == param) return; FLUSH_VERTICES(ctx, _NEW_PIXEL); ctx->Pixel.PostConvolutionBias[3] = param; break; default: _mesa_error( ctx, GL_INVALID_ENUM, "glPixelTransfer(pname)" ); return; } }
static bool use_shader_program(struct gl_context *ctx, GLenum type, struct gl_shader_program *shProg) { struct gl_shader_program **target; switch (type) { #if FEATURE_ARB_vertex_shader case GL_VERTEX_SHADER: target = &ctx->Shader.CurrentVertexProgram; if ((shProg == NULL) || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) { shProg = NULL; } break; #endif #if FEATURE_ARB_geometry_shader4 case GL_GEOMETRY_SHADER_ARB: target = &ctx->Shader.CurrentGeometryProgram; if ((shProg == NULL) || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) { shProg = NULL; } break; #endif #if FEATURE_ARB_fragment_shader case GL_FRAGMENT_SHADER: target = &ctx->Shader.CurrentFragmentProgram; if ((shProg == NULL) || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) { shProg = NULL; } break; #endif default: return false; } if (*target != shProg) { FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); /* If the shader is also bound as the current rendering shader, unbind * it from that binding point as well. This ensures that the correct * semantics of glDeleteProgram are maintained. */ switch (type) { #if FEATURE_ARB_vertex_shader case GL_VERTEX_SHADER: /* Empty for now. */ break; #endif #if FEATURE_ARB_geometry_shader4 case GL_GEOMETRY_SHADER_ARB: /* Empty for now. */ break; #endif #if FEATURE_ARB_fragment_shader case GL_FRAGMENT_SHADER: if (*target == ctx->Shader._CurrentFragmentProgram) { _mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram, NULL); } break; #endif } _mesa_reference_shader_program(ctx, target, shProg); return true; } return false; }
/** * Called via glUniform*() functions. */ extern "C" void _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, GLint location, GLsizei count, const GLvoid *values, enum glsl_base_type basicType, unsigned src_components) { unsigned offset; int size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1; struct gl_uniform_storage *const uni = validate_uniform_parameters(ctx, shProg, location, count, &offset, "glUniform"); if (uni == NULL) return; if (uni->type->is_matrix()) { /* Can't set matrix uniforms (like mat4) with glUniform */ _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform%u(uniform \"%s\"@%d is matrix)", src_components, uni->name, location); return; } /* Verify that the types are compatible. */ const unsigned components = uni->type->is_sampler() ? 1 : uni->type->vector_elements; if (components != src_components) { /* glUniformN() must match float/vecN type */ _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform%u(\"%s\"@%u has %u components, not %u)", src_components, uni->name, location, components, src_components); return; } bool match; switch (uni->type->base_type) { case GLSL_TYPE_BOOL: match = (basicType != GLSL_TYPE_DOUBLE); break; case GLSL_TYPE_SAMPLER: case GLSL_TYPE_IMAGE: match = (basicType == GLSL_TYPE_INT); break; default: match = (basicType == uni->type->base_type); break; } if (!match) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform%u(\"%s\"@%d is %s, not %s)", src_components, uni->name, location, glsl_type_name(uni->type->base_type), glsl_type_name(basicType)); return; } if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) { log_uniform(values, basicType, components, 1, count, false, shProg, location, uni); } /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says: * * "Setting a sampler's value to i selects texture image unit number * i. The values of i range from zero to the implementation- dependent * maximum supported number of texture image units." * * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of * the PDF) says: * * "Error Description Offending command * ignored? * ... * INVALID_VALUE Numeric argument out of range Yes" * * Based on that, when an invalid sampler is specified, we generate a * GL_INVALID_VALUE error and ignore the command. */ if (uni->type->is_sampler()) { for (int i = 0; i < count; i++) { const unsigned texUnit = ((unsigned *) values)[i]; /* check that the sampler (tex unit index) is legal */ if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniform1i(invalid sampler/tex unit index for " "uniform %d)", location); return; } } } if (uni->type->is_image()) { for (int i = 0; i < count; i++) { const int unit = ((GLint *) values)[i]; /* check that the image unit is legal */ if (unit < 0 || unit >= (int)ctx->Const.MaxImageUnits) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniform1i(invalid image unit index for uniform %d)", location); return; } } } /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: * * "When loading N elements starting at an arbitrary position k in a * uniform declared as an array, elements k through k + N - 1 in the * array will be replaced with the new values. Values for any array * element that exceeds the highest array element index used, as * reported by GetActiveUniform, will be ignored by the GL." * * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 * will have already generated an error. */ if (uni->array_elements != 0) { count = MIN2(count, (int) (uni->array_elements - offset)); } FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); /* Store the data in the "actual type" backing storage for the uniform. */ if (!uni->type->is_boolean()) { memcpy(&uni->storage[size_mul * components * offset], values, sizeof(uni->storage[0]) * components * count * size_mul); } else { const union gl_constant_value *src = (const union gl_constant_value *) values; union gl_constant_value *dst = &uni->storage[components * offset]; const unsigned elems = components * count; for (unsigned i = 0; i < elems; i++) { if (basicType == GLSL_TYPE_FLOAT) { dst[i].i = src[i].f != 0.0f ? ctx->Const.UniformBooleanTrue : 0; } else { dst[i].i = src[i].i != 0 ? ctx->Const.UniformBooleanTrue : 0; } } } uni->initialized = true; _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); /* If the uniform is a sampler, do the extra magic necessary to propagate * the changes through. */ if (uni->type->is_sampler()) { bool flushed = false; for (int i = 0; i < MESA_SHADER_STAGES; i++) { struct gl_shader *const sh = shProg->_LinkedShaders[i]; /* If the shader stage doesn't use the sampler uniform, skip this. */ if (sh == NULL || !uni->sampler[i].active) continue; for (int j = 0; j < count; j++) { sh->SamplerUnits[uni->sampler[i].index + offset + j] = ((unsigned *) values)[j]; } struct gl_program *const prog = sh->Program; assert(sizeof(prog->SamplerUnits) == sizeof(sh->SamplerUnits)); /* Determine if any of the samplers used by this shader stage have * been modified. */ bool changed = false; for (unsigned j = 0; j < ARRAY_SIZE(prog->SamplerUnits); j++) { if ((sh->active_samplers & (1U << j)) != 0 && (prog->SamplerUnits[j] != sh->SamplerUnits[j])) { changed = true; break; } } if (changed) { if (!flushed) { FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM); flushed = true; } memcpy(prog->SamplerUnits, sh->SamplerUnits, sizeof(sh->SamplerUnits)); _mesa_update_shader_textures_used(shProg, prog); if (ctx->Driver.SamplerUniformChange) ctx->Driver.SamplerUniformChange(ctx, prog->Target, prog); } } } /* If the uniform is an image, update the mapping from image * uniforms to image units present in the shader data structure. */ if (uni->type->is_image()) { for (int i = 0; i < MESA_SHADER_STAGES; i++) { if (uni->image[i].active) { struct gl_shader *sh = shProg->_LinkedShaders[i]; for (int j = 0; j < count; j++) sh->ImageUnits[uni->image[i].index + offset + j] = ((GLint *) values)[j]; } } ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits; } }
/** * Called by glUniformMatrix*() functions. * Note: cols=2, rows=4 ==> array[2] of vec4 */ extern "C" void _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg, GLuint cols, GLuint rows, GLint location, GLsizei count, GLboolean transpose, const GLvoid *values, GLenum type) { unsigned offset; unsigned vectors; unsigned components; unsigned elements; int size_mul; struct gl_uniform_storage *const uni = validate_uniform_parameters(ctx, shProg, location, count, &offset, "glUniformMatrix"); if (uni == NULL) return; if (!uni->type->is_matrix()) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(non-matrix uniform)"); return; } assert(type == GL_FLOAT || type == GL_DOUBLE); size_mul = type == GL_DOUBLE ? 2 : 1; assert(!uni->type->is_sampler()); vectors = uni->type->matrix_columns; components = uni->type->vector_elements; /* Verify that the types are compatible. This is greatly simplified for * matrices because they can only have a float base type. */ if (vectors != cols || components != rows) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(matrix size mismatch)"); return; } /* GL_INVALID_VALUE is generated if `transpose' is not GL_FALSE. * http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml */ if (transpose) { if (ctx->API == API_OPENGLES2 && ctx->Version < 30) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(matrix transpose is not GL_FALSE)"); return; } } if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) { log_uniform(values, uni->type->base_type, components, vectors, count, bool(transpose), shProg, location, uni); } /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: * * "When loading N elements starting at an arbitrary position k in a * uniform declared as an array, elements k through k + N - 1 in the * array will be replaced with the new values. Values for any array * element that exceeds the highest array element index used, as * reported by GetActiveUniform, will be ignored by the GL." * * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 * will have already generated an error. */ if (uni->array_elements != 0) { count = MIN2(count, (int) (uni->array_elements - offset)); } FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); /* Store the data in the "actual type" backing storage for the uniform. */ elements = components * vectors; if (!transpose) { memcpy(&uni->storage[elements * offset], values, sizeof(uni->storage[0]) * elements * count * size_mul); } else if (type == GL_FLOAT) { /* Copy and transpose the matrix. */ const float *src = (const float *)values; float *dst = &uni->storage[elements * offset].f; for (int i = 0; i < count; i++) { for (unsigned r = 0; r < rows; r++) { for (unsigned c = 0; c < cols; c++) { dst[(c * components) + r] = src[c + (r * vectors)]; } } dst += elements; src += elements; } } else { assert(type == GL_DOUBLE); const double *src = (const double *)values; double *dst = (double *)&uni->storage[elements * offset].f; for (int i = 0; i < count; i++) { for (unsigned r = 0; r < rows; r++) { for (unsigned c = 0; c < cols; c++) { dst[(c * components) + r] = src[c + (r * vectors)]; } } dst += elements; src += elements; } } uni->initialized = true; _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); }
/** * Load/parse/compile a program. * \note Called from the GL API dispatcher. */ void GLAPIENTRY _mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len, const GLubyte *program) { struct gl_program *prog; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (!ctx->Extensions.NV_vertex_program && !ctx->Extensions.NV_fragment_program) { _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV()"); return; } if (id == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)"); return; } if (len < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(len)"); return; } FLUSH_VERTICES(ctx, _NEW_PROGRAM); prog = _mesa_lookup_program(ctx, id); if (prog && prog->Target != 0 && prog->Target != target) { _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)"); return; } if ((target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_STATE_PROGRAM_NV) && ctx->Extensions.NV_vertex_program) { struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog; if (!vprog || prog == &_mesa_DummyProgram) { vprog = (struct gl_vertex_program *) ctx->Driver.NewProgram(ctx, target, id); if (!vprog) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); return; } _mesa_HashInsert(ctx->Shared->Programs, id, vprog); } if (ctx->Extensions.ARB_vertex_program && (strncmp((char *) program, "!!ARB", 5) == 0)) { _mesa_parse_arb_vertex_program(ctx, target, program, len, vprog); } else { _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog); } } else if (target == GL_FRAGMENT_PROGRAM_NV && ctx->Extensions.NV_fragment_program) { struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog; if (!fprog || prog == &_mesa_DummyProgram) { fprog = (struct gl_fragment_program *) ctx->Driver.NewProgram(ctx, target, id); if (!fprog) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); return; } _mesa_HashInsert(ctx->Shared->Programs, id, fprog); } _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog); } else if (target == GL_FRAGMENT_PROGRAM_ARB && ctx->Extensions.ARB_fragment_program) { struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog; if (!fprog || prog == &_mesa_DummyProgram) { fprog = (struct gl_fragment_program *) ctx->Driver.NewProgram(ctx, target, id); if (!fprog) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); return; } _mesa_HashInsert(ctx->Shared->Programs, id, fprog); } _mesa_parse_arb_fragment_program(ctx, target, program, len, fprog); } else { _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)"); } }
/** * Set rasterization mode. * * \param mode rasterization mode. * * \note this function can't be put in a display list. * * \sa glRenderMode(). * * Flushes the vertices and do the necessary cleanup according to the previous * rasterization mode, such as writing the hit record or resent the select * buffer index when exiting the select mode. Updates * __struct gl_contextRec::RenderMode and notifies the driver via the * dd_function_table::RenderMode callback. */ GLint GLAPIENTRY _mesa_RenderMode( GLenum mode ) { GET_CURRENT_CONTEXT(ctx); GLint result; ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glRenderMode %s\n", _mesa_lookup_enum_by_nr(mode)); FLUSH_VERTICES(ctx, _NEW_RENDERMODE); switch (ctx->RenderMode) { case GL_RENDER: result = 0; break; case GL_SELECT: if (ctx->Select.HitFlag) { write_hit_record( ctx ); } if (ctx->Select.BufferCount > ctx->Select.BufferSize) { /* overflow */ #ifdef DEBUG _mesa_warning(ctx, "Feedback buffer overflow"); #endif result = -1; } else { result = ctx->Select.Hits; } ctx->Select.BufferCount = 0; ctx->Select.Hits = 0; ctx->Select.NameStackDepth = 0; break; #if _HAVE_FULL_GL case GL_FEEDBACK: if (ctx->Feedback.Count > ctx->Feedback.BufferSize) { /* overflow */ result = -1; } else { result = ctx->Feedback.Count; } ctx->Feedback.Count = 0; break; #endif default: _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" ); return 0; } switch (mode) { case GL_RENDER: break; case GL_SELECT: if (ctx->Select.BufferSize==0) { /* haven't called glSelectBuffer yet */ _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" ); } break; #if _HAVE_FULL_GL case GL_FEEDBACK: if (ctx->Feedback.BufferSize==0) { /* haven't called glFeedbackBuffer yet */ _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" ); } break; #endif default: _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" ); return 0; } ctx->RenderMode = mode; if (ctx->Driver.RenderMode) ctx->Driver.RenderMode( ctx, mode ); return result; }
void GLAPIENTRY _mesa_BindImageTextures(GLuint first, GLsizei count, const GLuint *textures) { GET_CURRENT_CONTEXT(ctx); int i; if (!ctx->Extensions.ARB_shader_image_load_store) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTextures()"); return; } if (first + count > ctx->Const.MaxImageUnits) { /* The ARB_multi_bind spec says: * * "An INVALID_OPERATION error is generated if <first> + <count> * is greater than the number of image units supported by * the implementation." */ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTextures(first=%u + count=%d > the value of " "GL_MAX_IMAGE_UNITS=%u)", first, count, ctx->Const.MaxImageUnits); return; } /* Assume that at least one binding will be changed */ FLUSH_VERTICES(ctx, 0); ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits; /* Note that the error semantics for multi-bind commands differ from * those of other GL commands. * * The Issues section in the ARB_multi_bind spec says: * * "(11) Typically, OpenGL specifies that if an error is generated by * a command, that command has no effect. This is somewhat * unfortunate for multi-bind commands, because it would require * a first pass to scan the entire list of bound objects for * errors and then a second pass to actually perform the * bindings. Should we have different error semantics? * * RESOLVED: Yes. In this specification, when the parameters for * one of the <count> binding points are invalid, that binding * point is not updated and an error will be generated. However, * other binding points in the same command will be updated if * their parameters are valid and no other error occurs." */ _mesa_begin_texture_lookups(ctx); for (i = 0; i < count; i++) { struct gl_image_unit *u = &ctx->ImageUnits[first + i]; const GLuint texture = textures ? textures[i] : 0; if (texture != 0) { struct gl_texture_object *texObj; GLenum tex_format; if (!u->TexObj || u->TexObj->Name != texture) { texObj = _mesa_lookup_texture_locked(ctx, texture); if (!texObj) { /* The ARB_multi_bind spec says: * * "An INVALID_OPERATION error is generated if any value * in <textures> is not zero or the name of an existing * texture object (per binding)." */ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTextures(textures[%d]=%u " "is not zero or the name of an existing texture " "object)", i, texture); continue; } } else { texObj = u->TexObj; } if (texObj->Target == GL_TEXTURE_BUFFER) { tex_format = texObj->BufferObjectFormat; } else { struct gl_texture_image *image = texObj->Image[0][0]; if (!image || image->Width == 0 || image->Height == 0 || image->Depth == 0) { /* The ARB_multi_bind spec says: * * "An INVALID_OPERATION error is generated if the width, * height, or depth of the level zero texture image of * any texture in <textures> is zero (per binding)." */ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTextures(the width, height or depth " "of the level zero texture image of " "textures[%d]=%u is zero)", i, texture); continue; } tex_format = image->InternalFormat; } if (!is_image_format_supported(ctx, tex_format)) { /* The ARB_multi_bind spec says: * * "An INVALID_OPERATION error is generated if the internal * format of the level zero texture image of any texture * in <textures> is not found in table 8.33 (per binding)." */ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTextures(the internal format %s of " "the level zero texture image of textures[%d]=%u " "is not supported)", _mesa_enum_to_string(tex_format), i, texture); continue; } /* Update the texture binding */ _mesa_reference_texobj(&u->TexObj, texObj); u->Level = 0; u->Layered = _mesa_tex_target_is_layered(texObj->Target); u->_Layer = u->Layer = 0; u->Access = GL_READ_WRITE; u->Format = tex_format; u->_ActualFormat = _mesa_get_shader_image_format(tex_format); } else { /* Unbind the texture from the unit */ _mesa_reference_texobj(&u->TexObj, NULL); u->Level = 0; u->Layered = GL_FALSE; u->_Layer = u->Layer = 0; u->Access = GL_READ_ONLY; u->Format = GL_R8; u->_ActualFormat = MESA_FORMAT_R_UNORM8; } /* Pass the BindImageTexture call down to the device driver */ if (ctx->Driver.BindImageTexture) ctx->Driver.BindImageTexture(ctx, u, u->TexObj, u->Level, u->Layered, u->Layer, u->Access, u->Format); } _mesa_end_texture_lookups(ctx); }
void GLAPIENTRY _mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id) { struct gl_query_object *q, **bindpt; GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n", _mesa_lookup_enum_by_nr(target), index, id); if (!query_error_check_index(ctx, target, index)) return; FLUSH_VERTICES(ctx, 0); bindpt = get_query_binding_point(ctx, target); if (!bindpt) { _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)"); return; } /* From the GL_ARB_occlusion_query spec: * * "If BeginQueryARB is called while another query is already in * progress with the same target, an INVALID_OPERATION error is * generated." */ if (*bindpt) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(target=%s is active)", _mesa_lookup_enum_by_nr(target)); return; } if (id == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)"); return; } q = _mesa_lookup_query_object(ctx, id); if (!q) { if (ctx->API != API_OPENGL_COMPAT) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(non-gen name)"); return; } else { /* create new object */ q = ctx->Driver.NewQueryObject(ctx, id); if (!q) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}"); return; } _mesa_HashInsert(ctx->Query.QueryObjects, id, q); } } else { /* pre-existing object */ if (q->Active) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(query already active)"); return; } } q->Target = target; q->Active = GL_TRUE; q->Result = 0; q->Ready = GL_FALSE; q->EverBound = GL_TRUE; /* XXX should probably refcount query objects */ *bindpt = q; ctx->Driver.BeginQuery(ctx, q); }
/** * Helper to enable/disable client-side state. */ static void client_state(GLcontext *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 */ default: _mesa_error( ctx, GL_INVALID_ENUM, "glEnable/DisableClientState(0x%x)", cap); return; } 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 ); } }
/** * This is called just prior to changing any sampler object state. */ static inline void flush(struct gl_context *ctx) { FLUSH_VERTICES(ctx, _NEW_TEXTURE); }
void GLAPIENTRY _mesa_TexGenfv( GLenum coord, GLenum pname, const GLfloat *params ) { struct gl_texture_unit *texUnit; struct gl_texgen *texgen; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (MESA_VERBOSE&(VERBOSE_API|VERBOSE_TEXTURE)) _mesa_debug(ctx, "glTexGen %s %s %.1f(%s)...\n", _mesa_lookup_enum_by_nr(coord), _mesa_lookup_enum_by_nr(pname), *params, _mesa_lookup_enum_by_nr((GLenum) (GLint) *params)); if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexGen(current unit)"); return; } texUnit = _mesa_get_current_tex_unit(ctx); texgen = get_texgen(ctx, texUnit, coord); if (!texgen) { _mesa_error(ctx, GL_INVALID_ENUM, "glTexGen(coord)"); return; } switch (pname) { case GL_TEXTURE_GEN_MODE: { GLenum mode = (GLenum) (GLint) params[0]; GLbitfield bit = 0x0; if (texgen->Mode == mode) return; switch (mode) { case GL_OBJECT_LINEAR: bit = TEXGEN_OBJ_LINEAR; break; case GL_EYE_LINEAR: bit = TEXGEN_EYE_LINEAR; break; case GL_SPHERE_MAP: if (coord == GL_S || coord == GL_T) bit = TEXGEN_SPHERE_MAP; break; case GL_REFLECTION_MAP_NV: if (coord != GL_Q) bit = TEXGEN_REFLECTION_MAP_NV; break; case GL_NORMAL_MAP_NV: if (coord != GL_Q) bit = TEXGEN_NORMAL_MAP_NV; break; default: ; /* nop */ } if (!bit) { _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" ); return; } if (ctx->API != API_OPENGL && (bit & (TEXGEN_REFLECTION_MAP_NV | TEXGEN_NORMAL_MAP_NV)) == 0) { _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" ); return; } FLUSH_VERTICES(ctx, _NEW_TEXTURE); texgen->Mode = mode; texgen->_ModeBit = bit; } break; case GL_OBJECT_PLANE: { if (ctx->API != API_OPENGL) { _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" ); return; } if (TEST_EQ_4V(texgen->ObjectPlane, params)) return; FLUSH_VERTICES(ctx, _NEW_TEXTURE); COPY_4FV(texgen->ObjectPlane, params); } break; case GL_EYE_PLANE: { GLfloat tmp[4]; if (ctx->API != API_OPENGL) { _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(param)" ); return; } /* Transform plane equation by the inverse modelview matrix */ if (_math_matrix_is_dirty(ctx->ModelviewMatrixStack.Top)) { _math_matrix_analyse(ctx->ModelviewMatrixStack.Top); } _mesa_transform_vector(tmp, params, ctx->ModelviewMatrixStack.Top->inv); if (TEST_EQ_4V(texgen->EyePlane, tmp)) return; FLUSH_VERTICES(ctx, _NEW_TEXTURE); COPY_4FV(texgen->EyePlane, tmp); } break; default: _mesa_error( ctx, GL_INVALID_ENUM, "glTexGenfv(pname)" ); return; } if (ctx->Driver.TexGen) ctx->Driver.TexGen( ctx, coord, pname, params ); }
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 (ctx->Unpack.BufferObj->Name) { /* unpack pixelmap from PBO */ GLubyte *buf; /* Note, need to use DefaultPacking and Unpack's buffer object */ ctx->DefaultPacking.BufferObj = ctx->Unpack.BufferObj; if (!_mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1, GL_INTENSITY, GL_UNSIGNED_SHORT, values)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glPixelMapusv(invalid PBO access)"); return; } /* restore */ ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj; buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, GL_READ_ONLY_ARB, ctx->Unpack.BufferObj); if (!buf) { /* buffer is already mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "glPixelMapusv(PBO is mapped)"); return; } values = (const GLushort *) ADD_POINTERS(buf, values); } else if (!values) { 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] ); } } if (ctx->Unpack.BufferObj->Name) { ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, ctx->Unpack.BufferObj); } store_pixelmap(ctx, map, mapsize, fvalues); }
void GLAPIENTRY _mesa_Fogfv( GLenum pname, const GLfloat *params ) { GET_CURRENT_CONTEXT(ctx); GLenum m; switch (pname) { case GL_FOG_MODE: m = (GLenum) (GLint) *params; switch (m) { case GL_LINEAR: case GL_EXP: case GL_EXP2: break; default: _mesa_error( ctx, GL_INVALID_ENUM, "glFog" ); return; } if (ctx->Fog.Mode == m) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.Mode = m; break; case GL_FOG_DENSITY: if (*params<0.0) { _mesa_error( ctx, GL_INVALID_VALUE, "glFog" ); return; } if (ctx->Fog.Density == *params) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.Density = *params; break; case GL_FOG_START: if (ctx->Fog.Start == *params) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.Start = *params; update_fog_scale(ctx); break; case GL_FOG_END: if (ctx->Fog.End == *params) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.End = *params; update_fog_scale(ctx); break; case GL_FOG_INDEX: if (ctx->API != API_OPENGL_COMPAT) goto invalid_pname; if (ctx->Fog.Index == *params) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.Index = *params; break; case GL_FOG_COLOR: if (TEST_EQ_4V(ctx->Fog.Color, params)) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.ColorUnclamped[0] = params[0]; ctx->Fog.ColorUnclamped[1] = params[1]; ctx->Fog.ColorUnclamped[2] = params[2]; ctx->Fog.ColorUnclamped[3] = params[3]; ctx->Fog.Color[0] = CLAMP(params[0], 0.0F, 1.0F); ctx->Fog.Color[1] = CLAMP(params[1], 0.0F, 1.0F); ctx->Fog.Color[2] = CLAMP(params[2], 0.0F, 1.0F); ctx->Fog.Color[3] = CLAMP(params[3], 0.0F, 1.0F); break; case GL_FOG_COORDINATE_SOURCE_EXT: { GLenum p = (GLenum) (GLint) *params; if (ctx->API != API_OPENGL_COMPAT || (p != GL_FOG_COORDINATE_EXT && p != GL_FRAGMENT_DEPTH_EXT)) { _mesa_error(ctx, GL_INVALID_ENUM, "glFog"); return; } if (ctx->Fog.FogCoordinateSource == p) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.FogCoordinateSource = p; break; } case GL_FOG_DISTANCE_MODE_NV: { GLenum p = (GLenum) (GLint) *params; if (ctx->API != API_OPENGL_COMPAT || !ctx->Extensions.NV_fog_distance || (p != GL_EYE_RADIAL_NV && p != GL_EYE_PLANE && p != GL_EYE_PLANE_ABSOLUTE_NV)) { _mesa_error(ctx, GL_INVALID_ENUM, "glFog"); return; } if (ctx->Fog.FogDistanceMode == p) return; FLUSH_VERTICES(ctx, _NEW_FOG); ctx->Fog.FogDistanceMode = p; break; } default: goto invalid_pname; } if (ctx->Driver.Fogfv) { (*ctx->Driver.Fogfv)( ctx, pname, params ); } return; invalid_pname: _mesa_error( ctx, GL_INVALID_ENUM, "glFog" ); return; }
void GLAPIENTRY _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *pixels ) { GLenum err = GL_NO_ERROR; struct gl_renderbuffer *rb; struct gl_pixelstore_attrib clippedPacking; GET_CURRENT_CONTEXT(ctx); FLUSH_VERTICES(ctx, 0); FLUSH_CURRENT(ctx, 0); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n", width, height, _mesa_enum_to_string(format), _mesa_enum_to_string(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 (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "glReadPixels(incomplete framebuffer)" ); return; } rb = _mesa_get_read_renderbuffer_for_format(ctx, format); if (rb == NULL) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(read buffer)"); return; } /* OpenGL ES 1.x and OpenGL ES 2.0 impose additional restrictions on the * combinations of format and type that can be used. * * Technically, only two combinations are actually allowed: * GL_RGBA/GL_UNSIGNED_BYTE, and some implementation-specific internal * preferred combination. This code doesn't know what that preferred * combination is, and Mesa can handle anything valid. Just work instead. */ if (_mesa_is_gles(ctx)) { if (ctx->API == API_OPENGLES2 && _mesa_is_color_format(format) && _mesa_get_color_read_format(ctx) == format && _mesa_get_color_read_type(ctx) == type) { err = GL_NO_ERROR; } else if (ctx->Version < 30) { err = _mesa_es_error_check_format_and_type(ctx, format, type, 2); if (err == GL_NO_ERROR) { if (type == GL_FLOAT || type == GL_HALF_FLOAT_OES) { err = GL_INVALID_OPERATION; } } } else { err = read_pixels_es3_error_check(format, type, rb); } if (err != GL_NO_ERROR) { _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)", _mesa_enum_to_string(format), _mesa_enum_to_string(type)); return; } } err = _mesa_error_check_format_and_type(ctx, format, type); if (err != GL_NO_ERROR) { _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)", _mesa_enum_to_string(format), _mesa_enum_to_string(type)); return; } if (_mesa_is_user_fbo(ctx->ReadBuffer) && ctx->ReadBuffer->Visual.samples > 0) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)"); return; } if (!_mesa_source_buffer_exists(ctx, format)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)"); 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_enum_format_integer(format); if (dstInteger != srcInteger) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(integer / non-integer format mismatch"); return; } } /* Do all needed clipping here, so that we can forget about it later */ clippedPacking = ctx->Pack; if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) return; /* nothing to do */ if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1, format, type, bufSize, pixels)) { if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(out of bounds PBO access)"); } else { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadnPixelsARB(out of bounds access:" " bufSize (%d) is too small)", bufSize); } return; } if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && _mesa_check_disallowed_mapping(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, &clippedPacking, pixels); }
void GLAPIENTRY _mesa_PointParameterfv( GLenum pname, const GLfloat *params) { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); switch (pname) { case GL_DISTANCE_ATTENUATION_EXT: if (ctx->Extensions.EXT_point_parameters) { if (TEST_EQ_3V(ctx->Point.Params, params)) return; FLUSH_VERTICES(ctx, _NEW_POINT); COPY_3V(ctx->Point.Params, params); ctx->Point._Attenuated = (ctx->Point.Params[0] != 1.0 || ctx->Point.Params[1] != 0.0 || ctx->Point.Params[2] != 0.0); if (ctx->Point._Attenuated) ctx->_TriangleCaps |= DD_POINT_ATTEN; else ctx->_TriangleCaps &= ~DD_POINT_ATTEN; } else { _mesa_error(ctx, GL_INVALID_ENUM, "glPointParameterf[v]{EXT,ARB}(pname)"); return; } break; case GL_POINT_SIZE_MIN_EXT: if (ctx->Extensions.EXT_point_parameters) { if (params[0] < 0.0F) { _mesa_error( ctx, GL_INVALID_VALUE, "glPointParameterf[v]{EXT,ARB}(param)" ); return; } if (ctx->Point.MinSize == params[0]) return; FLUSH_VERTICES(ctx, _NEW_POINT); ctx->Point.MinSize = params[0]; } else { _mesa_error(ctx, GL_INVALID_ENUM, "glPointParameterf[v]{EXT,ARB}(pname)"); return; } break; case GL_POINT_SIZE_MAX_EXT: if (ctx->Extensions.EXT_point_parameters) { if (params[0] < 0.0F) { _mesa_error( ctx, GL_INVALID_VALUE, "glPointParameterf[v]{EXT,ARB}(param)" ); return; } if (ctx->Point.MaxSize == params[0]) return; FLUSH_VERTICES(ctx, _NEW_POINT); ctx->Point.MaxSize = params[0]; } else { _mesa_error(ctx, GL_INVALID_ENUM, "glPointParameterf[v]{EXT,ARB}(pname)"); return; } break; case GL_POINT_FADE_THRESHOLD_SIZE_EXT: if (ctx->Extensions.EXT_point_parameters) { if (params[0] < 0.0F) { _mesa_error( ctx, GL_INVALID_VALUE, "glPointParameterf[v]{EXT,ARB}(param)" ); return; } if (ctx->Point.Threshold == params[0]) return; FLUSH_VERTICES(ctx, _NEW_POINT); ctx->Point.Threshold = params[0]; } else { _mesa_error(ctx, GL_INVALID_ENUM, "glPointParameterf[v]{EXT,ARB}(pname)"); return; } break; case GL_POINT_SPRITE_R_MODE_NV: /* This is one area where ARB_point_sprite and NV_point_sprite * differ. In ARB_point_sprite the POINT_SPRITE_R_MODE is * always ZERO. NV_point_sprite adds the S and R modes. */ if (ctx->Extensions.NV_point_sprite) { GLenum value = (GLenum) params[0]; if (value != GL_ZERO && value != GL_S && value != GL_R) { _mesa_error(ctx, GL_INVALID_VALUE, "glPointParameterf[v]{EXT,ARB}(param)"); return; } if (ctx->Point.SpriteRMode == value) return; FLUSH_VERTICES(ctx, _NEW_POINT); ctx->Point.SpriteRMode = value; } else { _mesa_error(ctx, GL_INVALID_ENUM, "glPointParameterf[v]{EXT,ARB}(pname)"); return; } break; case GL_POINT_SPRITE_COORD_ORIGIN: if (ctx->Extensions.ARB_point_sprite || ctx->Extensions.NV_point_sprite) { GLenum value = (GLenum) params[0]; if (value != GL_LOWER_LEFT && value != GL_UPPER_LEFT) { _mesa_error(ctx, GL_INVALID_VALUE, "glPointParameterf[v]{EXT,ARB}(param)"); return; } if (ctx->Point.SpriteOrigin == value) return; FLUSH_VERTICES(ctx, _NEW_POINT); ctx->Point.SpriteOrigin = value; } else { _mesa_error(ctx, GL_INVALID_ENUM, "glPointParameterf[v]{EXT,ARB}(pname)"); return; } break; default: _mesa_error( ctx, GL_INVALID_ENUM, "glPointParameterf[v]{EXT,ARB}(pname)" ); return; } if (ctx->Driver.PointParameterfv) (*ctx->Driver.PointParameterfv)(ctx, pname, params); }
/** * Bind a named texture to a texturing target. * * \param target texture target. * \param texName texture name. * * \sa glBindTexture(). * * Determines the old texture object bound and returns immediately if rebinding * the same texture. Get the current texture which is either a default texture * if name is null, a named texture from the hash, or a new texture if the * given texture name is new. Increments its reference count, binds it, and * calls dd_function_table::BindTexture. Decrements the old texture reference * count and deletes it if it reaches zero. */ void GLAPIENTRY _mesa_BindTexture( GLenum target, GLuint texName ) { GET_CURRENT_CONTEXT(ctx); struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); struct gl_texture_object *newTexObj = NULL; GLint targetIndex; ASSERT_OUTSIDE_BEGIN_END(ctx); if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) _mesa_debug(ctx, "glBindTexture %s %d\n", _mesa_lookup_enum_by_nr(target), (GLint) texName); targetIndex = target_enum_to_index(target); if (targetIndex < 0) { _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)"); return; } assert(targetIndex < NUM_TEXTURE_TARGETS); /* * Get pointer to new texture object (newTexObj) */ if (texName == 0) { /* Use a default texture object */ newTexObj = ctx->Shared->DefaultTex[targetIndex]; } else { /* non-default texture object */ newTexObj = _mesa_lookup_texture(ctx, texName); if (newTexObj) { /* error checking */ if (newTexObj->Target != 0 && newTexObj->Target != target) { /* the named texture object's target doesn't match the given target */ _mesa_error( ctx, GL_INVALID_OPERATION, "glBindTexture(target mismatch)" ); return; } if (newTexObj->Target == 0) { finish_texture_init(ctx, target, newTexObj); } } else { /* if this is a new texture id, allocate a texture object now */ newTexObj = ctx->Driver.NewTextureObject(ctx, texName, target); if (!newTexObj) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture"); return; } /* and insert it into hash table */ _glthread_LOCK_MUTEX(ctx->Shared->Mutex); _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); } newTexObj->Target = target; } assert(valid_texture_object(newTexObj)); /* Check if this texture is only used by this context and is already bound. * If so, just return. */ { GLboolean early_out; _glthread_LOCK_MUTEX(ctx->Shared->Mutex); early_out = ((ctx->Shared->RefCount == 1) && (newTexObj == texUnit->CurrentTex[targetIndex])); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); if (early_out) { return; } } /* flush before changing binding */ FLUSH_VERTICES(ctx, _NEW_TEXTURE); /* Do the actual binding. The refcount on the previously bound * texture object will be decremented. It'll be deleted if the * count hits zero. */ _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj); ASSERT(texUnit->CurrentTex[targetIndex]); /* Pass BindTexture call to device driver */ if (ctx->Driver.BindTexture) ctx->Driver.BindTexture(ctx, target, newTexObj); }
/** * Clear buffers. * * \param mask bit-mask indicating the buffers to be cleared. * * Flushes the vertices and verifies the parameter. If __struct gl_contextRec::NewState * is set then calls _mesa_update_state() to update gl_frame_buffer::_Xmin, * etc. If the rasterization mode is set to GL_RENDER then requests the driver * to clear the buffers, via the dd_function_table::Clear callback. */ void GLAPIENTRY _mesa_Clear( GLbitfield mask ) { GET_CURRENT_CONTEXT(ctx); FLUSH_VERTICES(ctx, 0); FLUSH_CURRENT(ctx, 0); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glClear 0x%x\n", mask); if (mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_ACCUM_BUFFER_BIT)) { /* invalid bit set */ _mesa_error( ctx, GL_INVALID_VALUE, "glClear(0x%x)", mask); return; } /* Accumulation buffers were removed in core contexts, and they never * existed in OpenGL ES. */ if ((mask & GL_ACCUM_BUFFER_BIT) != 0 && (ctx->API == API_OPENGL_CORE || _mesa_is_gles(ctx))) { _mesa_error( ctx, GL_INVALID_VALUE, "glClear(GL_ACCUM_BUFFER_BIT)"); return; } if (ctx->NewState) { _mesa_update_state( ctx ); /* update _Xmin, etc */ } if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "glClear(incomplete framebuffer)"); return; } if (ctx->DrawBuffer->Width == 0 || ctx->DrawBuffer->Height == 0 || ctx->DrawBuffer->_Xmin >= ctx->DrawBuffer->_Xmax || ctx->DrawBuffer->_Ymin >= ctx->DrawBuffer->_Ymax) return; if (ctx->RasterDiscard) return; if (ctx->RenderMode == GL_RENDER) { GLbitfield bufferMask; /* don't clear depth buffer if depth writing disabled */ if (!ctx->Depth.Mask) mask &= ~GL_DEPTH_BUFFER_BIT; /* Build the bitmask to send to device driver's Clear function. * Note that the GL_COLOR_BUFFER_BIT flag will expand to 0, 1, 2 or 4 * of the BUFFER_BIT_FRONT/BACK_LEFT/RIGHT flags, or one of the * BUFFER_BIT_COLORn flags. */ bufferMask = 0; if (mask & GL_COLOR_BUFFER_BIT) { GLuint i; for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { bufferMask |= (1 << ctx->DrawBuffer->_ColorDrawBufferIndexes[i]); } } if ((mask & GL_DEPTH_BUFFER_BIT) && ctx->DrawBuffer->Visual.haveDepthBuffer) { bufferMask |= BUFFER_BIT_DEPTH; } if ((mask & GL_STENCIL_BUFFER_BIT) && ctx->DrawBuffer->Visual.haveStencilBuffer) { bufferMask |= BUFFER_BIT_STENCIL; } if ((mask & GL_ACCUM_BUFFER_BIT) && ctx->DrawBuffer->Visual.haveAccumBuffer) { bufferMask |= BUFFER_BIT_ACCUM; } ASSERT(ctx->Driver.Clear); ctx->Driver.Clear(ctx, bufferMask); } }
/** * Called by ctx->Driver.UniformMatrix(). */ void _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows, GLenum matrixType, GLint location, GLsizei count, GLboolean transpose, const GLfloat *values) { GLsizei maxCount, i; struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; if (!shProg || !shProg->LinkStatus) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(program not linked)"); return; } if (location == -1) return; /* The standard specifies this as a no-op */ /* The spec says this is GL_INVALID_OPERATION, although it seems like it * ought to be GL_INVALID_VALUE */ if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)"); return; } if (values == NULL) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix"); return; } if (count < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(count < 0)"); return; } FLUSH_VERTICES(ctx, _NEW_PROGRAM); /* * Note: the _columns_ of a matrix are stored in program registers, not * the rows. */ /* XXXX need to test 3x3 and 2x2 matrices... */ maxCount = shProg->Uniforms->Parameters[location].Size / (4 * cols); if (count > maxCount) count = maxCount; for (i = 0; i < count; i++) { if (transpose) { GLuint row, col; for (col = 0; col < cols; col++) { GLfloat *v = shProg->Uniforms->ParameterValues[location + col]; for (row = 0; row < rows; row++) { v[row] = values[row * cols + col]; } } } else { GLuint row, col; for (col = 0; col < cols; col++) { GLfloat *v = shProg->Uniforms->ParameterValues[location + col]; for (row = 0; row < rows; row++) { v[row] = values[col * rows + row]; } } } location += cols; values += rows * cols; } }
/** * New in GL 3.0 * Clear unsigned integer color buffer (not depth, not stencil). */ void GLAPIENTRY _mesa_ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value) { GET_CURRENT_CONTEXT(ctx); FLUSH_VERTICES(ctx, 0); FLUSH_CURRENT(ctx, 0); if (ctx->NewState) { _mesa_update_state( ctx ); } switch (buffer) { case GL_COLOR: { const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer); if (mask == INVALID_MASK) { _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferuiv(drawbuffer=%d)", drawbuffer); return; } else if (mask && !ctx->RasterDiscard) { union gl_color_union clearSave; /* save color */ clearSave = ctx->Color.ClearColor; /* set color */ COPY_4V(ctx->Color.ClearColor.ui, value); /* clear buffer(s) */ ctx->Driver.Clear(ctx, mask); /* restore color */ ctx->Color.ClearColor = clearSave; } } break; case GL_DEPTH: case GL_STENCIL: /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says: * * "The result of ClearBuffer is undefined if no conversion between * the type of the specified value and the type of the buffer being * cleared is defined (for example, if ClearBufferiv is called for a * fixed- or floating-point buffer, or if ClearBufferfv is called * for a signed or unsigned integer buffer). This is not an error." * * In this case we take "undefined" and "not an error" to mean "ignore." * Even though we could do something sensible for GL_STENCIL, page 263 * (page 279 of the PDF) says: * * "Only ClearBufferiv should be used to clear stencil buffers." * * Note that we still need to generate an error for the invalid * drawbuffer case (see the GL_STENCIL case in _mesa_ClearBufferiv). */ if (drawbuffer != 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferuiv(drawbuffer=%d)", drawbuffer); return; } return; default: _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferuiv(buffer=%s)", _mesa_lookup_enum_by_nr(buffer)); return; } }
static void map2( GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLvoid *points, GLenum type ) { GET_CURRENT_CONTEXT(ctx); GLint k; GLfloat *pnts; struct gl_2d_map *map = NULL; ASSERT_OUTSIDE_BEGIN_END(ctx); ASSERT(type == GL_FLOAT || type == GL_DOUBLE); if (u1==u2) { _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(u1,u2)" ); return; } if (v1==v2) { _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(v1,v2)" ); return; } if (uorder<1 || uorder>MAX_EVAL_ORDER) { _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(uorder)" ); return; } if (vorder<1 || vorder>MAX_EVAL_ORDER) { _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(vorder)" ); return; } k = _mesa_evaluator_components( target ); if (k==0) { _mesa_error( ctx, GL_INVALID_ENUM, "glMap2(target)" ); } if (ustride < k) { _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(ustride)" ); return; } if (vstride < k) { _mesa_error( ctx, GL_INVALID_VALUE, "glMap2(vstride)" ); return; } map = get_2d_map(ctx, target); if (!map) { _mesa_error( ctx, GL_INVALID_ENUM, "glMap2(target)" ); return; } /* make copy of the control points */ if (type == GL_FLOAT) pnts = _mesa_copy_map_points2f(target, ustride, uorder, vstride, vorder, (GLfloat*) points); else pnts = _mesa_copy_map_points2d(target, ustride, uorder, vstride, vorder, (GLdouble*) points); FLUSH_VERTICES(ctx, _NEW_EVAL); map->Uorder = uorder; map->u1 = u1; map->u2 = u2; map->du = 1.0F / (u2 - u1); map->Vorder = vorder; map->v1 = v1; map->v2 = v2; map->dv = 1.0F / (v2 - v1); if (map->Points) FREE( map->Points ); map->Points = pnts; }
/** * New in GL 3.0 * Clear fixed-pt or float color buffer or depth buffer (not stencil). */ void GLAPIENTRY _mesa_ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value) { GET_CURRENT_CONTEXT(ctx); FLUSH_VERTICES(ctx, 0); FLUSH_CURRENT(ctx, 0); if (ctx->NewState) { _mesa_update_state( ctx ); } switch (buffer) { case GL_DEPTH: /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says: * * "ClearBuffer generates an INVALID VALUE error if buffer is * COLOR and drawbuffer is less than zero, or greater than the * value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH, * STENCIL, or DEPTH STENCIL and drawbuffer is not zero." */ if (drawbuffer != 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)", drawbuffer); return; } else if (ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer && !ctx->RasterDiscard) { /* Save current depth clear value, set to 'value', do the * depth clear and restore the clear value. * XXX in the future we may have a new ctx->Driver.ClearBuffer() * hook instead. */ const GLclampd clearSave = ctx->Depth.Clear; ctx->Depth.Clear = *value; ctx->Driver.Clear(ctx, BUFFER_BIT_DEPTH); ctx->Depth.Clear = clearSave; } /* clear depth buffer to value */ break; case GL_COLOR: { const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer); if (mask == INVALID_MASK) { _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)", drawbuffer); return; } else if (mask && !ctx->RasterDiscard) { union gl_color_union clearSave; /* save color */ clearSave = ctx->Color.ClearColor; /* set color */ COPY_4V(ctx->Color.ClearColor.f, value); /* clear buffer(s) */ ctx->Driver.Clear(ctx, mask); /* restore color */ ctx->Color.ClearColor = clearSave; } } break; case GL_STENCIL: /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says: * * "The result of ClearBuffer is undefined if no conversion between * the type of the specified value and the type of the buffer being * cleared is defined (for example, if ClearBufferiv is called for a * fixed- or floating-point buffer, or if ClearBufferfv is called * for a signed or unsigned integer buffer). This is not an error." * * In this case we take "undefined" and "not an error" to mean "ignore." * Note that we still need to generate an error for the invalid * drawbuffer case (see the GL_DEPTH case above). */ if (drawbuffer != 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)", drawbuffer); return; } return; default: _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfv(buffer=%s)", _mesa_lookup_enum_by_nr(buffer)); return; } }
/** * Called via glUniform*() functions. */ extern "C" void _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, GLint location, GLsizei count, const GLvoid *values, GLenum type) { unsigned loc, offset; unsigned components; unsigned src_components; enum glsl_base_type basicType; struct gl_uniform_storage *uni; ASSERT_OUTSIDE_BEGIN_END(ctx); if (!validate_uniform_parameters(ctx, shProg, location, count, &loc, &offset, "glUniform", false)) return; uni = &shProg->UniformStorage[loc]; /* Verify that the types are compatible. */ switch (type) { case GL_FLOAT: basicType = GLSL_TYPE_FLOAT; src_components = 1; break; case GL_FLOAT_VEC2: basicType = GLSL_TYPE_FLOAT; src_components = 2; break; case GL_FLOAT_VEC3: basicType = GLSL_TYPE_FLOAT; src_components = 3; break; case GL_FLOAT_VEC4: basicType = GLSL_TYPE_FLOAT; src_components = 4; break; case GL_UNSIGNED_INT: basicType = GLSL_TYPE_UINT; src_components = 1; break; case GL_UNSIGNED_INT_VEC2: basicType = GLSL_TYPE_UINT; src_components = 2; break; case GL_UNSIGNED_INT_VEC3: basicType = GLSL_TYPE_UINT; src_components = 3; break; case GL_UNSIGNED_INT_VEC4: basicType = GLSL_TYPE_UINT; src_components = 4; break; case GL_INT: basicType = GLSL_TYPE_INT; src_components = 1; break; case GL_INT_VEC2: basicType = GLSL_TYPE_INT; src_components = 2; break; case GL_INT_VEC3: basicType = GLSL_TYPE_INT; src_components = 3; break; case GL_INT_VEC4: basicType = GLSL_TYPE_INT; src_components = 4; break; case GL_BOOL: case GL_BOOL_VEC2: case GL_BOOL_VEC3: case GL_BOOL_VEC4: case GL_FLOAT_MAT2: case GL_FLOAT_MAT2x3: case GL_FLOAT_MAT2x4: case GL_FLOAT_MAT3x2: case GL_FLOAT_MAT3: case GL_FLOAT_MAT3x4: case GL_FLOAT_MAT4x2: case GL_FLOAT_MAT4x3: case GL_FLOAT_MAT4: default: _mesa_problem(NULL, "Invalid type in %s", __func__); return; } if (uni->type->is_sampler()) { components = 1; } else { components = uni->type->vector_elements; } bool match; switch (uni->type->base_type) { case GLSL_TYPE_BOOL: match = true; break; case GLSL_TYPE_SAMPLER: match = (basicType == GLSL_TYPE_INT); break; default: match = (basicType == uni->type->base_type); break; } if (uni->type->is_matrix() || components != src_components || !match) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)"); return; } if (ctx->Shader.Flags & GLSL_UNIFORMS) { log_uniform(values, basicType, components, 1, count, false, shProg, location, uni); } /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says: * * "Setting a sampler's value to i selects texture image unit number * i. The values of i range from zero to the implementation- dependent * maximum supported number of texture image units." * * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of * the PDF) says: * * "Error Description Offending command * ignored? * ... * INVALID_VALUE Numeric argument out of range Yes" * * Based on that, when an invalid sampler is specified, we generate a * GL_INVALID_VALUE error and ignore the command. */ if (uni->type->is_sampler()) { int i; for (i = 0; i < count; i++) { const unsigned texUnit = ((unsigned *) values)[i]; /* check that the sampler (tex unit index) is legal */ if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) { _mesa_error(ctx, GL_INVALID_VALUE, "glUniform1i(invalid sampler/tex unit index for " "uniform %d)", location); return; } } } /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: * * "When loading N elements starting at an arbitrary position k in a * uniform declared as an array, elements k through k + N - 1 in the * array will be replaced with the new values. Values for any array * element that exceeds the highest array element index used, as * reported by GetActiveUniform, will be ignored by the GL." * * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 * will have already generated an error. */ if (uni->array_elements != 0) { if (offset >= uni->array_elements) return; count = MIN2(count, (int) (uni->array_elements - offset)); } FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); /* Store the data in the "actual type" backing storage for the uniform. */ if (!uni->type->is_boolean()) { memcpy(&uni->storage[components * offset], values, sizeof(uni->storage[0]) * components * count); } else { const union gl_constant_value *src = (const union gl_constant_value *) values; union gl_constant_value *dst = &uni->storage[components * offset]; const unsigned elems = components * count; unsigned i; for (i = 0; i < elems; i++) { if (basicType == GLSL_TYPE_FLOAT) { dst[i].i = src[i].f != 0.0f ? 1 : 0; } else { dst[i].i = src[i].i != 0 ? 1 : 0; } } } uni->initialized = true; _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); /* If the uniform is a sampler, do the extra magic necessary to propagate * the changes through. */ if (uni->type->is_sampler()) { int i; for (i = 0; i < count; i++) { shProg->SamplerUnits[uni->sampler + offset + i] = ((unsigned *) values)[i]; } bool flushed = false; for (i = 0; i < MESA_SHADER_TYPES; i++) { struct gl_shader *const sh = shProg->_LinkedShaders[i]; /* If the shader stage doesn't use any samplers, don't bother * checking if any samplers have changed. */ if (sh == NULL || sh->active_samplers == 0) continue; struct gl_program *const prog = sh->Program; assert(sizeof(prog->SamplerUnits) == sizeof(shProg->SamplerUnits)); /* Determine if any of the samplers used by this shader stage have * been modified. */ bool changed = false; for (unsigned j = 0; j < Elements(prog->SamplerUnits); j++) { if ((sh->active_samplers & (1U << j)) != 0 && (prog->SamplerUnits[j] != shProg->SamplerUnits[j])) { changed = true; break; } } if (changed) { if (!flushed) { FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM); flushed = true; } memcpy(prog->SamplerUnits, shProg->SamplerUnits, sizeof(shProg->SamplerUnits)); _mesa_update_shader_textures_used(shProg, prog); (void) ctx->Driver.ProgramStringNotify(ctx, prog->Target, prog); } } } }
void GLAPIENTRY _mesa_BindSamplers(GLuint first, GLsizei count, const GLuint *samplers) { GET_CURRENT_CONTEXT(ctx); GLint i; /* The ARB_multi_bind spec says: * * "An INVALID_OPERATION error is generated if <first> + <count> is * greater than the number of texture image units supported by * the implementation." */ if (first + count > ctx->Const.MaxCombinedTextureImageUnits) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindSamplers(first=%u + count=%d > the value of " "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)", first, count, ctx->Const.MaxCombinedTextureImageUnits); return; } FLUSH_VERTICES(ctx, 0); if (samplers) { /* Note that the error semantics for multi-bind commands differ from * those of other GL commands. * * The Issues section in the ARB_multi_bind spec says: * * "(11) Typically, OpenGL specifies that if an error is generated by * a command, that command has no effect. This is somewhat * unfortunate for multi-bind commands, because it would require * a first pass to scan the entire list of bound objects for * errors and then a second pass to actually perform the * bindings. Should we have different error semantics? * * RESOLVED: Yes. In this specification, when the parameters for * one of the <count> binding points are invalid, that binding * point is not updated and an error will be generated. However, * other binding points in the same command will be updated if * their parameters are valid and no other error occurs." */ begin_samplerobj_lookups(ctx); for (i = 0; i < count; i++) { const GLuint unit = first + i; struct gl_sampler_object * const currentSampler = ctx->Texture.Unit[unit].Sampler; struct gl_sampler_object *sampObj; if (samplers[i] != 0) { if (currentSampler && currentSampler->Name == samplers[i]) sampObj = currentSampler; else sampObj = lookup_samplerobj_locked(ctx, samplers[i]); /* The ARB_multi_bind spec says: * * "An INVALID_OPERATION error is generated if any value * in <samplers> is not zero or the name of an existing * sampler object (per binding)." */ if (!sampObj) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindSamplers(samplers[%d]=%u is not zero or " "the name of an existing sampler object)", i, samplers[i]); continue; } } else { sampObj = NULL; } /* Bind the new sampler */ if (sampObj != currentSampler) { _mesa_reference_sampler_object(ctx, &ctx->Texture.Unit[unit].Sampler, sampObj); ctx->NewState |= _NEW_TEXTURE; } } end_samplerobj_lookups(ctx); } else { /* Unbind all samplers in the range <first> through <first>+<count>-1 */ for (i = 0; i < count; i++) { const GLuint unit = first + i; if (ctx->Texture.Unit[unit].Sampler) { _mesa_reference_sampler_object(ctx, &ctx->Texture.Unit[unit].Sampler, NULL); ctx->NewState |= _NEW_TEXTURE; } } } }
static void GLAPIENTRY _mesa_Histogram(GLenum target, GLsizei width, GLenum internalFormat, GLboolean sink) { GLuint i; GLboolean error = GL_FALSE; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* sideeffects */ if (!ctx->Extensions.EXT_histogram && !ctx->Extensions.ARB_imaging) { _mesa_error(ctx, GL_INVALID_OPERATION, "glHistogram"); return; } if (target != GL_HISTOGRAM && target != GL_PROXY_HISTOGRAM) { _mesa_error(ctx, GL_INVALID_ENUM, "glHistogram(target)"); return; } if (width < 0 || width > HISTOGRAM_TABLE_SIZE) { if (target == GL_PROXY_HISTOGRAM) { error = GL_TRUE; } else { if (width < 0) _mesa_error(ctx, GL_INVALID_VALUE, "glHistogram(width)"); else _mesa_error(ctx, GL_TABLE_TOO_LARGE, "glHistogram(width)"); return; } } if (width != 0 && !_mesa_is_pow_two(width)) { if (target == GL_PROXY_HISTOGRAM) { error = GL_TRUE; } else { _mesa_error(ctx, GL_INVALID_VALUE, "glHistogram(width)"); return; } } if (base_histogram_format(internalFormat) < 0) { if (target == GL_PROXY_HISTOGRAM) { error = GL_TRUE; } else { _mesa_error(ctx, GL_INVALID_ENUM, "glHistogram(internalFormat)"); return; } } FLUSH_VERTICES(ctx, _NEW_PIXEL); /* reset histograms */ for (i = 0; i < HISTOGRAM_TABLE_SIZE; i++) { ctx->Histogram.Count[i][0] = 0; ctx->Histogram.Count[i][1] = 0; ctx->Histogram.Count[i][2] = 0; ctx->Histogram.Count[i][3] = 0; } if (error) { ctx->Histogram.Width = 0; ctx->Histogram.Format = 0; ctx->Histogram.RedSize = 0; ctx->Histogram.GreenSize = 0; ctx->Histogram.BlueSize = 0; ctx->Histogram.AlphaSize = 0; ctx->Histogram.LuminanceSize = 0; } else { ctx->Histogram.Width = width; ctx->Histogram.Format = internalFormat; ctx->Histogram.Sink = sink; ctx->Histogram.RedSize = 8 * sizeof(GLuint); ctx->Histogram.GreenSize = 8 * sizeof(GLuint); ctx->Histogram.BlueSize = 8 * sizeof(GLuint); ctx->Histogram.AlphaSize = 8 * sizeof(GLuint); ctx->Histogram.LuminanceSize = 8 * sizeof(GLuint); } }
/** * Helper function to set the GL_DRAW_BUFFER state in the context and * current FBO. Called via glDrawBuffer(), glDrawBuffersARB() * * All error checking will have been done prior to calling this function * so nothing should go wrong at this point. * * \param ctx current context * \param n number of color outputs to set * \param buffers array[n] of colorbuffer names, like GL_LEFT. * \param destMask array[n] of BUFFER_BIT_* bitmasks which correspond to the * colorbuffer names. (i.e. GL_FRONT_AND_BACK => * BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT). */ void _mesa_drawbuffers(GLcontext *ctx, GLuint n, const GLenum *buffers, const GLbitfield *destMask) { struct gl_framebuffer *fb = ctx->DrawBuffer; GLbitfield mask[MAX_DRAW_BUFFERS]; GLboolean newState = GL_FALSE; if (!destMask) { /* compute destMask values now */ const GLbitfield supportedMask = supported_buffer_bitmask(ctx, fb); GLuint output; for (output = 0; output < n; output++) { mask[output] = draw_buffer_enum_to_bitmask(buffers[output]); ASSERT(mask[output] != BAD_MASK); mask[output] &= supportedMask; } destMask = mask; } /* * If n==1, destMask[0] may have up to four bits set. * Otherwise, destMask[x] can only have one bit set. */ if (n == 1) { GLuint count = 0, destMask0 = destMask[0]; while (destMask0) { GLint bufIndex = _mesa_ffs(destMask0) - 1; if (fb->_ColorDrawBufferIndexes[count] != bufIndex) { fb->_ColorDrawBufferIndexes[count] = bufIndex; newState = GL_TRUE; } count++; destMask0 &= ~(1 << bufIndex); } fb->ColorDrawBuffer[0] = buffers[0]; if (fb->_NumColorDrawBuffers != count) { fb->_NumColorDrawBuffers = count; newState = GL_TRUE; } } else { GLuint buf, count = 0; for (buf = 0; buf < n; buf++ ) { if (destMask[buf]) { GLint bufIndex = _mesa_ffs(destMask[buf]) - 1; /* only one bit should be set in the destMask[buf] field */ ASSERT(_mesa_bitcount(destMask[buf]) == 1); if (fb->_ColorDrawBufferIndexes[buf] != bufIndex) { fb->_ColorDrawBufferIndexes[buf] = bufIndex; newState = GL_TRUE; } fb->ColorDrawBuffer[buf] = buffers[buf]; count = buf + 1; } else { if (fb->_ColorDrawBufferIndexes[buf] != -1) { fb->_ColorDrawBufferIndexes[buf] = -1; newState = GL_TRUE; } } } /* set remaining outputs to -1 (GL_NONE) */ while (buf < ctx->Const.MaxDrawBuffers) { if (fb->_ColorDrawBufferIndexes[buf] != -1) { fb->_ColorDrawBufferIndexes[buf] = -1; newState = GL_TRUE; } fb->ColorDrawBuffer[buf] = GL_NONE; buf++; } fb->_NumColorDrawBuffers = count; } if (fb->Name == 0) { /* also set context drawbuffer state */ GLuint buf; for (buf = 0; buf < ctx->Const.MaxDrawBuffers; buf++) { if (ctx->Color.DrawBuffer[buf] != fb->ColorDrawBuffer[buf]) { ctx->Color.DrawBuffer[buf] = fb->ColorDrawBuffer[buf]; newState = GL_TRUE; } } } if (newState) FLUSH_VERTICES(ctx, _NEW_BUFFERS); }