
Withaaa4b0e6
state validation is no longer called for all changed states, but only for states that will be active with a new shader program. Not all drivers support this and might prefer if the state validation is emitted for all states that might be changed. So add a cap that the driver can signal one or the other preference, and default to the new behavior. Fixes:aaa4b0e6
st/mesa: move check_program_state code into _mesa_update_state v2: - Rename cap and and invert its meaning, query the cap only once and store it in st, handle the mask update when updating the shader i.e. not in st_validate_state (Marek) Signed-off-by: Gert Wollny <gert.wollny@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20493>
723 lines
25 KiB
C
723 lines
25 KiB
C
/*
|
|
* Mesa 3-D graphics library
|
|
*
|
|
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
|
|
/**
|
|
* \file state.c
|
|
* State management.
|
|
*
|
|
* This file manages recalculation of derived values in struct gl_context.
|
|
*/
|
|
|
|
|
|
#include "util/glheader.h"
|
|
#include "mtypes.h"
|
|
#include "arrayobj.h"
|
|
#include "context.h"
|
|
#include "debug.h"
|
|
#include "macros.h"
|
|
#include "ffvertex_prog.h"
|
|
#include "framebuffer.h"
|
|
#include "light.h"
|
|
#include "matrix.h"
|
|
#include "pixel.h"
|
|
#include "program/program.h"
|
|
#include "program/prog_parameter.h"
|
|
#include "shaderobj.h"
|
|
#include "state.h"
|
|
#include "stencil.h"
|
|
#include "texenvprogram.h"
|
|
#include "texobj.h"
|
|
#include "texstate.h"
|
|
#include "varray.h"
|
|
#include "vbo/vbo.h"
|
|
#include "viewport.h"
|
|
#include "blend.h"
|
|
|
|
#include "state_tracker/st_context.h"
|
|
#include "state_tracker/st_util.h"
|
|
|
|
void
|
|
_mesa_update_allow_draw_out_of_order(struct gl_context *ctx)
|
|
{
|
|
/* Out-of-order drawing is useful when vertex array draws and immediate
|
|
* mode are interleaved.
|
|
*
|
|
* Example with 3 draws:
|
|
* glBegin();
|
|
* glVertex();
|
|
* glEnd();
|
|
* glDrawElements();
|
|
* glBegin();
|
|
* glVertex();
|
|
* glEnd();
|
|
*
|
|
* Out-of-order drawing changes the execution order like this:
|
|
* glDrawElements();
|
|
* glBegin();
|
|
* glVertex();
|
|
* glVertex();
|
|
* glEnd();
|
|
*
|
|
* If out-of-order draws are enabled, immediate mode vertices are not
|
|
* flushed before glDrawElements, resulting in fewer draws and lower CPU
|
|
* overhead. This helps workstation applications.
|
|
*
|
|
* This is a simplified version of out-of-order determination to catch
|
|
* common cases.
|
|
*
|
|
* RadeonSI has a complete and more complicated out-of-order determination
|
|
* for driver-internal reasons.
|
|
*/
|
|
/* Only the compatibility profile with immediate mode needs this. */
|
|
if (!ctx->Const.AllowDrawOutOfOrder)
|
|
return;
|
|
|
|
assert(ctx->API == API_OPENGL_COMPAT);
|
|
|
|
/* If all of these are NULL, GLSL is disabled. */
|
|
struct gl_program *vs =
|
|
ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX];
|
|
struct gl_program *tcs =
|
|
ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_CTRL];
|
|
struct gl_program *tes =
|
|
ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL];
|
|
struct gl_program *gs =
|
|
ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY];
|
|
struct gl_program *fs =
|
|
ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT];
|
|
GLenum16 depth_func = ctx->Depth.Func;
|
|
|
|
/* Z fighting and any primitives with equal Z shouldn't be reordered
|
|
* with LESS/LEQUAL/GREATER/GEQUAL functions.
|
|
*
|
|
* When drawing 2 primitive with equal Z:
|
|
* - with LEQUAL/GEQUAL, the last primitive wins the Z test.
|
|
* - with LESS/GREATER, the first primitive wins the Z test.
|
|
*
|
|
* Here we ignore that on the basis that such cases don't occur in real
|
|
* apps, and we they do occur, they occur with blending where out-of-order
|
|
* drawing is always disabled.
|
|
*/
|
|
bool previous_state = ctx->_AllowDrawOutOfOrder;
|
|
ctx->_AllowDrawOutOfOrder =
|
|
ctx->DrawBuffer &&
|
|
ctx->DrawBuffer->Visual.depthBits &&
|
|
ctx->Depth.Test &&
|
|
ctx->Depth.Mask &&
|
|
(depth_func == GL_NEVER ||
|
|
depth_func == GL_LESS ||
|
|
depth_func == GL_LEQUAL ||
|
|
depth_func == GL_GREATER ||
|
|
depth_func == GL_GEQUAL) &&
|
|
(!ctx->DrawBuffer->Visual.stencilBits ||
|
|
!ctx->Stencil.Enabled) &&
|
|
(!ctx->Color.ColorMask ||
|
|
(!ctx->Color.BlendEnabled &&
|
|
(!ctx->Color.ColorLogicOpEnabled ||
|
|
ctx->Color._LogicOp == COLOR_LOGICOP_COPY))) &&
|
|
(!vs || !vs->info.writes_memory) &&
|
|
(!tes || !tes->info.writes_memory) &&
|
|
(!tcs || !tcs->info.writes_memory) &&
|
|
(!gs || !gs->info.writes_memory) &&
|
|
(!fs || !fs->info.writes_memory || !fs->info.fs.early_fragment_tests);
|
|
|
|
/* If we are disabling out-of-order drawing, we need to flush queued
|
|
* vertices.
|
|
*/
|
|
if (previous_state && !ctx->_AllowDrawOutOfOrder)
|
|
FLUSH_VERTICES(ctx, 0, 0);
|
|
}
|
|
|
|
uint64_t
|
|
_mesa_get_active_states(struct gl_context *ctx)
|
|
{
|
|
struct gl_program *vp = ctx->VertexProgram._Current;
|
|
struct gl_program *tcp = ctx->TessCtrlProgram._Current;
|
|
struct gl_program *tep = ctx->TessEvalProgram._Current;
|
|
struct gl_program *gp = ctx->GeometryProgram._Current;
|
|
struct gl_program *fp = ctx->FragmentProgram._Current;
|
|
struct gl_program *cp = ctx->ComputeProgram._Current;
|
|
uint64_t active_shader_states = 0;
|
|
|
|
if (vp)
|
|
active_shader_states |= vp->affected_states;
|
|
if (tcp)
|
|
active_shader_states |= tcp->affected_states;
|
|
if (tep)
|
|
active_shader_states |= tep->affected_states;
|
|
if (gp)
|
|
active_shader_states |= gp->affected_states;
|
|
if (fp)
|
|
active_shader_states |= fp->affected_states;
|
|
if (cp)
|
|
active_shader_states |= cp->affected_states;
|
|
|
|
/* Mark non-shader-resource shader states as "always active". */
|
|
return active_shader_states | ~ST_ALL_SHADER_RESOURCES;
|
|
}
|
|
|
|
/**
|
|
* Update the ctx->*Program._Current pointers to point to the
|
|
* current/active programs.
|
|
*
|
|
* Programs may come from 3 sources: GLSL shaders, ARB/NV_vertex/fragment
|
|
* programs or programs derived from fixed-function state.
|
|
*
|
|
* This function needs to be called after texture state validation in case
|
|
* we're generating a fragment program from fixed-function texture state.
|
|
*
|
|
* \return bitfield which will indicate _NEW_PROGRAM state if a new vertex
|
|
* or fragment program is being used.
|
|
*/
|
|
static GLbitfield
|
|
update_program(struct gl_context *ctx)
|
|
{
|
|
struct gl_program *vsProg =
|
|
ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX];
|
|
struct gl_program *tcsProg =
|
|
ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_CTRL];
|
|
struct gl_program *tesProg =
|
|
ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL];
|
|
struct gl_program *gsProg =
|
|
ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY];
|
|
struct gl_program *fsProg =
|
|
ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT];
|
|
struct gl_program *csProg =
|
|
ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE];
|
|
const struct gl_program *prevVP = ctx->VertexProgram._Current;
|
|
const struct gl_program *prevFP = ctx->FragmentProgram._Current;
|
|
const struct gl_program *prevGP = ctx->GeometryProgram._Current;
|
|
const struct gl_program *prevTCP = ctx->TessCtrlProgram._Current;
|
|
const struct gl_program *prevTEP = ctx->TessEvalProgram._Current;
|
|
const struct gl_program *prevCP = ctx->ComputeProgram._Current;
|
|
uint64_t prev_vp_affected_states = prevVP ? prevVP->affected_states : 0;
|
|
uint64_t prev_tcp_affected_states = prevTCP ? prevTCP->affected_states : 0;
|
|
uint64_t prev_tep_affected_states = prevTEP ? prevTEP->affected_states : 0;
|
|
uint64_t prev_gp_affected_states = prevGP ? prevGP->affected_states : 0;
|
|
uint64_t prev_fp_affected_states = prevFP ? prevFP->affected_states : 0;
|
|
uint64_t prev_cp_affected_states = prevCP ? prevCP->affected_states : 0;
|
|
|
|
/*
|
|
* Set the ctx->VertexProgram._Current and ctx->FragmentProgram._Current
|
|
* pointers to the programs that should be used for rendering. If either
|
|
* is NULL, use fixed-function code paths.
|
|
*
|
|
* These programs may come from several sources. The priority is as
|
|
* follows:
|
|
* 1. OpenGL 2.0/ARB vertex/fragment shaders
|
|
* 2. ARB/NV vertex/fragment programs
|
|
* 3. ATI fragment shader
|
|
* 4. Programs derived from fixed-function state.
|
|
*
|
|
* Note: it's possible for a vertex shader to get used with a fragment
|
|
* program (and vice versa) here, but in practice that shouldn't ever
|
|
* come up, or matter.
|
|
*/
|
|
|
|
if (fsProg) {
|
|
/* Use GLSL fragment shader */
|
|
_mesa_reference_program(ctx, &ctx->FragmentProgram._Current, fsProg);
|
|
_mesa_reference_program(ctx, &ctx->FragmentProgram._TexEnvProgram,
|
|
NULL);
|
|
} else if (_mesa_arb_fragment_program_enabled(ctx)) {
|
|
/* Use user-defined fragment program */
|
|
_mesa_reference_program(ctx, &ctx->FragmentProgram._Current,
|
|
ctx->FragmentProgram.Current);
|
|
_mesa_reference_program(ctx, &ctx->FragmentProgram._TexEnvProgram,
|
|
NULL);
|
|
} else if (_mesa_ati_fragment_shader_enabled(ctx) &&
|
|
ctx->ATIFragmentShader.Current->Program) {
|
|
/* Use the enabled ATI fragment shader's associated program */
|
|
_mesa_reference_program(ctx, &ctx->FragmentProgram._Current,
|
|
ctx->ATIFragmentShader.Current->Program);
|
|
_mesa_reference_program(ctx, &ctx->FragmentProgram._TexEnvProgram,
|
|
NULL);
|
|
} else {
|
|
/* Use fragment program generated from fixed-function state */
|
|
struct gl_shader_program *f = _mesa_get_fixed_func_fragment_program(ctx);
|
|
|
|
_mesa_reference_program(ctx, &ctx->FragmentProgram._Current,
|
|
f->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program);
|
|
_mesa_reference_program(ctx, &ctx->FragmentProgram._TexEnvProgram,
|
|
f->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program);
|
|
}
|
|
|
|
/* Examine vertex program after fragment program as
|
|
* _mesa_get_fixed_func_vertex_program() needs to know active
|
|
* fragprog inputs.
|
|
*/
|
|
if (vsProg) {
|
|
/* Use GLSL vertex shader */
|
|
assert(VP_MODE_SHADER == ctx->VertexProgram._VPMode);
|
|
_mesa_reference_program(ctx, &ctx->VertexProgram._Current, vsProg);
|
|
} else if (_mesa_arb_vertex_program_enabled(ctx)) {
|
|
/* Use user-defined vertex program */
|
|
assert(VP_MODE_SHADER == ctx->VertexProgram._VPMode);
|
|
_mesa_reference_program(ctx, &ctx->VertexProgram._Current,
|
|
ctx->VertexProgram.Current);
|
|
} else {
|
|
/* Use vertex program generated from fixed-function state */
|
|
assert(VP_MODE_FF == ctx->VertexProgram._VPMode);
|
|
_mesa_reference_program(ctx, &ctx->VertexProgram._Current,
|
|
_mesa_get_fixed_func_vertex_program(ctx));
|
|
_mesa_reference_program(ctx, &ctx->VertexProgram._TnlProgram,
|
|
ctx->VertexProgram._Current);
|
|
}
|
|
|
|
/* Bind or unbind these shaders. (NULL = unbind) */
|
|
_mesa_reference_program(ctx, &ctx->GeometryProgram._Current, gsProg);
|
|
_mesa_reference_program(ctx, &ctx->TessEvalProgram._Current, tesProg);
|
|
_mesa_reference_program(ctx, &ctx->TessCtrlProgram._Current, tcsProg);
|
|
_mesa_reference_program(ctx, &ctx->ComputeProgram._Current, csProg);
|
|
|
|
bool vp_changed = ctx->VertexProgram._Current != prevVP;
|
|
bool tcp_changed = ctx->TessCtrlProgram._Current != prevTCP;
|
|
bool tep_changed = ctx->TessEvalProgram._Current != prevTEP;
|
|
bool gp_changed = ctx->GeometryProgram._Current != prevGP;
|
|
bool fp_changed = ctx->FragmentProgram._Current != prevFP;
|
|
bool cp_changed = ctx->ComputeProgram._Current != prevCP;
|
|
|
|
/* Set NewDriverState depending on which shaders have changed. */
|
|
uint64_t dirty = 0;
|
|
|
|
/* Flag states used by both new and old shaders to rebind shader resources
|
|
* (because shaders pack them and reorder them) and to unbind shader
|
|
* resources properly when transitioning to shaders that don't use them.
|
|
*/
|
|
if (vp_changed) {
|
|
ctx->Array.NewVertexElements = true;
|
|
dirty |= prev_vp_affected_states;
|
|
if (ctx->VertexProgram._Current)
|
|
dirty |= ST_NEW_VERTEX_PROGRAM(ctx, ctx->VertexProgram._Current);
|
|
}
|
|
|
|
if (tcp_changed) {
|
|
dirty |= prev_tcp_affected_states;
|
|
if (ctx->TessCtrlProgram._Current)
|
|
dirty |= ctx->TessCtrlProgram._Current->affected_states;
|
|
}
|
|
|
|
if (tep_changed) {
|
|
dirty |= prev_tep_affected_states;
|
|
if (ctx->TessEvalProgram._Current)
|
|
dirty |= ctx->TessEvalProgram._Current->affected_states;
|
|
}
|
|
|
|
if (gp_changed) {
|
|
dirty |= prev_gp_affected_states;
|
|
if (ctx->GeometryProgram._Current)
|
|
dirty |= ctx->GeometryProgram._Current->affected_states;
|
|
}
|
|
|
|
if (fp_changed) {
|
|
dirty |= prev_fp_affected_states;
|
|
if (ctx->FragmentProgram._Current)
|
|
dirty |= ctx->FragmentProgram._Current->affected_states;
|
|
|
|
if (!ctx->st->needs_texcoord_semantic)
|
|
dirty |= ST_NEW_RASTERIZER;
|
|
}
|
|
|
|
if (cp_changed) {
|
|
dirty |= prev_cp_affected_states;
|
|
if (ctx->ComputeProgram._Current)
|
|
dirty |= ctx->ComputeProgram._Current->affected_states;
|
|
}
|
|
|
|
struct gl_program *last_vertex_stage;
|
|
bool last_vertex_stage_dirty;
|
|
|
|
if (ctx->GeometryProgram._Current) {
|
|
last_vertex_stage = ctx->GeometryProgram._Current;
|
|
last_vertex_stage_dirty = gp_changed;
|
|
} else if (ctx->TessEvalProgram._Current) {
|
|
last_vertex_stage = ctx->TessEvalProgram._Current;
|
|
last_vertex_stage_dirty = gp_changed | tep_changed;
|
|
} else {
|
|
last_vertex_stage = ctx->VertexProgram._Current;
|
|
last_vertex_stage_dirty = gp_changed | tep_changed | vp_changed;
|
|
}
|
|
|
|
/* Find out the number of viewports. This determines how many scissors
|
|
* and viewport states we need to update.
|
|
*/
|
|
struct st_context *st = ctx->st;
|
|
unsigned num_viewports = 1;
|
|
|
|
if (last_vertex_stage &&
|
|
last_vertex_stage->info.outputs_written & (
|
|
VARYING_BIT_VIEWPORT | VARYING_BIT_VIEWPORT_MASK))
|
|
num_viewports = ctx->Const.MaxViewports;
|
|
|
|
if (st->state.num_viewports != num_viewports) {
|
|
st->state.num_viewports = num_viewports;
|
|
dirty |= ST_NEW_VIEWPORT;
|
|
|
|
if (ctx->Scissor.EnableFlags & u_bit_consecutive(0, num_viewports))
|
|
dirty |= ST_NEW_SCISSOR;
|
|
}
|
|
|
|
if (st->lower_point_size && last_vertex_stage_dirty &&
|
|
!ctx->VertexProgram.PointSizeEnabled && !ctx->PointSizeIsSet) {
|
|
if (ctx->GeometryProgram._Current) {
|
|
ctx->NewDriverState |= ST_NEW_GS_CONSTANTS;
|
|
} else if (ctx->TessEvalProgram._Current) {
|
|
ctx->NewDriverState |= ST_NEW_TES_CONSTANTS;
|
|
} else {
|
|
ctx->NewDriverState |= ST_NEW_VS_CONSTANTS;
|
|
}
|
|
}
|
|
|
|
ctx->NewDriverState |= dirty;
|
|
|
|
/* Let the driver know what's happening: */
|
|
if (fp_changed || vp_changed || gp_changed || tep_changed ||
|
|
tcp_changed || cp_changed) {
|
|
/* This will mask out unused shader resources. */
|
|
st->active_states = _mesa_get_active_states(ctx);
|
|
|
|
/* Some drivers need to clean up previous states too */
|
|
if (st->validate_all_dirty_states)
|
|
st->active_states |= dirty;
|
|
|
|
return _NEW_PROGRAM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static GLbitfield
|
|
update_single_program_constants(struct gl_context *ctx,
|
|
struct gl_program *prog,
|
|
gl_shader_stage stage)
|
|
{
|
|
if (prog) {
|
|
const struct gl_program_parameter_list *params = prog->Parameters;
|
|
if (params && params->StateFlags & ctx->NewState) {
|
|
if (ctx->DriverFlags.NewShaderConstants[stage])
|
|
ctx->NewDriverState |= ctx->DriverFlags.NewShaderConstants[stage];
|
|
else
|
|
return _NEW_PROGRAM_CONSTANTS;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* This updates fixed-func state constants such as gl_ModelViewMatrix.
|
|
* Examine shader constants and return either _NEW_PROGRAM_CONSTANTS or 0.
|
|
*/
|
|
static GLbitfield
|
|
update_program_constants(struct gl_context *ctx)
|
|
{
|
|
GLbitfield new_state =
|
|
update_single_program_constants(ctx, ctx->VertexProgram._Current,
|
|
MESA_SHADER_VERTEX) |
|
|
update_single_program_constants(ctx, ctx->FragmentProgram._Current,
|
|
MESA_SHADER_FRAGMENT);
|
|
|
|
if (ctx->API == API_OPENGL_COMPAT &&
|
|
ctx->Const.GLSLVersionCompat >= 150) {
|
|
new_state |=
|
|
update_single_program_constants(ctx, ctx->GeometryProgram._Current,
|
|
MESA_SHADER_GEOMETRY);
|
|
|
|
if (_mesa_has_ARB_tessellation_shader(ctx)) {
|
|
new_state |=
|
|
update_single_program_constants(ctx, ctx->TessCtrlProgram._Current,
|
|
MESA_SHADER_TESS_CTRL) |
|
|
update_single_program_constants(ctx, ctx->TessEvalProgram._Current,
|
|
MESA_SHADER_TESS_EVAL);
|
|
}
|
|
}
|
|
|
|
return new_state;
|
|
}
|
|
|
|
|
|
static void
|
|
update_fixed_func_program_usage(struct gl_context *ctx)
|
|
{
|
|
ctx->FragmentProgram._UsesTexEnvProgram =
|
|
!ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT] && /* GLSL*/
|
|
!_mesa_arb_fragment_program_enabled(ctx) &&
|
|
!(_mesa_ati_fragment_shader_enabled(ctx) &&
|
|
ctx->ATIFragmentShader.Current->Program);
|
|
|
|
ctx->VertexProgram._UsesTnlProgram =
|
|
!ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX] && /* GLSL */
|
|
!_mesa_arb_vertex_program_enabled(ctx);
|
|
}
|
|
|
|
|
|
/**
|
|
* Compute derived GL state.
|
|
* 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
|
|
* management necessary.
|
|
*
|
|
* \sa _mesa_update_modelview_project(), _mesa_update_texture(),
|
|
* _mesa_update_buffer_bounds(),
|
|
* _mesa_update_lighting() and _mesa_update_tnl_spaces().
|
|
*/
|
|
void
|
|
_mesa_update_state_locked( struct gl_context *ctx )
|
|
{
|
|
GLbitfield new_state = ctx->NewState;
|
|
GLbitfield new_prog_state = 0x0;
|
|
const GLbitfield checked_states =
|
|
_NEW_BUFFERS | _NEW_MODELVIEW | _NEW_PROJECTION | _NEW_TEXTURE_MATRIX |
|
|
_NEW_TEXTURE_OBJECT | _NEW_TEXTURE_STATE | _NEW_PROGRAM |
|
|
_NEW_LIGHT_CONSTANTS | _NEW_POINT | _NEW_FF_VERT_PROGRAM |
|
|
_NEW_FF_FRAG_PROGRAM | _NEW_TNL_SPACES;
|
|
|
|
/* we can skip a bunch of state validation checks if the dirty
|
|
* state matches one or more bits in 'computed_states'.
|
|
*/
|
|
if (!(new_state & checked_states))
|
|
goto out;
|
|
|
|
if (MESA_VERBOSE & VERBOSE_STATE)
|
|
_mesa_print_state("_mesa_update_state", new_state);
|
|
|
|
if (new_state & _NEW_BUFFERS)
|
|
_mesa_update_framebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer);
|
|
|
|
/* Handle Core and Compatibility contexts separately. */
|
|
if (ctx->API == API_OPENGL_COMPAT ||
|
|
ctx->API == API_OPENGLES) {
|
|
/* Update derived state. */
|
|
if (new_state & (_NEW_MODELVIEW|_NEW_PROJECTION))
|
|
_mesa_update_modelview_project( ctx, new_state );
|
|
|
|
if (new_state & _NEW_TEXTURE_MATRIX)
|
|
new_state |= _mesa_update_texture_matrices(ctx);
|
|
|
|
if (new_state & (_NEW_TEXTURE_OBJECT | _NEW_TEXTURE_STATE | _NEW_PROGRAM))
|
|
new_state |= _mesa_update_texture_state(ctx);
|
|
|
|
if (new_state & _NEW_LIGHT_CONSTANTS)
|
|
new_state |= _mesa_update_lighting(ctx);
|
|
|
|
/* ctx->_NeedEyeCoords is determined here.
|
|
*
|
|
* If the truth value of this variable has changed, update for the
|
|
* new lighting space and recompute the positions of lights and the
|
|
* normal transform.
|
|
*
|
|
* If the lighting space hasn't changed, may still need to recompute
|
|
* light positions & normal transforms for other reasons.
|
|
*/
|
|
if (new_state & (_NEW_TNL_SPACES | _NEW_LIGHT_CONSTANTS |
|
|
_NEW_MODELVIEW)) {
|
|
if (_mesa_update_tnl_spaces(ctx, new_state))
|
|
new_state |= _NEW_FF_VERT_PROGRAM;
|
|
}
|
|
|
|
if (new_state & _NEW_PROGRAM)
|
|
update_fixed_func_program_usage(ctx);
|
|
|
|
/* Determine which states affect fixed-func vertex/fragment program. */
|
|
GLbitfield prog_flags = _NEW_PROGRAM;
|
|
|
|
if (ctx->FragmentProgram._UsesTexEnvProgram) {
|
|
prog_flags |= _NEW_BUFFERS | _NEW_TEXTURE_OBJECT |
|
|
_NEW_FF_FRAG_PROGRAM | _NEW_TEXTURE_STATE;
|
|
}
|
|
|
|
if (ctx->VertexProgram._UsesTnlProgram)
|
|
prog_flags |= _NEW_FF_VERT_PROGRAM;
|
|
|
|
if (new_state & prog_flags) {
|
|
/* When we generate programs from fixed-function vertex/fragment state
|
|
* this call may generate/bind a new program. If so, we need to
|
|
* propogate the _NEW_PROGRAM flag to the driver.
|
|
*/
|
|
new_prog_state |= update_program(ctx);
|
|
}
|
|
} else {
|
|
/* GL Core and GLES 2/3 contexts */
|
|
if (new_state & (_NEW_TEXTURE_OBJECT | _NEW_PROGRAM))
|
|
_mesa_update_texture_state(ctx);
|
|
|
|
if (new_state & _NEW_PROGRAM)
|
|
update_program(ctx);
|
|
}
|
|
|
|
out:
|
|
new_prog_state |= update_program_constants(ctx);
|
|
|
|
ctx->NewState |= new_prog_state;
|
|
|
|
/*
|
|
* Give the driver a chance to act upon the new_state flags.
|
|
* The driver might plug in different span functions, for example.
|
|
* Also, this is where the driver can invalidate the state of any
|
|
* active modules (such as swrast_setup, swrast, tnl, etc).
|
|
*/
|
|
st_invalidate_state(ctx);
|
|
ctx->NewState = 0;
|
|
}
|
|
|
|
|
|
/* This is the usual entrypoint for state updates:
|
|
*/
|
|
void
|
|
_mesa_update_state( struct gl_context *ctx )
|
|
{
|
|
_mesa_lock_context_textures(ctx);
|
|
_mesa_update_state_locked(ctx);
|
|
_mesa_unlock_context_textures(ctx);
|
|
}
|
|
|
|
/* This is the usual entrypoint for state updates in glClear calls:
|
|
*/
|
|
void
|
|
_mesa_update_clear_state( struct gl_context *ctx )
|
|
{
|
|
GLbitfield new_state = ctx->NewState;
|
|
|
|
if (MESA_VERBOSE & VERBOSE_STATE)
|
|
_mesa_print_state("_mesa_update_clear_state", new_state);
|
|
|
|
if (new_state & _NEW_BUFFERS) {
|
|
_mesa_update_framebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer);
|
|
|
|
st_invalidate_buffers(st_context(ctx));
|
|
ctx->NewState &= ~_NEW_BUFFERS;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Used by drivers to tell core Mesa that the driver is going to
|
|
* install/ use its own vertex program. In particular, this will
|
|
* prevent generated fragment programs from using state vars instead
|
|
* of ordinary varyings/inputs.
|
|
*/
|
|
void
|
|
_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_PROGRAM;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
set_vertex_processing_mode(struct gl_context *ctx, gl_vertex_processing_mode m)
|
|
{
|
|
if (ctx->VertexProgram._VPMode == m)
|
|
return;
|
|
|
|
/* On change we may get new maps into the current values */
|
|
ctx->NewDriverState |= ST_NEW_VERTEX_ARRAYS;
|
|
ctx->Array.NewVertexElements = true;
|
|
|
|
/* Finally memorize the value */
|
|
ctx->VertexProgram._VPMode = m;
|
|
|
|
/* The gl_context::VertexProgram._VaryingInputs value is only used when in
|
|
* VP_MODE_FF mode and the fixed-func pipeline is emulated by shaders.
|
|
*/
|
|
ctx->VertexProgram._VPModeOptimizesConstantAttribs =
|
|
m == VP_MODE_FF;
|
|
|
|
/* Set a filter mask for the net enabled vao arrays.
|
|
* This is to mask out arrays that would otherwise supersede required current
|
|
* values for the fixed function shaders for example.
|
|
*/
|
|
switch (m) {
|
|
case VP_MODE_FF:
|
|
/* When no vertex program is active (or the vertex program is generated
|
|
* from fixed-function state). We put the material values into the
|
|
* generic slots. Since the vao has no material arrays, mute these
|
|
* slots from the enabled arrays so that the current material values
|
|
* are pulled instead of the vao arrays.
|
|
*/
|
|
ctx->VertexProgram._VPModeInputFilter = VERT_BIT_FF_ALL;
|
|
break;
|
|
|
|
case VP_MODE_SHADER:
|
|
/* There are no shaders in OpenGL ES 1.x, so this code path should be
|
|
* impossible to reach. The meta code is careful to not use shaders in
|
|
* ES1.
|
|
*/
|
|
assert(ctx->API != API_OPENGLES);
|
|
|
|
/* Other parts of the code assume that inputs[VERT_ATTRIB_POS] through
|
|
* inputs[VERT_ATTRIB_GENERIC0-1] will be non-NULL. However, in OpenGL
|
|
* ES 2.0+ or OpenGL core profile, none of these arrays should ever
|
|
* be enabled.
|
|
*/
|
|
if (ctx->API == API_OPENGL_COMPAT)
|
|
ctx->VertexProgram._VPModeInputFilter = VERT_BIT_ALL;
|
|
else
|
|
ctx->VertexProgram._VPModeInputFilter = VERT_BIT_GENERIC_ALL;
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
}
|
|
|
|
_mesa_set_varying_vp_inputs(ctx, ctx->VertexProgram._VPModeInputFilter &
|
|
ctx->Array._DrawVAO->_EnabledWithMapMode);
|
|
}
|
|
|
|
|
|
/**
|
|
* Update ctx->VertexProgram._VPMode.
|
|
* This is to distinguish whether we're running
|
|
* a vertex program/shader,
|
|
* a fixed-function TNL program or
|
|
* a fixed function vertex transformation without any program.
|
|
*/
|
|
void
|
|
_mesa_update_vertex_processing_mode(struct gl_context *ctx)
|
|
{
|
|
if (ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX])
|
|
set_vertex_processing_mode(ctx, VP_MODE_SHADER);
|
|
else if (_mesa_arb_vertex_program_enabled(ctx))
|
|
set_vertex_processing_mode(ctx, VP_MODE_SHADER);
|
|
else
|
|
set_vertex_processing_mode(ctx, VP_MODE_FF);
|
|
}
|
|
|
|
|
|
void
|
|
_mesa_reset_vertex_processing_mode(struct gl_context *ctx)
|
|
{
|
|
ctx->VertexProgram._VPMode = -1; /* force the update */
|
|
_mesa_update_vertex_processing_mode(ctx);
|
|
}
|