summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2014-04-23 16:27:56 -0700
committerEric Anholt <eric@anholt.net>2014-04-30 14:33:20 -0700
commita580b500edb25298d99e8e78d04eaca418dcd4ce (patch)
treebff6a1d210aa44fac19244e7e6238d4ee7c32a3a
parente5e50fae6aaf2a1901f43f05f677e48f447087cc (diff)
mesa: Split the shader texture update logic from fixed function.
I want to avoid walking the entire long array texture image units, but the obvious way to do so means walking program samplers, and thus hitting the units in a random order. This change replaces the previous behavior of only setting up the fallback texture for a fragment shader with setting up the fallback texture for any shader that's missing a complete texture of the right target in its unit. Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
-rw-r--r--src/mesa/main/texstate.c250
1 files changed, 160 insertions, 90 deletions
diff --git a/src/mesa/main/texstate.c b/src/mesa/main/texstate.c
index 24469da59b4..0082caf2b1e 100644
--- a/src/mesa/main/texstate.c
+++ b/src/mesa/main/texstate.c
@@ -40,7 +40,7 @@
#include "teximage.h"
#include "texstate.h"
#include "mtypes.h"
-
+#include "bitset.h"
/**
@@ -515,79 +515,28 @@ update_texgen(struct gl_context *ctx)
}
}
-/**
- * \note This routine refers to derived texture matrix values to
- * compute the ENABLE_TEXMAT flags, but is only called on
- * _NEW_TEXTURE. On changes to _NEW_TEXTURE_MATRIX, the ENABLE_TEXMAT
- * flags are updated by _mesa_update_texture_matrices, above.
- *
- * \param ctx GL context.
- */
static void
-update_texture_state( struct gl_context *ctx )
+update_program_texture_state(struct gl_context *ctx, struct gl_program **prog,
+ BITSET_WORD *enabled_texture_units)
{
GLuint unit;
- struct gl_program *prog[MESA_SHADER_STAGES];
- GLbitfield enabledFragUnits = 0x0;
int i;
- for (i = 0; i < MESA_SHADER_STAGES; i++) {
- if (ctx->_Shader->CurrentProgram[i] &&
- ctx->_Shader->CurrentProgram[i]->LinkStatus) {
- prog[i] = ctx->_Shader->CurrentProgram[i]->_LinkedShaders[i]->Program;
- } else {
- if (i == MESA_SHADER_FRAGMENT && ctx->FragmentProgram._Enabled)
- prog[i] = &ctx->FragmentProgram.Current->Base;
- else
- prog[i] = NULL;
- }
- }
-
- /* TODO: only set this if there are actual changes */
- ctx->NewState |= _NEW_TEXTURE;
-
- ctx->Texture._GenFlags = 0x0;
- ctx->Texture._TexMatEnabled = 0x0;
- ctx->Texture._TexGenEnabled = 0x0;
- ctx->Texture._MaxEnabledTexImageUnit = -1;
-
- /*
- * Update texture unit state.
- */
for (unit = 0; unit < ctx->Const.MaxCombinedTextureImageUnits; unit++) {
struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
- GLbitfield enabledTargetsByStage[MESA_SHADER_STAGES];
GLbitfield enabledTargets = 0x0;
GLuint texIndex;
- /* Get the bitmask of texture target enables.
- * enableBits will be a mask of the TEXTURE_*_BIT flags indicating
- * which texture targets are enabled (fixed function) or referenced
- * by a fragment program/program. When multiple flags are set, we'll
- * settle on the one with highest priority (see below).
- */
for (i = 0; i < MESA_SHADER_STAGES; i++) {
if (prog[i])
- enabledTargetsByStage[i] = prog[i]->TexturesUsed[unit];
- else if (i == MESA_SHADER_FRAGMENT)
- enabledTargetsByStage[i] = texUnit->Enabled;
- else
- enabledTargetsByStage[i] = 0;
- enabledTargets |= enabledTargetsByStage[i];
+ enabledTargets |= prog[i]->TexturesUsed[unit];
}
if (enabledTargets == 0x0) {
- _mesa_reference_texobj(&texUnit->_Current, NULL);
/* neither vertex nor fragment processing uses this unit */
continue;
}
- /* Look for the highest priority texture target that's enabled (or used
- * by the vert/frag shaders) and "complete". That's the one we'll use
- * for texturing.
- *
- * Note that the TEXTURE_x_INDEX values are in high to low priority.
- */
for (texIndex = 0; texIndex < NUM_TEXTURE_TARGETS; texIndex++) {
if (enabledTargets & (1 << texIndex)) {
struct gl_texture_object *texObj = texUnit->CurrentTex[texIndex];
@@ -605,52 +554,173 @@ update_texture_state( struct gl_context *ctx )
}
if (texIndex == NUM_TEXTURE_TARGETS) {
- if (prog[MESA_SHADER_FRAGMENT]) {
- /* If we get here it means the shader is expecting a texture
- * object, but there isn't one (or it's incomplete). Use the
- * fallback texture.
- */
- struct gl_texture_object *texObj;
- gl_texture_index texTarget;
-
- texTarget = (gl_texture_index) (ffs(enabledTargets) - 1);
- texObj = _mesa_get_fallback_texture(ctx, texTarget);
-
- assert(texObj);
- if (!texObj) {
- /* invalid fallback texture: don't enable the texture unit */
- continue;
- }
-
- _mesa_reference_texobj(&texUnit->_Current, texObj);
- }
- else {
- /* fixed-function: texture unit is really disabled */
- _mesa_reference_texobj(&texUnit->_Current, NULL);
+ /* If we get here it means the shader is expecting a texture
+ * object, but there isn't one (or it's incomplete). Use the
+ * fallback texture.
+ */
+ struct gl_texture_object *texObj;
+ gl_texture_index texTarget;
+
+ texTarget = (gl_texture_index) (ffs(enabledTargets) - 1);
+ texObj = _mesa_get_fallback_texture(ctx, texTarget);
+
+ assert(texObj);
+ if (!texObj) {
+ /* invalid fallback texture: don't enable the texture unit */
continue;
}
+
+ _mesa_reference_texobj(&texUnit->_Current, texObj);
}
/* if we get here, we know this texture unit is enabled */
- ctx->Texture._MaxEnabledTexImageUnit = unit;
-
- if (enabledTargetsByStage[MESA_SHADER_FRAGMENT])
- enabledFragUnits |= (1 << unit);
-
- if (!prog[MESA_SHADER_FRAGMENT])
- update_tex_combine(ctx, texUnit);
+ BITSET_SET(enabled_texture_units, unit);
+ ctx->Texture._MaxEnabledTexImageUnit =
+ MAX2(ctx->Texture._MaxEnabledTexImageUnit, (int)unit);
}
-
- /* Determine which texture coordinate sets are actually needed */
if (prog[MESA_SHADER_FRAGMENT]) {
const GLuint coordMask = (1 << MAX_TEXTURE_COORD_UNITS) - 1;
- ctx->Texture._EnabledCoordUnits
- = (prog[MESA_SHADER_FRAGMENT]->InputsRead >> VARYING_SLOT_TEX0) &
+ ctx->Texture._EnabledCoordUnits |=
+ (prog[MESA_SHADER_FRAGMENT]->InputsRead >> VARYING_SLOT_TEX0) &
coordMask;
}
- else {
- ctx->Texture._EnabledCoordUnits = enabledFragUnits;
+}
+
+static void
+update_ff_texture_state(struct gl_context *ctx,
+ BITSET_WORD *enabled_texture_units)
+{
+ int unit;
+
+ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ GLuint texIndex;
+
+ if (texUnit->Enabled == 0x0)
+ continue;
+
+ /* If a shader already dictated what texture target was used for this
+ * unit, just go along with it.
+ */
+ if (BITSET_TEST(enabled_texture_units, unit))
+ continue;
+
+ /* From the GL 4.4 compat specification, section 16.2 ("Texture Application"):
+ *
+ * "Texturing is enabled or disabled using the generic Enable and
+ * Disable commands, respectively, with the symbolic constants
+ * TEXTURE_1D, TEXTURE_2D, TEXTURE_RECTANGLE, TEXTURE_3D, or
+ * TEXTURE_CUBE_MAP to enable the one-, two-, rectangular,
+ * three-dimensional, or cube map texture, respectively. If more
+ * than one of these textures is enabled, the first one enabled
+ * from the following list is used:
+ *
+ * • cube map texture
+ * • three-dimensional texture
+ * • rectangular texture
+ * • two-dimensional texture
+ * • one-dimensional texture"
+ *
+ * Note that the TEXTURE_x_INDEX values are in high to low priority.
+ * Also:
+ *
+ * "If a texture unit is disabled or has an invalid or incomplete
+ * texture (as defined in section 8.17) bound to it, then blending
+ * is disabled for that texture unit. If the texture environment
+ * for a given enabled texture unit references a disabled texture
+ * unit, or an invalid or incomplete texture that is bound to
+ * another unit, then the results of texture blending are
+ * undefined."
+ */
+ for (texIndex = 0; texIndex < NUM_TEXTURE_TARGETS; texIndex++) {
+ if (texUnit->Enabled & (1 << texIndex)) {
+ struct gl_texture_object *texObj = texUnit->CurrentTex[texIndex];
+ struct gl_sampler_object *sampler = texUnit->Sampler ?
+ texUnit->Sampler : &texObj->Sampler;
+
+ if (!_mesa_is_texture_complete(texObj, sampler)) {
+ _mesa_test_texobj_completeness(ctx, texObj);
+ }
+ if (_mesa_is_texture_complete(texObj, sampler)) {
+ _mesa_reference_texobj(&texUnit->_Current, texObj);
+ break;
+ }
+ }
+ }
+
+ if (texIndex == NUM_TEXTURE_TARGETS)
+ continue;
+
+ /* if we get here, we know this texture unit is enabled */
+ BITSET_SET(enabled_texture_units, unit);
+ ctx->Texture._MaxEnabledTexImageUnit =
+ MAX2(ctx->Texture._MaxEnabledTexImageUnit, (int)unit);
+
+ ctx->Texture._EnabledCoordUnits |= 1 << unit;
+
+ update_tex_combine(ctx, texUnit);
+ }
+}
+
+/**
+ * \note This routine refers to derived texture matrix values to
+ * compute the ENABLE_TEXMAT flags, but is only called on
+ * _NEW_TEXTURE. On changes to _NEW_TEXTURE_MATRIX, the ENABLE_TEXMAT
+ * flags are updated by _mesa_update_texture_matrices, above.
+ *
+ * \param ctx GL context.
+ */
+static void
+update_texture_state( struct gl_context *ctx )
+{
+ struct gl_program *prog[MESA_SHADER_STAGES];
+ int i;
+ int old_max_unit = ctx->Texture._MaxEnabledTexImageUnit;
+ BITSET_DECLARE(enabled_texture_units, MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+
+ for (i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (ctx->_Shader->CurrentProgram[i] &&
+ ctx->_Shader->CurrentProgram[i]->LinkStatus) {
+ prog[i] = ctx->_Shader->CurrentProgram[i]->_LinkedShaders[i]->Program;
+ } else {
+ if (i == MESA_SHADER_FRAGMENT && ctx->FragmentProgram._Enabled)
+ prog[i] = &ctx->FragmentProgram.Current->Base;
+ else
+ prog[i] = NULL;
+ }
+ }
+
+ /* TODO: only set this if there are actual changes */
+ ctx->NewState |= _NEW_TEXTURE;
+
+ ctx->Texture._GenFlags = 0x0;
+ ctx->Texture._TexMatEnabled = 0x0;
+ ctx->Texture._TexGenEnabled = 0x0;
+ ctx->Texture._MaxEnabledTexImageUnit = -1;
+ ctx->Texture._EnabledCoordUnits = 0x0;
+
+ memset(&enabled_texture_units, 0, sizeof(enabled_texture_units));
+
+ /* First, walk over our programs pulling in all the textures for them.
+ * Programs dictate specific texture targets to be enabled, and for a draw
+ * call to be valid they can't conflict about which texture targets are
+ * used.
+ */
+ update_program_texture_state(ctx, prog, enabled_texture_units);
+
+ /* Also pull in any textures necessary for fixed function fragment shading.
+ */
+ if (!prog[MESA_SHADER_FRAGMENT])
+ update_ff_texture_state(ctx, enabled_texture_units);
+
+ /* Now, clear out the _Current of any disabled texture units. */
+ for (i = 0; i <= ctx->Texture._MaxEnabledTexImageUnit; i++) {
+ if (!BITSET_TEST(enabled_texture_units, i))
+ _mesa_reference_texobj(&ctx->Texture.Unit[i]._Current, NULL);
+ }
+ for (i = ctx->Texture._MaxEnabledTexImageUnit + 1; i <= old_max_unit; i++) {
+ _mesa_reference_texobj(&ctx->Texture.Unit[i]._Current, NULL);
}
if (!prog[MESA_SHADER_FRAGMENT] || !prog[MESA_SHADER_VERTEX])