mesa/main: Add generic bits of ARB_clear_texture implementation

This adds the driver entry point for glClearTexSubImage and fills in the
_mesa_ClearTexImage and _mesa_ClearTexSubImage functions that call it.

v2: Don't clear some of the images if only one of them makes an error

Reviewed-by: Jason Ekstrand <jason.ekstrand@intel.com>
This commit is contained in:
Neil Roberts 2014-06-10 16:11:00 +01:00
parent 2e63f91e60
commit fbbbf7529c
3 changed files with 271 additions and 1 deletions

View file

@ -238,6 +238,20 @@ struct dd_function_table {
GLenum format, GLenum type, GLvoid *pixels,
struct gl_texture_image *texImage );
/**
* Called by glClearTex[Sub]Image
*
* Clears a rectangular region of the image to a given value. The
* clearValue argument is either NULL or points to a single texel to use as
* the clear value in the same internal format as the texture image. If it
* is NULL then the texture should be cleared to zeroes.
*/
void (*ClearTexSubImage)(struct gl_context *ctx,
struct gl_texture_image *texImage,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
const GLvoid *clearValue);
/**
* Called by glCopyTex[Sub]Image[123]D().
*

View file

@ -51,6 +51,7 @@
#include "textureview.h"
#include "mtypes.h"
#include "glformats.h"
#include "texstore.h"
/**
@ -3835,20 +3836,264 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level,
x, y, width, height);
}
static bool
check_clear_tex_image(struct gl_context *ctx,
const char *function,
struct gl_texture_image *texImage,
GLenum format, GLenum type,
const void *data,
GLubyte *clearValue)
{
struct gl_texture_object *texObj = texImage->TexObject;
static const GLubyte zeroData[MAX_PIXEL_BYTES];
GLenum internalFormat = texImage->InternalFormat;
GLenum err;
if (texObj->Target == GL_TEXTURE_BUFFER) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(buffer texture)", function);
return false;
}
if (_mesa_is_compressed_format(ctx, internalFormat)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(compressed texture)", function);
return false;
}
err = _mesa_error_check_format_and_type(ctx, format, type);
if (err != GL_NO_ERROR) {
_mesa_error(ctx, err,
"%s(incompatible format = %s, type = %s)",
function,
_mesa_lookup_enum_by_nr(format),
_mesa_lookup_enum_by_nr(type));
return false;
}
/* make sure internal format and format basically agree */
if (!texture_formats_agree(internalFormat, format)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(incompatible internalFormat = %s, format = %s)",
function,
_mesa_lookup_enum_by_nr(internalFormat),
_mesa_lookup_enum_by_nr(format));
return false;
}
if (ctx->Version >= 30 || ctx->Extensions.EXT_texture_integer) {
/* both source and dest must be integer-valued, or neither */
if (_mesa_is_format_integer_color(texImage->TexFormat) !=
_mesa_is_enum_format_integer(format)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(integer/non-integer format mismatch)",
function);
return false;
}
}
if (!_mesa_texstore(ctx,
1, /* dims */
texImage->_BaseFormat,
texImage->TexFormat,
0, /* dstRowStride */
&clearValue,
1, 1, 1, /* srcWidth/Height/Depth */
format, type,
data ? data : zeroData,
&ctx->DefaultPacking)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid format)", function);
return false;
}
return true;
}
static struct gl_texture_object *
get_tex_obj_for_clear(struct gl_context *ctx,
const char *function,
GLuint texture)
{
struct gl_texture_object *texObj;
if (texture == 0) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(zero texture)", function);
return NULL;
}
texObj = _mesa_lookup_texture(ctx, texture);
if (texObj == NULL) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", function);
return NULL;
}
if (texObj->Target == 0) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(unbound tex)", function);
return NULL;
}
return texObj;
}
static int
get_tex_images_for_clear(struct gl_context *ctx,
const char *function,
struct gl_texture_object *texObj,
GLint level,
struct gl_texture_image **texImages)
{
GLenum target;
int i;
if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function);
return 0;
}
if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
for (i = 0; i < MAX_FACES; i++) {
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
texImages[i] = _mesa_select_tex_image(ctx, texObj, target, level);
if (texImages[i] == NULL) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(invalid level)", function);
return 0;
}
}
return MAX_FACES;
}
texImages[0] = _mesa_select_tex_image(ctx, texObj, texObj->Target, level);
if (texImages[0] == NULL) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function);
return 0;
}
return 1;
}
void GLAPIENTRY
_mesa_ClearTexSubImage( GLuint texture, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type, const void *data )
{
GET_CURRENT_CONTEXT(ctx);
struct gl_texture_object *texObj;
struct gl_texture_image *texImages[MAX_FACES];
GLubyte clearValue[MAX_FACES][MAX_PIXEL_BYTES];
int i, numImages;
int minDepth, maxDepth;
texObj = get_tex_obj_for_clear(ctx, "glClearTexSubImage", texture);
if (texObj == NULL)
return;
_mesa_lock_texture(ctx, texObj);
numImages = get_tex_images_for_clear(ctx, "glClearTexSubImage",
texObj, level, texImages);
if (numImages == 0)
goto out;
if (numImages == 1) {
minDepth = -(int) texImages[0]->Border;
maxDepth = texImages[0]->Depth;
} else {
minDepth = 0;
maxDepth = numImages;
}
if (xoffset < -(GLint) texImages[0]->Border ||
yoffset < -(GLint) texImages[0]->Border ||
zoffset < minDepth ||
width < 0 ||
height < 0 ||
depth < 0 ||
xoffset + width > texImages[0]->Width ||
yoffset + height > texImages[0]->Height ||
zoffset + depth > maxDepth) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glClearSubTexImage(invalid dimensions)");
goto out;
}
if (numImages == 1) {
if (check_clear_tex_image(ctx, "glClearTexSubImage",
texImages[0],
format, type, data, clearValue[0])) {
ctx->Driver.ClearTexSubImage(ctx,
texImages[0],
xoffset, yoffset, zoffset,
width, height, depth,
data ? clearValue[0] : NULL);
}
} else {
for (i = zoffset; i < zoffset + depth; i++) {
if (!check_clear_tex_image(ctx, "glClearTexSubImage",
texImages[i],
format, type, data, clearValue[i]))
goto out;
}
for (i = zoffset; i < zoffset + depth; i++) {
ctx->Driver.ClearTexSubImage(ctx,
texImages[i],
xoffset, yoffset, 0,
width, height, 1,
data ? clearValue[i] : NULL);
}
}
out:
_mesa_unlock_texture(ctx, texObj);
}
void GLAPIENTRY
_mesa_ClearTexImage( GLuint texture, GLint level,
GLenum format, GLenum type, const void *data )
{
GET_CURRENT_CONTEXT(ctx);
struct gl_texture_object *texObj;
struct gl_texture_image *texImages[MAX_FACES];
GLubyte clearValue[MAX_FACES][MAX_PIXEL_BYTES];
int i, numImages;
texObj = get_tex_obj_for_clear(ctx, "glClearTexImage", texture);
if (texObj == NULL)
return;
_mesa_lock_texture(ctx, texObj);
numImages = get_tex_images_for_clear(ctx, "glClearTexImage",
texObj, level, texImages);
for (i = 0; i < numImages; i++) {
if (!check_clear_tex_image(ctx, "glClearTexImage",
texImages[i],
format, type, data,
clearValue[i]))
goto out;
}
for (i = 0; i < numImages; i++) {
ctx->Driver.ClearTexSubImage(ctx, texImages[i],
-(GLint) texImages[i]->Border, /* xoffset */
-(GLint) texImages[i]->Border, /* yoffset */
-(GLint) texImages[i]->Border, /* zoffset */
texImages[i]->Width,
texImages[i]->Height,
texImages[i]->Depth,
data ? clearValue[i] : NULL);
}
out:
_mesa_unlock_texture(ctx, texObj);
}
@ -4611,7 +4856,6 @@ _mesa_TexStorage2DMultisample(GLenum target, GLsizei samples,
"glTexStorage2DMultisample");
}
void GLAPIENTRY
_mesa_TexStorage3DMultisample(GLenum target, GLsizei samples,
GLenum internalformat, GLsizei width,

View file

@ -336,6 +336,18 @@ _mesa_TexStorage3DMultisample(GLenum target, GLsizei samples,
GLsizei height, GLsizei depth,
GLboolean fixedsamplelocations);
extern void GLAPIENTRY
_mesa_ClearTexImage(GLuint texture, GLint level,
GLenum format, GLenum type,
const void *data);
extern void GLAPIENTRY
_mesa_ClearTexSubImage(GLuint texture, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type,
const void *data);
bool
_mesa_compressed_texture_pixel_storage_error_check(struct gl_context *ctx,
GLint dimensions,