/** * Get texture image. Called by glGetTexImage. * * \param target texture target. * \param level image level. * \param format pixel data format for returned image. * \param type pixel data type for returned image. * \param bufSize size of the pixels data buffer. * \param pixels returned pixel data. */ void GLAPIENTRY _mesa_GetTexImage( GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels ) { struct gl_texture_object *texObj; struct gl_texture_image *texImage; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (getteximage_error_check(ctx, target, level, format, type, pixels)) { return; } if (!pixels) { /* not an error, do nothing */ return; } texObj = _mesa_select_tex_object(ctx, target); texImage = _mesa_select_tex_image(ctx, texObj, target, level); if (_mesa_is_zero_size_texture(texImage)) return; if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d," " dstFmt=0x%x, dstType=0x%x\n", texObj->Name, _mesa_get_format_name(texImage->TexFormat), texImage->Width, texImage->Height, format, type); } _mesa_lock_texture(ctx, texObj); { ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage); } _mesa_unlock_texture(ctx, texObj); }
/** * Set separate blend equations for one color buffer/target. */ void GLAPIENTRY _mesa_BlendEquationSeparateiARB(GLuint buf, GLenum modeRGB, GLenum modeA) { GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf, _mesa_enum_to_string(modeRGB), _mesa_enum_to_string(modeA)); if (buf >= ctx->Const.MaxDrawBuffers) { _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)", buf); return; } if (!legal_blend_equation(ctx, modeRGB)) { _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)"); return; } if (!legal_blend_equation(ctx, modeA)) { _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)"); return; } if (ctx->Color.Blend[buf].EquationRGB == modeRGB && ctx->Color.Blend[buf].EquationA == modeA) return; /* no change */ FLUSH_VERTICES(ctx, _NEW_COLOR); ctx->Color.Blend[buf].EquationRGB = modeRGB; ctx->Color.Blend[buf].EquationA = modeA; ctx->Color._BlendEquationPerBuffer = GL_TRUE; if (ctx->Driver.BlendEquationSeparatei) ctx->Driver.BlendEquationSeparatei(ctx, buf, modeRGB, modeA); }
/** * Helper used by _mesa_TexStorage1/2/3D(). */ static void texstorage(GLuint dims, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, const char *caller) { struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); /* Check target. This is done here so that texture_storage * can receive unsized formats. */ if (!legal_texobj_target(ctx, dims, target)) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(illegal target=%s)", caller, _mesa_enum_to_string(target)); return; } if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) _mesa_debug(ctx, "%s %s %d %s %d %d %d\n", caller, _mesa_enum_to_string(target), levels, _mesa_enum_to_string(internalformat), width, height, depth); /* Check the format to make sure it is sized. */ if (!_mesa_is_legal_tex_storage_format(ctx, internalformat)) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalformat = %s)", caller, _mesa_enum_to_string(internalformat)); return; } texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj) return; texture_storage(ctx, dims, texObj, target, levels, internalformat, width, height, depth, false); }
void GLAPIENTRY _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize, GLvoid *img) { struct gl_texture_object *texObj; struct gl_texture_image *texImage; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) { return; } if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) { /* not an error, do nothing */ return; } texObj = _mesa_get_current_tex_object(ctx, target); texImage = _mesa_select_tex_image(ctx, texObj, target, level); if (_mesa_is_zero_size_texture(texImage)) return; if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { _mesa_debug(ctx, "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n", texObj->Name, _mesa_get_format_name(texImage->TexFormat), texImage->Width, texImage->Height); } _mesa_lock_texture(ctx, texObj); { ctx->Driver.GetCompressedTexImage(ctx, texImage, img); } _mesa_unlock_texture(ctx, texObj); }
/** * Specified by the GL_EXT_depth_bounds_test extension. */ void GLAPIENTRY _mesa_DepthBoundsEXT( GLclampd zmin, GLclampd zmax ) { GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glDepthBounds(%f, %f)\n", zmin, zmax); if (zmin > zmax) { _mesa_error(ctx, GL_INVALID_VALUE, "glDepthBoundsEXT(zmin > zmax)"); return; } zmin = CLAMP(zmin, 0.0, 1.0); zmax = CLAMP(zmax, 0.0, 1.0); if (ctx->Depth.BoundsMin == zmin && ctx->Depth.BoundsMax == zmax) return; FLUSH_VERTICES(ctx, _NEW_DEPTH); ctx->Depth.BoundsMin = (GLfloat) zmin; ctx->Depth.BoundsMax = (GLfloat) zmax; }
void _mesa_print_tri_caps( const char *name, GLuint flags ) { _mesa_debug(NULL, "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", name, flags, (flags & DD_FLATSHADE) ? "flat-shade, " : "", (flags & DD_SEPARATE_SPECULAR) ? "separate-specular, " : "", (flags & DD_TRI_LIGHT_TWOSIDE) ? "tri-light-twoside, " : "", (flags & DD_TRI_UNFILLED) ? "tri-unfilled, " : "", (flags & DD_TRI_STIPPLE) ? "tri-stipple, " : "", (flags & DD_TRI_OFFSET) ? "tri-offset, " : "", (flags & DD_TRI_SMOOTH) ? "tri-smooth, " : "", (flags & DD_LINE_SMOOTH) ? "line-smooth, " : "", (flags & DD_LINE_STIPPLE) ? "line-stipple, " : "", (flags & DD_LINE_WIDTH) ? "line-wide, " : "", (flags & DD_POINT_SMOOTH) ? "point-smooth, " : "", (flags & DD_POINT_SIZE) ? "point-size, " : "", (flags & DD_POINT_ATTEN) ? "point-atten, " : "", (flags & DD_TRI_CULL_FRONT_BACK) ? "cull-all, " : "" ); }
/** * Called from glDrawArraysInstancedBaseInstance when in immediate mode. */ static void GLAPIENTRY vbo_exec_DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei numInstances, GLuint baseInstance) { GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & VERBOSE_DRAW) _mesa_debug(ctx, "glDrawArraysInstancedBaseInstance(%s, %d, %d, %d, %d)\n", _mesa_lookup_enum_by_nr(mode), first, count, numInstances, baseInstance); if (!_mesa_validate_DrawArraysInstanced(ctx, mode, first, count, numInstances)) return; if (0) check_draw_arrays_data(ctx, first, count); vbo_draw_arrays(ctx, mode, first, count, numInstances, baseInstance); if (0) print_draw_arrays(ctx, mode, first, count); }
struct dynfn *tnl_makeX86Attr2f( TNLcontext *tnl, int key ) { static char temp[] = { 0xba, 0x78, 0x56, 0x34, 0x12, /* mov $DEST,%edx */ 0x8b, 0x44, 0x24, 0x04, /* mov 0x4(%esp,1),%eax */ 0x8b, 0x4c, 0x24, 0x08, /* mov 0x8(%esp,1),%ecx */ 0x89, 0x02, /* mov %eax,(%edx) */ 0x89, 0x4a, 0x04, /* mov %ecx,0x4(%edx) */ 0xc3, /* ret */ }; struct dynfn *dfn = MALLOC_STRUCT( dynfn ); if (TNL_DEBUG & DEBUG_CODEGEN) _mesa_debug(NULL, "%s 0x%08x\n", __FUNCTION__, key ); insert_at_head( &tnl->dfn_cache.TexCoord2f, dfn ); dfn->key = key; dfn->code = ALIGN_MALLOC( sizeof(temp), 16 ); memcpy (dfn->code, temp, sizeof(temp)); FIXUP(dfn->code, 1, 0x12345678, (int)tnl->texcoordptr[0]); return dfn; }
/** * Specify whether to cull front- or back-facing facets. * * \param mode culling mode. * * \sa glCullFace(). * * Verifies the parameter and updates gl_polygon_attrib::CullFaceMode. On * change, flushes the vertices and notifies the driver via * the dd_function_table::CullFace callback. */ void GLAPIENTRY _mesa_CullFace( GLenum mode ) { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (MESA_VERBOSE&VERBOSE_API) _mesa_debug(ctx, "glCullFace %s\n", _mesa_lookup_enum_by_nr(mode)); if (mode!=GL_FRONT && mode!=GL_BACK && mode!=GL_FRONT_AND_BACK) { _mesa_error( ctx, GL_INVALID_ENUM, "glCullFace" ); return; } if (ctx->Polygon.CullFaceMode == mode) return; FLUSH_VERTICES(ctx, _NEW_POLYGON); ctx->Polygon.CullFaceMode = mode; if (ctx->Driver.CullFace) ctx->Driver.CullFace( ctx, mode ); }
static void vbo_print_vertex_list( struct gl_context *ctx, void *data ) { struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data; GLuint i; (void) ctx; printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n", node->count, node->prim_count, node->vertex_size); for (i = 0 ; i < node->prim_count ; i++) { struct _mesa_prim *prim = &node->prim[i]; _mesa_debug(NULL, " prim %d: %s%s %d..%d %s %s\n", i, _mesa_lookup_prim_by_nr(prim->mode), prim->weak ? " (weak)" : "", prim->start, prim->start + prim->count, (prim->begin) ? "BEGIN" : "(wrap)", (prim->end) ? "END" : "(wrap)"); } }
/* * Called whenever we find an error during parsing. */ static void record_error(struct parse_state *parseState, const char *msg, int lineNo) { #ifdef DEBUG GLint line, column; const GLubyte *lineStr; lineStr = _mesa_find_line_column(parseState->start, parseState->pos, &line, &column); _mesa_debug(parseState->ctx, "nvfragparse.c(%d): line %d, column %d:%s (%s)\n", lineNo, line, column, (char *) lineStr, msg); _mesa_free((void *) lineStr); #else (void) lineNo; #endif /* Check that no error was already recorded. Only record the first one. */ if (parseState->ctx->Program.ErrorString[0] == 0) { _mesa_set_program_error(parseState->ctx, parseState->pos - parseState->start, msg); } }
static void GLAPIENTRY _mesa_GenQueriesARB(GLsizei n, GLuint *ids) { GLuint first; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glGenQueries(%d)\n", n); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)"); return; } /* No query objects can be active at this time! */ if (ctx->Query.CurrentOcclusionObject || ctx->Query.CurrentTimerObject) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB"); return; } first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n); if (first) { GLsizei i; for (i = 0; i < n; i++) { struct gl_query_object *q = ctx->Driver.NewQueryObject(ctx, first + i); if (!q) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB"); return; } ids[i] = first + i; _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q); } } }
/** * Enable or disable writing of frame buffer color components. * * \param red whether to mask writing of the red color component. * \param green whether to mask writing of the green color component. * \param blue whether to mask writing of the blue color component. * \param alpha whether to mask writing of the alpha color component. * * \sa glColorMask(). * * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a * change, flushes the vertices and notifies the driver via the * dd_function_table::ColorMask callback. */ void GLAPIENTRY _mesa_ColorMask( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha ) { GET_CURRENT_CONTEXT(ctx); GLubyte tmp[4]; GLuint i; GLboolean flushed; if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glColorMask(%d, %d, %d, %d)\n", red, green, blue, alpha); /* Shouldn't have any information about channel depth in core mesa * -- should probably store these as the native booleans: */ tmp[RCOMP] = red ? 0xff : 0x0; tmp[GCOMP] = green ? 0xff : 0x0; tmp[BCOMP] = blue ? 0xff : 0x0; tmp[ACOMP] = alpha ? 0xff : 0x0; flushed = GL_FALSE; for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) { if (!flushed) { FLUSH_VERTICES(ctx, ctx->DriverFlags.NewColorMask ? 0 : _NEW_COLOR); ctx->NewDriverState |= ctx->DriverFlags.NewColorMask; } flushed = GL_TRUE; COPY_4UBV(ctx->Color.ColorMask[i], tmp); } } if (ctx->Driver.ColorMask) ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); }
/** * Specify the alpha test function. * * \param func alpha comparison function. * \param ref reference value. * * Verifies the parameters and updates gl_colorbuffer_attrib. * On a change, flushes the vertices and notifies the driver via * dd_function_table::AlphaFunc callback. */ void GLAPIENTRY _mesa_AlphaFunc( GLenum func, GLclampf ref ) { GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n", _mesa_enum_to_string(func), ref); if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRefUnclamped == ref) return; /* no change */ switch (func) { case GL_NEVER: case GL_LESS: case GL_EQUAL: case GL_LEQUAL: case GL_GREATER: case GL_NOTEQUAL: case GL_GEQUAL: case GL_ALWAYS: FLUSH_VERTICES(ctx, ctx->DriverFlags.NewAlphaTest ? 0 : _NEW_COLOR); ctx->NewDriverState |= ctx->DriverFlags.NewAlphaTest; ctx->Color.AlphaFunc = func; ctx->Color.AlphaRefUnclamped = ref; ctx->Color.AlphaRef = CLAMP(ref, 0.0F, 1.0F); if (ctx->Driver.AlphaFunc) ctx->Driver.AlphaFunc(ctx, func, ctx->Color.AlphaRef); return; default: _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); return; } }
/* GL_ARB_multitexture */ void GLAPIENTRY _mesa_ActiveTextureARB(GLenum texture) { const GLuint texUnit = texture - GL_TEXTURE0; GLuint k; GET_CURRENT_CONTEXT(ctx); /* See OpenGL spec for glActiveTexture: */ k = MAX2(ctx->Const.MaxCombinedTextureImageUnits, ctx->Const.MaxTextureCoordUnits); ASSERT(k <= Elements(ctx->Texture.Unit)); ASSERT_OUTSIDE_BEGIN_END(ctx); if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) _mesa_debug(ctx, "glActiveTexture %s\n", _mesa_lookup_enum_by_nr(texture)); if (texUnit >= k) { _mesa_error(ctx, GL_INVALID_ENUM, "glActiveTexture(texture=%s)", _mesa_lookup_enum_by_nr(texture)); return; } if (ctx->Texture.CurrentUnit == texUnit) return; FLUSH_VERTICES(ctx, _NEW_TEXTURE); ctx->Texture.CurrentUnit = texUnit; if (ctx->Transform.MatrixMode == GL_TEXTURE) { /* update current stack pointer */ ctx->CurrentStack = &ctx->TextureMatrixStack[texUnit]; } }
/** * New with GL_EXT_timer_query */ static void GLAPIENTRY _mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params) { struct gl_query_object *q = NULL; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id, _mesa_lookup_enum_by_nr(pname)); if (id) q = _mesa_lookup_query_object(ctx, id); if (!q || q->Active) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id); return; } switch (pname) { case GL_QUERY_RESULT_ARB: if (!q->Ready) ctx->Driver.WaitQuery(ctx, q); *params = q->Result; break; case GL_QUERY_RESULT_AVAILABLE_ARB: if (!q->Ready) ctx->Driver.CheckQuery( ctx, q ); *params = q->Ready; break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)"); return; } }
void GLAPIENTRY _mesa_DispatchComputeGroupSizeARB(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z) { GET_CURRENT_CONTEXT(ctx); const GLuint num_groups[3] = { num_groups_x, num_groups_y, num_groups_z }; const GLuint group_size[3] = { group_size_x, group_size_y, group_size_z }; if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glDispatchComputeGroupSizeARB(%d, %d, %d, %d, %d, %d)\n", num_groups_x, num_groups_y, num_groups_z, group_size_x, group_size_y, group_size_z); if (!_mesa_validate_DispatchComputeGroupSizeARB(ctx, num_groups, group_size)) return; if (num_groups_x == 0u || num_groups_y == 0u || num_groups_z == 0u) return; ctx->Driver.DispatchComputeGroupSize(ctx, num_groups, group_size); }
/** * Specify the alpha test function. * * \param func alpha comparison function. * \param ref reference value. * * Verifies the parameters and updates gl_colorbuffer_attrib. * On a change, flushes the vertices and notifies the driver via * dd_function_table::AlphaFunc callback. */ void GLAPIENTRY _mesa_AlphaFunc( GLenum func, GLclampf ref ) { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n", _mesa_lookup_enum_by_nr(func), ref); switch (func) { case GL_NEVER: case GL_LESS: case GL_EQUAL: case GL_LEQUAL: case GL_GREATER: case GL_NOTEQUAL: case GL_GEQUAL: case GL_ALWAYS: if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRefUnclamped == ref) return; /* no change */ FLUSH_VERTICES(ctx, _NEW_COLOR); ctx->Color.AlphaFunc = func; ctx->Color.AlphaRefUnclamped = ref; ctx->Color.AlphaRef = CLAMP(ref, 0.0F, 1.0F); if (ctx->Driver.AlphaFunc) ctx->Driver.AlphaFunc(ctx, func, ctx->Color.AlphaRef); return; default: _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); return; } }
/** * Generate a set of unique buffer object IDs and store them in \c buffer. * * \param n Number of IDs to generate. * \param buffer Array of \c n locations to store the IDs. */ void GLAPIENTRY _mesa_GenBuffersARB(GLsizei n, GLuint *buffer) { GET_CURRENT_CONTEXT(ctx); GLuint first; GLint i; ASSERT_OUTSIDE_BEGIN_END(ctx); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glGenBuffers(%d)\n", n); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB"); return; } if (!buffer) { return; } /* * This must be atomic (generation and allocation of buffer object IDs) */ _glthread_LOCK_MUTEX(ctx->Shared->Mutex); first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n); /* Insert the ID and pointer to dummy buffer object into hash table */ for (i = 0; i < n; i++) { _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, &DummyBufferObject); buffer[i] = first + i; } _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); }
struct dynfn *tnl_makeX86Attr4ub( TNLcontext *tnl, int key ) { if (TNL_DEBUG & DEBUG_CODEGEN) _mesa_debug(NULL, "%s 0x%08x\n", __FUNCTION__, key ); if (key & TNL_CP_VC_FRMT_PKCOLOR) { /* XXX push/pop */ static char temp[] = { 0x53, /* push %ebx */ 0x8b, 0x44, 0x24, 0x08, /* mov 0x8(%esp,1),%eax */ 0x8b, 0x54, 0x24, 0x0c, /* mov 0xc(%esp,1),%edx */ 0x8b, 0x4c, 0x24, 0x10, /* mov 0x10(%esp,1),%ecx */ 0x8b, 0x5c, 0x24, 0x14, /* mov 0x14(%esp,1),%ebx */ 0xa2, 0, 0, 0, 0, /* mov %al,DEST */ 0x88, 0x15, 0, 0, 0, 0, /* mov %dl,DEST+1 */ 0x88, 0x0d, 0, 0, 0, 0, /* mov %cl,DEST+2 */ 0x88, 0x1d, 0, 0, 0, 0, /* mov %bl,DEST+3 */ 0x5b, /* pop %ebx */ 0xc3, /* ret */ }; struct dynfn *dfn = MALLOC_STRUCT( dynfn ); insert_at_head( &tnl->dfn_cache.Color4ub, dfn ); dfn->key = key; dfn->code = ALIGN_MALLOC( sizeof(temp), 16 ); memcpy (dfn->code, temp, sizeof(temp)); FIXUP(dfn->code, 18, 0x0, (int)tnl->ubytecolorptr); FIXUP(dfn->code, 24, 0x0, (int)tnl->ubytecolorptr+1); FIXUP(dfn->code, 30, 0x0, (int)tnl->ubytecolorptr+2); FIXUP(dfn->code, 36, 0x0, (int)tnl->ubytecolorptr+3); return dfn; } else return 0; }
void GLAPIENTRY _mesa_GetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params) { GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & VERBOSE_API) { _mesa_debug(ctx, "glGetProgramResourceiv(%u, %s, %u, %d, %p, %d, %p, %p)\n", program, _mesa_enum_to_string(programInterface), index, propCount, props, bufSize, length, params); } struct gl_shader_program *shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceiv"); if (!shProg || !params) return; /* The error INVALID_VALUE is generated if <propCount> is zero. * Note that we check < 0 here because it makes sense to bail early. */ if (propCount <= 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramResourceiv(propCount <= 0)"); return; } /* No need to write any properties, user requested none. */ if (bufSize == 0) return; _mesa_get_program_resourceiv(shProg, programInterface, index, propCount, props, bufSize, length, params); }
/** * Update a range DepthRange values * * \param first starting array index * \param count count of DepthRange items to update * \param v pointer to memory containing * GLclampd near and far clip-plane values */ void GLAPIENTRY _mesa_DepthRangeArrayv(GLuint first, GLsizei count, const GLclampd *v) { int i; const struct gl_depthrange_inputs *const p = (struct gl_depthrange_inputs *) v; GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glDepthRangeArrayv %d %d\n", first, count); if ((first + count) > ctx->Const.MaxViewports) { _mesa_error(ctx, GL_INVALID_VALUE, "glDepthRangev: first (%d) + count (%d) >= MaxViewports (%d)", first, count, ctx->Const.MaxViewports); return; } for (i = 0; i < count; i++) set_depth_range_no_notify(ctx, i + first, p[i].Near, p[i].Far); if (ctx->Driver.DepthRange) ctx->Driver.DepthRange(ctx); }
/** * See if textures are loaded in texture memory. * * \param n number of textures to query. * \param texName array with the texture names. * \param residences array which will hold the residence status. * * \return GL_TRUE if all textures are resident and \p residences is left unchanged, * * Note: we assume all textures are always resident */ GLboolean GLAPIENTRY _mesa_AreTexturesResident(GLsizei n, const GLuint *texName, GLboolean *residences) { GET_CURRENT_CONTEXT(ctx); GLboolean allResident = GL_TRUE; GLint i; ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) _mesa_debug(ctx, "glAreTexturesResident %d\n", n); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)"); return GL_FALSE; } if (!texName || !residences) return GL_FALSE; /* We only do error checking on the texture names */ for (i = 0; i < n; i++) { struct gl_texture_object *t; if (texName[i] == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); return GL_FALSE; } t = _mesa_lookup_texture(ctx, texName[i]); if (!t) { _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); return GL_FALSE; } } return allResident; }
void GLAPIENTRY _mesa_BlendEquationSeparate( GLenum modeRGB, GLenum modeA ) { GET_CURRENT_CONTEXT(ctx); const unsigned numBuffers = num_buffers(ctx); unsigned buf; bool changed = false; if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n", _mesa_enum_to_string(modeRGB), _mesa_enum_to_string(modeA)); if (ctx->Color._BlendEquationPerBuffer) { /* Check all per-buffer states */ for (buf = 0; buf < numBuffers; buf++) { if (ctx->Color.Blend[buf].EquationRGB != modeRGB || ctx->Color.Blend[buf].EquationA != modeA) { changed = true; break; } } } else { /* only need to check 0th per-buffer state */ if (ctx->Color.Blend[0].EquationRGB != modeRGB || ctx->Color.Blend[0].EquationA != modeA) { changed = true; } } if (!changed) return; if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendEquationSeparateEXT not supported by driver"); return; } /* Only allow simple blending equations. * The GL_KHR_blend_equation_advanced spec says: * * "NOTE: These enums are not accepted by the <modeRGB> or <modeAlpha> * parameters of BlendEquationSeparate or BlendEquationSeparatei." */ if (!legal_simple_blend_equation(ctx, modeRGB)) { _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); return; } if (!legal_simple_blend_equation(ctx, modeA)) { _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); return; } FLUSH_VERTICES(ctx, _NEW_COLOR); for (buf = 0; buf < numBuffers; buf++) { ctx->Color.Blend[buf].EquationRGB = modeRGB; ctx->Color.Blend[buf].EquationA = modeA; } ctx->Color._BlendEquationPerBuffer = GL_FALSE; ctx->Color._AdvancedBlendMode = BLEND_NONE; if (ctx->Driver.BlendEquationSeparate) ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA); }
/** * 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(ctx, 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 (ctx->API == API_OPENGL_CORE) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTexture"); return; } /* 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); }
/** * Set the separate blend source/dest factors for all draw buffers. * * \param sfactorRGB RGB source factor operator. * \param dfactorRGB RGB destination factor operator. * \param sfactorA alpha source factor operator. * \param dfactorA alpha destination factor operator. */ void GLAPIENTRY _mesa_BlendFuncSeparate( GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorA, GLenum dfactorA ) { GET_CURRENT_CONTEXT(ctx); const unsigned numBuffers = num_buffers(ctx); unsigned buf; bool changed = false; if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n", _mesa_enum_to_string(sfactorRGB), _mesa_enum_to_string(dfactorRGB), _mesa_enum_to_string(sfactorA), _mesa_enum_to_string(dfactorA)); /* Check if we're really changing any state. If not, return early. */ if (ctx->Color._BlendFuncPerBuffer) { /* Check all per-buffer states */ for (buf = 0; buf < numBuffers; buf++) { if (ctx->Color.Blend[buf].SrcRGB != sfactorRGB || ctx->Color.Blend[buf].DstRGB != dfactorRGB || ctx->Color.Blend[buf].SrcA != sfactorA || ctx->Color.Blend[buf].DstA != dfactorA) { changed = true; break; } } } else { /* only need to check 0th per-buffer state */ if (ctx->Color.Blend[0].SrcRGB != sfactorRGB || ctx->Color.Blend[0].DstRGB != dfactorRGB || ctx->Color.Blend[0].SrcA != sfactorA || ctx->Color.Blend[0].DstA != dfactorA) { changed = true; } } if (!changed) return; if (!validate_blend_factors(ctx, "glBlendFuncSeparate", sfactorRGB, dfactorRGB, sfactorA, dfactorA)) { return; } FLUSH_VERTICES(ctx, _NEW_COLOR); for (buf = 0; buf < numBuffers; buf++) { ctx->Color.Blend[buf].SrcRGB = sfactorRGB; ctx->Color.Blend[buf].DstRGB = dfactorRGB; ctx->Color.Blend[buf].SrcA = sfactorA; ctx->Color.Blend[buf].DstA = dfactorA; } update_uses_dual_src(ctx, 0); for (buf = 1; buf < numBuffers; buf++) { ctx->Color.Blend[buf]._UsesDualSrc = ctx->Color.Blend[0]._UsesDualSrc; } ctx->Color._BlendFuncPerBuffer = GL_FALSE; if (ctx->Driver.BlendFuncSeparate) { ctx->Driver.BlendFuncSeparate(ctx, sfactorRGB, dfactorRGB, sfactorA, dfactorA); } }
/** * Return pointer-valued state, such as a vertex array pointer. * * \param pname names state to be queried * \param params returns the pointer value * * \sa glGetPointerv(). * * Tries to get the specified pointer via dd_function_table::GetPointerv, * otherwise gets the specified pointer from the current context. */ void GLAPIENTRY _mesa_GetPointerv( GLenum pname, GLvoid **params ) { GET_CURRENT_CONTEXT(ctx); const GLuint clientUnit = ctx->Array.ActiveTexture; ASSERT_OUTSIDE_BEGIN_END(ctx); if (!params) return; if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glGetPointerv %s\n", _mesa_lookup_enum_by_nr(pname)); switch (pname) { case GL_VERTEX_ARRAY_POINTER: if (ctx->API != API_OPENGL_COMPAT && ctx->API != API_OPENGLES) goto invalid_pname; *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Ptr; break; case GL_NORMAL_ARRAY_POINTER: if (ctx->API != API_OPENGL_COMPAT && ctx->API != API_OPENGLES) goto invalid_pname; *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Ptr; break; case GL_COLOR_ARRAY_POINTER: if (ctx->API != API_OPENGL_COMPAT && ctx->API != API_OPENGLES) goto invalid_pname; *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Ptr; break; case GL_SECONDARY_COLOR_ARRAY_POINTER_EXT: if (ctx->API != API_OPENGL_COMPAT) goto invalid_pname; *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Ptr; break; case GL_FOG_COORDINATE_ARRAY_POINTER_EXT: if (ctx->API != API_OPENGL_COMPAT) goto invalid_pname; *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_FOG].Ptr; break; case GL_INDEX_ARRAY_POINTER: if (ctx->API != API_OPENGL_COMPAT) goto invalid_pname; *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Ptr; break; case GL_TEXTURE_COORD_ARRAY_POINTER: if (ctx->API != API_OPENGL_COMPAT && ctx->API != API_OPENGLES) goto invalid_pname; *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_TEX(clientUnit)].Ptr; break; case GL_EDGE_FLAG_ARRAY_POINTER: if (ctx->API != API_OPENGL_COMPAT) goto invalid_pname; *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Ptr; break; case GL_FEEDBACK_BUFFER_POINTER: if (ctx->API != API_OPENGL_COMPAT) goto invalid_pname; *params = ctx->Feedback.Buffer; break; case GL_SELECTION_BUFFER_POINTER: if (ctx->API != API_OPENGL_COMPAT) goto invalid_pname; *params = ctx->Select.Buffer; break; case GL_POINT_SIZE_ARRAY_POINTER_OES: if (ctx->API != API_OPENGLES) goto invalid_pname; *params = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POINT_SIZE].Ptr; break; case GL_DEBUG_CALLBACK_FUNCTION_ARB: if (!_mesa_is_desktop_gl(ctx)) goto invalid_pname; *params = (GLvoid *) ctx->Debug.Callback; break; case GL_DEBUG_CALLBACK_USER_PARAM_ARB: if (!_mesa_is_desktop_gl(ctx)) goto invalid_pname; *params = ctx->Debug.CallbackData; break; default: goto invalid_pname; } return; invalid_pname: _mesa_error( ctx, GL_INVALID_ENUM, "glGetPointerv" ); return; }
/** * Construct the GL_EXTENSIONS string. Called the first time that * glGetString(GL_EXTENSIONS) is called. */ GLubyte* _mesa_make_extension_string(struct gl_context *ctx) { /* The extension string. */ char *exts = 0; /* Length of extension string. */ size_t length = 0; /* Number of extensions */ unsigned count; /* Indices of the extensions sorted by year */ extension_index *extension_indices; /* String of extra extensions. */ char *extra_extensions = get_extension_override(ctx); GLboolean *base = (GLboolean *) &ctx->Extensions; const struct extension *i; unsigned j; unsigned maxYear = ~0; unsigned api_set = (1 << ctx->API); if (_mesa_is_gles3(ctx)) api_set |= ES3; /* Check if the MESA_EXTENSION_MAX_YEAR env var is set */ { const char *env = getenv("MESA_EXTENSION_MAX_YEAR"); if (env) { maxYear = atoi(env); _mesa_debug(ctx, "Note: limiting GL extensions to %u or earlier\n", maxYear); } } /* Compute length of the extension string. */ count = 0; for (i = extension_table; i->name != 0; ++i) { if (base[i->offset] && i->year <= maxYear && (i->api_set & api_set)) { length += strlen(i->name) + 1; /* +1 for space */ ++count; } } if (extra_extensions != NULL) length += 1 + strlen(extra_extensions); /* +1 for space */ exts = calloc(ALIGN(length + 1, 4), sizeof(char)); if (exts == NULL) { free(extra_extensions); return NULL; } extension_indices = malloc(count * sizeof(extension_index)); if (extension_indices == NULL) { free(exts); free(extra_extensions); return NULL; } /* Sort extensions in chronological order because certain old applications (e.g., * Quake3 demo) store the extension list in a static size buffer so chronologically * order ensure that the extensions that such applications expect will fit into * that buffer. */ j = 0; for (i = extension_table; i->name != 0; ++i) { if (base[i->offset] && i->year <= maxYear && (i->api_set & api_set)) { extension_indices[j++] = i - extension_table; } } assert(j == count); qsort(extension_indices, count, sizeof *extension_indices, extension_compare); /* Build the extension string.*/ for (j = 0; j < count; ++j) { i = &extension_table[extension_indices[j]]; assert(base[i->offset] && (i->api_set & api_set)); strcat(exts, i->name); strcat(exts, " "); } free(extension_indices); if (extra_extensions != 0) { strcat(exts, extra_extensions); free(extra_extensions); } return (GLubyte *) exts; }
/** * 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 (state && ctx->DrawBuffer->Visual.depthBits == 0) { _mesa_warning(ctx, "glEnable(GL_DEPTH_BOUNDS_TEST_EXT) but no depth buffer"); return; } if (ctx->Depth.BoundsTest == state) return; FLUSH_VERTICES(ctx, _NEW_DEPTH); ctx->Depth.BoundsTest = 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; 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_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param ) { GLuint maxUnit; GET_CURRENT_CONTEXT(ctx); struct gl_texture_unit *texUnit; ASSERT_OUTSIDE_BEGIN_END(ctx); maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV) ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxTextureImageUnits; if (ctx->Texture.CurrentUnit >= maxUnit) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexEnvfv(current unit)"); return; } texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; #define TE_ERROR(errCode, msg, value) \ _mesa_error(ctx, errCode, msg, _mesa_lookup_enum_by_nr(value)); if (target == GL_TEXTURE_ENV) { switch (pname) { case GL_TEXTURE_ENV_MODE: { GLenum mode = (GLenum) (GLint) *param; if (mode == GL_REPLACE_EXT) mode = GL_REPLACE; if (texUnit->EnvMode == mode) return; if (mode == GL_MODULATE || mode == GL_BLEND || mode == GL_DECAL || mode == GL_REPLACE || (mode == GL_ADD && ctx->Extensions.EXT_texture_env_add) || (mode == GL_COMBINE && (ctx->Extensions.EXT_texture_env_combine || ctx->Extensions.ARB_texture_env_combine))) { /* legal */ FLUSH_VERTICES(ctx, _NEW_TEXTURE); texUnit->EnvMode = mode; } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode); return; } } break; case GL_TEXTURE_ENV_COLOR: { GLfloat tmp[4]; tmp[0] = CLAMP( param[0], 0.0F, 1.0F ); tmp[1] = CLAMP( param[1], 0.0F, 1.0F ); tmp[2] = CLAMP( param[2], 0.0F, 1.0F ); tmp[3] = CLAMP( param[3], 0.0F, 1.0F ); if (TEST_EQ_4V(tmp, texUnit->EnvColor)) return; FLUSH_VERTICES(ctx, _NEW_TEXTURE); COPY_4FV(texUnit->EnvColor, tmp); } break; case GL_COMBINE_RGB: if (ctx->Extensions.EXT_texture_env_combine || ctx->Extensions.ARB_texture_env_combine) { const GLenum mode = (GLenum) (GLint) *param; if (texUnit->Combine.ModeRGB == mode) return; switch (mode) { case GL_REPLACE: case GL_MODULATE: case GL_ADD: case GL_ADD_SIGNED: case GL_INTERPOLATE: /* OK */ break; case GL_SUBTRACT: if (!ctx->Extensions.ARB_texture_env_combine) { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode); return; } break; case GL_DOT3_RGB_EXT: case GL_DOT3_RGBA_EXT: if (!ctx->Extensions.EXT_texture_env_dot3) { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode); return; } break; case GL_DOT3_RGB: case GL_DOT3_RGBA: if (!ctx->Extensions.ARB_texture_env_dot3) { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode); return; } break; case GL_MODULATE_ADD_ATI: case GL_MODULATE_SIGNED_ADD_ATI: case GL_MODULATE_SUBTRACT_ATI: if (!ctx->Extensions.ATI_texture_env_combine3) { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode); return; } break; default: TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode); return; } FLUSH_VERTICES(ctx, _NEW_TEXTURE); texUnit->Combine.ModeRGB = mode; } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); return; } break; case GL_COMBINE_ALPHA: if (ctx->Extensions.EXT_texture_env_combine || ctx->Extensions.ARB_texture_env_combine) { const GLenum mode = (GLenum) (GLint) *param; if (texUnit->Combine.ModeA == mode) return; switch (mode) { case GL_REPLACE: case GL_MODULATE: case GL_ADD: case GL_ADD_SIGNED: case GL_INTERPOLATE: /* OK */ break; case GL_SUBTRACT: if (!ctx->Extensions.ARB_texture_env_combine) { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode); return; } break; case GL_MODULATE_ADD_ATI: case GL_MODULATE_SIGNED_ADD_ATI: case GL_MODULATE_SUBTRACT_ATI: if (!ctx->Extensions.ATI_texture_env_combine3) { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode); return; } break; default: TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode); return; } FLUSH_VERTICES(ctx, _NEW_TEXTURE); texUnit->Combine.ModeA = mode; } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); return; } break; case GL_SOURCE0_RGB: case GL_SOURCE1_RGB: case GL_SOURCE2_RGB: if (ctx->Extensions.EXT_texture_env_combine || ctx->Extensions.ARB_texture_env_combine) { const GLenum source = (GLenum) (GLint) *param; const GLuint s = pname - GL_SOURCE0_RGB; if (texUnit->Combine.SourceRGB[s] == source) return; if (source == GL_TEXTURE || source == GL_CONSTANT || source == GL_PRIMARY_COLOR || source == GL_PREVIOUS || (ctx->Extensions.ARB_texture_env_crossbar && source >= GL_TEXTURE0 && source < GL_TEXTURE0 + ctx->Const.MaxTextureUnits) || (ctx->Extensions.ATI_texture_env_combine3 && (source == GL_ZERO || source == GL_ONE))) { /* legal */ FLUSH_VERTICES(ctx, _NEW_TEXTURE); texUnit->Combine.SourceRGB[s] = source; } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", source); return; } } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); return; } break; case GL_SOURCE0_ALPHA: case GL_SOURCE1_ALPHA: case GL_SOURCE2_ALPHA: if (ctx->Extensions.EXT_texture_env_combine || ctx->Extensions.ARB_texture_env_combine) { const GLenum source = (GLenum) (GLint) *param; const GLuint s = pname - GL_SOURCE0_ALPHA; if (texUnit->Combine.SourceA[s] == source) return; if (source == GL_TEXTURE || source == GL_CONSTANT || source == GL_PRIMARY_COLOR || source == GL_PREVIOUS || (ctx->Extensions.ARB_texture_env_crossbar && source >= GL_TEXTURE0 && source < GL_TEXTURE0 + ctx->Const.MaxTextureUnits) || (ctx->Extensions.ATI_texture_env_combine3 && (source == GL_ZERO || source == GL_ONE))) { /* legal */ FLUSH_VERTICES(ctx, _NEW_TEXTURE); texUnit->Combine.SourceA[s] = source; } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", source); return; } } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); return; } break; case GL_OPERAND0_RGB: case GL_OPERAND1_RGB: if (ctx->Extensions.EXT_texture_env_combine || ctx->Extensions.ARB_texture_env_combine) { const GLenum operand = (GLenum) (GLint) *param; const GLuint s = pname - GL_OPERAND0_RGB; if (texUnit->Combine.OperandRGB[s] == operand) return; switch (operand) { case GL_SRC_COLOR: case GL_ONE_MINUS_SRC_COLOR: case GL_SRC_ALPHA: case GL_ONE_MINUS_SRC_ALPHA: FLUSH_VERTICES(ctx, _NEW_TEXTURE); texUnit->Combine.OperandRGB[s] = operand; break; default: TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand); return; } } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); return; } break; case GL_OPERAND0_ALPHA: case GL_OPERAND1_ALPHA: if (ctx->Extensions.EXT_texture_env_combine || ctx->Extensions.ARB_texture_env_combine) { const GLenum operand = (GLenum) (GLint) *param; if (texUnit->Combine.OperandA[pname-GL_OPERAND0_ALPHA] == operand) return; switch (operand) { case GL_SRC_ALPHA: case GL_ONE_MINUS_SRC_ALPHA: FLUSH_VERTICES(ctx, _NEW_TEXTURE); texUnit->Combine.OperandA[pname-GL_OPERAND0_ALPHA] = operand; break; default: TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand); return; } } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); return; } break; case GL_OPERAND2_RGB: if (ctx->Extensions.ARB_texture_env_combine) { const GLenum operand = (GLenum) (GLint) *param; if (texUnit->Combine.OperandRGB[2] == operand) return; switch (operand) { case GL_SRC_COLOR: /* ARB combine only */ case GL_ONE_MINUS_SRC_COLOR: /* ARB combine only */ case GL_SRC_ALPHA: case GL_ONE_MINUS_SRC_ALPHA: /* ARB combine only */ FLUSH_VERTICES(ctx, _NEW_TEXTURE); texUnit->Combine.OperandRGB[2] = operand; break; default: TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand); return; } } else if (ctx->Extensions.EXT_texture_env_combine) { const GLenum operand = (GLenum) (GLint) *param; if (texUnit->Combine.OperandRGB[2] == operand) return; /* operand must be GL_SRC_ALPHA which is the initial value - thus don't need to actually compare the operand to the possible value */ else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand); return; } } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); return; } break; case GL_OPERAND2_ALPHA: if (ctx->Extensions.ARB_texture_env_combine) { const GLenum operand = (GLenum) (GLint) *param; if (texUnit->Combine.OperandA[2] == operand) return; switch (operand) { case GL_SRC_ALPHA: case GL_ONE_MINUS_SRC_ALPHA: /* ARB combine only */ FLUSH_VERTICES(ctx, _NEW_TEXTURE); texUnit->Combine.OperandA[2] = operand; break; default: TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand); return; } } else if (ctx->Extensions.EXT_texture_env_combine) { const GLenum operand = (GLenum) (GLint) *param; if (texUnit->Combine.OperandA[2] == operand) return; /* operand must be GL_SRC_ALPHA which is the initial value - thus don't need to actually compare the operand to the possible value */ else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand); return; } } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); return; } break; case GL_RGB_SCALE: if (ctx->Extensions.EXT_texture_env_combine || ctx->Extensions.ARB_texture_env_combine) { GLuint newshift; if (*param == 1.0) { newshift = 0; } else if (*param == 2.0) { newshift = 1; } else if (*param == 4.0) { newshift = 2; } else { _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(GL_RGB_SCALE not 1, 2 or 4)" ); return; } if (texUnit->Combine.ScaleShiftRGB == newshift) return; FLUSH_VERTICES(ctx, _NEW_TEXTURE); texUnit->Combine.ScaleShiftRGB = newshift; } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); return; } break; case GL_ALPHA_SCALE: if (ctx->Extensions.EXT_texture_env_combine || ctx->Extensions.ARB_texture_env_combine) { GLuint newshift; if (*param == 1.0) { newshift = 0; } else if (*param == 2.0) { newshift = 1; } else if (*param == 4.0) { newshift = 2; } else { _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(GL_ALPHA_SCALE not 1, 2 or 4)" ); return; } if (texUnit->Combine.ScaleShiftA == newshift) return; FLUSH_VERTICES(ctx, _NEW_TEXTURE); texUnit->Combine.ScaleShiftA = newshift; } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); return; } break; default: _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname)" ); return; } } else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) { /* GL_EXT_texture_lod_bias */ if (!ctx->Extensions.EXT_texture_lod_bias) { _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)", target ); return; } if (pname == GL_TEXTURE_LOD_BIAS_EXT) { if (texUnit->LodBias == param[0]) return; FLUSH_VERTICES(ctx, _NEW_TEXTURE); texUnit->LodBias = param[0]; } else { TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); return; } } else if (target == GL_POINT_SPRITE_NV) { /* GL_ARB_point_sprite / GL_NV_point_sprite */ if (!ctx->Extensions.NV_point_sprite && !ctx->Extensions.ARB_point_sprite) { _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)", target ); return; } if (pname == GL_COORD_REPLACE_NV) { const GLenum value = (GLenum) param[0]; if (value == GL_TRUE || value == GL_FALSE) { /* It's kind of weird to set point state via glTexEnv, * but that's what the spec calls for. */ const GLboolean state = (GLboolean) value; if (ctx->Point.CoordReplace[ctx->Texture.CurrentUnit] == state) return; FLUSH_VERTICES(ctx, _NEW_POINT); ctx->Point.CoordReplace[ctx->Texture.CurrentUnit] = state; } else { _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(param=0x%x)", value); return; } } else { _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname=0x%x)", pname ); return; } } else { _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)",target ); return; } if (MESA_VERBOSE&(VERBOSE_API|VERBOSE_TEXTURE)) _mesa_debug(ctx, "glTexEnv %s %s %.1f(%s) ...\n", _mesa_lookup_enum_by_nr(target), _mesa_lookup_enum_by_nr(pname), *param, _mesa_lookup_enum_by_nr((GLenum) (GLint) *param)); /* Tell device driver about the new texture environment */ if (ctx->Driver.TexEnv) { (*ctx->Driver.TexEnv)( ctx, target, pname, param ); } }