* \file state.c
* State management.
*
- * This file manages recalculation of derived values in GLcontext.
+ * This file manages recalculation of derived values in struct gl_context.
*/
#include "framebuffer.h"
#include "light.h"
#include "matrix.h"
-#if FEATURE_pixel_transfer
#include "pixel.h"
-#endif
-#include "shader/program.h"
-#include "shader/prog_parameter.h"
+#include "program/program.h"
+#include "program/prog_parameter.h"
#include "state.h"
#include "stencil.h"
#include "texenvprogram.h"
#include "texobj.h"
#include "texstate.h"
-#include "viewport.h"
static void
-update_separate_specular(GLcontext *ctx)
+update_separate_specular(struct gl_context *ctx)
{
if (NEED_SECONDARY_COLOR(ctx))
ctx->_TriangleCaps |= DD_SEPARATE_SPECULAR;
/**
- * Update state dependent on vertex arrays.
+ * Compute the index of the last array element that can be safely accessed
+ * in a vertex array. We can really only do this when the array lives in
+ * a VBO.
+ * The array->_MaxElement field will be updated.
+ * Later in glDrawArrays/Elements/etc we can do some bounds checking.
+ */
+static void
+compute_max_element(struct gl_client_array *array)
+{
+ assert(array->Enabled);
+ if (array->BufferObj->Name) {
+ GLsizeiptrARB offset = (GLsizeiptrARB) array->Ptr;
+ GLsizeiptrARB obj_size = (GLsizeiptrARB) array->BufferObj->Size;
+
+ if (offset < obj_size) {
+ array->_MaxElement = (obj_size - offset +
+ array->StrideB -
+ array->_ElementSize) / array->StrideB;
+ } else {
+ array->_MaxElement = 0;
+ }
+ }
+ else {
+ /* user-space array, no idea how big it is */
+ array->_MaxElement = 2 * 1000 * 1000 * 1000; /* just a big number */
+ }
+}
+
+
+/**
+ * Helper for update_arrays().
+ * \return min(current min, array->_MaxElement).
+ */
+static GLuint
+update_min(GLuint min, struct gl_client_array *array)
+{
+ compute_max_element(array);
+ return MIN2(min, array->_MaxElement);
+}
+
+
+/**
+ * Update ctx->Array._MaxElement (the max legal index into all enabled arrays).
+ * Need to do this upon new array state or new buffer object state.
*/
static void
-update_arrays( GLcontext *ctx )
+update_arrays( struct gl_context *ctx )
{
- GLuint i, min;
+ struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
+ GLuint i, min = ~0;
/* find min of _MaxElement values for all enabled arrays */
/* 0 */
if (ctx->VertexProgram._Current
- && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) {
- min = ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS]._MaxElement;
+ && arrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_POS]);
}
- else if (ctx->Array.ArrayObj->Vertex.Enabled) {
- min = ctx->Array.ArrayObj->Vertex._MaxElement;
- }
- else {
- /* can't draw anything without vertex positions! */
- min = 0;
+ else if (arrayObj->Vertex.Enabled) {
+ min = update_min(min, &arrayObj->Vertex);
}
/* 1 */
if (ctx->VertexProgram._Enabled
- && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT].Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT]._MaxElement);
+ && arrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT]);
}
/* no conventional vertex weight array */
/* 2 */
if (ctx->VertexProgram._Enabled
- && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_NORMAL]._MaxElement);
+ && arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL]);
}
- else if (ctx->Array.ArrayObj->Normal.Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->Normal._MaxElement);
+ else if (arrayObj->Normal.Enabled) {
+ min = update_min(min, &arrayObj->Normal);
}
/* 3 */
if (ctx->VertexProgram._Enabled
- && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR0]._MaxElement);
+ && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0]);
}
- else if (ctx->Array.ArrayObj->Color.Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->Color._MaxElement);
+ else if (arrayObj->Color.Enabled) {
+ min = update_min(min, &arrayObj->Color);
}
/* 4 */
if (ctx->VertexProgram._Enabled
- && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR1]._MaxElement);
+ && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1]);
}
- else if (ctx->Array.ArrayObj->SecondaryColor.Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->SecondaryColor._MaxElement);
+ else if (arrayObj->SecondaryColor.Enabled) {
+ min = update_min(min, &arrayObj->SecondaryColor);
}
/* 5 */
if (ctx->VertexProgram._Enabled
- && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_FOG].Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_FOG]._MaxElement);
+ && arrayObj->VertexAttrib[VERT_ATTRIB_FOG].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_FOG]);
}
- else if (ctx->Array.ArrayObj->FogCoord.Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->FogCoord._MaxElement);
+ else if (arrayObj->FogCoord.Enabled) {
+ min = update_min(min, &arrayObj->FogCoord);
}
/* 6 */
if (ctx->VertexProgram._Enabled
- && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX]._MaxElement);
+ && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX]);
}
- else if (ctx->Array.ArrayObj->Index.Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->Index._MaxElement);
+ else if (arrayObj->Index.Enabled) {
+ min = update_min(min, &arrayObj->Index);
}
-
/* 7 */
if (ctx->VertexProgram._Enabled
- && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG]._MaxElement);
+ && arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG]);
}
/* 8..15 */
for (i = VERT_ATTRIB_TEX0; i <= VERT_ATTRIB_TEX7; i++) {
if (ctx->VertexProgram._Enabled
- && ctx->Array.ArrayObj->VertexAttrib[i].Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[i]._MaxElement);
+ && arrayObj->VertexAttrib[i].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[i]);
}
else if (i - VERT_ATTRIB_TEX0 < ctx->Const.MaxTextureCoordUnits
- && ctx->Array.ArrayObj->TexCoord[i - VERT_ATTRIB_TEX0].Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->TexCoord[i - VERT_ATTRIB_TEX0]._MaxElement);
+ && arrayObj->TexCoord[i - VERT_ATTRIB_TEX0].Enabled) {
+ min = update_min(min, &arrayObj->TexCoord[i - VERT_ATTRIB_TEX0]);
}
}
/* 16..31 */
if (ctx->VertexProgram._Current) {
- for (i = 0; i < Elements(ctx->Array.ArrayObj->VertexAttrib); i++) {
- if (ctx->Array.ArrayObj->VertexAttrib[i].Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[i]._MaxElement);
+ for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) {
+ if (arrayObj->VertexAttrib[i].Enabled) {
+ min = update_min(min, &arrayObj->VertexAttrib[i]);
}
}
}
- if (ctx->Array.ArrayObj->EdgeFlag.Enabled) {
- min = MIN2(min, ctx->Array.ArrayObj->EdgeFlag._MaxElement);
+ if (arrayObj->EdgeFlag.Enabled) {
+ min = update_min(min, &arrayObj->EdgeFlag);
}
/* _MaxElement is one past the last legal array element */
- ctx->Array._MaxElement = min;
+ arrayObj->_MaxElement = min;
}
* This needs to be done before texture state validation.
*/
static void
-update_program_enables(GLcontext *ctx)
+update_program_enables(struct gl_context *ctx)
{
/* These _Enabled flags indicate if the program is enabled AND valid. */
ctx->VertexProgram._Enabled = ctx->VertexProgram.Enabled
* or fragment program is being used.
*/
static GLbitfield
-update_program(GLcontext *ctx)
+update_program(struct gl_context *ctx)
{
- const struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
+ const struct gl_shader_program *vsProg = ctx->Shader.CurrentVertexProgram;
+ const struct gl_shader_program *gsProg = ctx->Shader.CurrentGeometryProgram;
+ const struct gl_shader_program *fsProg = ctx->Shader.CurrentFragmentProgram;
const struct gl_vertex_program *prevVP = ctx->VertexProgram._Current;
const struct gl_fragment_program *prevFP = ctx->FragmentProgram._Current;
+ const struct gl_geometry_program *prevGP = ctx->GeometryProgram._Current;
GLbitfield new_state = 0x0;
/*
* come up, or matter.
*/
- if (shProg && shProg->LinkStatus && shProg->FragmentProgram) {
+ if (fsProg && fsProg->LinkStatus && fsProg->FragmentProgram) {
/* Use shader programs */
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
- shProg->FragmentProgram);
+ fsProg->FragmentProgram);
}
else if (ctx->FragmentProgram._Enabled) {
/* use user-defined vertex program */
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL);
}
+ if (gsProg && gsProg->LinkStatus && gsProg->GeometryProgram) {
+ /* Use shader programs */
+ _mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current,
+ gsProg->GeometryProgram);
+ } else {
+ /* no fragment program */
+ _mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current, NULL);
+ }
+
/* Examine vertex program after fragment program as
* _mesa_get_fixed_func_vertex_program() needs to know active
* fragprog inputs.
*/
- if (shProg && shProg->LinkStatus && shProg->VertexProgram) {
+ if (vsProg && vsProg->LinkStatus && vsProg->VertexProgram) {
/* Use shader programs */
_mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current,
- shProg->VertexProgram);
+ vsProg->VertexProgram);
}
else if (ctx->VertexProgram._Enabled) {
/* use user-defined vertex program */
(struct gl_program *) ctx->FragmentProgram._Current);
}
}
-
+
+ if (ctx->GeometryProgram._Current != prevGP) {
+ new_state |= _NEW_PROGRAM;
+ if (ctx->Driver.BindProgram) {
+ ctx->Driver.BindProgram(ctx, MESA_GEOMETRY_PROGRAM,
+ (struct gl_program *) ctx->GeometryProgram._Current);
+ }
+ }
+
if (ctx->VertexProgram._Current != prevVP) {
new_state |= _NEW_PROGRAM;
if (ctx->Driver.BindProgram) {
* Examine shader constants and return either _NEW_PROGRAM_CONSTANTS or 0.
*/
static GLbitfield
-update_program_constants(GLcontext *ctx)
+update_program_constants(struct gl_context *ctx)
{
GLbitfield new_state = 0x0;
}
}
+ if (ctx->GeometryProgram._Current) {
+ const struct gl_program_parameter_list *params =
+ ctx->GeometryProgram._Current->Base.Parameters;
+ /*FIXME: StateFlags is always 0 because we have unnamed constant
+ * not state changes */
+ if (params /*&& params->StateFlags & ctx->NewState*/) {
+ new_state |= _NEW_PROGRAM_CONSTANTS;
+ }
+ }
+
if (ctx->VertexProgram._Current) {
const struct gl_program_parameter_list *params =
ctx->VertexProgram._Current->Base.Parameters;
static void
-update_viewport_matrix(GLcontext *ctx)
+update_viewport_matrix(struct gl_context *ctx)
{
const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
* Update derived multisample state.
*/
static void
-update_multisample(GLcontext *ctx)
+update_multisample(struct gl_context *ctx)
{
ctx->Multisample._Enabled = GL_FALSE;
if (ctx->Multisample.Enabled &&
* Update derived color/blend/logicop state.
*/
static void
-update_color(GLcontext *ctx)
+update_color(struct gl_context *ctx)
{
/* This is needed to support 1.1's RGB logic ops AND
* 1.0's blending logicops.
* in ctx->_TriangleCaps if needed.
*/
static void
-update_polygon(GLcontext *ctx)
+update_polygon(struct gl_context *ctx)
{
ctx->_TriangleCaps &= ~(DD_TRI_CULL_FRONT_BACK | DD_TRI_OFFSET);
*/
#if 0
static void
-update_tricaps(GLcontext *ctx, GLbitfield new_state)
+update_tricaps(struct gl_context *ctx, GLbitfield new_state)
{
ctx->_TriangleCaps = 0;
/**
* Compute derived GL state.
- * If __GLcontextRec::NewState is non-zero then this function \b must
+ * If __struct gl_contextRec::NewState is non-zero then this function \b must
* be called before rendering anything.
*
* Calls dd_function_table::UpdateState to perform any internal state
* _mesa_update_lighting() and _mesa_update_tnl_spaces().
*/
void
-_mesa_update_state_locked( GLcontext *ctx )
+_mesa_update_state_locked( struct gl_context *ctx )
{
GLbitfield new_state = ctx->NewState;
GLbitfield prog_flags = _NEW_PROGRAM;
/* Determine which state flags effect vertex/fragment program state */
if (ctx->FragmentProgram._MaintainTexEnvProgram) {
- prog_flags |= (_NEW_TEXTURE | _NEW_FOG | _DD_NEW_SEPARATE_SPECULAR |
+ prog_flags |= (_NEW_BUFFERS | _NEW_TEXTURE | _NEW_FOG |
_NEW_ARRAY | _NEW_LIGHT | _NEW_POINT | _NEW_RENDERMODE |
_NEW_PROGRAM);
}
if (new_state & (_NEW_STENCIL | _NEW_BUFFERS))
_mesa_update_stencil( ctx );
-#if FEATURE_pixel_transfer
if (new_state & _MESA_NEW_TRANSFER_STATE)
_mesa_update_pixel( ctx, new_state );
-#endif
if (new_state & _DD_NEW_SEPARATE_SPECULAR)
update_separate_specular( ctx );
- if (new_state & (_NEW_ARRAY | _NEW_PROGRAM))
- update_arrays( ctx );
-
if (new_state & (_NEW_BUFFERS | _NEW_VIEWPORT))
update_viewport_matrix(ctx);
new_prog_state |= update_program( ctx );
}
+ if (new_state & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT))
+ update_arrays( ctx );
out:
new_prog_state |= update_program_constants(ctx);
/* This is the usual entrypoint for state updates:
*/
void
-_mesa_update_state( GLcontext *ctx )
+_mesa_update_state( struct gl_context *ctx )
{
_mesa_lock_context_textures(ctx);
_mesa_update_state_locked(ctx);
* Otherwise, the fp should track them as state values instead.
*/
void
-_mesa_set_varying_vp_inputs( GLcontext *ctx,
+_mesa_set_varying_vp_inputs( struct gl_context *ctx,
GLbitfield varying_inputs )
{
if (ctx->varying_vp_inputs != varying_inputs) {
ctx->varying_vp_inputs = varying_inputs;
ctx->NewState |= _NEW_ARRAY;
- /*_mesa_printf("%s %x\n", __FUNCTION__, varying_inputs);*/
+ /*printf("%s %x\n", __FUNCTION__, varying_inputs);*/
}
}
* of ordinary varyings/inputs.
*/
void
-_mesa_set_vp_override(GLcontext *ctx, GLboolean flag)
+_mesa_set_vp_override(struct gl_context *ctx, GLboolean flag)
{
if (ctx->VertexProgram._Overriden != flag) {
ctx->VertexProgram._Overriden = flag;
/* Set one of the bits which will trigger fragment program
* regeneration:
*/
- ctx->NewState |= _NEW_ARRAY;
+ ctx->NewState |= _NEW_PROGRAM;
}
}