mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 22:38:05 +02:00
mesa: rework texture completeness testing
Instead of gl_texture_object::_Complete there are now two fields: _BaseComplete and _MipmapComplete. The former indicates whether the base texture level is valid. The later indicates whether the whole mipmap is valid. With sampler objects, a single texture can appear to be both complete and incomplete at the same time. See the GL_ARB_sampler_objects spec for more details. To implement this we now check if the texture is complete with respect to a sampler state. Another benefit of this is we no longer need to invalidate a texture's completeness state when we change the minification/magnification filters with glTexParameter(). Reviewed-by: José Fonseca <jfonseca@vmware.com> Reviewed-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
parent
b219b2c310
commit
f4a93e0665
10 changed files with 79 additions and 38 deletions
|
|
@ -45,7 +45,7 @@ intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit)
|
|||
|
||||
/* We know/require this is true by now:
|
||||
*/
|
||||
assert(intelObj->base._Complete);
|
||||
assert(intelObj->base._BaseComplete);
|
||||
|
||||
/* What levels must the tree include at a minimum?
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1316,7 +1316,8 @@ struct gl_texture_object
|
|||
GLenum Swizzle[4]; /**< GL_EXT_texture_swizzle */
|
||||
GLuint _Swizzle; /**< same as Swizzle, but SWIZZLE_* format */
|
||||
GLboolean GenerateMipmap; /**< GL_SGIS_generate_mipmap */
|
||||
GLboolean _Complete; /**< Is texture object complete? */
|
||||
GLboolean _BaseComplete; /**< Is the base texture level valid? */
|
||||
GLboolean _MipmapComplete; /**< Is the whole mipmap valid? */
|
||||
GLboolean _RenderToTexture; /**< Any rendering to this texture? */
|
||||
GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */
|
||||
GLboolean Immutable; /**< GL_ARB_texture_storage */
|
||||
|
|
|
|||
|
|
@ -262,7 +262,8 @@ _mesa_copy_texture_object( struct gl_texture_object *dest,
|
|||
dest->_MaxLevel = src->_MaxLevel;
|
||||
dest->_MaxLambda = src->_MaxLambda;
|
||||
dest->GenerateMipmap = src->GenerateMipmap;
|
||||
dest->_Complete = src->_Complete;
|
||||
dest->_BaseComplete = src->_BaseComplete;
|
||||
dest->_MipmapComplete = src->_MipmapComplete;
|
||||
COPY_4V(dest->Swizzle, src->Swizzle);
|
||||
dest->_Swizzle = src->_Swizzle;
|
||||
|
||||
|
|
@ -386,14 +387,26 @@ _mesa_reference_texobj_(struct gl_texture_object **ptr,
|
|||
}
|
||||
|
||||
|
||||
enum base_mipmap { BASE, MIPMAP };
|
||||
|
||||
|
||||
/**
|
||||
* Mark a texture object as incomplete.
|
||||
* Mark a texture object as incomplete. There are actually three kinds of
|
||||
* (in)completeness:
|
||||
* 1. "base incomplete": the base level of the texture is invalid so no
|
||||
* texturing is possible.
|
||||
* 2. "mipmap incomplete": a non-base level of the texture is invalid so
|
||||
* mipmap filtering isn't possible, but non-mipmap filtering is.
|
||||
* 3. "texture incompleteness": some combination of texture state and
|
||||
* sampler state renders the texture incomplete.
|
||||
*
|
||||
* \param t texture object
|
||||
* \param bm either BASE or MIPMAP to indicate what's incomplete
|
||||
* \param fmt... string describing why it's incomplete (for debugging).
|
||||
*/
|
||||
static void
|
||||
incomplete(struct gl_texture_object *t, const char *fmt, ...)
|
||||
incomplete(struct gl_texture_object *t, enum base_mipmap bm,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
#if 0
|
||||
va_list args;
|
||||
|
|
@ -405,7 +418,9 @@ incomplete(struct gl_texture_object *t, const char *fmt, ...)
|
|||
|
||||
printf("Texture Obj %d incomplete because: %s\n", t->Name, s);
|
||||
#endif
|
||||
t->_Complete = GL_FALSE;
|
||||
if (bm == BASE)
|
||||
t->_BaseComplete = GL_FALSE;
|
||||
t->_MipmapComplete = GL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -429,18 +444,20 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
|
|||
const struct gl_texture_image *baseImage;
|
||||
GLint maxLog2 = 0, maxLevels = 0;
|
||||
|
||||
t->_Complete = GL_TRUE; /* be optimistic */
|
||||
/* We'll set these to FALSE if tests fail below */
|
||||
t->_BaseComplete = GL_TRUE;
|
||||
t->_MipmapComplete = GL_TRUE;
|
||||
|
||||
/* Detect cases where the application set the base level to an invalid
|
||||
* value.
|
||||
*/
|
||||
if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) {
|
||||
incomplete(t, "base level = %d is invalid", baseLevel);
|
||||
incomplete(t, BASE, "base level = %d is invalid", baseLevel);
|
||||
return;
|
||||
}
|
||||
|
||||
if (t->MaxLevel < baseLevel) {
|
||||
incomplete(t, "MAX_LEVEL (%d) < BASE_LEVEL (%d)",
|
||||
incomplete(t, BASE, "MAX_LEVEL (%d) < BASE_LEVEL (%d)",
|
||||
t->MaxLevel, baseLevel);
|
||||
return;
|
||||
}
|
||||
|
|
@ -449,7 +466,7 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
|
|||
|
||||
/* Always need the base level image */
|
||||
if (!baseImage) {
|
||||
incomplete(t, "Image[baseLevel=%d] == NULL", baseLevel);
|
||||
incomplete(t, BASE, "Image[baseLevel=%d] == NULL", baseLevel);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -457,7 +474,7 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
|
|||
if (baseImage->Width == 0 ||
|
||||
baseImage->Height == 0 ||
|
||||
baseImage->Depth == 0) {
|
||||
incomplete(t, "texture width or height or depth = 0");
|
||||
incomplete(t, BASE, "texture width or height or depth = 0");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -525,26 +542,26 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
|
|||
if (t->Image[face][baseLevel] == NULL ||
|
||||
t->Image[face][baseLevel]->Width2 != w ||
|
||||
t->Image[face][baseLevel]->Height2 != h) {
|
||||
incomplete(t, "Cube face missing or mismatched size");
|
||||
incomplete(t, BASE, "Cube face missing or mismatched size");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do mipmap consistency checking
|
||||
* Do mipmap consistency checking.
|
||||
* Note: we don't care about the current texture sampler state here.
|
||||
* To determine texture completeness we'll either look at _BaseComplete
|
||||
* or _MipmapComplete depending on the current minification filter mode.
|
||||
*/
|
||||
if (t->Sampler.MinFilter != GL_NEAREST && t->Sampler.MinFilter != GL_LINEAR) {
|
||||
/*
|
||||
* Mipmapping: determine if we have a complete set of mipmaps
|
||||
*/
|
||||
{
|
||||
GLint i;
|
||||
const GLint minLevel = baseLevel;
|
||||
const GLint maxLevel = t->_MaxLevel;
|
||||
GLuint width, height, depth, face, numFaces = 1;
|
||||
|
||||
if (minLevel > maxLevel) {
|
||||
incomplete(t, "minLevel > maxLevel");
|
||||
incomplete(t, BASE, "minLevel > maxLevel");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -572,27 +589,27 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
|
|||
const struct gl_texture_image *img = t->Image[face][i];
|
||||
|
||||
if (!img) {
|
||||
incomplete(t, "TexImage[%d] is missing", i);
|
||||
incomplete(t, MIPMAP, "TexImage[%d] is missing", i);
|
||||
return;
|
||||
}
|
||||
if (img->TexFormat != baseImage->TexFormat) {
|
||||
incomplete(t, "Format[i] != Format[baseLevel]");
|
||||
incomplete(t, MIPMAP, "Format[i] != Format[baseLevel]");
|
||||
return;
|
||||
}
|
||||
if (img->Border != baseImage->Border) {
|
||||
incomplete(t, "Border[i] != Border[baseLevel]");
|
||||
incomplete(t, MIPMAP, "Border[i] != Border[baseLevel]");
|
||||
return;
|
||||
}
|
||||
if (img->Width2 != width) {
|
||||
incomplete(t, "TexImage[%d] bad width %u", i, img->Width2);
|
||||
incomplete(t, MIPMAP, "TexImage[%d] bad width %u", i, img->Width2);
|
||||
return;
|
||||
}
|
||||
if (img->Height2 != height) {
|
||||
incomplete(t, "TexImage[%d] bad height %u", i, img->Height2);
|
||||
incomplete(t, MIPMAP, "TexImage[%d] bad height %u", i, img->Height2);
|
||||
return;
|
||||
}
|
||||
if (img->Depth2 != depth) {
|
||||
incomplete(t, "TexImage[%d] bad depth %u", i, img->Depth2);
|
||||
incomplete(t, MIPMAP, "TexImage[%d] bad depth %u", i, img->Depth2);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -601,7 +618,7 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
|
|||
/* check that cube faces are the same size */
|
||||
if (img->Width2 != t->Image[0][i]->Width2 ||
|
||||
img->Height2 != t->Image[0][i]->Height2) {
|
||||
incomplete(t, "CubeMap Image[n][i] bad size");
|
||||
incomplete(t, MIPMAP, "CubeMap Image[n][i] bad size");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -666,7 +683,8 @@ void
|
|||
_mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj,
|
||||
GLboolean invalidate_state)
|
||||
{
|
||||
texObj->_Complete = GL_FALSE;
|
||||
texObj->_BaseComplete = GL_FALSE;
|
||||
texObj->_MipmapComplete = GL_FALSE;
|
||||
if (invalidate_state)
|
||||
ctx->NewState |= _NEW_TEXTURE;
|
||||
}
|
||||
|
|
@ -789,7 +807,8 @@ _mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex)
|
|||
}
|
||||
|
||||
_mesa_test_texobj_completeness(ctx, texObj);
|
||||
assert(texObj->_Complete);
|
||||
assert(texObj->_BaseComplete);
|
||||
assert(texObj->_MipmapComplete);
|
||||
|
||||
ctx->Shared->FallbackTex[tex] = texObj;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "compiler.h"
|
||||
#include "glheader.h"
|
||||
#include "mtypes.h"
|
||||
#include "samplerobj.h"
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -77,6 +78,18 @@ _mesa_reference_texobj(struct gl_texture_object **ptr,
|
|||
}
|
||||
|
||||
|
||||
/** Is the texture "complete" with respect to the given sampler state? */
|
||||
static inline GLboolean
|
||||
_mesa_is_texture_complete(const struct gl_texture_object *texObj,
|
||||
const struct gl_sampler_object *sampler)
|
||||
{
|
||||
if (_mesa_is_mipmap_filter(sampler))
|
||||
return texObj->_MipmapComplete;
|
||||
else
|
||||
return texObj->_BaseComplete;
|
||||
}
|
||||
|
||||
|
||||
extern void
|
||||
_mesa_test_texobj_completeness( const struct gl_context *ctx,
|
||||
struct gl_texture_object *obj );
|
||||
|
|
|
|||
|
|
@ -212,8 +212,7 @@ flush(struct gl_context *ctx)
|
|||
|
||||
/**
|
||||
* This is called just prior to changing any texture object state which
|
||||
* can effect texture completeness (texture base level, max level,
|
||||
* minification filter).
|
||||
* can effect texture completeness (texture base level, max level).
|
||||
* Any pending rendering will be flushed out, we'll set the _NEW_TEXTURE
|
||||
* state flag and then mark the texture object as 'incomplete' so that any
|
||||
* per-texture derived state gets recomputed.
|
||||
|
|
@ -242,7 +241,7 @@ set_tex_parameteri(struct gl_context *ctx,
|
|||
switch (params[0]) {
|
||||
case GL_NEAREST:
|
||||
case GL_LINEAR:
|
||||
incomplete(ctx, texObj);
|
||||
flush(ctx);
|
||||
texObj->Sampler.MinFilter = params[0];
|
||||
return GL_TRUE;
|
||||
case GL_NEAREST_MIPMAP_NEAREST:
|
||||
|
|
@ -251,7 +250,7 @@ set_tex_parameteri(struct gl_context *ctx,
|
|||
case GL_LINEAR_MIPMAP_LINEAR:
|
||||
if (texObj->Target != GL_TEXTURE_RECTANGLE_NV &&
|
||||
texObj->Target != GL_TEXTURE_EXTERNAL_OES) {
|
||||
incomplete(ctx, texObj);
|
||||
flush(ctx);
|
||||
texObj->Sampler.MinFilter = params[0];
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -569,10 +569,13 @@ update_texture_state( struct gl_context *ctx )
|
|||
for (texIndex = 0; texIndex < NUM_TEXTURE_TARGETS; texIndex++) {
|
||||
if (enabledTargets & (1 << texIndex)) {
|
||||
struct gl_texture_object *texObj = texUnit->CurrentTex[texIndex];
|
||||
if (!texObj->_Complete) {
|
||||
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 (texObj->_Complete) {
|
||||
if (_mesa_is_texture_complete(texObj, sampler)) {
|
||||
texUnit->_ReallyEnabled = 1 << texIndex;
|
||||
_mesa_reference_texobj(&texUnit->_Current, texObj);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1243,7 +1243,7 @@ st_finalize_texture(struct gl_context *ctx,
|
|||
enum pipe_format firstImageFormat;
|
||||
GLuint ptWidth, ptHeight, ptDepth, ptLayers;
|
||||
|
||||
if (stObj->base._Complete) {
|
||||
if (_mesa_is_texture_complete(tObj, &tObj->Sampler)) {
|
||||
/* The texture is complete and we know exactly how many mipmap levels
|
||||
* are present/needed. This is conditional because we may be called
|
||||
* from the st_generate_mipmap() function when the texture object is
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "main/bufferobj.h"
|
||||
#include "main/colormac.h"
|
||||
#include "main/mtypes.h"
|
||||
#include "main/samplerobj.h"
|
||||
#include "main/teximage.h"
|
||||
#include "program/prog_parameter.h"
|
||||
#include "program/prog_statevars.h"
|
||||
|
|
@ -482,7 +483,9 @@ _swrast_update_texture_samplers(struct gl_context *ctx)
|
|||
if (tObj) {
|
||||
_mesa_update_fetch_functions(tObj);
|
||||
}
|
||||
swrast->TextureSample[u] = _swrast_choose_texture_sample_func(ctx, tObj);
|
||||
swrast->TextureSample[u] =
|
||||
_swrast_choose_texture_sample_func(ctx, tObj,
|
||||
_mesa_get_samplerobj(ctx, u));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "main/context.h"
|
||||
#include "main/colormac.h"
|
||||
#include "main/imports.h"
|
||||
#include "main/texobj.h"
|
||||
|
||||
#include "s_context.h"
|
||||
#include "s_texfilter.h"
|
||||
|
|
@ -3612,9 +3613,10 @@ null_sample_func( struct gl_context *ctx,
|
|||
*/
|
||||
texture_sample_func
|
||||
_swrast_choose_texture_sample_func( struct gl_context *ctx,
|
||||
const struct gl_texture_object *t )
|
||||
const struct gl_texture_object *t,
|
||||
const struct gl_sampler_object *sampler)
|
||||
{
|
||||
if (!t || !t->_Complete) {
|
||||
if (!t || !_mesa_is_texture_complete(t, sampler)) {
|
||||
return &null_sample_func;
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@ struct gl_texture_object;
|
|||
|
||||
extern texture_sample_func
|
||||
_swrast_choose_texture_sample_func( struct gl_context *ctx,
|
||||
const struct gl_texture_object *tObj );
|
||||
const struct gl_texture_object *tObj,
|
||||
const struct gl_sampler_object *sampler);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue