mesa: fix _mesa_get_fallback_texture() to handle all texture targets
Previously, this function only handled 2D textures. The fallback texture is used when we try to sample from an incomplete texture object. GLSL says sampling an incomplete texture should return (0,0,0,1). v2: use a 1-texel texture image, per José. Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
This commit is contained in:
@@ -2483,7 +2483,7 @@ struct gl_shared_state
|
||||
struct gl_texture_object *DefaultTex[NUM_TEXTURE_TARGETS];
|
||||
|
||||
/** Fallback texture used when a bound texture is incomplete */
|
||||
struct gl_texture_object *FallbackTex;
|
||||
struct gl_texture_object *FallbackTex[NUM_TEXTURE_TARGETS];
|
||||
|
||||
/**
|
||||
* \name Thread safety and statechange notification for texture
|
||||
|
@@ -307,9 +307,11 @@ free_shared_state(struct gl_context *ctx, struct gl_shared_state *shared)
|
||||
{
|
||||
GLuint i;
|
||||
|
||||
/* Free the dummy/fallback texture object */
|
||||
if (shared->FallbackTex)
|
||||
ctx->Driver.DeleteTexture(ctx, shared->FallbackTex);
|
||||
/* Free the dummy/fallback texture objects */
|
||||
for (i = 0; i < NUM_TEXTURE_TARGETS; i++) {
|
||||
if (shared->FallbackTex[i])
|
||||
ctx->Driver.DeleteTexture(ctx, shared->FallbackTex[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free display lists
|
||||
|
@@ -759,59 +759,127 @@ _mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj,
|
||||
|
||||
|
||||
/**
|
||||
* Return pointer to a default/fallback texture.
|
||||
* The texture is a 2D 8x8 RGBA texture with all texels = (0,0,0,1).
|
||||
* That's the value a sampler should get when sampling from an
|
||||
* Return pointer to a default/fallback texture of the given type/target.
|
||||
* The texture is an RGBA texture with all texels = (0,0,0,1).
|
||||
* That's the value a GLSL sampler should get when sampling from an
|
||||
* incomplete texture.
|
||||
*/
|
||||
struct gl_texture_object *
|
||||
_mesa_get_fallback_texture(struct gl_context *ctx)
|
||||
_mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex)
|
||||
{
|
||||
if (!ctx->Shared->FallbackTex) {
|
||||
if (!ctx->Shared->FallbackTex[tex]) {
|
||||
/* create fallback texture now */
|
||||
static GLubyte texels[8 * 8][4];
|
||||
const GLsizei width = 1, height = 1, depth = 1;
|
||||
GLubyte texel[4];
|
||||
struct gl_texture_object *texObj;
|
||||
struct gl_texture_image *texImage;
|
||||
gl_format texFormat;
|
||||
GLuint i;
|
||||
GLuint dims, face, numFaces = 1;
|
||||
GLenum target;
|
||||
|
||||
for (i = 0; i < 8 * 8; i++) {
|
||||
texels[i][0] =
|
||||
texels[i][1] =
|
||||
texels[i][2] = 0x0;
|
||||
texels[i][3] = 0xff;
|
||||
texel[0] =
|
||||
texel[1] =
|
||||
texel[2] = 0x0;
|
||||
texel[3] = 0xff;
|
||||
|
||||
switch (tex) {
|
||||
case TEXTURE_2D_ARRAY_INDEX:
|
||||
dims = 3;
|
||||
target = GL_TEXTURE_2D_ARRAY;
|
||||
break;
|
||||
case TEXTURE_1D_ARRAY_INDEX:
|
||||
dims = 2;
|
||||
target = GL_TEXTURE_1D_ARRAY;
|
||||
break;
|
||||
case TEXTURE_CUBE_INDEX:
|
||||
dims = 2;
|
||||
target = GL_TEXTURE_CUBE_MAP;
|
||||
numFaces = 6;
|
||||
break;
|
||||
case TEXTURE_3D_INDEX:
|
||||
dims = 3;
|
||||
target = GL_TEXTURE_3D;
|
||||
break;
|
||||
case TEXTURE_RECT_INDEX:
|
||||
dims = 2;
|
||||
target = GL_TEXTURE_RECTANGLE;
|
||||
break;
|
||||
case TEXTURE_2D_INDEX:
|
||||
dims = 2;
|
||||
target = GL_TEXTURE_2D;
|
||||
break;
|
||||
case TEXTURE_1D_INDEX:
|
||||
dims = 1;
|
||||
target = GL_TEXTURE_1D;
|
||||
break;
|
||||
case TEXTURE_BUFFER_INDEX:
|
||||
case TEXTURE_EXTERNAL_INDEX:
|
||||
default:
|
||||
/* no-op */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create texture object */
|
||||
texObj = ctx->Driver.NewTextureObject(ctx, 0, GL_TEXTURE_2D);
|
||||
texObj = ctx->Driver.NewTextureObject(ctx, 0, target);
|
||||
if (!texObj)
|
||||
return NULL;
|
||||
|
||||
assert(texObj->RefCount == 1);
|
||||
texObj->Sampler.MinFilter = GL_NEAREST;
|
||||
texObj->Sampler.MagFilter = GL_NEAREST;
|
||||
|
||||
/* create level[0] texture image */
|
||||
texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, 0);
|
||||
|
||||
texFormat = ctx->Driver.ChooseTextureFormat(ctx, GL_RGBA, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE);
|
||||
|
||||
/* init the image fields */
|
||||
_mesa_init_teximage_fields(ctx, texImage,
|
||||
8, 8, 1, 0, GL_RGBA, texFormat);
|
||||
/* need a loop here just for cube maps */
|
||||
for (face = 0; face < numFaces; face++) {
|
||||
GLenum faceTarget;
|
||||
|
||||
ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
|
||||
if (target == GL_TEXTURE_CUBE_MAP)
|
||||
faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
|
||||
else
|
||||
faceTarget = target;
|
||||
|
||||
/* set image data */
|
||||
ctx->Driver.TexImage2D(ctx, texImage, GL_RGBA,
|
||||
8, 8, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, texels,
|
||||
&ctx->DefaultPacking);
|
||||
/* initialize level[0] texture image */
|
||||
texImage = _mesa_get_tex_image(ctx, texObj, faceTarget, 0);
|
||||
|
||||
_mesa_init_teximage_fields(ctx, texImage,
|
||||
width,
|
||||
(dims > 1) ? height : 1,
|
||||
(dims > 2) ? depth : 1,
|
||||
0, /* border */
|
||||
GL_RGBA, texFormat);
|
||||
|
||||
switch (dims) {
|
||||
case 1:
|
||||
ctx->Driver.TexImage1D(ctx, texImage, GL_RGBA,
|
||||
width, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, texel,
|
||||
&ctx->DefaultPacking);
|
||||
break;
|
||||
case 2:
|
||||
ctx->Driver.TexImage2D(ctx, texImage, GL_RGBA,
|
||||
width, height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, texel,
|
||||
&ctx->DefaultPacking);
|
||||
break;
|
||||
case 3:
|
||||
ctx->Driver.TexImage3D(ctx, texImage, GL_RGBA,
|
||||
width, height, depth, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, texel,
|
||||
&ctx->DefaultPacking);
|
||||
break;
|
||||
default:
|
||||
_mesa_problem(ctx, "bad dims in _mesa_get_fallback_texture()");
|
||||
}
|
||||
}
|
||||
|
||||
_mesa_test_texobj_completeness(ctx, texObj);
|
||||
assert(texObj->_Complete);
|
||||
|
||||
ctx->Shared->FallbackTex = texObj;
|
||||
ctx->Shared->FallbackTex[tex] = texObj;
|
||||
}
|
||||
return ctx->Shared->FallbackTex;
|
||||
return ctx->Shared->FallbackTex[tex];
|
||||
}
|
||||
|
||||
|
||||
|
@@ -34,8 +34,8 @@
|
||||
|
||||
#include "compiler.h"
|
||||
#include "glheader.h"
|
||||
#include "mtypes.h"
|
||||
|
||||
struct gl_context;
|
||||
|
||||
/**
|
||||
* \name Internal functions
|
||||
@@ -89,7 +89,7 @@ _mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj,
|
||||
GLboolean invalidate_state);
|
||||
|
||||
extern struct gl_texture_object *
|
||||
_mesa_get_fallback_texture(struct gl_context *ctx);
|
||||
_mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex);
|
||||
|
||||
extern void
|
||||
_mesa_unlock_context_textures( struct gl_context *ctx );
|
||||
|
@@ -586,9 +586,15 @@ update_texture_state( struct gl_context *ctx )
|
||||
* object, but there isn't one (or it's incomplete). Use the
|
||||
* fallback texture.
|
||||
*/
|
||||
struct gl_texture_object *texObj = _mesa_get_fallback_texture(ctx);
|
||||
texUnit->_ReallyEnabled = 1 << TEXTURE_2D_INDEX;
|
||||
struct gl_texture_object *texObj;
|
||||
gl_texture_index texTarget;
|
||||
|
||||
assert(_mesa_bitcount(enabledTargets) == 1);
|
||||
|
||||
texTarget = (gl_texture_index) (ffs(enabledTargets) - 1);
|
||||
texObj = _mesa_get_fallback_texture(ctx, texTarget);
|
||||
_mesa_reference_texobj(&texUnit->_Current, texObj);
|
||||
texUnit->_ReallyEnabled = 1 << texTarget;
|
||||
}
|
||||
else {
|
||||
/* fixed-function: texture unit is really disabled */
|
||||
|
Reference in New Issue
Block a user