From 23a7aebae0a742d94ffe2304357dcc1234a99155 Mon Sep 17 00:00:00 2001 From: marha Date: Thu, 8 Sep 2011 10:54:11 +0200 Subject: mesa git update 8 sep 2011 --- mesalib/src/glsl/ir_reader.cpp | 7 +- mesalib/src/mesa/drivers/common/driverfuncs.c | 5 - mesalib/src/mesa/drivers/common/meta.c | 55 - mesalib/src/mesa/drivers/common/meta.h | 20 - mesalib/src/mesa/main/colortab.c | 689 +-- mesalib/src/mesa/main/colortab.h | 160 +- mesalib/src/mesa/main/dd.h | 23 - mesalib/src/mesa/main/enable.c | 8 - mesalib/src/mesa/main/extensions.c | 4 - mesalib/src/mesa/main/formats.c | 1 - mesalib/src/mesa/main/framebuffer.c | 2 - mesalib/src/mesa/main/get.c | 1 - mesalib/src/mesa/main/image.c | 27 - mesalib/src/mesa/main/image.h | 349 +- mesalib/src/mesa/main/mtypes.h | 87 +- mesalib/src/mesa/main/pack.c | 52 +- mesalib/src/mesa/main/pixeltransfer.c | 873 +-- mesalib/src/mesa/main/pixeltransfer.h | 171 +- mesalib/src/mesa/main/texformat.c | 7 - mesalib/src/mesa/main/texgetimage.c | 71 +- mesalib/src/mesa/main/teximage.c | 25 +- mesalib/src/mesa/main/texobj.c | 3 - mesalib/src/mesa/main/texparam.c | 6 - mesalib/src/mesa/main/texstate.c | 10 +- mesalib/src/mesa/main/texstore.c | 2 - mesalib/src/mesa/main/varray.c | 15 +- mesalib/src/mesa/state_tracker/st_cb_eglimage.c | 339 +- mesalib/src/mesa/state_tracker/st_cb_fbo.c | 15 - mesalib/src/mesa/state_tracker/st_cb_fbo.h | 180 +- mesalib/src/mesa/swrast/s_drawpix.c | 2 +- mesalib/src/mesa/swrast/s_texfilter.c | 7416 +++++++++++------------ mesalib/src/mesa/vbo/vbo_attrib_tmp.h | 12 +- 32 files changed, 4707 insertions(+), 5930 deletions(-) (limited to 'mesalib/src') diff --git a/mesalib/src/glsl/ir_reader.cpp b/mesalib/src/glsl/ir_reader.cpp index 22009eebc..2d0bccb78 100644 --- a/mesalib/src/glsl/ir_reader.cpp +++ b/mesalib/src/glsl/ir_reader.cpp @@ -777,7 +777,7 @@ ir_reader::read_constant(s_expression *expr) ir_constant_data data = { { 0 } }; // Read in list of values (at most 16). - int k = 0; + unsigned k = 0; foreach_iter(exec_list_iterator, it, values->subexpressions) { if (k >= 16) { ir_read_error(values, "expected at most 16 numbers"); @@ -820,6 +820,11 @@ ir_reader::read_constant(s_expression *expr) } ++k; } + if (k != type->components()) { + ir_read_error(values, "expected %u constant values, found %u", + type->components(), k); + return NULL; + } return new(mem_ctx) ir_constant(type, &data); } diff --git a/mesalib/src/mesa/drivers/common/driverfuncs.c b/mesalib/src/mesa/drivers/common/driverfuncs.c index 78caa0542..6484d284d 100644 --- a/mesalib/src/mesa/drivers/common/driverfuncs.c +++ b/mesalib/src/mesa/drivers/common/driverfuncs.c @@ -118,11 +118,6 @@ _mesa_init_driver_functions(struct dd_function_table *driver) driver->UnmapTexture = NULL; driver->TextureMemCpy = memcpy; driver->IsTextureResident = NULL; - driver->UpdateTexturePalette = NULL; - - /* imaging */ - driver->CopyColorTable = _mesa_meta_CopyColorTable; - driver->CopyColorSubTable = _mesa_meta_CopyColorSubTable; /* Vertex/fragment programs */ driver->BindProgram = NULL; diff --git a/mesalib/src/mesa/drivers/common/meta.c b/mesalib/src/mesa/drivers/common/meta.c index 291d91212..ad04d369f 100644 --- a/mesalib/src/mesa/drivers/common/meta.c +++ b/mesalib/src/mesa/drivers/common/meta.c @@ -2939,58 +2939,3 @@ _mesa_meta_CopyTexSubImage3D(struct gl_context *ctx, GLenum target, GLint level, copy_tex_sub_image(ctx, 3, target, level, xoffset, yoffset, zoffset, x, y, width, height); } - - -void -_mesa_meta_CopyColorTable(struct gl_context *ctx, - GLenum target, GLenum internalformat, - GLint x, GLint y, GLsizei width) -{ - GLfloat *buf; - - buf = (GLfloat *) malloc(width * 4 * sizeof(GLfloat)); - if (!buf) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyColorTable"); - return; - } - - /* - * Read image from framebuffer (disable pixel transfer ops) - */ - _mesa_meta_begin(ctx, MESA_META_PIXEL_STORE | MESA_META_PIXEL_TRANSFER); - ctx->Driver.ReadPixels(ctx, x, y, width, 1, - GL_RGBA, GL_FLOAT, &ctx->Pack, buf); - - _mesa_ColorTable(target, internalformat, width, GL_RGBA, GL_FLOAT, buf); - - _mesa_meta_end(ctx); - - free(buf); -} - - -void -_mesa_meta_CopyColorSubTable(struct gl_context *ctx,GLenum target, GLsizei start, - GLint x, GLint y, GLsizei width) -{ - GLfloat *buf; - - buf = (GLfloat *) malloc(width * 4 * sizeof(GLfloat)); - if (!buf) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyColorSubTable"); - return; - } - - /* - * Read image from framebuffer (disable pixel transfer ops) - */ - _mesa_meta_begin(ctx, MESA_META_PIXEL_STORE | MESA_META_PIXEL_TRANSFER); - ctx->Driver.ReadPixels(ctx, x, y, width, 1, - GL_RGBA, GL_FLOAT, &ctx->Pack, buf); - - _mesa_ColorSubTable(target, start, width, GL_RGBA, GL_FLOAT, buf); - - _mesa_meta_end(ctx); - - free(buf); -} diff --git a/mesalib/src/mesa/drivers/common/meta.h b/mesalib/src/mesa/drivers/common/meta.h index ac20e370e..9a92613c4 100644 --- a/mesalib/src/mesa/drivers/common/meta.h +++ b/mesalib/src/mesa/drivers/common/meta.h @@ -121,24 +121,4 @@ _mesa_meta_CopyTexSubImage3D(struct gl_context *ctx, GLenum target, GLint level, GLint x, GLint y, GLsizei width, GLsizei height); -extern void -_mesa_meta_CopyColorTable(struct gl_context *ctx, - GLenum target, GLenum internalformat, - GLint x, GLint y, GLsizei width); - -extern void -_mesa_meta_CopyColorSubTable(struct gl_context *ctx,GLenum target, GLsizei start, - GLint x, GLint y, GLsizei width); - -extern void -_mesa_meta_CopyConvolutionFilter1D(struct gl_context *ctx, GLenum target, - GLenum internalFormat, - GLint x, GLint y, GLsizei width); - -extern void -_mesa_meta_CopyConvolutionFilter2D(struct gl_context *ctx, GLenum target, - GLenum internalFormat, GLint x, GLint y, - GLsizei width, GLsizei height); - - #endif /* META_H */ diff --git a/mesalib/src/mesa/main/colortab.c b/mesalib/src/mesa/main/colortab.c index ddb0f1f65..f20dee677 100644 --- a/mesalib/src/mesa/main/colortab.c +++ b/mesalib/src/mesa/main/colortab.c @@ -41,361 +41,14 @@ #if FEATURE_colortable - -/** - * Given an internalFormat token passed to glColorTable, - * return the corresponding base format. - * Return -1 if invalid token. - */ -static GLint -base_colortab_format( GLenum format ) -{ - switch (format) { - case GL_ALPHA: - case GL_ALPHA4: - case GL_ALPHA8: - case GL_ALPHA12: - case GL_ALPHA16: - return GL_ALPHA; - case GL_LUMINANCE: - case GL_LUMINANCE4: - case GL_LUMINANCE8: - case GL_LUMINANCE12: - case GL_LUMINANCE16: - return GL_LUMINANCE; - case GL_LUMINANCE_ALPHA: - case GL_LUMINANCE4_ALPHA4: - case GL_LUMINANCE6_ALPHA2: - case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE12_ALPHA4: - case GL_LUMINANCE12_ALPHA12: - case GL_LUMINANCE16_ALPHA16: - return GL_LUMINANCE_ALPHA; - case GL_INTENSITY: - case GL_INTENSITY4: - case GL_INTENSITY8: - case GL_INTENSITY12: - case GL_INTENSITY16: - return GL_INTENSITY; - case GL_RGB: - case GL_R3_G3_B2: - case GL_RGB4: - case GL_RGB5: - case GL_RGB8: - case GL_RGB10: - case GL_RGB12: - case GL_RGB16: - return GL_RGB; - case GL_RGBA: - case GL_RGBA2: - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGBA8: - case GL_RGB10_A2: - case GL_RGBA12: - case GL_RGBA16: - return GL_RGBA; - default: - return -1; /* error */ - } -} - - - -/** - * Examine table's format and set the component sizes accordingly. - */ -static void -set_component_sizes( struct gl_color_table *table ) -{ - /* assuming the ubyte table */ - const GLubyte sz = 8; - - switch (table->_BaseFormat) { - case GL_ALPHA: - table->RedSize = 0; - table->GreenSize = 0; - table->BlueSize = 0; - table->AlphaSize = sz; - table->IntensitySize = 0; - table->LuminanceSize = 0; - break; - case GL_LUMINANCE: - table->RedSize = 0; - table->GreenSize = 0; - table->BlueSize = 0; - table->AlphaSize = 0; - table->IntensitySize = 0; - table->LuminanceSize = sz; - break; - case GL_LUMINANCE_ALPHA: - table->RedSize = 0; - table->GreenSize = 0; - table->BlueSize = 0; - table->AlphaSize = sz; - table->IntensitySize = 0; - table->LuminanceSize = sz; - break; - case GL_INTENSITY: - table->RedSize = 0; - table->GreenSize = 0; - table->BlueSize = 0; - table->AlphaSize = 0; - table->IntensitySize = sz; - table->LuminanceSize = 0; - break; - case GL_RGB: - table->RedSize = sz; - table->GreenSize = sz; - table->BlueSize = sz; - table->AlphaSize = 0; - table->IntensitySize = 0; - table->LuminanceSize = 0; - break; - case GL_RGBA: - table->RedSize = sz; - table->GreenSize = sz; - table->BlueSize = sz; - table->AlphaSize = sz; - table->IntensitySize = 0; - table->LuminanceSize = 0; - break; - default: - _mesa_problem(NULL, "unexpected format in set_component_sizes"); - } -} - - - -/** - * Update/replace all or part of a color table. Helper function - * used by _mesa_ColorTable() and _mesa_ColorSubTable(). - * The table->Table buffer should already be allocated. - * \param start first entry to update - * \param count number of entries to update - * \param format format of user-provided table data - * \param type datatype of user-provided table data - * \param data user-provided table data - * \param [rgba]Scale - RGBA scale factors - * \param [rgba]Bias - RGBA bias factors - */ -static void -store_colortable_entries(struct gl_context *ctx, struct gl_color_table *table, - GLsizei start, GLsizei count, - GLenum format, GLenum type, const GLvoid *data, - GLfloat rScale, GLfloat rBias, - GLfloat gScale, GLfloat gBias, - GLfloat bScale, GLfloat bBias, - GLfloat aScale, GLfloat aBias) -{ - data = _mesa_map_validate_pbo_source(ctx, - 1, &ctx->Unpack, count, 1, 1, - format, type, INT_MAX, data, - "glColor[Sub]Table"); - if (!data) - return; - - { - /* convert user-provided data to GLfloat values */ - GLfloat tempTab[MAX_COLOR_TABLE_SIZE * 4]; - GLfloat *tableF; - GLint i; - - _mesa_unpack_color_span_float(ctx, - count, /* number of pixels */ - table->_BaseFormat, /* dest format */ - tempTab, /* dest address */ - format, type, /* src format/type */ - data, /* src data */ - &ctx->Unpack, - IMAGE_CLAMP_BIT); /* transfer ops */ - - /* the destination */ - tableF = table->TableF; - - /* Apply scale & bias & clamp now */ - switch (table->_BaseFormat) { - case GL_INTENSITY: - for (i = 0; i < count; i++) { - GLuint j = start + i; - tableF[j] = CLAMP(tempTab[i] * rScale + rBias, 0.0F, 1.0F); - } - break; - case GL_LUMINANCE: - for (i = 0; i < count; i++) { - GLuint j = start + i; - tableF[j] = CLAMP(tempTab[i] * rScale + rBias, 0.0F, 1.0F); - } - break; - case GL_ALPHA: - for (i = 0; i < count; i++) { - GLuint j = start + i; - tableF[j] = CLAMP(tempTab[i] * aScale + aBias, 0.0F, 1.0F); - } - break; - case GL_LUMINANCE_ALPHA: - for (i = 0; i < count; i++) { - GLuint j = start + i; - tableF[j*2+0] = CLAMP(tempTab[i*2+0] * rScale + rBias, 0.0F, 1.0F); - tableF[j*2+1] = CLAMP(tempTab[i*2+1] * aScale + aBias, 0.0F, 1.0F); - } - break; - case GL_RGB: - for (i = 0; i < count; i++) { - GLuint j = start + i; - tableF[j*3+0] = CLAMP(tempTab[i*3+0] * rScale + rBias, 0.0F, 1.0F); - tableF[j*3+1] = CLAMP(tempTab[i*3+1] * gScale + gBias, 0.0F, 1.0F); - tableF[j*3+2] = CLAMP(tempTab[i*3+2] * bScale + bBias, 0.0F, 1.0F); - } - break; - case GL_RGBA: - for (i = 0; i < count; i++) { - GLuint j = start + i; - tableF[j*4+0] = CLAMP(tempTab[i*4+0] * rScale + rBias, 0.0F, 1.0F); - tableF[j*4+1] = CLAMP(tempTab[i*4+1] * gScale + gBias, 0.0F, 1.0F); - tableF[j*4+2] = CLAMP(tempTab[i*4+2] * bScale + bBias, 0.0F, 1.0F); - tableF[j*4+3] = CLAMP(tempTab[i*4+3] * aScale + aBias, 0.0F, 1.0F); - } - break; - default: - _mesa_problem(ctx, "Bad format in store_colortable_entries"); - return; - } - } - - /* update the ubyte table */ - { - const GLint comps = _mesa_components_in_format(table->_BaseFormat); - const GLfloat *tableF = table->TableF + start * comps; - GLubyte *tableUB = table->TableUB + start * comps; - GLint i; - for (i = 0; i < count * comps; i++) { - CLAMPED_FLOAT_TO_UBYTE(tableUB[i], tableF[i]); - } - } - - _mesa_unmap_pbo_source(ctx, &ctx->Unpack); -} - - - void GLAPIENTRY _mesa_ColorTable( GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *data ) { - static const GLfloat one[4] = { 1.0, 1.0, 1.0, 1.0 }; - static const GLfloat zero[4] = { 0.0, 0.0, 0.0, 0.0 }; GET_CURRENT_CONTEXT(ctx); - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - struct gl_texture_object *texObj = NULL; - struct gl_color_table *table = NULL; - GLboolean proxy = GL_FALSE; - GLint baseFormat; - const GLfloat *scale = one, *bias = zero; - GLint comps; - - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */ - - switch (target) { - case GL_SHARED_TEXTURE_PALETTE_EXT: - table = &ctx->Texture.Palette; - break; - default: - /* try texture targets */ - { - struct gl_texture_object *texobj - = _mesa_select_tex_object(ctx, texUnit, target); - if (texobj) { - table = &texobj->Palette; - proxy = _mesa_is_proxy_texture(target); - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(target)"); - return; - } - } - } - - assert(table); - - if (!_mesa_is_legal_format_and_type(ctx, format, type) || - format == GL_INTENSITY) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glColorTable(format or type)"); - return; - } - - baseFormat = base_colortab_format(internalFormat); - if (baseFormat < 0) { - _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(internalFormat)"); - return; - } - - if (width < 0 || (width != 0 && !_mesa_is_pow_two(width))) { - /* error */ - if (proxy) { - table->Size = 0; - table->InternalFormat = (GLenum) 0; - table->_BaseFormat = (GLenum) 0; - } - else { - _mesa_error(ctx, GL_INVALID_VALUE, "glColorTable(width=%d)", width); - } - return; - } - - if (width > (GLsizei) ctx->Const.MaxColorTableSize) { - if (proxy) { - table->Size = 0; - table->InternalFormat = (GLenum) 0; - table->_BaseFormat = (GLenum) 0; - } - else { - _mesa_error(ctx, GL_TABLE_TOO_LARGE, "glColorTable(width)"); - } - return; - } - - table->Size = width; - table->InternalFormat = internalFormat; - table->_BaseFormat = (GLenum) baseFormat; - - comps = _mesa_components_in_format(table->_BaseFormat); - assert(comps > 0); /* error should have been caught sooner */ - - if (!proxy) { - _mesa_free_colortable_data(table); - - if (width > 0) { - table->TableF = (GLfloat *) malloc(comps * width * sizeof(GLfloat)); - table->TableUB = (GLubyte *) malloc(comps * width * sizeof(GLubyte)); - - if (!table->TableF || !table->TableUB) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glColorTable"); - return; - } - - store_colortable_entries(ctx, table, - 0, width, /* start, count */ - format, type, data, - scale[0], bias[0], - scale[1], bias[1], - scale[2], bias[2], - scale[3], bias[3]); - } - } /* proxy */ - - /* do this after the table's Type and Format are set */ - set_component_sizes(table); - - if (texObj || target == GL_SHARED_TEXTURE_PALETTE_EXT) { - /* texture object palette, texObj==NULL means the shared palette */ - if (ctx->Driver.UpdateTexturePalette) { - (*ctx->Driver.UpdateTexturePalette)( ctx, texObj ); - } - } - - ctx->NewState |= _NEW_PIXEL; + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + _mesa_error(ctx, GL_INVALID_ENUM, "glColorTable(target)"); } @@ -405,73 +58,9 @@ _mesa_ColorSubTable( GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data ) { - static const GLfloat one[4] = { 1.0, 1.0, 1.0, 1.0 }; - static const GLfloat zero[4] = { 0.0, 0.0, 0.0, 0.0 }; GET_CURRENT_CONTEXT(ctx); - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - struct gl_texture_object *texObj = NULL; - struct gl_color_table *table = NULL; - const GLfloat *scale = one, *bias = zero; - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - switch (target) { - case GL_SHARED_TEXTURE_PALETTE_EXT: - table = &ctx->Texture.Palette; - break; - default: - /* try texture targets */ - texObj = _mesa_select_tex_object(ctx, texUnit, target); - if (texObj && !_mesa_is_proxy_texture(target)) { - table = &texObj->Palette; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glColorSubTable(target)"); - return; - } - } - - assert(table); - - if (!_mesa_is_legal_format_and_type(ctx, format, type) || - format == GL_INTENSITY) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glColorSubTable(format or type)"); - return; - } - - if (count < 1) { - _mesa_error(ctx, GL_INVALID_VALUE, "glColorSubTable(count)"); - return; - } - - /* error should have been caught sooner */ - assert(_mesa_components_in_format(table->_BaseFormat) > 0); - - if (start + count > (GLint) table->Size) { - _mesa_error(ctx, GL_INVALID_VALUE, "glColorSubTable(count)"); - return; - } - - if (!table->TableF || !table->TableUB) { - /* a GL_OUT_OF_MEMORY error would have been recorded previously */ - return; - } - - store_colortable_entries(ctx, table, start, count, - format, type, data, - scale[0], bias[0], - scale[1], bias[1], - scale[2], bias[2], - scale[3], bias[3]); - - if (texObj || target == GL_SHARED_TEXTURE_PALETTE_EXT) { - /* per-texture object palette */ - if (ctx->Driver.UpdateTexturePalette) { - (*ctx->Driver.UpdateTexturePalette)( ctx, texObj ); - } - } - - ctx->NewState |= _NEW_PIXEL; + _mesa_error(ctx, GL_INVALID_ENUM, "glColorSubTable(target)"); } @@ -482,12 +71,7 @@ _mesa_CopyColorTable(GLenum target, GLenum internalformat, { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (!ctx->ReadBuffer->_ColorReadBuffer) { - return; /* no readbuffer - OK */ - } - - ctx->Driver.CopyColorTable( ctx, target, internalformat, x, y, width ); + _mesa_error(ctx, GL_INVALID_ENUM, "glCopyColorTable(target)"); } @@ -498,12 +82,7 @@ _mesa_CopyColorSubTable(GLenum target, GLsizei start, { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (!ctx->ReadBuffer->_ColorReadBuffer) { - return; /* no readbuffer - OK */ - } - - ctx->Driver.CopyColorSubTable( ctx, target, start, x, y, width ); + _mesa_error(ctx, GL_INVALID_ENUM, "glCopyColorSubTable(target)"); } @@ -513,120 +92,8 @@ _mesa_GetnColorTableARB( GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data ) { GET_CURRENT_CONTEXT(ctx); - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - struct gl_color_table *table = NULL; - GLfloat rgba[MAX_COLOR_TABLE_SIZE][4]; - GLbitfield transferOps = 0; ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (ctx->NewState) { - _mesa_update_state(ctx); - } - - switch (target) { - case GL_SHARED_TEXTURE_PALETTE_EXT: - table = &ctx->Texture.Palette; - break; - default: - /* try texture targets */ - { - struct gl_texture_object *texobj - = _mesa_select_tex_object(ctx, texUnit, target); - if (texobj && !_mesa_is_proxy_texture(target)) { - table = &texobj->Palette; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTable(target)"); - return; - } - } - } - - ASSERT(table); - - if (table->Size <= 0) { - return; - } - - switch (table->_BaseFormat) { - case GL_ALPHA: - { - GLuint i; - for (i = 0; i < table->Size; i++) { - rgba[i][RCOMP] = 0; - rgba[i][GCOMP] = 0; - rgba[i][BCOMP] = 0; - rgba[i][ACOMP] = table->TableF[i]; - } - } - break; - case GL_LUMINANCE: - { - GLuint i; - for (i = 0; i < table->Size; i++) { - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = table->TableF[i]; - rgba[i][ACOMP] = 1.0F; - } - } - break; - case GL_LUMINANCE_ALPHA: - { - GLuint i; - for (i = 0; i < table->Size; i++) { - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = table->TableF[i*2+0]; - rgba[i][ACOMP] = table->TableF[i*2+1]; - } - } - break; - case GL_INTENSITY: - { - GLuint i; - for (i = 0; i < table->Size; i++) { - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = - rgba[i][ACOMP] = table->TableF[i]; - } - } - break; - case GL_RGB: - { - GLuint i; - for (i = 0; i < table->Size; i++) { - rgba[i][RCOMP] = table->TableF[i*3+0]; - rgba[i][GCOMP] = table->TableF[i*3+1]; - rgba[i][BCOMP] = table->TableF[i*3+2]; - rgba[i][ACOMP] = 1.0F; - } - } - break; - case GL_RGBA: - memcpy(rgba, table->TableF, 4 * table->Size * sizeof(GLfloat)); - break; - default: - _mesa_problem(ctx, "bad table format in glGetColorTable"); - return; - } - - data = _mesa_map_validate_pbo_dest(ctx, - 1, &ctx->Pack, table->Size, 1, 1, - format, type, bufSize, data, - "glGetColorTable"); - if (!data) - return; - - /* TODO: is this correct? */ - if(ctx->Color._ClampReadColor) - transferOps |= IMAGE_CLAMP_BIT; - - _mesa_pack_rgba_span_float(ctx, table->Size, rgba, - format, type, data, &ctx->Pack, transferOps); - - _mesa_unmap_pbo_dest(ctx, &ctx->Pack); + _mesa_error(ctx, GL_INVALID_ENUM, "glGetnColorTableARB(target)"); } @@ -634,7 +101,9 @@ static void GLAPIENTRY _mesa_GetColorTable( GLenum target, GLenum format, GLenum type, GLvoid *data ) { - _mesa_GetnColorTableARB(target, format, type, INT_MAX, data); + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTable(target)"); } @@ -664,61 +133,8 @@ static void GLAPIENTRY _mesa_GetColorTableParameterfv( GLenum target, GLenum pname, GLfloat *params ) { GET_CURRENT_CONTEXT(ctx); - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - struct gl_color_table *table = NULL; ASSERT_OUTSIDE_BEGIN_END(ctx); - - switch (target) { - case GL_SHARED_TEXTURE_PALETTE_EXT: - table = &ctx->Texture.Palette; - break; - default: - /* try texture targets */ - { - struct gl_texture_object *texobj - = _mesa_select_tex_object(ctx, texUnit, target); - if (texobj) { - table = &texobj->Palette; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetColorTableParameterfv(target)"); - return; - } - } - } - - assert(table); - - switch (pname) { - case GL_COLOR_TABLE_FORMAT: - *params = (GLfloat) table->InternalFormat; - break; - case GL_COLOR_TABLE_WIDTH: - *params = (GLfloat) table->Size; - break; - case GL_COLOR_TABLE_RED_SIZE: - *params = (GLfloat) table->RedSize; - break; - case GL_COLOR_TABLE_GREEN_SIZE: - *params = (GLfloat) table->GreenSize; - break; - case GL_COLOR_TABLE_BLUE_SIZE: - *params = (GLfloat) table->BlueSize; - break; - case GL_COLOR_TABLE_ALPHA_SIZE: - *params = (GLfloat) table->AlphaSize; - break; - case GL_COLOR_TABLE_LUMINANCE_SIZE: - *params = (GLfloat) table->LuminanceSize; - break; - case GL_COLOR_TABLE_INTENSITY_SIZE: - *params = (GLfloat) table->IntensitySize; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameterfv(pname)" ); - return; - } + _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameterfv(target)"); } @@ -727,61 +143,8 @@ static void GLAPIENTRY _mesa_GetColorTableParameteriv( GLenum target, GLenum pname, GLint *params ) { GET_CURRENT_CONTEXT(ctx); - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - struct gl_color_table *table = NULL; ASSERT_OUTSIDE_BEGIN_END(ctx); - - switch (target) { - case GL_SHARED_TEXTURE_PALETTE_EXT: - table = &ctx->Texture.Palette; - break; - default: - /* Try texture targets */ - { - struct gl_texture_object *texobj - = _mesa_select_tex_object(ctx, texUnit, target); - if (texobj) { - table = &texobj->Palette; - } - else { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetColorTableParameteriv(target)"); - return; - } - } - } - - assert(table); - - switch (pname) { - case GL_COLOR_TABLE_FORMAT: - *params = table->InternalFormat; - break; - case GL_COLOR_TABLE_WIDTH: - *params = table->Size; - break; - case GL_COLOR_TABLE_RED_SIZE: - *params = table->RedSize; - break; - case GL_COLOR_TABLE_GREEN_SIZE: - *params = table->GreenSize; - break; - case GL_COLOR_TABLE_BLUE_SIZE: - *params = table->BlueSize; - break; - case GL_COLOR_TABLE_ALPHA_SIZE: - *params = table->AlphaSize; - break; - case GL_COLOR_TABLE_LUMINANCE_SIZE: - *params = table->LuminanceSize; - break; - case GL_COLOR_TABLE_INTENSITY_SIZE: - *params = table->IntensitySize; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameteriv(pname)" ); - return; - } + _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTableParameteriv(target)"); } @@ -804,33 +167,3 @@ _mesa_init_colortable_dispatch(struct _glapi_table *disp) #endif /* FEATURE_colortable */ - - -/**********************************************************************/ -/***** Initialization *****/ -/**********************************************************************/ - - -void -_mesa_init_colortable( struct gl_color_table *p ) -{ - p->TableF = NULL; - p->TableUB = NULL; - p->Size = 0; - p->InternalFormat = GL_RGBA; -} - - - -void -_mesa_free_colortable_data( struct gl_color_table *p ) -{ - if (p->TableF) { - free(p->TableF); - p->TableF = NULL; - } - if (p->TableUB) { - free(p->TableUB); - p->TableUB = NULL; - } -} diff --git a/mesalib/src/mesa/main/colortab.h b/mesalib/src/mesa/main/colortab.h index 81b4e008b..b0d2b5db8 100644 --- a/mesalib/src/mesa/main/colortab.h +++ b/mesalib/src/mesa/main/colortab.h @@ -1,84 +1,76 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.2 - * - * Copyright (C) 1999-2006 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 - * BRIAN PAUL 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. - */ - - -#ifndef COLORTAB_H -#define COLORTAB_H - - -#include "compiler.h" -#include "glheader.h" -#include "mfeatures.h" - -struct _glapi_table; -struct gl_color_table; - -#if FEATURE_colortable - -extern void GLAPIENTRY -_mesa_ColorTable( GLenum target, GLenum internalformat, - GLsizei width, GLenum format, GLenum type, - const GLvoid *table ); - -extern void GLAPIENTRY -_mesa_ColorSubTable( GLenum target, GLsizei start, - GLsizei count, GLenum format, GLenum type, - const GLvoid *table ); - -extern void -_mesa_init_colortable_dispatch(struct _glapi_table *disp); - -#else /* FEATURE_colortable */ - -static INLINE void GLAPIENTRY -_mesa_ColorTable( GLenum target, GLenum internalformat, - GLsizei width, GLenum format, GLenum type, - const GLvoid *table ) -{ - ASSERT_NO_FEATURE(); -} - -static INLINE void GLAPIENTRY -_mesa_ColorSubTable( GLenum target, GLsizei start, - GLsizei count, GLenum format, GLenum type, - const GLvoid *table ) -{ - ASSERT_NO_FEATURE(); -} - -static INLINE void -_mesa_init_colortable_dispatch(struct _glapi_table *disp) -{ -} - -#endif /* FEATURE_colortable */ - - -extern void -_mesa_init_colortable( struct gl_color_table *table ); - -extern void -_mesa_free_colortable_data( struct gl_color_table *table ); - -#endif /* COLORTAB_H */ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * Copyright (C) 1999-2006 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 + * BRIAN PAUL 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. + */ + + +#ifndef COLORTAB_H +#define COLORTAB_H + + +#include "compiler.h" +#include "glheader.h" +#include "mfeatures.h" + +struct _glapi_table; + +#if FEATURE_colortable + +extern void GLAPIENTRY +_mesa_ColorTable( GLenum target, GLenum internalformat, + GLsizei width, GLenum format, GLenum type, + const GLvoid *table ); + +extern void GLAPIENTRY +_mesa_ColorSubTable( GLenum target, GLsizei start, + GLsizei count, GLenum format, GLenum type, + const GLvoid *table ); + +extern void +_mesa_init_colortable_dispatch(struct _glapi_table *disp); + +#else /* FEATURE_colortable */ + +static INLINE void GLAPIENTRY +_mesa_ColorTable( GLenum target, GLenum internalformat, + GLsizei width, GLenum format, GLenum type, + const GLvoid *table ) +{ + ASSERT_NO_FEATURE(); +} + +static INLINE void GLAPIENTRY +_mesa_ColorSubTable( GLenum target, GLsizei start, + GLsizei count, GLenum format, GLenum type, + const GLvoid *table ) +{ + ASSERT_NO_FEATURE(); +} + +static INLINE void +_mesa_init_colortable_dispatch(struct _glapi_table *disp) +{ +} + +#endif /* FEATURE_colortable */ + +#endif /* COLORTAB_H */ diff --git a/mesalib/src/mesa/main/dd.h b/mesalib/src/mesa/main/dd.h index b9305addc..b77e4f092 100644 --- a/mesalib/src/mesa/main/dd.h +++ b/mesalib/src/mesa/main/dd.h @@ -523,29 +523,6 @@ struct dd_function_table { */ GLboolean (*IsTextureResident)( struct gl_context *ctx, struct gl_texture_object *t ); - - /** - * Called when the texture's color lookup table is changed. - * - * If \p tObj is NULL then the shared texture palette - * gl_texture_object::Palette is to be updated. - */ - void (*UpdateTexturePalette)( struct gl_context *ctx, - struct gl_texture_object *tObj ); - /*@}*/ - - - /** - * \name Imaging functionality - */ - /*@{*/ - void (*CopyColorTable)( struct gl_context *ctx, - GLenum target, GLenum internalformat, - GLint x, GLint y, GLsizei width ); - - void (*CopyColorSubTable)( struct gl_context *ctx, - GLenum target, GLsizei start, - GLint x, GLint y, GLsizei width ); /*@}*/ diff --git a/mesalib/src/mesa/main/enable.c b/mesalib/src/mesa/main/enable.c index 3ba4df634..4bf1809e7 100644 --- a/mesalib/src/mesa/main/enable.c +++ b/mesalib/src/mesa/main/enable.c @@ -576,12 +576,6 @@ _mesa_set_enable(struct gl_context *ctx, GLenum cap, GLboolean state) FLUSH_VERTICES(ctx, _NEW_SCISSOR); ctx->Scissor.Enabled = state; break; - case GL_SHARED_TEXTURE_PALETTE_EXT: - if (ctx->Texture.SharedPalette == state) - return; - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - ctx->Texture.SharedPalette = state; - break; case GL_STENCIL_TEST: if (ctx->Stencil.Enabled == state) return; @@ -1175,8 +1169,6 @@ _mesa_IsEnabled( GLenum cap ) return ctx->Transform.RescaleNormals; case GL_SCISSOR_TEST: return ctx->Scissor.Enabled; - case GL_SHARED_TEXTURE_PALETTE_EXT: - return ctx->Texture.SharedPalette; case GL_STENCIL_TEST: return ctx->Stencil.Enabled; case GL_TEXTURE_1D: diff --git a/mesalib/src/mesa/main/extensions.c b/mesalib/src/mesa/main/extensions.c index 14b0cf9ac..1903a503c 100644 --- a/mesalib/src/mesa/main/extensions.c +++ b/mesalib/src/mesa/main/extensions.c @@ -172,7 +172,6 @@ static const struct extension extension_table[] = { { "GL_EXT_packed_depth_stencil", o(EXT_packed_depth_stencil), GL, 2005 }, { "GL_EXT_packed_float", o(EXT_packed_float), GL, 2004 }, { "GL_EXT_packed_pixels", o(EXT_packed_pixels), GL, 1997 }, - { "GL_EXT_paletted_texture", o(EXT_paletted_texture), GL, 1995 }, { "GL_EXT_pixel_buffer_object", o(EXT_pixel_buffer_object), GL, 2004 }, { "GL_EXT_point_parameters", o(EXT_point_parameters), GL, 1997 }, { "GL_EXT_polygon_offset", o(EXT_polygon_offset), GL, 1995 }, @@ -182,7 +181,6 @@ static const struct extension extension_table[] = { { "GL_EXT_separate_shader_objects", o(EXT_separate_shader_objects), GL, 2008 }, { "GL_EXT_separate_specular_color", o(EXT_separate_specular_color), GL, 1997 }, { "GL_EXT_shadow_funcs", o(EXT_shadow_funcs), GL, 2002 }, - { "GL_EXT_shared_texture_palette", o(EXT_shared_texture_palette), GL, 2000 }, { "GL_EXT_stencil_two_side", o(EXT_stencil_two_side), GL, 2001 }, { "GL_EXT_stencil_wrap", o(EXT_stencil_wrap), GL, 2002 }, { "GL_EXT_subtexture", o(EXT_subtexture), GL, 1995 }, @@ -488,7 +486,6 @@ _mesa_enable_sw_extensions(struct gl_context *ctx) #endif /*ctx->Extensions.EXT_multi_draw_arrays = GL_TRUE;*/ ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE; - ctx->Extensions.EXT_paletted_texture = GL_TRUE; #if FEATURE_EXT_pixel_buffer_object ctx->Extensions.EXT_pixel_buffer_object = GL_TRUE; #endif @@ -496,7 +493,6 @@ _mesa_enable_sw_extensions(struct gl_context *ctx) ctx->Extensions.EXT_provoking_vertex = GL_TRUE; ctx->Extensions.EXT_shadow_funcs = GL_TRUE; ctx->Extensions.EXT_secondary_color = GL_TRUE; - ctx->Extensions.EXT_shared_texture_palette = GL_TRUE; ctx->Extensions.EXT_stencil_wrap = GL_TRUE; ctx->Extensions.EXT_stencil_two_side = GL_TRUE; ctx->Extensions.EXT_texture_array = GL_TRUE; diff --git a/mesalib/src/mesa/main/formats.c b/mesalib/src/mesa/main/formats.c index c0fcf9cd4..c6634c458 100644 --- a/mesalib/src/mesa/main/formats.c +++ b/mesalib/src/mesa/main/formats.c @@ -1175,7 +1175,6 @@ _mesa_get_format_bits(gl_format format, GLenum pname) case GL_TEXTURE_LUMINANCE_SIZE: return info->LuminanceBits; case GL_INDEX_BITS: - case GL_TEXTURE_INDEX_SIZE_EXT: return info->IndexBits; case GL_DEPTH_BITS: case GL_TEXTURE_DEPTH_SIZE_ARB: diff --git a/mesalib/src/mesa/main/framebuffer.c b/mesalib/src/mesa/main/framebuffer.c index 23fa1b2c1..42da17678 100644 --- a/mesalib/src/mesa/main/framebuffer.c +++ b/mesalib/src/mesa/main/framebuffer.c @@ -888,7 +888,6 @@ _mesa_source_buffer_exists(struct gl_context *ctx, GLenum format) case GL_RGBA: case GL_BGRA: case GL_ABGR_EXT: - case GL_COLOR_INDEX: case GL_RED_INTEGER_EXT: case GL_GREEN_INTEGER_EXT: case GL_BLUE_INTEGER_EXT: @@ -976,7 +975,6 @@ _mesa_dest_buffer_exists(struct gl_context *ctx, GLenum format) case GL_RGBA: case GL_BGRA: case GL_ABGR_EXT: - case GL_COLOR_INDEX: case GL_RED_INTEGER_EXT: case GL_GREEN_INTEGER_EXT: case GL_BLUE_INTEGER_EXT: diff --git a/mesalib/src/mesa/main/get.c b/mesalib/src/mesa/main/get.c index d32c68a53..069254b18 100644 --- a/mesalib/src/mesa/main/get.c +++ b/mesalib/src/mesa/main/get.c @@ -857,7 +857,6 @@ static const struct value_desc values[] = { { GL_RENDER_MODE, CONTEXT_ENUM(RenderMode), NO_EXTRA }, { GL_RGBA_MODE, CONST(1), NO_EXTRA }, { GL_SELECTION_BUFFER_SIZE, CONTEXT_INT(Select.BufferSize), NO_EXTRA }, - { GL_SHARED_TEXTURE_PALETTE_EXT, CONTEXT_BOOL(Texture.SharedPalette), NO_EXTRA }, { GL_STEREO, BUFFER_INT(Visual.stereoMode), NO_EXTRA }, diff --git a/mesalib/src/mesa/main/image.c b/mesalib/src/mesa/main/image.c index 37127dcb7..3e75e7c6b 100644 --- a/mesalib/src/mesa/main/image.c +++ b/mesalib/src/mesa/main/image.c @@ -249,12 +249,6 @@ _mesa_components_in_format( GLenum format ) { switch (format) { case GL_COLOR_INDEX: - case GL_COLOR_INDEX1_EXT: - case GL_COLOR_INDEX2_EXT: - case GL_COLOR_INDEX4_EXT: - case GL_COLOR_INDEX8_EXT: - case GL_COLOR_INDEX12_EXT: - case GL_COLOR_INDEX16_EXT: case GL_STENCIL_INDEX: case GL_DEPTH_COMPONENT: case GL_RED: @@ -862,27 +856,6 @@ _mesa_is_color_format(GLenum format) } -/** - * Test if the given image format is a color index format. - */ -GLboolean -_mesa_is_index_format(GLenum format) -{ - switch (format) { - case GL_COLOR_INDEX: - case GL_COLOR_INDEX1_EXT: - case GL_COLOR_INDEX2_EXT: - case GL_COLOR_INDEX4_EXT: - case GL_COLOR_INDEX8_EXT: - case GL_COLOR_INDEX12_EXT: - case GL_COLOR_INDEX16_EXT: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - /** * Test if the given image format is a depth component format. */ diff --git a/mesalib/src/mesa/main/image.h b/mesalib/src/mesa/main/image.h index 6fa93924c..46adaec41 100644 --- a/mesalib/src/mesa/main/image.h +++ b/mesalib/src/mesa/main/image.h @@ -1,176 +1,173 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * 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 - * BRIAN PAUL 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. - */ - - -#ifndef IMAGE_H -#define IMAGE_H - - -#include "glheader.h" - -struct gl_context; -struct gl_pixelstore_attrib; - -extern void -_mesa_swap2( GLushort *p, GLuint n ); - -extern void -_mesa_swap4( GLuint *p, GLuint n ); - -extern GLboolean -_mesa_type_is_packed(GLenum type); - -extern GLint -_mesa_sizeof_type( GLenum type ); - -extern GLint -_mesa_sizeof_packed_type( GLenum type ); - -extern GLint -_mesa_components_in_format( GLenum format ); - -extern GLint -_mesa_bytes_per_pixel( GLenum format, GLenum type ); - -extern GLboolean -_mesa_is_legal_format_and_type(const struct gl_context *ctx, - GLenum format, GLenum type); - -extern GLboolean -_mesa_is_color_format(GLenum format); - -extern GLboolean -_mesa_is_index_format(GLenum format); - -extern GLboolean -_mesa_is_depth_format(GLenum format); - -extern GLboolean -_mesa_is_stencil_format(GLenum format); - -extern GLboolean -_mesa_is_ycbcr_format(GLenum format); - -extern GLboolean -_mesa_is_depthstencil_format(GLenum format); - -extern GLboolean -_mesa_is_depth_or_stencil_format(GLenum format); - -extern GLboolean -_mesa_is_dudv_format(GLenum format); - -extern GLboolean -_mesa_is_integer_format(GLenum format); - -extern GLboolean -_mesa_is_compressed_format(struct gl_context *ctx, GLenum format); - -extern GLvoid * -_mesa_image_address( GLuint dimensions, - const struct gl_pixelstore_attrib *packing, - const GLvoid *image, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - GLint img, GLint row, GLint column ); - -extern GLvoid * -_mesa_image_address1d( const struct gl_pixelstore_attrib *packing, - const GLvoid *image, - GLsizei width, - GLenum format, GLenum type, - GLint column ); - -extern GLvoid * -_mesa_image_address2d( const struct gl_pixelstore_attrib *packing, - const GLvoid *image, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - GLint row, GLint column ); - -extern GLvoid * -_mesa_image_address3d( const struct gl_pixelstore_attrib *packing, - const GLvoid *image, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - GLint img, GLint row, GLint column ); - - -extern GLint -_mesa_image_row_stride( const struct gl_pixelstore_attrib *packing, - GLint width, GLenum format, GLenum type ); - - -extern GLint -_mesa_image_image_stride( const struct gl_pixelstore_attrib *packing, - GLint width, GLint height, - GLenum format, GLenum type ); - - -extern void -_mesa_expand_bitmap(GLsizei width, GLsizei height, - const struct gl_pixelstore_attrib *unpack, - const GLubyte *bitmap, - GLubyte *destBuffer, GLint destStride, - GLubyte onValue); - - -extern void -_mesa_convert_colors(GLenum srcType, const GLvoid *src, - GLenum dstType, GLvoid *dst, - GLuint count, const GLubyte mask[]); - - -extern GLboolean -_mesa_clip_drawpixels(const struct gl_context *ctx, - GLint *destX, GLint *destY, - GLsizei *width, GLsizei *height, - struct gl_pixelstore_attrib *unpack); - - -extern GLboolean -_mesa_clip_readpixels(const struct gl_context *ctx, - GLint *srcX, GLint *srcY, - GLsizei *width, GLsizei *height, - struct gl_pixelstore_attrib *pack); - -extern GLboolean -_mesa_clip_copytexsubimage(const struct gl_context *ctx, - GLint *destX, GLint *destY, - GLint *srcX, GLint *srcY, - GLsizei *width, GLsizei *height); - -extern GLboolean -_mesa_clip_to_region(GLint xmin, GLint ymin, - GLint xmax, GLint ymax, - GLint *x, GLint *y, - GLsizei *width, GLsizei *height ); - -extern GLboolean -_mesa_clip_blit(struct gl_context *ctx, - GLint *srcX0, GLint *srcY0, GLint *srcX1, GLint *srcY1, - GLint *dstX0, GLint *dstY0, GLint *dstX1, GLint *dstY1); - - -#endif +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * 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 + * BRIAN PAUL 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. + */ + + +#ifndef IMAGE_H +#define IMAGE_H + + +#include "glheader.h" + +struct gl_context; +struct gl_pixelstore_attrib; + +extern void +_mesa_swap2( GLushort *p, GLuint n ); + +extern void +_mesa_swap4( GLuint *p, GLuint n ); + +extern GLboolean +_mesa_type_is_packed(GLenum type); + +extern GLint +_mesa_sizeof_type( GLenum type ); + +extern GLint +_mesa_sizeof_packed_type( GLenum type ); + +extern GLint +_mesa_components_in_format( GLenum format ); + +extern GLint +_mesa_bytes_per_pixel( GLenum format, GLenum type ); + +extern GLboolean +_mesa_is_legal_format_and_type(const struct gl_context *ctx, + GLenum format, GLenum type); + +extern GLboolean +_mesa_is_color_format(GLenum format); + +extern GLboolean +_mesa_is_depth_format(GLenum format); + +extern GLboolean +_mesa_is_stencil_format(GLenum format); + +extern GLboolean +_mesa_is_ycbcr_format(GLenum format); + +extern GLboolean +_mesa_is_depthstencil_format(GLenum format); + +extern GLboolean +_mesa_is_depth_or_stencil_format(GLenum format); + +extern GLboolean +_mesa_is_dudv_format(GLenum format); + +extern GLboolean +_mesa_is_integer_format(GLenum format); + +extern GLboolean +_mesa_is_compressed_format(struct gl_context *ctx, GLenum format); + +extern GLvoid * +_mesa_image_address( GLuint dimensions, + const struct gl_pixelstore_attrib *packing, + const GLvoid *image, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLint img, GLint row, GLint column ); + +extern GLvoid * +_mesa_image_address1d( const struct gl_pixelstore_attrib *packing, + const GLvoid *image, + GLsizei width, + GLenum format, GLenum type, + GLint column ); + +extern GLvoid * +_mesa_image_address2d( const struct gl_pixelstore_attrib *packing, + const GLvoid *image, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLint row, GLint column ); + +extern GLvoid * +_mesa_image_address3d( const struct gl_pixelstore_attrib *packing, + const GLvoid *image, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLint img, GLint row, GLint column ); + + +extern GLint +_mesa_image_row_stride( const struct gl_pixelstore_attrib *packing, + GLint width, GLenum format, GLenum type ); + + +extern GLint +_mesa_image_image_stride( const struct gl_pixelstore_attrib *packing, + GLint width, GLint height, + GLenum format, GLenum type ); + + +extern void +_mesa_expand_bitmap(GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap, + GLubyte *destBuffer, GLint destStride, + GLubyte onValue); + + +extern void +_mesa_convert_colors(GLenum srcType, const GLvoid *src, + GLenum dstType, GLvoid *dst, + GLuint count, const GLubyte mask[]); + + +extern GLboolean +_mesa_clip_drawpixels(const struct gl_context *ctx, + GLint *destX, GLint *destY, + GLsizei *width, GLsizei *height, + struct gl_pixelstore_attrib *unpack); + + +extern GLboolean +_mesa_clip_readpixels(const struct gl_context *ctx, + GLint *srcX, GLint *srcY, + GLsizei *width, GLsizei *height, + struct gl_pixelstore_attrib *pack); + +extern GLboolean +_mesa_clip_copytexsubimage(const struct gl_context *ctx, + GLint *destX, GLint *destY, + GLint *srcX, GLint *srcY, + GLsizei *width, GLsizei *height); + +extern GLboolean +_mesa_clip_to_region(GLint xmin, GLint ymin, + GLint xmax, GLint ymax, + GLint *x, GLint *y, + GLsizei *width, GLsizei *height ); + +extern GLboolean +_mesa_clip_blit(struct gl_context *ctx, + GLint *srcX0, GLint *srcY0, GLint *srcX1, GLint *srcY1, + GLint *dstX0, GLint *dstY0, GLint *dstX1, GLint *dstY1); + + +#endif diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h index ad5979796..ae500b4c2 100644 --- a/mesalib/src/mesa/main/mtypes.h +++ b/mesalib/src/mesa/main/mtypes.h @@ -215,7 +215,9 @@ typedef enum /** - * Indexes for vertex program result attributes + * Indexes for vertex program result attributes. Note that + * _mesa_vert_result_to_frag_attrib() and _mesa_frag_attrib_to_vert_result() make + * assumptions about the layout of this enum. */ typedef enum { @@ -313,7 +315,9 @@ typedef enum /** - * Indexes for fragment program input attributes. + * Indexes for fragment program input attributes. Note that + * _mesa_vert_result_to_frag_attrib() and frag_attrib_to_vert_result() make + * assumptions about the layout of this enum. */ typedef enum { @@ -335,6 +339,48 @@ typedef enum FRAG_ATTRIB_MAX = (FRAG_ATTRIB_VAR0 + MAX_VARYING) } gl_frag_attrib; + +/** + * Convert from a gl_vert_result value to the corresponding gl_frag_attrib. + * + * VERT_RESULT_HPOS is converted to FRAG_ATTRIB_WPOS. + * + * gl_vert_result values which have no corresponding gl_frag_attrib + * (VERT_RESULT_PSIZ, VERT_RESULT_BFC0, VERT_RESULT_BFC1, and + * VERT_RESULT_EDGE) are converted to a value of -1. + */ +static INLINE int +_mesa_vert_result_to_frag_attrib(gl_vert_result vert_result) +{ + if (vert_result >= VERT_RESULT_VAR0) + return vert_result - VERT_RESULT_VAR0 + FRAG_ATTRIB_VAR0; + else if (vert_result <= VERT_RESULT_TEX7) + return vert_result; + else + return -1; +} + + +/** + * Convert from a gl_frag_attrib value to the corresponding gl_vert_result. + * + * FRAG_ATTRIB_WPOS is converted to VERT_RESULT_HPOS. + * + * gl_frag_attrib values which have no corresponding gl_vert_result + * (FRAG_ATTRIB_FACE and FRAG_ATTRIB_PNTC) are converted to a value of -1. + */ +static INLINE int +_mesa_frag_attrib_to_vert_result(gl_frag_attrib frag_attrib) +{ + if (frag_attrib <= FRAG_ATTRIB_TEX7) + return frag_attrib; + else if (frag_attrib >= FRAG_ATTRIB_VAR0) + return frag_attrib - FRAG_ATTRIB_VAR0 + VERT_RESULT_VAR0; + else + return -1; +} + + /** * Bitflags for fragment program input attributes. */ @@ -523,25 +569,6 @@ struct gl_config }; -/** - * Data structure for color tables - */ -struct gl_color_table -{ - GLenum InternalFormat; /**< The user-specified format */ - GLenum _BaseFormat; /**< GL_ALPHA, GL_RGBA, GL_RGB, etc */ - GLuint Size; /**< number of entries in table */ - GLfloat *TableF; /**< Color table, floating point values */ - GLubyte *TableUB; /**< Color table, ubyte values */ - GLubyte RedSize; - GLubyte GreenSize; - GLubyte BlueSize; - GLubyte AlphaSize; - GLubyte LuminanceSize; - GLubyte IntensitySize; -}; - - /** * \name Bit flags used for updating material values. */ @@ -1255,9 +1282,9 @@ struct gl_texture_image GLint InternalFormat; /**< Internal format as given by the user */ GLenum _BaseFormat; /**< Either GL_RGB, GL_RGBA, GL_ALPHA, * GL_LUMINANCE, GL_LUMINANCE_ALPHA, - * GL_INTENSITY, GL_COLOR_INDEX, - * GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT - * only. Used for choosing TexEnv arithmetic. + * GL_INTENSITY, GL_DEPTH_COMPONENT or + * GL_DEPTH_STENCIL_EXT only. Used for + * choosing TexEnv arithmetic. */ gl_format TexFormat; /**< The actual texture memory format */ @@ -1354,8 +1381,7 @@ struct gl_sampler_object /** * Texture object state. Contains the array of mipmap images, border color, - * wrap modes, filter modes, shadow/texcompare state, and the per-texture - * color palette. + * wrap modes, filter modes, and shadow/texcompare state. */ struct gl_texture_object { @@ -1386,9 +1412,6 @@ struct gl_texture_object struct gl_buffer_object *BufferObject; GLenum BufferObjectFormat; - /** GL_EXT_paletted_texture */ - struct gl_color_table Palette; - /** * \name For device driver. * Note: instead of attaching driver data to this pointer, it's preferable @@ -1504,10 +1527,6 @@ struct gl_texture_attrib /** GL_ARB_seamless_cubemap */ GLboolean CubeMapSeamless; - /** GL_EXT_shared_texture_palette */ - GLboolean SharedPalette; - struct gl_color_table Palette; - /** Texture units/samplers used by vertex or fragment texturing */ GLbitfield _EnabledUnits; @@ -2852,7 +2871,6 @@ struct gl_extensions GLboolean EXT_gpu_program_parameters; GLboolean EXT_gpu_shader4; GLboolean EXT_multi_draw_arrays; - GLboolean EXT_paletted_texture; GLboolean EXT_packed_depth_stencil; GLboolean EXT_packed_float; GLboolean EXT_packed_pixels; @@ -2865,7 +2883,6 @@ struct gl_extensions GLboolean EXT_secondary_color; GLboolean EXT_separate_shader_objects; GLboolean EXT_separate_specular_color; - GLboolean EXT_shared_texture_palette; GLboolean EXT_stencil_wrap; GLboolean EXT_stencil_two_side; GLboolean EXT_subtexture; diff --git a/mesalib/src/mesa/main/pack.c b/mesalib/src/mesa/main/pack.c index 7de1d05b9..fd3f89d82 100644 --- a/mesalib/src/mesa/main/pack.c +++ b/mesalib/src/mesa/main/pack.c @@ -3459,8 +3459,7 @@ _mesa_unpack_color_span_chan( struct gl_context *ctx, dstFormat == GL_RED || dstFormat == GL_RG || dstFormat == GL_RGB || - dstFormat == GL_RGBA || - dstFormat == GL_COLOR_INDEX); + dstFormat == GL_RGBA); ASSERT(srcFormat == GL_RED || srcFormat == GL_GREEN || @@ -3646,24 +3645,11 @@ _mesa_unpack_color_span_chan( struct gl_context *ctx, extract_uint_indexes(n, indexes, srcFormat, srcType, source, srcPacking); - if (dstFormat == GL_COLOR_INDEX) { - GLuint i; - _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); - /* convert to GLchan and return */ - for (i = 0; i < n; i++) { - dest[i] = (GLchan) (indexes[i] & 0xff); - } - free(indexes); - free(rgba); - return; - } - else { - /* Convert indexes to RGBA */ - if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { - _mesa_shift_and_offset_ci(ctx, n, indexes); - } - _mesa_map_ci_to_rgba(ctx, n, indexes, rgba); - } + /* Convert indexes to RGBA */ + if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { + _mesa_shift_and_offset_ci(ctx, n, indexes); + } + _mesa_map_ci_to_rgba(ctx, n, indexes, rgba); /* Don't do RGBA scale/bias or RGBA->RGBA mapping if starting * with color indexes. @@ -3773,8 +3759,7 @@ _mesa_unpack_color_span_float( struct gl_context *ctx, dstFormat == GL_RED || dstFormat == GL_RG || dstFormat == GL_RGB || - dstFormat == GL_RGBA || - dstFormat == GL_COLOR_INDEX); + dstFormat == GL_RGBA); ASSERT(srcFormat == GL_RED || srcFormat == GL_GREEN || @@ -3855,24 +3840,11 @@ _mesa_unpack_color_span_float( struct gl_context *ctx, extract_uint_indexes(n, indexes, srcFormat, srcType, source, srcPacking); - if (dstFormat == GL_COLOR_INDEX) { - GLuint i; - _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); - /* convert to GLchan and return */ - for (i = 0; i < n; i++) { - dest[i] = (GLchan) (indexes[i] & 0xff); - } - free(indexes); - free(rgba); - return; - } - else { - /* Convert indexes to RGBA */ - if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { - _mesa_shift_and_offset_ci(ctx, n, indexes); - } - _mesa_map_ci_to_rgba(ctx, n, indexes, rgba); - } + /* Convert indexes to RGBA */ + if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { + _mesa_shift_and_offset_ci(ctx, n, indexes); + } + _mesa_map_ci_to_rgba(ctx, n, indexes, rgba); /* Don't do RGBA scale/bias or RGBA->RGBA mapping if starting * with color indexes. diff --git a/mesalib/src/mesa/main/pixeltransfer.c b/mesalib/src/mesa/main/pixeltransfer.c index 092ee3a14..5e881436a 100644 --- a/mesalib/src/mesa/main/pixeltransfer.c +++ b/mesalib/src/mesa/main/pixeltransfer.c @@ -1,567 +1,306 @@ -/* - * Mesa 3-D graphics library - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009-2010 VMware, Inc. 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 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 pixeltransfer.c - * Pixel transfer operations (scale, bias, table lookups, etc) - */ - - -#include "glheader.h" -#include "colormac.h" -#include "pixeltransfer.h" -#include "imports.h" -#include "mtypes.h" - - -/* - * Apply scale and bias factors to an array of RGBA pixels. - */ -void -_mesa_scale_and_bias_rgba(GLuint n, GLfloat rgba[][4], - GLfloat rScale, GLfloat gScale, - GLfloat bScale, GLfloat aScale, - GLfloat rBias, GLfloat gBias, - GLfloat bBias, GLfloat aBias) -{ - if (rScale != 1.0 || rBias != 0.0) { - GLuint i; - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = rgba[i][RCOMP] * rScale + rBias; - } - } - if (gScale != 1.0 || gBias != 0.0) { - GLuint i; - for (i = 0; i < n; i++) { - rgba[i][GCOMP] = rgba[i][GCOMP] * gScale + gBias; - } - } - if (bScale != 1.0 || bBias != 0.0) { - GLuint i; - for (i = 0; i < n; i++) { - rgba[i][BCOMP] = rgba[i][BCOMP] * bScale + bBias; - } - } - if (aScale != 1.0 || aBias != 0.0) { - GLuint i; - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = rgba[i][ACOMP] * aScale + aBias; - } - } -} - - -/* - * Apply pixel mapping to an array of floating point RGBA pixels. - */ -void -_mesa_map_rgba( const struct gl_context *ctx, GLuint n, GLfloat rgba[][4] ) -{ - const GLfloat rscale = (GLfloat) (ctx->PixelMaps.RtoR.Size - 1); - const GLfloat gscale = (GLfloat) (ctx->PixelMaps.GtoG.Size - 1); - const GLfloat bscale = (GLfloat) (ctx->PixelMaps.BtoB.Size - 1); - const GLfloat ascale = (GLfloat) (ctx->PixelMaps.AtoA.Size - 1); - const GLfloat *rMap = ctx->PixelMaps.RtoR.Map; - const GLfloat *gMap = ctx->PixelMaps.GtoG.Map; - const GLfloat *bMap = ctx->PixelMaps.BtoB.Map; - const GLfloat *aMap = ctx->PixelMaps.AtoA.Map; - GLuint i; - for (i=0;iSize - 1; - const GLfloat scale = (GLfloat) max; - const GLfloat *lut = table->TableF; - GLuint i; - - if (!table->TableF || table->Size == 0) - return; - - switch (table->_BaseFormat) { - case GL_INTENSITY: - /* replace RGBA with I */ - for (i = 0; i < n; i++) { - GLint j = IROUND(rgba[i][RCOMP] * scale); - GLfloat c = lut[CLAMP(j, 0, max)]; - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = - rgba[i][ACOMP] = c; - } - break; - case GL_LUMINANCE: - /* replace RGB with L */ - for (i = 0; i < n; i++) { - GLint j = IROUND(rgba[i][RCOMP] * scale); - GLfloat c = lut[CLAMP(j, 0, max)]; - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = c; - } - break; - case GL_ALPHA: - /* replace A with A */ - for (i = 0; i < n; i++) { - GLint j = IROUND(rgba[i][ACOMP] * scale); - rgba[i][ACOMP] = lut[CLAMP(j, 0, max)]; - } - break; - case GL_LUMINANCE_ALPHA: - /* replace RGBA with LLLA */ - for (i = 0; i < n; i++) { - GLint jL = IROUND(rgba[i][RCOMP] * scale); - GLint jA = IROUND(rgba[i][ACOMP] * scale); - GLfloat luminance, alpha; - jL = CLAMP(jL, 0, max); - jA = CLAMP(jA, 0, max); - luminance = lut[jL * 2 + 0]; - alpha = lut[jA * 2 + 1]; - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = luminance; - rgba[i][ACOMP] = alpha;; - } - break; - case GL_RED: - /* replace RGB with RGB */ - for (i = 0; i < n; i++) { - GLint jR = IROUND(rgba[i][RCOMP] * scale); - jR = CLAMP(jR, 0, max); - rgba[i][RCOMP] = lut[jR * 3 + 0]; - } - break; - case GL_RG: - /* replace RG with RG */ - for (i = 0; i < n; i++) { - GLint jR = IROUND(rgba[i][RCOMP] * scale); - GLint jG = IROUND(rgba[i][GCOMP] * scale); - jR = CLAMP(jR, 0, max); - jG = CLAMP(jG, 0, max); - rgba[i][RCOMP] = lut[jR * 3 + 0]; - rgba[i][GCOMP] = lut[jG * 3 + 1]; - } - break; - case GL_RGB: - /* replace RGB with RGB */ - for (i = 0; i < n; i++) { - GLint jR = IROUND(rgba[i][RCOMP] * scale); - GLint jG = IROUND(rgba[i][GCOMP] * scale); - GLint jB = IROUND(rgba[i][BCOMP] * scale); - jR = CLAMP(jR, 0, max); - jG = CLAMP(jG, 0, max); - jB = CLAMP(jB, 0, max); - rgba[i][RCOMP] = lut[jR * 3 + 0]; - rgba[i][GCOMP] = lut[jG * 3 + 1]; - rgba[i][BCOMP] = lut[jB * 3 + 2]; - } - break; - case GL_RGBA: - /* replace RGBA with RGBA */ - for (i = 0; i < n; i++) { - GLint jR = IROUND(rgba[i][RCOMP] * scale); - GLint jG = IROUND(rgba[i][GCOMP] * scale); - GLint jB = IROUND(rgba[i][BCOMP] * scale); - GLint jA = IROUND(rgba[i][ACOMP] * scale); - jR = CLAMP(jR, 0, max); - jG = CLAMP(jG, 0, max); - jB = CLAMP(jB, 0, max); - jA = CLAMP(jA, 0, max); - rgba[i][RCOMP] = lut[jR * 4 + 0]; - rgba[i][GCOMP] = lut[jG * 4 + 1]; - rgba[i][BCOMP] = lut[jB * 4 + 2]; - rgba[i][ACOMP] = lut[jA * 4 + 3]; - } - break; - default: - _mesa_problem(NULL, "Bad format in _mesa_lookup_rgba_float"); - return; - } -} - - - -/** - * Apply a color table lookup to an array of ubyte/RGBA colors. - */ -void -_mesa_lookup_rgba_ubyte(const struct gl_color_table *table, - GLuint n, GLubyte rgba[][4]) -{ - const GLubyte *lut = table->TableUB; - const GLfloat scale = (GLfloat) (table->Size - 1) / (GLfloat)255.0; - GLuint i; - - if (!table->TableUB || table->Size == 0) - return; - - switch (table->_BaseFormat) { - case GL_INTENSITY: - /* replace RGBA with I */ - if (table->Size == 256) { - for (i = 0; i < n; i++) { - const GLubyte c = lut[rgba[i][RCOMP]]; - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = - rgba[i][ACOMP] = c; - } - } - else { - for (i = 0; i < n; i++) { - GLint j = IROUND((GLfloat) rgba[i][RCOMP] * scale); - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = - rgba[i][ACOMP] = lut[j]; - } - } - break; - case GL_LUMINANCE: - /* replace RGB with L */ - if (table->Size == 256) { - for (i = 0; i < n; i++) { - const GLubyte c = lut[rgba[i][RCOMP]]; - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = c; - } - } - else { - for (i = 0; i < n; i++) { - GLint j = IROUND((GLfloat) rgba[i][RCOMP] * scale); - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = lut[j]; - } - } - break; - case GL_ALPHA: - /* replace A with A */ - if (table->Size == 256) { - for (i = 0; i < n; i++) { - rgba[i][ACOMP] = lut[rgba[i][ACOMP]]; - } - } - else { - for (i = 0; i < n; i++) { - GLint j = IROUND((GLfloat) rgba[i][ACOMP] * scale); - rgba[i][ACOMP] = lut[j]; - } - } - break; - case GL_LUMINANCE_ALPHA: - /* replace RGBA with LLLA */ - if (table->Size == 256) { - for (i = 0; i < n; i++) { - GLubyte l = lut[rgba[i][RCOMP] * 2 + 0]; - GLubyte a = lut[rgba[i][ACOMP] * 2 + 1];; - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = l; - rgba[i][ACOMP] = a; - } - } - else { - for (i = 0; i < n; i++) { - GLint jL = IROUND((GLfloat) rgba[i][RCOMP] * scale); - GLint jA = IROUND((GLfloat) rgba[i][ACOMP] * scale); - GLubyte luminance = lut[jL * 2 + 0]; - GLubyte alpha = lut[jA * 2 + 1]; - rgba[i][RCOMP] = - rgba[i][GCOMP] = - rgba[i][BCOMP] = luminance; - rgba[i][ACOMP] = alpha; - } - } - break; - case GL_RGB: - if (table->Size == 256) { - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = lut[rgba[i][RCOMP] * 3 + 0]; - rgba[i][GCOMP] = lut[rgba[i][GCOMP] * 3 + 1]; - rgba[i][BCOMP] = lut[rgba[i][BCOMP] * 3 + 2]; - } - } - else { - for (i = 0; i < n; i++) { - GLint jR = IROUND((GLfloat) rgba[i][RCOMP] * scale); - GLint jG = IROUND((GLfloat) rgba[i][GCOMP] * scale); - GLint jB = IROUND((GLfloat) rgba[i][BCOMP] * scale); - rgba[i][RCOMP] = lut[jR * 3 + 0]; - rgba[i][GCOMP] = lut[jG * 3 + 1]; - rgba[i][BCOMP] = lut[jB * 3 + 2]; - } - } - break; - case GL_RGBA: - if (table->Size == 256) { - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = lut[rgba[i][RCOMP] * 4 + 0]; - rgba[i][GCOMP] = lut[rgba[i][GCOMP] * 4 + 1]; - rgba[i][BCOMP] = lut[rgba[i][BCOMP] * 4 + 2]; - rgba[i][ACOMP] = lut[rgba[i][ACOMP] * 4 + 3]; - } - } - else { - for (i = 0; i < n; i++) { - GLint jR = IROUND((GLfloat) rgba[i][RCOMP] * scale); - GLint jG = IROUND((GLfloat) rgba[i][GCOMP] * scale); - GLint jB = IROUND((GLfloat) rgba[i][BCOMP] * scale); - GLint jA = IROUND((GLfloat) rgba[i][ACOMP] * scale); - CLAMPED_FLOAT_TO_CHAN(rgba[i][RCOMP], lut[jR * 4 + 0]); - CLAMPED_FLOAT_TO_CHAN(rgba[i][GCOMP], lut[jG * 4 + 1]); - CLAMPED_FLOAT_TO_CHAN(rgba[i][BCOMP], lut[jB * 4 + 2]); - CLAMPED_FLOAT_TO_CHAN(rgba[i][ACOMP], lut[jA * 4 + 3]); - } - } - break; - default: - _mesa_problem(NULL, "Bad format in _mesa_lookup_rgba_chan"); - return; - } -} - - - -/* - * Map color indexes to float rgba values. - */ -void -_mesa_map_ci_to_rgba( const struct gl_context *ctx, GLuint n, - const GLuint index[], GLfloat rgba[][4] ) -{ - GLuint rmask = ctx->PixelMaps.ItoR.Size - 1; - GLuint gmask = ctx->PixelMaps.ItoG.Size - 1; - GLuint bmask = ctx->PixelMaps.ItoB.Size - 1; - GLuint amask = ctx->PixelMaps.ItoA.Size - 1; - const GLfloat *rMap = ctx->PixelMaps.ItoR.Map; - const GLfloat *gMap = ctx->PixelMaps.ItoG.Map; - const GLfloat *bMap = ctx->PixelMaps.ItoB.Map; - const GLfloat *aMap = ctx->PixelMaps.ItoA.Map; - GLuint i; - for (i=0;iPixelMaps.ItoR.Size - 1; - GLuint gmask = ctx->PixelMaps.ItoG.Size - 1; - GLuint bmask = ctx->PixelMaps.ItoB.Size - 1; - GLuint amask = ctx->PixelMaps.ItoA.Size - 1; - const GLubyte *rMap = ctx->PixelMaps.ItoR.Map8; - const GLubyte *gMap = ctx->PixelMaps.ItoG.Map8; - const GLubyte *bMap = ctx->PixelMaps.ItoB.Map8; - const GLubyte *aMap = ctx->PixelMaps.ItoA.Map8; - GLuint i; - for (i=0;iPixel.DepthScale; - const GLfloat bias = ctx->Pixel.DepthBias; - GLuint i; - for (i = 0; i < n; i++) { - GLfloat d = depthValues[i] * scale + bias; - depthValues[i] = CLAMP(d, 0.0F, 1.0F); - } -} - - -void -_mesa_scale_and_bias_depth_uint(const struct gl_context *ctx, GLuint n, - GLuint depthValues[]) -{ - const GLdouble max = (double) 0xffffffff; - const GLdouble scale = ctx->Pixel.DepthScale; - const GLdouble bias = ctx->Pixel.DepthBias * max; - GLuint i; - for (i = 0; i < n; i++) { - GLdouble d = (GLdouble) depthValues[i] * scale + bias; - d = CLAMP(d, 0.0, max); - depthValues[i] = (GLuint) d; - } -} - -/** - * Apply various pixel transfer operations to an array of RGBA pixels - * as indicated by the transferOps bitmask - */ -void -_mesa_apply_rgba_transfer_ops(struct gl_context *ctx, GLbitfield transferOps, - GLuint n, GLfloat rgba[][4]) -{ - /* scale & bias */ - if (transferOps & IMAGE_SCALE_BIAS_BIT) { - _mesa_scale_and_bias_rgba(n, rgba, - ctx->Pixel.RedScale, ctx->Pixel.GreenScale, - ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale, - ctx->Pixel.RedBias, ctx->Pixel.GreenBias, - ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias); - } - /* color map lookup */ - if (transferOps & IMAGE_MAP_COLOR_BIT) { - _mesa_map_rgba( ctx, n, rgba ); - } - - /* clamping to [0,1] */ - if (transferOps & IMAGE_CLAMP_BIT) { - GLuint i; - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], 0.0F, 1.0F); - rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], 0.0F, 1.0F); - rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], 0.0F, 1.0F); - rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], 0.0F, 1.0F); - } - } -} - - -/* - * Apply color index shift and offset to an array of pixels. - */ -void -_mesa_shift_and_offset_ci(const struct gl_context *ctx, - GLuint n, GLuint indexes[]) -{ - GLint shift = ctx->Pixel.IndexShift; - GLint offset = ctx->Pixel.IndexOffset; - GLuint i; - if (shift > 0) { - for (i=0;i> shift) + offset; - } - } - else { - for (i=0;iPixelMaps.ItoI.Size - 1; - GLuint i; - for (i = 0; i < n; i++) { - const GLuint j = indexes[i] & mask; - indexes[i] = IROUND(ctx->PixelMaps.ItoI.Map[j]); - } - } -} - - -/** - * Apply stencil index shift, offset and table lookup to an array - * of stencil values. - */ -void -_mesa_apply_stencil_transfer_ops(const struct gl_context *ctx, GLuint n, - GLstencil stencil[]) -{ - if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) { - const GLint offset = ctx->Pixel.IndexOffset; - GLint shift = ctx->Pixel.IndexShift; - GLuint i; - if (shift > 0) { - for (i = 0; i < n; i++) { - stencil[i] = (stencil[i] << shift) + offset; - } - } - else if (shift < 0) { - shift = -shift; - for (i = 0; i < n; i++) { - stencil[i] = (stencil[i] >> shift) + offset; - } - } - else { - for (i = 0; i < n; i++) { - stencil[i] = stencil[i] + offset; - } - } - } - if (ctx->Pixel.MapStencilFlag) { - GLuint mask = ctx->PixelMaps.StoS.Size - 1; - GLuint i; - for (i = 0; i < n; i++) { - stencil[i] = (GLstencil)ctx->PixelMaps.StoS.Map[ stencil[i] & mask ]; - } - } -} +/* + * Mesa 3-D graphics library + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009-2010 VMware, Inc. 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 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 pixeltransfer.c + * Pixel transfer operations (scale, bias, table lookups, etc) + */ + + +#include "glheader.h" +#include "colormac.h" +#include "pixeltransfer.h" +#include "imports.h" +#include "mtypes.h" + + +/* + * Apply scale and bias factors to an array of RGBA pixels. + */ +void +_mesa_scale_and_bias_rgba(GLuint n, GLfloat rgba[][4], + GLfloat rScale, GLfloat gScale, + GLfloat bScale, GLfloat aScale, + GLfloat rBias, GLfloat gBias, + GLfloat bBias, GLfloat aBias) +{ + if (rScale != 1.0 || rBias != 0.0) { + GLuint i; + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = rgba[i][RCOMP] * rScale + rBias; + } + } + if (gScale != 1.0 || gBias != 0.0) { + GLuint i; + for (i = 0; i < n; i++) { + rgba[i][GCOMP] = rgba[i][GCOMP] * gScale + gBias; + } + } + if (bScale != 1.0 || bBias != 0.0) { + GLuint i; + for (i = 0; i < n; i++) { + rgba[i][BCOMP] = rgba[i][BCOMP] * bScale + bBias; + } + } + if (aScale != 1.0 || aBias != 0.0) { + GLuint i; + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = rgba[i][ACOMP] * aScale + aBias; + } + } +} + + +/* + * Apply pixel mapping to an array of floating point RGBA pixels. + */ +void +_mesa_map_rgba( const struct gl_context *ctx, GLuint n, GLfloat rgba[][4] ) +{ + const GLfloat rscale = (GLfloat) (ctx->PixelMaps.RtoR.Size - 1); + const GLfloat gscale = (GLfloat) (ctx->PixelMaps.GtoG.Size - 1); + const GLfloat bscale = (GLfloat) (ctx->PixelMaps.BtoB.Size - 1); + const GLfloat ascale = (GLfloat) (ctx->PixelMaps.AtoA.Size - 1); + const GLfloat *rMap = ctx->PixelMaps.RtoR.Map; + const GLfloat *gMap = ctx->PixelMaps.GtoG.Map; + const GLfloat *bMap = ctx->PixelMaps.BtoB.Map; + const GLfloat *aMap = ctx->PixelMaps.AtoA.Map; + GLuint i; + for (i=0;iPixelMaps.ItoR.Size - 1; + GLuint gmask = ctx->PixelMaps.ItoG.Size - 1; + GLuint bmask = ctx->PixelMaps.ItoB.Size - 1; + GLuint amask = ctx->PixelMaps.ItoA.Size - 1; + const GLfloat *rMap = ctx->PixelMaps.ItoR.Map; + const GLfloat *gMap = ctx->PixelMaps.ItoG.Map; + const GLfloat *bMap = ctx->PixelMaps.ItoB.Map; + const GLfloat *aMap = ctx->PixelMaps.ItoA.Map; + GLuint i; + for (i=0;iPixelMaps.ItoR.Size - 1; + GLuint gmask = ctx->PixelMaps.ItoG.Size - 1; + GLuint bmask = ctx->PixelMaps.ItoB.Size - 1; + GLuint amask = ctx->PixelMaps.ItoA.Size - 1; + const GLubyte *rMap = ctx->PixelMaps.ItoR.Map8; + const GLubyte *gMap = ctx->PixelMaps.ItoG.Map8; + const GLubyte *bMap = ctx->PixelMaps.ItoB.Map8; + const GLubyte *aMap = ctx->PixelMaps.ItoA.Map8; + GLuint i; + for (i=0;iPixel.DepthScale; + const GLfloat bias = ctx->Pixel.DepthBias; + GLuint i; + for (i = 0; i < n; i++) { + GLfloat d = depthValues[i] * scale + bias; + depthValues[i] = CLAMP(d, 0.0F, 1.0F); + } +} + + +void +_mesa_scale_and_bias_depth_uint(const struct gl_context *ctx, GLuint n, + GLuint depthValues[]) +{ + const GLdouble max = (double) 0xffffffff; + const GLdouble scale = ctx->Pixel.DepthScale; + const GLdouble bias = ctx->Pixel.DepthBias * max; + GLuint i; + for (i = 0; i < n; i++) { + GLdouble d = (GLdouble) depthValues[i] * scale + bias; + d = CLAMP(d, 0.0, max); + depthValues[i] = (GLuint) d; + } +} + +/** + * Apply various pixel transfer operations to an array of RGBA pixels + * as indicated by the transferOps bitmask + */ +void +_mesa_apply_rgba_transfer_ops(struct gl_context *ctx, GLbitfield transferOps, + GLuint n, GLfloat rgba[][4]) +{ + /* scale & bias */ + if (transferOps & IMAGE_SCALE_BIAS_BIT) { + _mesa_scale_and_bias_rgba(n, rgba, + ctx->Pixel.RedScale, ctx->Pixel.GreenScale, + ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale, + ctx->Pixel.RedBias, ctx->Pixel.GreenBias, + ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias); + } + /* color map lookup */ + if (transferOps & IMAGE_MAP_COLOR_BIT) { + _mesa_map_rgba( ctx, n, rgba ); + } + + /* clamping to [0,1] */ + if (transferOps & IMAGE_CLAMP_BIT) { + GLuint i; + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], 0.0F, 1.0F); + rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], 0.0F, 1.0F); + rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], 0.0F, 1.0F); + rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], 0.0F, 1.0F); + } + } +} + + +/* + * Apply color index shift and offset to an array of pixels. + */ +void +_mesa_shift_and_offset_ci(const struct gl_context *ctx, + GLuint n, GLuint indexes[]) +{ + GLint shift = ctx->Pixel.IndexShift; + GLint offset = ctx->Pixel.IndexOffset; + GLuint i; + if (shift > 0) { + for (i=0;i> shift) + offset; + } + } + else { + for (i=0;iPixelMaps.ItoI.Size - 1; + GLuint i; + for (i = 0; i < n; i++) { + const GLuint j = indexes[i] & mask; + indexes[i] = IROUND(ctx->PixelMaps.ItoI.Map[j]); + } + } +} + + +/** + * Apply stencil index shift, offset and table lookup to an array + * of stencil values. + */ +void +_mesa_apply_stencil_transfer_ops(const struct gl_context *ctx, GLuint n, + GLstencil stencil[]) +{ + if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) { + const GLint offset = ctx->Pixel.IndexOffset; + GLint shift = ctx->Pixel.IndexShift; + GLuint i; + if (shift > 0) { + for (i = 0; i < n; i++) { + stencil[i] = (stencil[i] << shift) + offset; + } + } + else if (shift < 0) { + shift = -shift; + for (i = 0; i < n; i++) { + stencil[i] = (stencil[i] >> shift) + offset; + } + } + else { + for (i = 0; i < n; i++) { + stencil[i] = stencil[i] + offset; + } + } + } + if (ctx->Pixel.MapStencilFlag) { + GLuint mask = ctx->PixelMaps.StoS.Size - 1; + GLuint i; + for (i = 0; i < n; i++) { + stencil[i] = (GLstencil)ctx->PixelMaps.StoS.Map[ stencil[i] & mask ]; + } + } +} diff --git a/mesalib/src/mesa/main/pixeltransfer.h b/mesalib/src/mesa/main/pixeltransfer.h index c00da3f2a..8af2e9ee2 100644 --- a/mesalib/src/mesa/main/pixeltransfer.h +++ b/mesalib/src/mesa/main/pixeltransfer.h @@ -1,90 +1,81 @@ -/* - * Mesa 3-D graphics library - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009-2010 VMware, Inc. 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 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. - */ - - -#ifndef PIXELTRANSFER_H -#define PIXELTRANSFER_H - - -#include "mtypes.h" - - -extern void -_mesa_scale_and_bias_rgba(GLuint n, GLfloat rgba[][4], - GLfloat rScale, GLfloat gScale, - GLfloat bScale, GLfloat aScale, - GLfloat rBias, GLfloat gBias, - GLfloat bBias, GLfloat aBias); - -extern void -_mesa_map_rgba(const struct gl_context *ctx, GLuint n, GLfloat rgba[][4]); - -extern void -_mesa_lookup_rgba_float(const struct gl_color_table *table, - GLuint n, GLfloat rgba[][4]); - -extern void -_mesa_lookup_rgba_ubyte(const struct gl_color_table *table, - GLuint n, GLubyte rgba[][4]); - - -extern void -_mesa_map_ci_to_rgba(const struct gl_context *ctx, - GLuint n, const GLuint index[], GLfloat rgba[][4]); - - -extern void -_mesa_map_ci8_to_rgba8(const struct gl_context *ctx, - GLuint n, const GLubyte index[], - GLubyte rgba[][4]); - - -extern void -_mesa_scale_and_bias_depth(const struct gl_context *ctx, GLuint n, - GLfloat depthValues[]); - -extern void -_mesa_scale_and_bias_depth_uint(const struct gl_context *ctx, GLuint n, - GLuint depthValues[]); - -extern void -_mesa_apply_rgba_transfer_ops(struct gl_context *ctx, GLbitfield transferOps, - GLuint n, GLfloat rgba[][4]); - -extern void -_mesa_shift_and_offset_ci(const struct gl_context *ctx, - GLuint n, GLuint indexes[]); - -extern void -_mesa_apply_ci_transfer_ops(const struct gl_context *ctx, - GLbitfield transferOps, - GLuint n, GLuint indexes[]); - - -extern void -_mesa_apply_stencil_transfer_ops(const struct gl_context *ctx, GLuint n, - GLstencil stencil[]); - - -#endif +/* + * Mesa 3-D graphics library + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009-2010 VMware, Inc. 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 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. + */ + + +#ifndef PIXELTRANSFER_H +#define PIXELTRANSFER_H + + +#include "mtypes.h" + + +extern void +_mesa_scale_and_bias_rgba(GLuint n, GLfloat rgba[][4], + GLfloat rScale, GLfloat gScale, + GLfloat bScale, GLfloat aScale, + GLfloat rBias, GLfloat gBias, + GLfloat bBias, GLfloat aBias); + +extern void +_mesa_map_rgba(const struct gl_context *ctx, GLuint n, GLfloat rgba[][4]); + +extern void +_mesa_map_ci_to_rgba(const struct gl_context *ctx, + GLuint n, const GLuint index[], GLfloat rgba[][4]); + + +extern void +_mesa_map_ci8_to_rgba8(const struct gl_context *ctx, + GLuint n, const GLubyte index[], + GLubyte rgba[][4]); + + +extern void +_mesa_scale_and_bias_depth(const struct gl_context *ctx, GLuint n, + GLfloat depthValues[]); + +extern void +_mesa_scale_and_bias_depth_uint(const struct gl_context *ctx, GLuint n, + GLuint depthValues[]); + +extern void +_mesa_apply_rgba_transfer_ops(struct gl_context *ctx, GLbitfield transferOps, + GLuint n, GLfloat rgba[][4]); + +extern void +_mesa_shift_and_offset_ci(const struct gl_context *ctx, + GLuint n, GLuint indexes[]); + +extern void +_mesa_apply_ci_transfer_ops(const struct gl_context *ctx, + GLbitfield transferOps, + GLuint n, GLuint indexes[]); + + +extern void +_mesa_apply_stencil_transfer_ops(const struct gl_context *ctx, GLuint n, + GLstencil stencil[]); + + +#endif diff --git a/mesalib/src/mesa/main/texformat.c b/mesalib/src/mesa/main/texformat.c index 075c40c86..4f02720ce 100644 --- a/mesalib/src/mesa/main/texformat.c +++ b/mesalib/src/mesa/main/texformat.c @@ -197,13 +197,6 @@ _mesa_choose_tex_format( struct gl_context *ctx, GLint internalFormat, RETURN_IF_SUPPORTED(MESA_FORMAT_I8); break; - case GL_COLOR_INDEX: - case GL_COLOR_INDEX1_EXT: - case GL_COLOR_INDEX2_EXT: - case GL_COLOR_INDEX4_EXT: - case GL_COLOR_INDEX12_EXT: - case GL_COLOR_INDEX16_EXT: - case GL_COLOR_INDEX8_EXT: default: ; /* fallthrough */ } diff --git a/mesalib/src/mesa/main/texgetimage.c b/mesalib/src/mesa/main/texgetimage.c index b2ebb0de4..99ace91a9 100644 --- a/mesalib/src/mesa/main/texgetimage.c +++ b/mesalib/src/mesa/main/texgetimage.c @@ -64,55 +64,6 @@ type_with_negative_values(GLenum type) } -/** - * glGetTexImage for color index pixels. - */ -static void -get_tex_color_index(struct gl_context *ctx, GLuint dimensions, - GLenum format, GLenum type, GLvoid *pixels, - const struct gl_texture_image *texImage) -{ - const GLint width = texImage->Width; - const GLint height = texImage->Height; - const GLint depth = texImage->Depth; - const GLint rowstride = texImage->RowStride; - const GLuint indexBits = - _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT); - const GLbitfield transferOps = 0x0; - GLint img, row, col; - - for (img = 0; img < depth; img++) { - for (row = 0; row < height; row++) { - GLuint indexRow[MAX_WIDTH] = { 0 }; - void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, - width, height, format, type, - img, row, 0); - assert(dest); - - if (indexBits == 8) { - const GLubyte *src = (const GLubyte *) texImage->Data; - src += rowstride * (img * height + row); - for (col = 0; col < width; col++) { - indexRow[col] = src[col]; - } - } - else if (indexBits == 16) { - const GLushort *src = (const GLushort *) texImage->Data; - src += rowstride * (img * height + row); - for (col = 0; col < width; col++) { - indexRow[col] = src[col]; - } - } - else { - _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage"); - } - _mesa_pack_index_span(ctx, width, type, dest, - indexRow, &ctx->Pack, transferOps); - } - } -} - - /** * glGetTexImage for depth/Z pixels. */ @@ -457,9 +408,6 @@ _mesa_get_teximage(struct gl_context *ctx, GLenum target, GLint level, if (get_tex_memcpy(ctx, format, type, pixels, texObj, texImage)) { /* all done */ } - else if (format == GL_COLOR_INDEX) { - get_tex_color_index(ctx, dimensions, format, type, pixels, texImage); - } else if (format == GL_DEPTH_COMPONENT) { get_tex_depth(ctx, dimensions, format, type, pixels, texImage); } @@ -567,16 +515,12 @@ getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, } if (_mesa_components_in_format(format) <= 0 || - format == GL_STENCIL_INDEX) { + format == GL_STENCIL_INDEX || + format == GL_COLOR_INDEX) { _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" ); return GL_TRUE; } - if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); - return GL_TRUE; - } - if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return GL_TRUE; @@ -615,17 +559,10 @@ getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, baseFormat = _mesa_get_format_base_format(texImage->TexFormat); /* Make sure the requested image format is compatible with the - * texture's format. Note that a color index texture can be converted - * to RGBA so that combo is allowed. + * texture's format. */ if (_mesa_is_color_format(format) - && !_mesa_is_color_format(baseFormat) - && !_mesa_is_index_format(baseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return GL_TRUE; - } - else if (_mesa_is_index_format(format) - && !_mesa_is_index_format(baseFormat)) { + && !_mesa_is_color_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } diff --git a/mesalib/src/mesa/main/teximage.c b/mesalib/src/mesa/main/teximage.c index 886e52114..cb4a5b4e4 100644 --- a/mesalib/src/mesa/main/teximage.c +++ b/mesalib/src/mesa/main/teximage.c @@ -159,21 +159,6 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) } } - if (ctx->Extensions.EXT_paletted_texture) { - switch (internalFormat) { - case GL_COLOR_INDEX: - case GL_COLOR_INDEX1_EXT: - case GL_COLOR_INDEX2_EXT: - case GL_COLOR_INDEX4_EXT: - case GL_COLOR_INDEX8_EXT: - case GL_COLOR_INDEX12_EXT: - case GL_COLOR_INDEX16_EXT: - return GL_COLOR_INDEX; - default: - ; /* fallthrough */ - } - } - if (ctx->Extensions.ARB_depth_texture) { switch (internalFormat) { case GL_DEPTH_COMPONENT: @@ -1554,7 +1539,13 @@ texture_error_check( struct gl_context *ctx, const GLenum proxyTarget = get_proxy_target(target); const GLboolean isProxy = target == proxyTarget; GLboolean sizeOK = GL_TRUE; - GLboolean colorFormat, indexFormat; + GLboolean colorFormat; + + /* Even though there are no color-index textures, we still have to support + * uploading color-index data and remapping it to RGB via the + * GL_PIXEL_MAP_I_TO_[RGBA] tables. + */ + const GLboolean indexFormat = (format == GL_COLOR_INDEX); /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */ if (level < 0 || level >= MAX_TEXTURE_LEVELS) { @@ -1635,9 +1626,7 @@ texture_error_check( struct gl_context *ctx, /* make sure internal format and format basically agree */ colorFormat = _mesa_is_color_format(format); - indexFormat = _mesa_is_index_format(format); if ((_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat) || - (_mesa_is_index_format(internalFormat) && !indexFormat) || (_mesa_is_depth_format(internalFormat) != _mesa_is_depth_format(format)) || (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format)) || (_mesa_is_depthstencil_format(internalFormat) != _mesa_is_depthstencil_format(format)) || diff --git a/mesalib/src/mesa/main/texobj.c b/mesalib/src/mesa/main/texobj.c index 078a43ab1..1168f1842 100644 --- a/mesalib/src/mesa/main/texobj.c +++ b/mesalib/src/mesa/main/texobj.c @@ -198,8 +198,6 @@ _mesa_delete_texture_object(struct gl_context *ctx, */ texObj->Target = 0x99; - _mesa_free_colortable_data(&texObj->Palette); - /* free the texture images */ for (face = 0; face < 6; face++) { for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { @@ -258,7 +256,6 @@ _mesa_copy_texture_object( struct gl_texture_object *dest, dest->_MaxLevel = src->_MaxLevel; dest->_MaxLambda = src->_MaxLambda; dest->GenerateMipmap = src->GenerateMipmap; - dest->Palette = src->Palette; dest->_Complete = src->_Complete; COPY_4V(dest->Swizzle, src->Swizzle); dest->_Swizzle = src->_Swizzle; diff --git a/mesalib/src/mesa/main/texparam.c b/mesalib/src/mesa/main/texparam.c index bbbb306b2..19a01a14d 100644 --- a/mesalib/src/mesa/main/texparam.c +++ b/mesalib/src/mesa/main/texparam.c @@ -987,12 +987,6 @@ _mesa_GetTexLevelParameteriv( GLenum target, GLint level, } } break; - case GL_TEXTURE_INDEX_SIZE_EXT: - if (img->_BaseFormat == GL_COLOR_INDEX) - *params = _mesa_get_format_bits(texFormat, pname); - else - *params = 0; - break; case GL_TEXTURE_DEPTH_SIZE_ARB: if (!ctx->Extensions.ARB_depth_texture) goto invalid_pname; diff --git a/mesalib/src/mesa/main/texstate.c b/mesalib/src/mesa/main/texstate.c index 1810b88b2..e02f16240 100644 --- a/mesalib/src/mesa/main/texstate.c +++ b/mesalib/src/mesa/main/texstate.c @@ -75,7 +75,6 @@ _mesa_copy_texture_state( const struct gl_context *src, struct gl_context *dst ) dst->Texture._GenFlags = src->Texture._GenFlags; dst->Texture._TexGenEnabled = src->Texture._TexGenEnabled; dst->Texture._TexMatEnabled = src->Texture._TexMatEnabled; - dst->Texture.SharedPalette = src->Texture.SharedPalette; /* per-unit state */ for (u = 0; u < src->Const.MaxCombinedTextureImageUnits; u++) { @@ -402,11 +401,8 @@ update_tex_combine(struct gl_context *ctx, struct gl_texture_unit *texUnit) else { const struct gl_texture_object *texObj = texUnit->_Current; GLenum format = texObj->Image[0][texObj->BaseLevel]->_BaseFormat; - if (format == GL_COLOR_INDEX) { - format = GL_RGBA; /* a bit of a hack */ - } - else if (format == GL_DEPTH_COMPONENT || - format == GL_DEPTH_STENCIL_EXT) { + + if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { format = texObj->Sampler.DepthMode; } calculate_derived_texenv(&texUnit->_EnvMode, texUnit->EnvMode, format); @@ -778,8 +774,6 @@ _mesa_init_texture(struct gl_context *ctx) /* Texture group */ ctx->Texture.CurrentUnit = 0; /* multitexture */ ctx->Texture._EnabledUnits = 0x0; - ctx->Texture.SharedPalette = GL_FALSE; - _mesa_init_colortable(&ctx->Texture.Palette); for (u = 0; u < Elements(ctx->Texture.Unit); u++) init_texture_unit(ctx, u); diff --git a/mesalib/src/mesa/main/texstore.c b/mesalib/src/mesa/main/texstore.c index e9915a7f0..2cdc8ed67 100644 --- a/mesalib/src/mesa/main/texstore.c +++ b/mesalib/src/mesa/main/texstore.c @@ -340,7 +340,6 @@ _mesa_make_temp_float_image(struct gl_context *ctx, GLuint dims, logicalBaseFormat == GL_LUMINANCE || logicalBaseFormat == GL_ALPHA || logicalBaseFormat == GL_INTENSITY || - logicalBaseFormat == GL_COLOR_INDEX || logicalBaseFormat == GL_DEPTH_COMPONENT); ASSERT(textureBaseFormat == GL_RGBA || @@ -351,7 +350,6 @@ _mesa_make_temp_float_image(struct gl_context *ctx, GLuint dims, textureBaseFormat == GL_LUMINANCE || textureBaseFormat == GL_ALPHA || textureBaseFormat == GL_INTENSITY || - textureBaseFormat == GL_COLOR_INDEX || textureBaseFormat == GL_DEPTH_COMPONENT); tempImage = (GLfloat *) malloc(srcWidth * srcHeight * srcDepth diff --git a/mesalib/src/mesa/main/varray.c b/mesalib/src/mesa/main/varray.c index 9c9d0d66e..13b3405e5 100644 --- a/mesalib/src/mesa/main/varray.c +++ b/mesalib/src/mesa/main/varray.c @@ -160,10 +160,17 @@ update_array(struct gl_context *ctx, if (ctx->Extensions.EXT_vertex_array_bgra && sizeMax == BGRA_OR_4 && size == GL_BGRA) { - if (type != GL_UNSIGNED_BYTE && - (ctx->Extensions.ARB_vertex_type_2_10_10_10_rev && - (type != GL_UNSIGNED_INT_2_10_10_10_REV && - type != GL_INT_2_10_10_10_REV))) { + GLboolean bgra_error = GL_FALSE; + + if (ctx->Extensions.ARB_vertex_type_2_10_10_10_rev) { + if (type != GL_UNSIGNED_INT_2_10_10_10_REV && + type != GL_INT_2_10_10_10_REV && + type != GL_UNSIGNED_BYTE) + bgra_error = GL_TRUE; + } else if (type != GL_UNSIGNED_BYTE) + bgra_error = GL_TRUE; + + if (bgra_error) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(GL_BGRA/GLubyte)", func); return; } diff --git a/mesalib/src/mesa/state_tracker/st_cb_eglimage.c b/mesalib/src/mesa/state_tracker/st_cb_eglimage.c index d7518c0b4..531296fb3 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_eglimage.c +++ b/mesalib/src/mesa/state_tracker/st_cb_eglimage.c @@ -1,170 +1,169 @@ -/* - * Mesa 3-D graphics library - * Version: 7.9 - * - * Copyright (C) 2010 LunarG Inc. - * - * 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. - * - * Authors: - * Chia-I Wu - */ - -#include "main/mfeatures.h" -#include "main/texobj.h" -#include "main/texfetch.h" -#include "main/teximage.h" -#include "util/u_inlines.h" -#include "util/u_format.h" -#include "st_cb_eglimage.h" -#include "st_cb_fbo.h" -#include "st_context.h" -#include "st_texture.h" -#include "st_format.h" -#include "st_manager.h" - -#if FEATURE_OES_EGL_image - -/** - * Return the base format just like _mesa_base_fbo_format does. - */ -static GLenum -st_pipe_format_to_base_format(enum pipe_format format) -{ - GLenum base_format; - - if (util_format_is_depth_or_stencil(format)) { - if (util_format_is_depth_and_stencil(format)) { - base_format = GL_DEPTH_STENCIL; - } - else { - if (format == PIPE_FORMAT_S8_USCALED) - base_format = GL_STENCIL_INDEX; - else - base_format = GL_DEPTH_COMPONENT; - } - } - else { - /* is this enough? */ - if (util_format_has_alpha(format)) - base_format = GL_RGBA; - else - base_format = GL_RGB; - } - - return base_format; -} - -static void -st_egl_image_target_renderbuffer_storage(struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLeglImageOES image_handle) -{ - struct st_context *st = st_context(ctx); - struct st_renderbuffer *strb = st_renderbuffer(rb); - struct pipe_surface *ps; - unsigned usage; - - usage = PIPE_BIND_RENDER_TARGET; - ps = st_manager_get_egl_image_surface(st, (void *) image_handle, usage); - if (ps) { - strb->Base.Width = ps->width; - strb->Base.Height = ps->height; - strb->Base.Format = st_pipe_format_to_mesa_format(ps->format); - strb->Base.DataType = st_format_datatype(ps->format); - strb->Base._BaseFormat = st_pipe_format_to_base_format(ps->format); - strb->Base.InternalFormat = strb->Base._BaseFormat; - - pipe_surface_reference(&strb->surface, ps); - pipe_resource_reference(&strb->texture, ps->texture); - - pipe_surface_reference(&ps, NULL); - } -} - -static void -st_bind_surface(struct gl_context *ctx, GLenum target, - struct gl_texture_object *texObj, - struct gl_texture_image *texImage, - struct pipe_surface *ps) -{ - struct st_texture_object *stObj; - struct st_texture_image *stImage; - GLenum internalFormat; - gl_format texFormat; - - /* map pipe format to base format */ - if (util_format_get_component_bits(ps->format, UTIL_FORMAT_COLORSPACE_RGB, 3) > 0) - internalFormat = GL_RGBA; - else - internalFormat = GL_RGB; - - stObj = st_texture_object(texObj); - stImage = st_texture_image(texImage); - - /* switch to surface based */ - if (!stObj->surface_based) { - _mesa_clear_texture_object(ctx, texObj); - stObj->surface_based = GL_TRUE; - } - - texFormat = st_pipe_format_to_mesa_format(ps->format); - - _mesa_init_teximage_fields(ctx, target, texImage, - ps->width, ps->height, 1, 0, internalFormat, - texFormat); - - /* FIXME create a non-default sampler view from the pipe_surface? */ - pipe_resource_reference(&stObj->pt, ps->texture); - pipe_sampler_view_reference(&stObj->sampler_view, NULL); - pipe_resource_reference(&stImage->pt, stObj->pt); - - stObj->width0 = ps->width; - stObj->height0 = ps->height; - stObj->depth0 = 1; - - _mesa_dirty_texobj(ctx, texObj, GL_TRUE); -} - -static void -st_egl_image_target_texture_2d(struct gl_context *ctx, GLenum target, - struct gl_texture_object *texObj, - struct gl_texture_image *texImage, - GLeglImageOES image_handle) -{ - struct st_context *st = st_context(ctx); - struct pipe_surface *ps; - unsigned usage; - - usage = PIPE_BIND_SAMPLER_VIEW; - ps = st_manager_get_egl_image_surface(st, (void *) image_handle, usage); - if (ps) { - st_bind_surface(ctx, target, texObj, texImage, ps); - pipe_surface_reference(&ps, NULL); - } -} - -void -st_init_eglimage_functions(struct dd_function_table *functions) -{ - functions->EGLImageTargetTexture2D = st_egl_image_target_texture_2d; - functions->EGLImageTargetRenderbufferStorage = st_egl_image_target_renderbuffer_storage; -} - -#endif /* FEATURE_OES_EGL_image */ +/* + * Mesa 3-D graphics library + * Version: 7.9 + * + * Copyright (C) 2010 LunarG Inc. + * + * 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. + * + * Authors: + * Chia-I Wu + */ + +#include "main/mfeatures.h" +#include "main/texobj.h" +#include "main/teximage.h" +#include "util/u_inlines.h" +#include "util/u_format.h" +#include "st_cb_eglimage.h" +#include "st_cb_fbo.h" +#include "st_context.h" +#include "st_texture.h" +#include "st_format.h" +#include "st_manager.h" + +#if FEATURE_OES_EGL_image + +/** + * Return the base format just like _mesa_base_fbo_format does. + */ +static GLenum +st_pipe_format_to_base_format(enum pipe_format format) +{ + GLenum base_format; + + if (util_format_is_depth_or_stencil(format)) { + if (util_format_is_depth_and_stencil(format)) { + base_format = GL_DEPTH_STENCIL; + } + else { + if (format == PIPE_FORMAT_S8_USCALED) + base_format = GL_STENCIL_INDEX; + else + base_format = GL_DEPTH_COMPONENT; + } + } + else { + /* is this enough? */ + if (util_format_has_alpha(format)) + base_format = GL_RGBA; + else + base_format = GL_RGB; + } + + return base_format; +} + +static void +st_egl_image_target_renderbuffer_storage(struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLeglImageOES image_handle) +{ + struct st_context *st = st_context(ctx); + struct st_renderbuffer *strb = st_renderbuffer(rb); + struct pipe_surface *ps; + unsigned usage; + + usage = PIPE_BIND_RENDER_TARGET; + ps = st_manager_get_egl_image_surface(st, (void *) image_handle, usage); + if (ps) { + strb->Base.Width = ps->width; + strb->Base.Height = ps->height; + strb->Base.Format = st_pipe_format_to_mesa_format(ps->format); + strb->Base.DataType = st_format_datatype(ps->format); + strb->Base._BaseFormat = st_pipe_format_to_base_format(ps->format); + strb->Base.InternalFormat = strb->Base._BaseFormat; + + pipe_surface_reference(&strb->surface, ps); + pipe_resource_reference(&strb->texture, ps->texture); + + pipe_surface_reference(&ps, NULL); + } +} + +static void +st_bind_surface(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage, + struct pipe_surface *ps) +{ + struct st_texture_object *stObj; + struct st_texture_image *stImage; + GLenum internalFormat; + gl_format texFormat; + + /* map pipe format to base format */ + if (util_format_get_component_bits(ps->format, UTIL_FORMAT_COLORSPACE_RGB, 3) > 0) + internalFormat = GL_RGBA; + else + internalFormat = GL_RGB; + + stObj = st_texture_object(texObj); + stImage = st_texture_image(texImage); + + /* switch to surface based */ + if (!stObj->surface_based) { + _mesa_clear_texture_object(ctx, texObj); + stObj->surface_based = GL_TRUE; + } + + texFormat = st_pipe_format_to_mesa_format(ps->format); + + _mesa_init_teximage_fields(ctx, target, texImage, + ps->width, ps->height, 1, 0, internalFormat, + texFormat); + + /* FIXME create a non-default sampler view from the pipe_surface? */ + pipe_resource_reference(&stObj->pt, ps->texture); + pipe_sampler_view_reference(&stObj->sampler_view, NULL); + pipe_resource_reference(&stImage->pt, stObj->pt); + + stObj->width0 = ps->width; + stObj->height0 = ps->height; + stObj->depth0 = 1; + + _mesa_dirty_texobj(ctx, texObj, GL_TRUE); +} + +static void +st_egl_image_target_texture_2d(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage, + GLeglImageOES image_handle) +{ + struct st_context *st = st_context(ctx); + struct pipe_surface *ps; + unsigned usage; + + usage = PIPE_BIND_SAMPLER_VIEW; + ps = st_manager_get_egl_image_surface(st, (void *) image_handle, usage); + if (ps) { + st_bind_surface(ctx, target, texObj, texImage, ps); + pipe_surface_reference(&ps, NULL); + } +} + +void +st_init_eglimage_functions(struct dd_function_table *functions) +{ + functions->EGLImageTargetTexture2D = st_egl_image_target_texture_2d; + functions->EGLImageTargetRenderbufferStorage = st_egl_image_target_renderbuffer_storage; +} + +#endif /* FEATURE_OES_EGL_image */ diff --git a/mesalib/src/mesa/state_tracker/st_cb_fbo.c b/mesalib/src/mesa/state_tracker/st_cb_fbo.c index 5b9e20374..d43f67ac9 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_fbo.c +++ b/mesalib/src/mesa/state_tracker/st_cb_fbo.c @@ -112,7 +112,6 @@ st_renderbuffer_alloc_storage(struct gl_context * ctx, */ pipe_surface_reference( &strb->surface, NULL ); pipe_resource_reference( &strb->texture, NULL ); - pipe_sampler_view_reference(&strb->sampler_view, NULL); /* Setup new texture template. */ @@ -165,7 +164,6 @@ st_renderbuffer_delete(struct gl_renderbuffer *rb) ASSERT(strb); pipe_surface_reference(&strb->surface, NULL); pipe_resource_reference(&strb->texture, NULL); - pipe_sampler_view_reference(&strb->sampler_view, NULL); free(strb->data); free(strb); } @@ -388,9 +386,6 @@ st_render_texture(struct gl_context *ctx, pipe_surface_reference(&strb->surface, NULL); - pipe_sampler_view_reference(&strb->sampler_view, - st_get_texture_sampler_view(stObj, pipe)); - assert(strb->rtt_level <= strb->texture->last_level); /* new surface for rendering into the texture */ @@ -650,14 +645,4 @@ void st_init_fbo_functions(struct dd_function_table *functions) functions->ReadBuffer = st_ReadBuffer; } -/* XXX unused ? */ -struct pipe_sampler_view * -st_get_renderbuffer_sampler_view(struct st_renderbuffer *rb, - struct pipe_context *pipe) -{ - if (!rb->sampler_view) { - rb->sampler_view = st_create_texture_sampler_view(pipe, rb->texture); - } - return rb->sampler_view; -} diff --git a/mesalib/src/mesa/state_tracker/st_cb_fbo.h b/mesalib/src/mesa/state_tracker/st_cb_fbo.h index 228be8fed..1afa3fe6e 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_fbo.h +++ b/mesalib/src/mesa/state_tracker/st_cb_fbo.h @@ -1,96 +1,84 @@ -/************************************************************************** - * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. - * 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, sub license, 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 (including the - * next paragraph) 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 NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. - * - **************************************************************************/ - - -#ifndef ST_CB_FBO_H -#define ST_CB_FBO_H - -#include "main/compiler.h" -#include "main/glheader.h" -#include "main/mtypes.h" - -#include "pipe/p_compiler.h" -#include "pipe/p_format.h" - -struct dd_function_table; -struct pipe_context; - -/** - * Derived renderbuffer class. Just need to add a pointer to the - * pipe surface. - */ -struct st_renderbuffer -{ - struct gl_renderbuffer Base; - struct pipe_resource *texture; - struct pipe_surface *surface; /* temporary view into texture */ - struct pipe_sampler_view *sampler_view; - enum pipe_format format; /** preferred format, or PIPE_FORMAT_NONE */ - GLboolean defined; /**< defined contents? */ - - /** - * Used only when hardware accumulation buffers are not supported. - */ - boolean software; - size_t stride; - void *data; - - struct st_texture_object *rtt; /**< GL render to texture's texture */ - int rtt_level, rtt_face, rtt_slice; - - /** Render to texture state */ - struct pipe_resource *texture_save; - struct pipe_surface *surface_save; - struct pipe_sampler_view *sampler_view_save; -}; - - -static INLINE struct st_renderbuffer * -st_renderbuffer(struct gl_renderbuffer *rb) -{ - return (struct st_renderbuffer *) rb; -} - - -extern struct gl_renderbuffer * -st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw); - -extern void -st_init_fbo_functions(struct dd_function_table *functions); - -/* XXX unused ? */ -extern struct pipe_sampler_view * -st_get_renderbuffer_sampler_view(struct st_renderbuffer *rb, - struct pipe_context *pipe); - - -extern GLboolean -st_is_depth_stencil_combined(const struct gl_renderbuffer_attachment *depth, - const struct gl_renderbuffer_attachment *stencil); - - -#endif /* ST_CB_FBO_H */ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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, sub license, 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 (including the + * next paragraph) 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + **************************************************************************/ + + +#ifndef ST_CB_FBO_H +#define ST_CB_FBO_H + +#include "main/compiler.h" +#include "main/glheader.h" +#include "main/mtypes.h" + +#include "pipe/p_compiler.h" +#include "pipe/p_format.h" + +struct dd_function_table; +struct pipe_context; + +/** + * Derived renderbuffer class. Just need to add a pointer to the + * pipe surface. + */ +struct st_renderbuffer +{ + struct gl_renderbuffer Base; + struct pipe_resource *texture; + struct pipe_surface *surface; /* temporary view into texture */ + enum pipe_format format; /** preferred format, or PIPE_FORMAT_NONE */ + GLboolean defined; /**< defined contents? */ + + /** + * Used only when hardware accumulation buffers are not supported. + */ + boolean software; + size_t stride; + void *data; + + struct st_texture_object *rtt; /**< GL render to texture's texture */ + int rtt_level, rtt_face, rtt_slice; +}; + + +static INLINE struct st_renderbuffer * +st_renderbuffer(struct gl_renderbuffer *rb) +{ + return (struct st_renderbuffer *) rb; +} + + +extern struct gl_renderbuffer * +st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw); + +extern void +st_init_fbo_functions(struct dd_function_table *functions); + +extern GLboolean +st_is_depth_stencil_combined(const struct gl_renderbuffer_attachment *depth, + const struct gl_renderbuffer_attachment *stencil); + + +#endif /* ST_CB_FBO_H */ diff --git a/mesalib/src/mesa/swrast/s_drawpix.c b/mesalib/src/mesa/swrast/s_drawpix.c index 11c63457f..63bfa79b5 100644 --- a/mesalib/src/mesa/swrast/s_drawpix.c +++ b/mesalib/src/mesa/swrast/s_drawpix.c @@ -335,7 +335,7 @@ draw_stencil_pixels( struct gl_context *ctx, GLint x, GLint y, ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; const GLvoid *source = _mesa_image_address2d(unpack, pixels, width, height, - GL_COLOR_INDEX, type, + GL_STENCIL_INDEX, type, row, skipPixels); _mesa_unpack_stencil_span(ctx, spanWidth, destType, values, type, source, unpack, diff --git a/mesalib/src/mesa/swrast/s_texfilter.c b/mesalib/src/mesa/swrast/s_texfilter.c index 237e5d28a..ad31e3778 100644 --- a/mesalib/src/mesa/swrast/s_texfilter.c +++ b/mesalib/src/mesa/swrast/s_texfilter.c @@ -1,3710 +1,3706 @@ -/* - * Mesa 3-D graphics library - * Version: 7.3 - * - * 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 - * BRIAN PAUL 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. - */ - - -#include "main/glheader.h" -#include "main/context.h" -#include "main/colormac.h" -#include "main/imports.h" - -#include "s_context.h" -#include "s_texfilter.h" - - -/* - * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes - * see 1-pixel bands of improperly weighted linear-filtered textures. - * The tests/texwrap.c demo is a good test. - * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0. - * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x). - */ -#define FRAC(f) ((f) - IFLOOR(f)) - - - -/** - * Linear interpolation macro - */ -#define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) ) - - -/** - * Do 2D/biliner interpolation of float values. - * v00, v10, v01 and v11 are typically four texture samples in a square/box. - * a and b are the horizontal and vertical interpolants. - * It's important that this function is inlined when compiled with - * optimization! If we find that's not true on some systems, convert - * to a macro. - */ -static INLINE GLfloat -lerp_2d(GLfloat a, GLfloat b, - GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11) -{ - const GLfloat temp0 = LERP(a, v00, v10); - const GLfloat temp1 = LERP(a, v01, v11); - return LERP(b, temp0, temp1); -} - - -/** - * Do 3D/trilinear interpolation of float values. - * \sa lerp_2d - */ -static INLINE GLfloat -lerp_3d(GLfloat a, GLfloat b, GLfloat c, - GLfloat v000, GLfloat v100, GLfloat v010, GLfloat v110, - GLfloat v001, GLfloat v101, GLfloat v011, GLfloat v111) -{ - const GLfloat temp00 = LERP(a, v000, v100); - const GLfloat temp10 = LERP(a, v010, v110); - const GLfloat temp01 = LERP(a, v001, v101); - const GLfloat temp11 = LERP(a, v011, v111); - const GLfloat temp0 = LERP(b, temp00, temp10); - const GLfloat temp1 = LERP(b, temp01, temp11); - return LERP(c, temp0, temp1); -} - - -/** - * Do linear interpolation of colors. - */ -static INLINE void -lerp_rgba(GLfloat result[4], GLfloat t, const GLfloat a[4], const GLfloat b[4]) -{ - result[0] = LERP(t, a[0], b[0]); - result[1] = LERP(t, a[1], b[1]); - result[2] = LERP(t, a[2], b[2]); - result[3] = LERP(t, a[3], b[3]); -} - - -/** - * Do bilinear interpolation of colors. - */ -static INLINE void -lerp_rgba_2d(GLfloat result[4], GLfloat a, GLfloat b, - const GLfloat t00[4], const GLfloat t10[4], - const GLfloat t01[4], const GLfloat t11[4]) -{ - result[0] = lerp_2d(a, b, t00[0], t10[0], t01[0], t11[0]); - result[1] = lerp_2d(a, b, t00[1], t10[1], t01[1], t11[1]); - result[2] = lerp_2d(a, b, t00[2], t10[2], t01[2], t11[2]); - result[3] = lerp_2d(a, b, t00[3], t10[3], t01[3], t11[3]); -} - - -/** - * Do trilinear interpolation of colors. - */ -static INLINE void -lerp_rgba_3d(GLfloat result[4], GLfloat a, GLfloat b, GLfloat c, - const GLfloat t000[4], const GLfloat t100[4], - const GLfloat t010[4], const GLfloat t110[4], - const GLfloat t001[4], const GLfloat t101[4], - const GLfloat t011[4], const GLfloat t111[4]) -{ - GLuint k; - /* compiler should unroll these short loops */ - for (k = 0; k < 4; k++) { - result[k] = lerp_3d(a, b, c, t000[k], t100[k], t010[k], t110[k], - t001[k], t101[k], t011[k], t111[k]); - } -} - - -/** - * Used for GL_REPEAT wrap mode. Using A % B doesn't produce the - * right results for A<0. Casting to A to be unsigned only works if B - * is a power of two. Adding a bias to A (which is a multiple of B) - * avoids the problems with A < 0 (for reasonable A) without using a - * conditional. - */ -#define REMAINDER(A, B) (((A) + (B) * 1024) % (B)) - - -/** - * Used to compute texel locations for linear sampling. - * Input: - * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER - * s = texcoord in [0,1] - * size = width (or height or depth) of texture - * Output: - * i0, i1 = returns two nearest texel indexes - * weight = returns blend factor between texels - */ -static INLINE void -linear_texel_locations(GLenum wrapMode, - const struct gl_texture_image *img, - GLint size, GLfloat s, - GLint *i0, GLint *i1, GLfloat *weight) -{ - GLfloat u; - switch (wrapMode) { - case GL_REPEAT: - u = s * size - 0.5F; - if (img->_IsPowerOfTwo) { - *i0 = IFLOOR(u) & (size - 1); - *i1 = (*i0 + 1) & (size - 1); - } - else { - *i0 = REMAINDER(IFLOOR(u), size); - *i1 = REMAINDER(*i0 + 1, size); - } - break; - case GL_CLAMP_TO_EDGE: - if (s <= 0.0F) - u = 0.0F; - else if (s >= 1.0F) - u = (GLfloat) size; - else - u = s * size; - u -= 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - if (*i0 < 0) - *i0 = 0; - if (*i1 >= (GLint) size) - *i1 = size - 1; - break; - case GL_CLAMP_TO_BORDER: - { - const GLfloat min = -1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - if (s <= min) - u = min * size; - else if (s >= max) - u = max * size; - else - u = s * size; - u -= 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - } - break; - case GL_MIRRORED_REPEAT: - { - const GLint flr = IFLOOR(s); - if (flr & 1) - u = 1.0F - (s - (GLfloat) flr); - else - u = s - (GLfloat) flr; - u = (u * size) - 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - if (*i0 < 0) - *i0 = 0; - if (*i1 >= (GLint) size) - *i1 = size - 1; - } - break; - case GL_MIRROR_CLAMP_EXT: - u = FABSF(s); - if (u >= 1.0F) - u = (GLfloat) size; - else - u *= size; - u -= 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - break; - case GL_MIRROR_CLAMP_TO_EDGE_EXT: - u = FABSF(s); - if (u >= 1.0F) - u = (GLfloat) size; - else - u *= size; - u -= 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - if (*i0 < 0) - *i0 = 0; - if (*i1 >= (GLint) size) - *i1 = size - 1; - break; - case GL_MIRROR_CLAMP_TO_BORDER_EXT: - { - const GLfloat min = -1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - u = FABSF(s); - if (u <= min) - u = min * size; - else if (u >= max) - u = max * size; - else - u *= size; - u -= 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - } - break; - case GL_CLAMP: - if (s <= 0.0F) - u = 0.0F; - else if (s >= 1.0F) - u = (GLfloat) size; - else - u = s * size; - u -= 0.5F; - *i0 = IFLOOR(u); - *i1 = *i0 + 1; - break; - default: - _mesa_problem(NULL, "Bad wrap mode"); - u = 0.0F; - } - *weight = FRAC(u); -} - - -/** - * Used to compute texel location for nearest sampling. - */ -static INLINE GLint -nearest_texel_location(GLenum wrapMode, - const struct gl_texture_image *img, - GLint size, GLfloat s) -{ - GLint i; - - switch (wrapMode) { - case GL_REPEAT: - /* s limited to [0,1) */ - /* i limited to [0,size-1] */ - i = IFLOOR(s * size); - if (img->_IsPowerOfTwo) - i &= (size - 1); - else - i = REMAINDER(i, size); - return i; - case GL_CLAMP_TO_EDGE: - { - /* s limited to [min,max] */ - /* i limited to [0, size-1] */ - const GLfloat min = 1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - if (s < min) - i = 0; - else if (s > max) - i = size - 1; - else - i = IFLOOR(s * size); - } - return i; - case GL_CLAMP_TO_BORDER: - { - /* s limited to [min,max] */ - /* i limited to [-1, size] */ - const GLfloat min = -1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - if (s <= min) - i = -1; - else if (s >= max) - i = size; - else - i = IFLOOR(s * size); - } - return i; - case GL_MIRRORED_REPEAT: - { - const GLfloat min = 1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - const GLint flr = IFLOOR(s); - GLfloat u; - if (flr & 1) - u = 1.0F - (s - (GLfloat) flr); - else - u = s - (GLfloat) flr; - if (u < min) - i = 0; - else if (u > max) - i = size - 1; - else - i = IFLOOR(u * size); - } - return i; - case GL_MIRROR_CLAMP_EXT: - { - /* s limited to [0,1] */ - /* i limited to [0,size-1] */ - const GLfloat u = FABSF(s); - if (u <= 0.0F) - i = 0; - else if (u >= 1.0F) - i = size - 1; - else - i = IFLOOR(u * size); - } - return i; - case GL_MIRROR_CLAMP_TO_EDGE_EXT: - { - /* s limited to [min,max] */ - /* i limited to [0, size-1] */ - const GLfloat min = 1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - const GLfloat u = FABSF(s); - if (u < min) - i = 0; - else if (u > max) - i = size - 1; - else - i = IFLOOR(u * size); - } - return i; - case GL_MIRROR_CLAMP_TO_BORDER_EXT: - { - /* s limited to [min,max] */ - /* i limited to [0, size-1] */ - const GLfloat min = -1.0F / (2.0F * size); - const GLfloat max = 1.0F - min; - const GLfloat u = FABSF(s); - if (u < min) - i = -1; - else if (u > max) - i = size; - else - i = IFLOOR(u * size); - } - return i; - case GL_CLAMP: - /* s limited to [0,1] */ - /* i limited to [0,size-1] */ - if (s <= 0.0F) - i = 0; - else if (s >= 1.0F) - i = size - 1; - else - i = IFLOOR(s * size); - return i; - default: - _mesa_problem(NULL, "Bad wrap mode"); - return 0; - } -} - - -/* Power of two image sizes only */ -static INLINE void -linear_repeat_texel_location(GLuint size, GLfloat s, - GLint *i0, GLint *i1, GLfloat *weight) -{ - GLfloat u = s * size - 0.5F; - *i0 = IFLOOR(u) & (size - 1); - *i1 = (*i0 + 1) & (size - 1); - *weight = FRAC(u); -} - - -/** - * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode. - */ -static INLINE GLint -clamp_rect_coord_nearest(GLenum wrapMode, GLfloat coord, GLint max) -{ - switch (wrapMode) { - case GL_CLAMP: - return IFLOOR( CLAMP(coord, 0.0F, max - 1) ); - case GL_CLAMP_TO_EDGE: - return IFLOOR( CLAMP(coord, 0.5F, max - 0.5F) ); - case GL_CLAMP_TO_BORDER: - return IFLOOR( CLAMP(coord, -0.5F, max + 0.5F) ); - default: - _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_nearest"); - return 0; - } -} - - -/** - * As above, but GL_LINEAR filtering. - */ -static INLINE void -clamp_rect_coord_linear(GLenum wrapMode, GLfloat coord, GLint max, - GLint *i0out, GLint *i1out, GLfloat *weight) -{ - GLfloat fcol; - GLint i0, i1; - switch (wrapMode) { - case GL_CLAMP: - /* Not exactly what the spec says, but it matches NVIDIA output */ - fcol = CLAMP(coord - 0.5F, 0.0F, max - 1); - i0 = IFLOOR(fcol); - i1 = i0 + 1; - break; - case GL_CLAMP_TO_EDGE: - fcol = CLAMP(coord, 0.5F, max - 0.5F); - fcol -= 0.5F; - i0 = IFLOOR(fcol); - i1 = i0 + 1; - if (i1 > max - 1) - i1 = max - 1; - break; - case GL_CLAMP_TO_BORDER: - fcol = CLAMP(coord, -0.5F, max + 0.5F); - fcol -= 0.5F; - i0 = IFLOOR(fcol); - i1 = i0 + 1; - break; - default: - _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_linear"); - i0 = i1 = 0; - fcol = 0.0F; - } - *i0out = i0; - *i1out = i1; - *weight = FRAC(fcol); -} - - -/** - * Compute slice/image to use for 1D or 2D array texture. - */ -static INLINE GLint -tex_array_slice(GLfloat coord, GLsizei size) -{ - GLint slice = IFLOOR(coord + 0.5f); - slice = CLAMP(slice, 0, size - 1); - return slice; -} - - -/** - * Compute nearest integer texcoords for given texobj and coordinate. - * NOTE: only used for depth texture sampling. - */ -static INLINE void -nearest_texcoord(const struct gl_texture_object *texObj, - GLuint level, - const GLfloat texcoord[4], - GLint *i, GLint *j, GLint *k) -{ - const struct gl_texture_image *img = texObj->Image[0][level]; - const GLint width = img->Width; - const GLint height = img->Height; - const GLint depth = img->Depth; - - switch (texObj->Target) { - case GL_TEXTURE_RECTANGLE_ARB: - *i = clamp_rect_coord_nearest(texObj->Sampler.WrapS, texcoord[0], width); - *j = clamp_rect_coord_nearest(texObj->Sampler.WrapT, texcoord[1], height); - *k = 0; - break; - case GL_TEXTURE_1D: - *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]); - *j = 0; - *k = 0; - break; - case GL_TEXTURE_2D: - *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]); - *j = nearest_texel_location(texObj->Sampler.WrapT, img, height, texcoord[1]); - *k = 0; - break; - case GL_TEXTURE_1D_ARRAY_EXT: - *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]); - *j = tex_array_slice(texcoord[1], height); - *k = 0; - break; - case GL_TEXTURE_2D_ARRAY_EXT: - *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]); - *j = nearest_texel_location(texObj->Sampler.WrapT, img, height, texcoord[1]); - *k = tex_array_slice(texcoord[2], depth); - break; - default: - *i = *j = *k = 0; - } -} - - -/** - * Compute linear integer texcoords for given texobj and coordinate. - * NOTE: only used for depth texture sampling. - */ -static INLINE void -linear_texcoord(const struct gl_texture_object *texObj, - GLuint level, - const GLfloat texcoord[4], - GLint *i0, GLint *i1, GLint *j0, GLint *j1, GLint *slice, - GLfloat *wi, GLfloat *wj) -{ - const struct gl_texture_image *img = texObj->Image[0][level]; - const GLint width = img->Width; - const GLint height = img->Height; - const GLint depth = img->Depth; - - switch (texObj->Target) { - case GL_TEXTURE_RECTANGLE_ARB: - clamp_rect_coord_linear(texObj->Sampler.WrapS, texcoord[0], - width, i0, i1, wi); - clamp_rect_coord_linear(texObj->Sampler.WrapT, texcoord[1], - height, j0, j1, wj); - *slice = 0; - break; - - case GL_TEXTURE_1D: - case GL_TEXTURE_2D: - linear_texel_locations(texObj->Sampler.WrapS, img, width, - texcoord[0], i0, i1, wi); - linear_texel_locations(texObj->Sampler.WrapT, img, height, - texcoord[1], j0, j1, wj); - *slice = 0; - break; - - case GL_TEXTURE_1D_ARRAY_EXT: - linear_texel_locations(texObj->Sampler.WrapS, img, width, - texcoord[0], i0, i1, wi); - *j0 = tex_array_slice(texcoord[1], height); - *j1 = *j0; - *slice = 0; - break; - - case GL_TEXTURE_2D_ARRAY_EXT: - linear_texel_locations(texObj->Sampler.WrapS, img, width, - texcoord[0], i0, i1, wi); - linear_texel_locations(texObj->Sampler.WrapT, img, height, - texcoord[1], j0, j1, wj); - *slice = tex_array_slice(texcoord[2], depth); - break; - - default: - *slice = 0; - } -} - - - -/** - * For linear interpolation between mipmap levels N and N+1, this function - * computes N. - */ -static INLINE GLint -linear_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda) -{ - if (lambda < 0.0F) - return tObj->BaseLevel; - else if (lambda > tObj->_MaxLambda) - return (GLint) (tObj->BaseLevel + tObj->_MaxLambda); - else - return (GLint) (tObj->BaseLevel + lambda); -} - - -/** - * Compute the nearest mipmap level to take texels from. - */ -static INLINE GLint -nearest_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda) -{ - GLfloat l; - GLint level; - if (lambda <= 0.5F) - l = 0.0F; - else if (lambda > tObj->_MaxLambda + 0.4999F) - l = tObj->_MaxLambda + 0.4999F; - else - l = lambda; - level = (GLint) (tObj->BaseLevel + l + 0.5F); - if (level > tObj->_MaxLevel) - level = tObj->_MaxLevel; - return level; -} - - - -/* - * Bitflags for texture border color sampling. - */ -#define I0BIT 1 -#define I1BIT 2 -#define J0BIT 4 -#define J1BIT 8 -#define K0BIT 16 -#define K1BIT 32 - - - -/** - * The lambda[] array values are always monotonic. Either the whole span - * will be minified, magnified, or split between the two. This function - * determines the subranges in [0, n-1] that are to be minified or magnified. - */ -static INLINE void -compute_min_mag_ranges(const struct gl_texture_object *tObj, - GLuint n, const GLfloat lambda[], - GLuint *minStart, GLuint *minEnd, - GLuint *magStart, GLuint *magEnd) -{ - GLfloat minMagThresh; - - /* we shouldn't be here if minfilter == magfilter */ - ASSERT(tObj->Sampler.MinFilter != tObj->Sampler.MagFilter); - - /* This bit comes from the OpenGL spec: */ - if (tObj->Sampler.MagFilter == GL_LINEAR - && (tObj->Sampler.MinFilter == GL_NEAREST_MIPMAP_NEAREST || - tObj->Sampler.MinFilter == GL_NEAREST_MIPMAP_LINEAR)) { - minMagThresh = 0.5F; - } - else { - minMagThresh = 0.0F; - } - -#if 0 - /* DEBUG CODE: Verify that lambda[] is monotonic. - * We can't really use this because the inaccuracy in the LOG2 function - * causes this test to fail, yet the resulting texturing is correct. - */ - if (n > 1) { - GLuint i; - printf("lambda delta = %g\n", lambda[0] - lambda[n-1]); - if (lambda[0] >= lambda[n-1]) { /* decreasing */ - for (i = 0; i < n - 1; i++) { - ASSERT((GLint) (lambda[i] * 10) >= (GLint) (lambda[i+1] * 10)); - } - } - else { /* increasing */ - for (i = 0; i < n - 1; i++) { - ASSERT((GLint) (lambda[i] * 10) <= (GLint) (lambda[i+1] * 10)); - } - } - } -#endif /* DEBUG */ - - if (lambda[0] <= minMagThresh && (n <= 1 || lambda[n-1] <= minMagThresh)) { - /* magnification for whole span */ - *magStart = 0; - *magEnd = n; - *minStart = *minEnd = 0; - } - else if (lambda[0] > minMagThresh && (n <=1 || lambda[n-1] > minMagThresh)) { - /* minification for whole span */ - *minStart = 0; - *minEnd = n; - *magStart = *magEnd = 0; - } - else { - /* a mix of minification and magnification */ - GLuint i; - if (lambda[0] > minMagThresh) { - /* start with minification */ - for (i = 1; i < n; i++) { - if (lambda[i] <= minMagThresh) - break; - } - *minStart = 0; - *minEnd = i; - *magStart = i; - *magEnd = n; - } - else { - /* start with magnification */ - for (i = 1; i < n; i++) { - if (lambda[i] > minMagThresh) - break; - } - *magStart = 0; - *magEnd = i; - *minStart = i; - *minEnd = n; - } - } - -#if 0 - /* Verify the min/mag Start/End values - * We don't use this either (see above) - */ - { - GLint i; - for (i = 0; i < n; i++) { - if (lambda[i] > minMagThresh) { - /* minification */ - ASSERT(i >= *minStart); - ASSERT(i < *minEnd); - } - else { - /* magnification */ - ASSERT(i >= *magStart); - ASSERT(i < *magEnd); - } - } - } -#endif -} - - -/** - * When we sample the border color, it must be interpreted according to - * the base texture format. Ex: if the texture base format it GL_ALPHA, - * we return (0,0,0,BorderAlpha). - */ -static INLINE void -get_border_color(const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - GLfloat rgba[4]) -{ - switch (img->_BaseFormat) { - case GL_RGB: - rgba[0] = tObj->Sampler.BorderColor.f[0]; - rgba[1] = tObj->Sampler.BorderColor.f[1]; - rgba[2] = tObj->Sampler.BorderColor.f[2]; - rgba[3] = 1.0F; - break; - case GL_ALPHA: - rgba[0] = rgba[1] = rgba[2] = 0.0; - rgba[3] = tObj->Sampler.BorderColor.f[3]; - break; - case GL_LUMINANCE: - rgba[0] = rgba[1] = rgba[2] = tObj->Sampler.BorderColor.f[0]; - rgba[3] = 1.0; - break; - case GL_LUMINANCE_ALPHA: - rgba[0] = rgba[1] = rgba[2] = tObj->Sampler.BorderColor.f[0]; - rgba[3] = tObj->Sampler.BorderColor.f[3]; - break; - case GL_INTENSITY: - rgba[0] = rgba[1] = rgba[2] = rgba[3] = tObj->Sampler.BorderColor.f[0]; - break; - default: - COPY_4V(rgba, tObj->Sampler.BorderColor.f); - } -} - - -/**********************************************************************/ -/* 1-D Texture Sampling Functions */ -/**********************************************************************/ - -/** - * Return the texture sample for coordinate (s) using GL_NEAREST filter. - */ -static INLINE void -sample_1d_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], GLfloat rgba[4]) -{ - const GLint width = img->Width2; /* without border, power of two */ - GLint i; - i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); - /* skip over the border, if any */ - i += img->Border; - if (i < 0 || i >= (GLint) img->Width) { - /* Need this test for GL_CLAMP_TO_BORDER mode */ - get_border_color(tObj, img, rgba); - } - else { - img->FetchTexelf(img, i, 0, 0, rgba); - } -} - - -/** - * Return the texture sample for coordinate (s) using GL_LINEAR filter. - */ -static INLINE void -sample_1d_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], GLfloat rgba[4]) -{ - const GLint width = img->Width2; - GLint i0, i1; - GLbitfield useBorderColor = 0x0; - GLfloat a; - GLfloat t0[4], t1[4]; /* texels */ - - linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); - - if (img->Border) { - i0 += img->Border; - i1 += img->Border; - } - else { - if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; - if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; - } - - /* fetch texel colors */ - if (useBorderColor & I0BIT) { - get_border_color(tObj, img, t0); - } - else { - img->FetchTexelf(img, i0, 0, 0, t0); - } - if (useBorderColor & I1BIT) { - get_border_color(tObj, img, t1); - } - else { - img->FetchTexelf(img, i1, 0, 0, t1); - } - - lerp_rgba(rgba, a, t0, t1); -} - - -static void -sample_1d_nearest_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_1d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); - } -} - - -static void -sample_1d_linear_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_1d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); - } -} - - -static void -sample_1d_nearest_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; - const GLfloat f = FRAC(lambda[i]); - sample_1d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_1d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_1d_linear_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; - const GLfloat f = FRAC(lambda[i]); - sample_1d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_1d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -/** Sample 1D texture, nearest filtering for both min/magnification */ -static void -sample_nearest_1d( struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4] ) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_1d_nearest(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 1D texture, linear filtering for both min/magnification */ -static void -sample_linear_1d( struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4] ) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_1d_linear(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 1D texture, using lambda to choose between min/magnification */ -static void -sample_lambda_1d( struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4] ) -{ - GLuint minStart, minEnd; /* texels with minification */ - GLuint magStart, magEnd; /* texels with magnification */ - GLuint i; - - ASSERT(lambda != NULL); - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - /* do the minified texels */ - const GLuint m = minEnd - minStart; - switch (tObj->Sampler.MinFilter) { - case GL_NEAREST: - for (i = minStart; i < minEnd; i++) - sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = minStart; i < minEnd; i++) - sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_NEAREST_MIPMAP_NEAREST: - sample_1d_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_NEAREST: - sample_1d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_NEAREST_MIPMAP_LINEAR: - sample_1d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_LINEAR: - sample_1d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - default: - _mesa_problem(ctx, "Bad min filter in sample_1d_texture"); - return; - } - } - - if (magStart < magEnd) { - /* do the magnified texels */ - switch (tObj->Sampler.MagFilter) { - case GL_NEAREST: - for (i = magStart; i < magEnd; i++) - sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = magStart; i < magEnd; i++) - sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - default: - _mesa_problem(ctx, "Bad mag filter in sample_1d_texture"); - return; - } - } -} - - -/**********************************************************************/ -/* 2-D Texture Sampling Functions */ -/**********************************************************************/ - - -/** - * Return the texture sample for coordinate (s,t) using GL_NEAREST filter. - */ -static INLINE void -sample_2d_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[]) -{ - const GLint width = img->Width2; /* without border, power of two */ - const GLint height = img->Height2; /* without border, power of two */ - GLint i, j; - (void) ctx; - - i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); - j = nearest_texel_location(tObj->Sampler.WrapT, img, height, texcoord[1]); - - /* skip over the border, if any */ - i += img->Border; - j += img->Border; - - if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height) { - /* Need this test for GL_CLAMP_TO_BORDER mode */ - get_border_color(tObj, img, rgba); - } - else { - img->FetchTexelf(img, i, j, 0, rgba); - } -} - - -/** - * Return the texture sample for coordinate (s,t) using GL_LINEAR filter. - * New sampling code contributed by Lynn Quam . - */ -static INLINE void -sample_2d_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[]) -{ - const GLint width = img->Width2; - const GLint height = img->Height2; - GLint i0, j0, i1, j1; - GLbitfield useBorderColor = 0x0; - GLfloat a, b; - GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */ - - linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); - linear_texel_locations(tObj->Sampler.WrapT, img, height, texcoord[1], &j0, &j1, &b); - - if (img->Border) { - i0 += img->Border; - i1 += img->Border; - j0 += img->Border; - j1 += img->Border; - } - else { - if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; - if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; - if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; - if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; - } - - /* fetch four texel colors */ - if (useBorderColor & (I0BIT | J0BIT)) { - get_border_color(tObj, img, t00); - } - else { - img->FetchTexelf(img, i0, j0, 0, t00); - } - if (useBorderColor & (I1BIT | J0BIT)) { - get_border_color(tObj, img, t10); - } - else { - img->FetchTexelf(img, i1, j0, 0, t10); - } - if (useBorderColor & (I0BIT | J1BIT)) { - get_border_color(tObj, img, t01); - } - else { - img->FetchTexelf(img, i0, j1, 0, t01); - } - if (useBorderColor & (I1BIT | J1BIT)) { - get_border_color(tObj, img, t11); - } - else { - img->FetchTexelf(img, i1, j1, 0, t11); - } - - lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11); -} - - -/** - * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT. - * We don't have to worry about the texture border. - */ -static INLINE void -sample_2d_linear_repeat(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[]) -{ - const GLint width = img->Width2; - const GLint height = img->Height2; - GLint i0, j0, i1, j1; - GLfloat wi, wj; - GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */ - - (void) ctx; - - ASSERT(tObj->Sampler.WrapS == GL_REPEAT); - ASSERT(tObj->Sampler.WrapT == GL_REPEAT); - ASSERT(img->Border == 0); - ASSERT(img->_BaseFormat != GL_COLOR_INDEX); - ASSERT(img->_IsPowerOfTwo); - - linear_repeat_texel_location(width, texcoord[0], &i0, &i1, &wi); - linear_repeat_texel_location(height, texcoord[1], &j0, &j1, &wj); - - img->FetchTexelf(img, i0, j0, 0, t00); - img->FetchTexelf(img, i1, j0, 0, t10); - img->FetchTexelf(img, i0, j1, 0, t01); - img->FetchTexelf(img, i1, j1, 0, t11); - - lerp_rgba_2d(rgba, wi, wj, t00, t10, t01, t11); -} - - -static void -sample_2d_nearest_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_2d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); - } -} - - -static void -sample_2d_linear_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_2d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); - } -} - - -static void -sample_2d_nearest_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_2d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_2d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_2d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_2d_linear_mipmap_linear( struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4] ) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_2d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_2d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_2d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_2d_linear_mipmap_linear_repeat(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - ASSERT(tObj->Sampler.WrapS == GL_REPEAT); - ASSERT(tObj->Sampler.WrapT == GL_REPEAT); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][level ], - texcoord[i], t0); - sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][level+1], - texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -/** Sample 2D texture, nearest filtering for both min/magnification */ -static void -sample_nearest_2d(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_2d_nearest(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 2D texture, linear filtering for both min/magnification */ -static void -sample_linear_2d(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - if (tObj->Sampler.WrapS == GL_REPEAT && - tObj->Sampler.WrapT == GL_REPEAT && - image->_IsPowerOfTwo && - image->Border == 0) { - for (i = 0; i < n; i++) { - sample_2d_linear_repeat(ctx, tObj, image, texcoords[i], rgba[i]); - } - } - else { - for (i = 0; i < n; i++) { - sample_2d_linear(ctx, tObj, image, texcoords[i], rgba[i]); - } - } -} - - -/** - * Optimized 2-D texture sampling: - * S and T wrap mode == GL_REPEAT - * GL_NEAREST min/mag filter - * No border, - * RowStride == Width, - * Format = GL_RGB - */ -static void -opt_sample_rgb_2d(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel]; - const GLfloat width = (GLfloat) img->Width; - const GLfloat height = (GLfloat) img->Height; - const GLint colMask = img->Width - 1; - const GLint rowMask = img->Height - 1; - const GLint shift = img->WidthLog2; - GLuint k; - (void) ctx; - (void) lambda; - ASSERT(tObj->Sampler.WrapS==GL_REPEAT); - ASSERT(tObj->Sampler.WrapT==GL_REPEAT); - ASSERT(img->Border==0); - ASSERT(img->TexFormat == MESA_FORMAT_RGB888); - ASSERT(img->_IsPowerOfTwo); - - for (k=0; kData) + 3*pos; - rgba[k][RCOMP] = UBYTE_TO_FLOAT(texel[2]); - rgba[k][GCOMP] = UBYTE_TO_FLOAT(texel[1]); - rgba[k][BCOMP] = UBYTE_TO_FLOAT(texel[0]); - rgba[k][ACOMP] = 1.0F; - } -} - - -/** - * Optimized 2-D texture sampling: - * S and T wrap mode == GL_REPEAT - * GL_NEAREST min/mag filter - * No border - * RowStride == Width, - * Format = GL_RGBA - */ -static void -opt_sample_rgba_2d(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel]; - const GLfloat width = (GLfloat) img->Width; - const GLfloat height = (GLfloat) img->Height; - const GLint colMask = img->Width - 1; - const GLint rowMask = img->Height - 1; - const GLint shift = img->WidthLog2; - GLuint i; - (void) ctx; - (void) lambda; - ASSERT(tObj->Sampler.WrapS==GL_REPEAT); - ASSERT(tObj->Sampler.WrapT==GL_REPEAT); - ASSERT(img->Border==0); - ASSERT(img->TexFormat == MESA_FORMAT_RGBA8888); - ASSERT(img->_IsPowerOfTwo); - - for (i = 0; i < n; i++) { - const GLint col = IFLOOR(texcoords[i][0] * width) & colMask; - const GLint row = IFLOOR(texcoords[i][1] * height) & rowMask; - const GLint pos = (row << shift) | col; - const GLuint texel = *((GLuint *) img->Data + pos); - rgba[i][RCOMP] = UBYTE_TO_FLOAT( (texel >> 24) ); - rgba[i][GCOMP] = UBYTE_TO_FLOAT( (texel >> 16) & 0xff ); - rgba[i][BCOMP] = UBYTE_TO_FLOAT( (texel >> 8) & 0xff ); - rgba[i][ACOMP] = UBYTE_TO_FLOAT( (texel ) & 0xff ); - } -} - - -/** Sample 2D texture, using lambda to choose between min/magnification */ -static void -sample_lambda_2d(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel]; - GLuint minStart, minEnd; /* texels with minification */ - GLuint magStart, magEnd; /* texels with magnification */ - - const GLboolean repeatNoBorderPOT = (tObj->Sampler.WrapS == GL_REPEAT) - && (tObj->Sampler.WrapT == GL_REPEAT) - && (tImg->Border == 0 && (tImg->Width == tImg->RowStride)) - && (tImg->_BaseFormat != GL_COLOR_INDEX) - && tImg->_IsPowerOfTwo; - - ASSERT(lambda != NULL); - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - /* do the minified texels */ - const GLuint m = minEnd - minStart; - switch (tObj->Sampler.MinFilter) { - case GL_NEAREST: - if (repeatNoBorderPOT) { - switch (tImg->TexFormat) { - case MESA_FORMAT_RGB888: - opt_sample_rgb_2d(ctx, tObj, m, texcoords + minStart, - NULL, rgba + minStart); - break; - case MESA_FORMAT_RGBA8888: - opt_sample_rgba_2d(ctx, tObj, m, texcoords + minStart, - NULL, rgba + minStart); - break; - default: - sample_nearest_2d(ctx, tObj, m, texcoords + minStart, - NULL, rgba + minStart ); - } - } - else { - sample_nearest_2d(ctx, tObj, m, texcoords + minStart, - NULL, rgba + minStart); - } - break; - case GL_LINEAR: - sample_linear_2d(ctx, tObj, m, texcoords + minStart, - NULL, rgba + minStart); - break; - case GL_NEAREST_MIPMAP_NEAREST: - sample_2d_nearest_mipmap_nearest(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_NEAREST: - sample_2d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_NEAREST_MIPMAP_LINEAR: - sample_2d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_LINEAR: - if (repeatNoBorderPOT) - sample_2d_linear_mipmap_linear_repeat(ctx, tObj, m, - texcoords + minStart, lambda + minStart, rgba + minStart); - else - sample_2d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - default: - _mesa_problem(ctx, "Bad min filter in sample_2d_texture"); - return; - } - } - - if (magStart < magEnd) { - /* do the magnified texels */ - const GLuint m = magEnd - magStart; - - switch (tObj->Sampler.MagFilter) { - case GL_NEAREST: - if (repeatNoBorderPOT) { - switch (tImg->TexFormat) { - case MESA_FORMAT_RGB888: - opt_sample_rgb_2d(ctx, tObj, m, texcoords + magStart, - NULL, rgba + magStart); - break; - case MESA_FORMAT_RGBA8888: - opt_sample_rgba_2d(ctx, tObj, m, texcoords + magStart, - NULL, rgba + magStart); - break; - default: - sample_nearest_2d(ctx, tObj, m, texcoords + magStart, - NULL, rgba + magStart ); - } - } - else { - sample_nearest_2d(ctx, tObj, m, texcoords + magStart, - NULL, rgba + magStart); - } - break; - case GL_LINEAR: - sample_linear_2d(ctx, tObj, m, texcoords + magStart, - NULL, rgba + magStart); - break; - default: - _mesa_problem(ctx, "Bad mag filter in sample_lambda_2d"); - } - } -} - - -/* For anisotropic filtering */ -#define WEIGHT_LUT_SIZE 1024 - -static GLfloat *weightLut = NULL; - -/** - * Creates the look-up table used to speed-up EWA sampling - */ -static void -create_filter_table(void) -{ - GLuint i; - if (!weightLut) { - weightLut = (GLfloat *) malloc(WEIGHT_LUT_SIZE * sizeof(GLfloat)); - - for (i = 0; i < WEIGHT_LUT_SIZE; ++i) { - GLfloat alpha = 2; - GLfloat r2 = (GLfloat) i / (GLfloat) (WEIGHT_LUT_SIZE - 1); - GLfloat weight = (GLfloat) exp(-alpha * r2); - weightLut[i] = weight; - } - } -} - - -/** - * Elliptical weighted average (EWA) filter for producing high quality - * anisotropic filtered results. - * Based on the Higher Quality Elliptical Weighted Avarage Filter - * published by Paul S. Heckbert in his Master's Thesis - * "Fundamentals of Texture Mapping and Image Warping" (1989) - */ -static void -sample_2d_ewa(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const GLfloat texcoord[4], - const GLfloat dudx, const GLfloat dvdx, - const GLfloat dudy, const GLfloat dvdy, const GLint lod, - GLfloat rgba[]) -{ - GLint level = lod > 0 ? lod : 0; - GLfloat scaling = 1.0 / (1 << level); - const struct gl_texture_image *img = tObj->Image[0][level]; - const struct gl_texture_image *mostDetailedImage = - tObj->Image[0][tObj->BaseLevel]; - GLfloat tex_u=-0.5 + texcoord[0] * mostDetailedImage->WidthScale * scaling; - GLfloat tex_v=-0.5 + texcoord[1] * mostDetailedImage->HeightScale * scaling; - - GLfloat ux = dudx * scaling; - GLfloat vx = dvdx * scaling; - GLfloat uy = dudy * scaling; - GLfloat vy = dvdy * scaling; - - /* compute ellipse coefficients to bound the region: - * A*x*x + B*x*y + C*y*y = F. - */ - GLfloat A = vx*vx+vy*vy+1; - GLfloat B = -2*(ux*vx+uy*vy); - GLfloat C = ux*ux+uy*uy+1; - GLfloat F = A*C-B*B/4.0; - - /* check if it is an ellipse */ - /* ASSERT(F > 0.0); */ - - /* Compute the ellipse's (u,v) bounding box in texture space */ - GLfloat d = -B*B+4.0*C*A; - GLfloat box_u = 2.0 / d * sqrt(d*C*F); /* box_u -> half of bbox with */ - GLfloat box_v = 2.0 / d * sqrt(A*d*F); /* box_v -> half of bbox height */ - - GLint u0 = floor(tex_u - box_u); - GLint u1 = ceil (tex_u + box_u); - GLint v0 = floor(tex_v - box_v); - GLint v1 = ceil (tex_v + box_v); - - GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F}; - GLfloat newCoord[2]; - GLfloat den = 0.0F; - GLfloat ddq; - GLfloat U = u0 - tex_u; - GLint v; - - /* Scale ellipse formula to directly index the Filter Lookup Table. - * i.e. scale so that F = WEIGHT_LUT_SIZE-1 - */ - double formScale = (double) (WEIGHT_LUT_SIZE - 1) / F; - A *= formScale; - B *= formScale; - C *= formScale; - /* F *= formScale; */ /* no need to scale F as we don't use it below here */ - - /* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse - * and incrementally update the value of Ax^2+Bxy*Cy^2; when this - * value, q, is less than F, we're inside the ellipse - */ - ddq = 2 * A; - for (v = v0; v <= v1; ++v) { - GLfloat V = v - tex_v; - GLfloat dq = A * (2 * U + 1) + B * V; - GLfloat q = (C * V + B * U) * V + A * U * U; - - GLint u; - for (u = u0; u <= u1; ++u) { - /* Note that the ellipse has been pre-scaled so F = WEIGHT_LUT_SIZE - 1 */ - if (q < WEIGHT_LUT_SIZE) { - /* as a LUT is used, q must never be negative; - * should not happen, though - */ - const GLint qClamped = q >= 0.0F ? q : 0; - GLfloat weight = weightLut[qClamped]; - - newCoord[0] = u / ((GLfloat) img->Width2); - newCoord[1] = v / ((GLfloat) img->Height2); - - sample_2d_nearest(ctx, tObj, img, newCoord, rgba); - num[0] += weight * rgba[0]; - num[1] += weight * rgba[1]; - num[2] += weight * rgba[2]; - num[3] += weight * rgba[3]; - - den += weight; - } - q += dq; - dq += ddq; - } - } - - if (den <= 0.0F) { - /* Reaching this place would mean - * that no pixels intersected the ellipse. - * This should never happen because - * the filter we use always - * intersects at least one pixel. - */ - - /*rgba[0]=0; - rgba[1]=0; - rgba[2]=0; - rgba[3]=0;*/ - /* not enough pixels in resampling, resort to direct interpolation */ - sample_2d_linear(ctx, tObj, img, texcoord, rgba); - return; - } - - rgba[0] = num[0] / den; - rgba[1] = num[1] / den; - rgba[2] = num[2] / den; - rgba[3] = num[3] / den; -} - - -/** - * Anisotropic filtering using footprint assembly as outlined in the - * EXT_texture_filter_anisotropic spec: - * http://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt - * Faster than EWA but has less quality (more aliasing effects) - */ -static void -sample_2d_footprint(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const GLfloat texcoord[4], - const GLfloat dudx, const GLfloat dvdx, - const GLfloat dudy, const GLfloat dvdy, const GLint lod, - GLfloat rgba[]) -{ - GLint level = lod > 0 ? lod : 0; - GLfloat scaling = 1.0F / (1 << level); - const struct gl_texture_image *img = tObj->Image[0][level]; - - GLfloat ux = dudx * scaling; - GLfloat vx = dvdx * scaling; - GLfloat uy = dudy * scaling; - GLfloat vy = dvdy * scaling; - - GLfloat Px2 = ux * ux + vx * vx; /* squared length of dx */ - GLfloat Py2 = uy * uy + vy * vy; /* squared length of dy */ - - GLint numSamples; - GLfloat ds; - GLfloat dt; - - GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F}; - GLfloat newCoord[2]; - GLint s; - - /* Calculate the per anisotropic sample offsets in s,t space. */ - if (Px2 > Py2) { - numSamples = ceil(SQRTF(Px2)); - ds = ux / ((GLfloat) img->Width2); - dt = vx / ((GLfloat) img->Height2); - } - else { - numSamples = ceil(SQRTF(Py2)); - ds = uy / ((GLfloat) img->Width2); - dt = vy / ((GLfloat) img->Height2); - } - - for (s = 0; sTexture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1; - GLuint u; - - /* XXX CoordUnits vs. ImageUnits */ - for (u = 0; u < maxUnit; u++) { - if (ctx->Texture.Unit[u]._Current == tObj) - break; /* found */ - } - if (u >= maxUnit) - u = 0; /* not found, use 1st one; should never happen */ - - return u; -} - - -/** - * Sample 2D texture using an anisotropic filter. - * NOTE: the const GLfloat lambda_iso[] parameter does *NOT* contain - * the lambda float array but a "hidden" SWspan struct which is required - * by this function but is not available in the texture_sample_func signature. - * See _swrast_texture_span( struct gl_context *ctx, SWspan *span ) on how - * this function is called. - */ -static void -sample_lambda_2d_aniso(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoords[][4], - const GLfloat lambda_iso[], GLfloat rgba[][4]) -{ - const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel]; - const GLfloat maxEccentricity = - tObj->Sampler.MaxAnisotropy * tObj->Sampler.MaxAnisotropy; - - /* re-calculate the lambda values so that they are usable with anisotropic - * filtering - */ - SWspan *span = (SWspan *)lambda_iso; /* access the "hidden" SWspan struct */ - - /* based on interpolate_texcoords(struct gl_context *ctx, SWspan *span) - * in swrast/s_span.c - */ - - /* find the texture unit index by looking up the current texture object - * from the context list of available texture objects. - */ - const GLuint u = texture_unit_index(ctx, tObj); - const GLuint attr = FRAG_ATTRIB_TEX0 + u; - GLfloat texW, texH; - - const GLfloat dsdx = span->attrStepX[attr][0]; - const GLfloat dsdy = span->attrStepY[attr][0]; - const GLfloat dtdx = span->attrStepX[attr][1]; - const GLfloat dtdy = span->attrStepY[attr][1]; - const GLfloat dqdx = span->attrStepX[attr][3]; - const GLfloat dqdy = span->attrStepY[attr][3]; - GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx; - GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx; - GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx; - - /* from swrast/s_texcombine.c _swrast_texture_span */ - const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[u]; - const GLboolean adjustLOD = - (texUnit->LodBias + tObj->Sampler.LodBias != 0.0F) - || (tObj->Sampler.MinLod != -1000.0 || tObj->Sampler.MaxLod != 1000.0); - - GLuint i; - - /* on first access create the lookup table containing the filter weights. */ - if (!weightLut) { - create_filter_table(); - } - - texW = tImg->WidthScale; - texH = tImg->HeightScale; - - for (i = 0; i < n; i++) { - const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); - - GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ); - GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ); - GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ); - GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ); - - /* note: instead of working with Px and Py, we will use the - * squared length instead, to avoid sqrt. - */ - GLfloat Px2 = dudx * dudx + dvdx * dvdx; - GLfloat Py2 = dudy * dudy + dvdy * dvdy; - - GLfloat Pmax2; - GLfloat Pmin2; - GLfloat e; - GLfloat lod; - - s += dsdx; - t += dtdx; - q += dqdx; - - if (Px2 < Py2) { - Pmax2 = Py2; - Pmin2 = Px2; - } - else { - Pmax2 = Px2; - Pmin2 = Py2; - } - - /* if the eccentricity of the ellipse is too big, scale up the shorter - * of the two vectors to limit the maximum amount of work per pixel - */ - e = Pmax2 / Pmin2; - if (e > maxEccentricity) { - /* GLfloat s=e / maxEccentricity; - minor[0] *= s; - minor[1] *= s; - Pmin2 *= s; */ - Pmin2 = Pmax2 / maxEccentricity; - } - - /* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid - * this since 0.5*log(x) = log(sqrt(x)) - */ - lod = 0.5 * LOG2(Pmin2); - - if (adjustLOD) { - /* from swrast/s_texcombine.c _swrast_texture_span */ - if (texUnit->LodBias + tObj->Sampler.LodBias != 0.0F) { - /* apply LOD bias, but don't clamp yet */ - const GLfloat bias = - CLAMP(texUnit->LodBias + tObj->Sampler.LodBias, - -ctx->Const.MaxTextureLodBias, - ctx->Const.MaxTextureLodBias); - lod += bias; - - if (tObj->Sampler.MinLod != -1000.0 || - tObj->Sampler.MaxLod != 1000.0) { - /* apply LOD clamping to lambda */ - lod = CLAMP(lod, tObj->Sampler.MinLod, tObj->Sampler.MaxLod); - } - } - } - - /* If the ellipse covers the whole image, we can - * simply return the average of the whole image. - */ - if (lod >= tObj->_MaxLevel) { - sample_2d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoords[i], rgba[i]); - } - else { - /* don't bother interpolating between multiple LODs; it doesn't - * seem to be worth the extra running time. - */ - sample_2d_ewa(ctx, tObj, texcoords[i], - dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]); - - /* unused: */ - (void) sample_2d_footprint; - /* - sample_2d_footprint(ctx, tObj, texcoords[i], - dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]); - */ - } - } -} - - - -/**********************************************************************/ -/* 3-D Texture Sampling Functions */ -/**********************************************************************/ - -/** - * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. - */ -static INLINE void -sample_3d_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[4]) -{ - const GLint width = img->Width2; /* without border, power of two */ - const GLint height = img->Height2; /* without border, power of two */ - const GLint depth = img->Depth2; /* without border, power of two */ - GLint i, j, k; - (void) ctx; - - i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); - j = nearest_texel_location(tObj->Sampler.WrapT, img, height, texcoord[1]); - k = nearest_texel_location(tObj->Sampler.WrapR, img, depth, texcoord[2]); - - if (i < 0 || i >= (GLint) img->Width || - j < 0 || j >= (GLint) img->Height || - k < 0 || k >= (GLint) img->Depth) { - /* Need this test for GL_CLAMP_TO_BORDER mode */ - get_border_color(tObj, img, rgba); - } - else { - img->FetchTexelf(img, i, j, k, rgba); - } -} - - -/** - * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. - */ -static void -sample_3d_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[4]) -{ - const GLint width = img->Width2; - const GLint height = img->Height2; - const GLint depth = img->Depth2; - GLint i0, j0, k0, i1, j1, k1; - GLbitfield useBorderColor = 0x0; - GLfloat a, b, c; - GLfloat t000[4], t010[4], t001[4], t011[4]; - GLfloat t100[4], t110[4], t101[4], t111[4]; - - linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); - linear_texel_locations(tObj->Sampler.WrapT, img, height, texcoord[1], &j0, &j1, &b); - linear_texel_locations(tObj->Sampler.WrapR, img, depth, texcoord[2], &k0, &k1, &c); - - if (img->Border) { - i0 += img->Border; - i1 += img->Border; - j0 += img->Border; - j1 += img->Border; - k0 += img->Border; - k1 += img->Border; - } - else { - /* check if sampling texture border color */ - if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; - if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; - if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; - if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; - if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT; - if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT; - } - - /* Fetch texels */ - if (useBorderColor & (I0BIT | J0BIT | K0BIT)) { - get_border_color(tObj, img, t000); - } - else { - img->FetchTexelf(img, i0, j0, k0, t000); - } - if (useBorderColor & (I1BIT | J0BIT | K0BIT)) { - get_border_color(tObj, img, t100); - } - else { - img->FetchTexelf(img, i1, j0, k0, t100); - } - if (useBorderColor & (I0BIT | J1BIT | K0BIT)) { - get_border_color(tObj, img, t010); - } - else { - img->FetchTexelf(img, i0, j1, k0, t010); - } - if (useBorderColor & (I1BIT | J1BIT | K0BIT)) { - get_border_color(tObj, img, t110); - } - else { - img->FetchTexelf(img, i1, j1, k0, t110); - } - - if (useBorderColor & (I0BIT | J0BIT | K1BIT)) { - get_border_color(tObj, img, t001); - } - else { - img->FetchTexelf(img, i0, j0, k1, t001); - } - if (useBorderColor & (I1BIT | J0BIT | K1BIT)) { - get_border_color(tObj, img, t101); - } - else { - img->FetchTexelf(img, i1, j0, k1, t101); - } - if (useBorderColor & (I0BIT | J1BIT | K1BIT)) { - get_border_color(tObj, img, t011); - } - else { - img->FetchTexelf(img, i0, j1, k1, t011); - } - if (useBorderColor & (I1BIT | J1BIT | K1BIT)) { - get_border_color(tObj, img, t111); - } - else { - img->FetchTexelf(img, i1, j1, k1, t111); - } - - /* trilinear interpolation of samples */ - lerp_rgba_3d(rgba, a, b, c, t000, t100, t010, t110, t001, t101, t011, t111); -} - - -static void -sample_3d_nearest_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4] ) -{ - GLuint i; - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_3d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); - } -} - - -static void -sample_3d_linear_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_3d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); - } -} - - -static void -sample_3d_nearest_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_3d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_3d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_3d_linear_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_3d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_3d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -/** Sample 3D texture, nearest filtering for both min/magnification */ -static void -sample_nearest_3d(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_3d_nearest(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 3D texture, linear filtering for both min/magnification */ -static void -sample_linear_3d(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_3d_linear(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 3D texture, using lambda to choose between min/magnification */ -static void -sample_lambda_3d(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint minStart, minEnd; /* texels with minification */ - GLuint magStart, magEnd; /* texels with magnification */ - GLuint i; - - ASSERT(lambda != NULL); - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - /* do the minified texels */ - GLuint m = minEnd - minStart; - switch (tObj->Sampler.MinFilter) { - case GL_NEAREST: - for (i = minStart; i < minEnd; i++) - sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = minStart; i < minEnd; i++) - sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_NEAREST_MIPMAP_NEAREST: - sample_3d_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_NEAREST: - sample_3d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_NEAREST_MIPMAP_LINEAR: - sample_3d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_LINEAR: - sample_3d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - default: - _mesa_problem(ctx, "Bad min filter in sample_3d_texture"); - return; - } - } - - if (magStart < magEnd) { - /* do the magnified texels */ - switch (tObj->Sampler.MagFilter) { - case GL_NEAREST: - for (i = magStart; i < magEnd; i++) - sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = magStart; i < magEnd; i++) - sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - default: - _mesa_problem(ctx, "Bad mag filter in sample_3d_texture"); - return; - } - } -} - - -/**********************************************************************/ -/* Texture Cube Map Sampling Functions */ -/**********************************************************************/ - -/** - * Choose one of six sides of a texture cube map given the texture - * coord (rx,ry,rz). Return pointer to corresponding array of texture - * images. - */ -static const struct gl_texture_image ** -choose_cube_face(const struct gl_texture_object *texObj, - const GLfloat texcoord[4], GLfloat newCoord[4]) -{ - /* - major axis - direction target sc tc ma - ---------- ------------------------------- --- --- --- - +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx - -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx - +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry - -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry - +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz - -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz - */ - const GLfloat rx = texcoord[0]; - const GLfloat ry = texcoord[1]; - const GLfloat rz = texcoord[2]; - const GLfloat arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz); - GLuint face; - GLfloat sc, tc, ma; - - if (arx >= ary && arx >= arz) { - if (rx >= 0.0F) { - face = FACE_POS_X; - sc = -rz; - tc = -ry; - ma = arx; - } - else { - face = FACE_NEG_X; - sc = rz; - tc = -ry; - ma = arx; - } - } - else if (ary >= arx && ary >= arz) { - if (ry >= 0.0F) { - face = FACE_POS_Y; - sc = rx; - tc = rz; - ma = ary; - } - else { - face = FACE_NEG_Y; - sc = rx; - tc = -rz; - ma = ary; - } - } - else { - if (rz > 0.0F) { - face = FACE_POS_Z; - sc = rx; - tc = -ry; - ma = arz; - } - else { - face = FACE_NEG_Z; - sc = -rx; - tc = -ry; - ma = arz; - } - } - - { - const float ima = 1.0F / ma; - newCoord[0] = ( sc * ima + 1.0F ) * 0.5F; - newCoord[1] = ( tc * ima + 1.0F ) * 0.5F; - } - - return (const struct gl_texture_image **) texObj->Image[face]; -} - - -static void -sample_nearest_cube(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint i; - (void) lambda; - for (i = 0; i < n; i++) { - const struct gl_texture_image **images; - GLfloat newCoord[4]; - images = choose_cube_face(tObj, texcoords[i], newCoord); - sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel], - newCoord, rgba[i]); - } -} - - -static void -sample_linear_cube(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - (void) lambda; - for (i = 0; i < n; i++) { - const struct gl_texture_image **images; - GLfloat newCoord[4]; - images = choose_cube_face(tObj, texcoords[i], newCoord); - sample_2d_linear(ctx, tObj, images[tObj->BaseLevel], - newCoord, rgba[i]); - } -} - - -static void -sample_cube_nearest_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - const struct gl_texture_image **images; - GLfloat newCoord[4]; - GLint level; - images = choose_cube_face(tObj, texcoord[i], newCoord); - - /* XXX we actually need to recompute lambda here based on the newCoords. - * But we would need the texcoords of adjacent fragments to compute that - * properly, and we don't have those here. - * For now, do an approximation: subtracting 1 from the chosen mipmap - * level seems to work in some test cases. - * The same adjustment is done in the next few functions. - */ - level = nearest_mipmap_level(tObj, lambda[i]); - level = MAX2(level - 1, 0); - - sample_2d_nearest(ctx, tObj, images[level], newCoord, rgba[i]); - } -} - - -static void -sample_cube_linear_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - const struct gl_texture_image **images; - GLfloat newCoord[4]; - GLint level = nearest_mipmap_level(tObj, lambda[i]); - level = MAX2(level - 1, 0); /* see comment above */ - images = choose_cube_face(tObj, texcoord[i], newCoord); - sample_2d_linear(ctx, tObj, images[level], newCoord, rgba[i]); - } -} - - -static void -sample_cube_nearest_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - const struct gl_texture_image **images; - GLfloat newCoord[4]; - GLint level = linear_mipmap_level(tObj, lambda[i]); - level = MAX2(level - 1, 0); /* see comment above */ - images = choose_cube_face(tObj, texcoord[i], newCoord); - if (level >= tObj->_MaxLevel) { - sample_2d_nearest(ctx, tObj, images[tObj->_MaxLevel], - newCoord, rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_2d_nearest(ctx, tObj, images[level ], newCoord, t0); - sample_2d_nearest(ctx, tObj, images[level+1], newCoord, t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_cube_linear_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - const struct gl_texture_image **images; - GLfloat newCoord[4]; - GLint level = linear_mipmap_level(tObj, lambda[i]); - level = MAX2(level - 1, 0); /* see comment above */ - images = choose_cube_face(tObj, texcoord[i], newCoord); - if (level >= tObj->_MaxLevel) { - sample_2d_linear(ctx, tObj, images[tObj->_MaxLevel], - newCoord, rgba[i]); - } - else { - GLfloat t0[4], t1[4]; - const GLfloat f = FRAC(lambda[i]); - sample_2d_linear(ctx, tObj, images[level ], newCoord, t0); - sample_2d_linear(ctx, tObj, images[level+1], newCoord, t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -/** Sample cube texture, using lambda to choose between min/magnification */ -static void -sample_lambda_cube(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint minStart, minEnd; /* texels with minification */ - GLuint magStart, magEnd; /* texels with magnification */ - - ASSERT(lambda != NULL); - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - /* do the minified texels */ - const GLuint m = minEnd - minStart; - switch (tObj->Sampler.MinFilter) { - case GL_NEAREST: - sample_nearest_cube(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR: - sample_linear_cube(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_NEAREST_MIPMAP_NEAREST: - sample_cube_nearest_mipmap_nearest(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_NEAREST: - sample_cube_linear_mipmap_nearest(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_NEAREST_MIPMAP_LINEAR: - sample_cube_nearest_mipmap_linear(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_LINEAR: - sample_cube_linear_mipmap_linear(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - default: - _mesa_problem(ctx, "Bad min filter in sample_lambda_cube"); - } - } - - if (magStart < magEnd) { - /* do the magnified texels */ - const GLuint m = magEnd - magStart; - switch (tObj->Sampler.MagFilter) { - case GL_NEAREST: - sample_nearest_cube(ctx, tObj, m, texcoords + magStart, - lambda + magStart, rgba + magStart); - break; - case GL_LINEAR: - sample_linear_cube(ctx, tObj, m, texcoords + magStart, - lambda + magStart, rgba + magStart); - break; - default: - _mesa_problem(ctx, "Bad mag filter in sample_lambda_cube"); - } - } -} - - -/**********************************************************************/ -/* Texture Rectangle Sampling Functions */ -/**********************************************************************/ - - -static void -sample_nearest_rect(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - const struct gl_texture_image *img = tObj->Image[0][0]; - const GLint width = img->Width; - const GLint height = img->Height; - GLuint i; - - (void) ctx; - (void) lambda; - - ASSERT(tObj->Sampler.WrapS == GL_CLAMP || - tObj->Sampler.WrapS == GL_CLAMP_TO_EDGE || - tObj->Sampler.WrapS == GL_CLAMP_TO_BORDER); - ASSERT(tObj->Sampler.WrapT == GL_CLAMP || - tObj->Sampler.WrapT == GL_CLAMP_TO_EDGE || - tObj->Sampler.WrapT == GL_CLAMP_TO_BORDER); - ASSERT(img->_BaseFormat != GL_COLOR_INDEX); - - for (i = 0; i < n; i++) { - GLint row, col; - col = clamp_rect_coord_nearest(tObj->Sampler.WrapS, texcoords[i][0], width); - row = clamp_rect_coord_nearest(tObj->Sampler.WrapT, texcoords[i][1], height); - if (col < 0 || col >= width || row < 0 || row >= height) - get_border_color(tObj, img, rgba[i]); - else - img->FetchTexelf(img, col, row, 0, rgba[i]); - } -} - - -static void -sample_linear_rect(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - const struct gl_texture_image *img = tObj->Image[0][0]; - const GLint width = img->Width; - const GLint height = img->Height; - GLuint i; - - (void) ctx; - (void) lambda; - - ASSERT(tObj->Sampler.WrapS == GL_CLAMP || - tObj->Sampler.WrapS == GL_CLAMP_TO_EDGE || - tObj->Sampler.WrapS == GL_CLAMP_TO_BORDER); - ASSERT(tObj->Sampler.WrapT == GL_CLAMP || - tObj->Sampler.WrapT == GL_CLAMP_TO_EDGE || - tObj->Sampler.WrapT == GL_CLAMP_TO_BORDER); - ASSERT(img->_BaseFormat != GL_COLOR_INDEX); - - for (i = 0; i < n; i++) { - GLint i0, j0, i1, j1; - GLfloat t00[4], t01[4], t10[4], t11[4]; - GLfloat a, b; - GLbitfield useBorderColor = 0x0; - - clamp_rect_coord_linear(tObj->Sampler.WrapS, texcoords[i][0], width, - &i0, &i1, &a); - clamp_rect_coord_linear(tObj->Sampler.WrapT, texcoords[i][1], height, - &j0, &j1, &b); - - /* compute integer rows/columns */ - if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; - if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; - if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; - if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; - - /* get four texel samples */ - if (useBorderColor & (I0BIT | J0BIT)) - get_border_color(tObj, img, t00); - else - img->FetchTexelf(img, i0, j0, 0, t00); - - if (useBorderColor & (I1BIT | J0BIT)) - get_border_color(tObj, img, t10); - else - img->FetchTexelf(img, i1, j0, 0, t10); - - if (useBorderColor & (I0BIT | J1BIT)) - get_border_color(tObj, img, t01); - else - img->FetchTexelf(img, i0, j1, 0, t01); - - if (useBorderColor & (I1BIT | J1BIT)) - get_border_color(tObj, img, t11); - else - img->FetchTexelf(img, i1, j1, 0, t11); - - lerp_rgba_2d(rgba[i], a, b, t00, t10, t01, t11); - } -} - - -/** Sample Rect texture, using lambda to choose between min/magnification */ -static void -sample_lambda_rect(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint minStart, minEnd, magStart, magEnd; - - /* We only need lambda to decide between minification and magnification. - * There is no mipmapping with rectangular textures. - */ - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - if (tObj->Sampler.MinFilter == GL_NEAREST) { - sample_nearest_rect(ctx, tObj, minEnd - minStart, - texcoords + minStart, NULL, rgba + minStart); - } - else { - sample_linear_rect(ctx, tObj, minEnd - minStart, - texcoords + minStart, NULL, rgba + minStart); - } - } - if (magStart < magEnd) { - if (tObj->Sampler.MagFilter == GL_NEAREST) { - sample_nearest_rect(ctx, tObj, magEnd - magStart, - texcoords + magStart, NULL, rgba + magStart); - } - else { - sample_linear_rect(ctx, tObj, magEnd - magStart, - texcoords + magStart, NULL, rgba + magStart); - } - } -} - - -/**********************************************************************/ -/* 2D Texture Array Sampling Functions */ -/**********************************************************************/ - -/** - * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. - */ -static void -sample_2d_array_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[4]) -{ - const GLint width = img->Width2; /* without border, power of two */ - const GLint height = img->Height2; /* without border, power of two */ - const GLint depth = img->Depth; - GLint i, j; - GLint array; - (void) ctx; - - i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); - j = nearest_texel_location(tObj->Sampler.WrapT, img, height, texcoord[1]); - array = tex_array_slice(texcoord[2], depth); - - if (i < 0 || i >= (GLint) img->Width || - j < 0 || j >= (GLint) img->Height || - array < 0 || array >= (GLint) img->Depth) { - /* Need this test for GL_CLAMP_TO_BORDER mode */ - get_border_color(tObj, img, rgba); - } - else { - img->FetchTexelf(img, i, j, array, rgba); - } -} - - -/** - * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. - */ -static void -sample_2d_array_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[4]) -{ - const GLint width = img->Width2; - const GLint height = img->Height2; - const GLint depth = img->Depth; - GLint i0, j0, i1, j1; - GLint array; - GLbitfield useBorderColor = 0x0; - GLfloat a, b; - GLfloat t00[4], t01[4], t10[4], t11[4]; - - linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); - linear_texel_locations(tObj->Sampler.WrapT, img, height, texcoord[1], &j0, &j1, &b); - array = tex_array_slice(texcoord[2], depth); - - if (array < 0 || array >= depth) { - COPY_4V(rgba, tObj->Sampler.BorderColor.f); - } - else { - if (img->Border) { - i0 += img->Border; - i1 += img->Border; - j0 += img->Border; - j1 += img->Border; - } - else { - /* check if sampling texture border color */ - if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; - if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; - if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; - if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; - } - - /* Fetch texels */ - if (useBorderColor & (I0BIT | J0BIT)) { - get_border_color(tObj, img, t00); - } - else { - img->FetchTexelf(img, i0, j0, array, t00); - } - if (useBorderColor & (I1BIT | J0BIT)) { - get_border_color(tObj, img, t10); - } - else { - img->FetchTexelf(img, i1, j0, array, t10); - } - if (useBorderColor & (I0BIT | J1BIT)) { - get_border_color(tObj, img, t01); - } - else { - img->FetchTexelf(img, i0, j1, array, t01); - } - if (useBorderColor & (I1BIT | J1BIT)) { - get_border_color(tObj, img, t11); - } - else { - img->FetchTexelf(img, i1, j1, array, t11); - } - - /* trilinear interpolation of samples */ - lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11); - } -} - - -static void -sample_2d_array_nearest_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], - rgba[i]); - } -} - - -static void -sample_2d_array_linear_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_2d_array_linear(ctx, tObj, tObj->Image[0][level], - texcoord[i], rgba[i]); - } -} - - -static void -sample_2d_array_nearest_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level ], - texcoord[i], t0); - sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level+1], - texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_2d_array_linear_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_2d_array_linear(ctx, tObj, tObj->Image[0][level ], - texcoord[i], t0); - sample_2d_array_linear(ctx, tObj, tObj->Image[0][level+1], - texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -/** Sample 2D Array texture, nearest filtering for both min/magnification */ -static void -sample_nearest_2d_array(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_2d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - - -/** Sample 2D Array texture, linear filtering for both min/magnification */ -static void -sample_linear_2d_array(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_2d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 2D Array texture, using lambda to choose between min/magnification */ -static void -sample_lambda_2d_array(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint minStart, minEnd; /* texels with minification */ - GLuint magStart, magEnd; /* texels with magnification */ - GLuint i; - - ASSERT(lambda != NULL); - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - /* do the minified texels */ - GLuint m = minEnd - minStart; - switch (tObj->Sampler.MinFilter) { - case GL_NEAREST: - for (i = minStart; i < minEnd; i++) - sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = minStart; i < minEnd; i++) - sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_NEAREST_MIPMAP_NEAREST: - sample_2d_array_nearest_mipmap_nearest(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, - rgba + minStart); - break; - case GL_LINEAR_MIPMAP_NEAREST: - sample_2d_array_linear_mipmap_nearest(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, - rgba + minStart); - break; - case GL_NEAREST_MIPMAP_LINEAR: - sample_2d_array_nearest_mipmap_linear(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, - rgba + minStart); - break; - case GL_LINEAR_MIPMAP_LINEAR: - sample_2d_array_linear_mipmap_linear(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, - rgba + minStart); - break; - default: - _mesa_problem(ctx, "Bad min filter in sample_2d_array_texture"); - return; - } - } - - if (magStart < magEnd) { - /* do the magnified texels */ - switch (tObj->Sampler.MagFilter) { - case GL_NEAREST: - for (i = magStart; i < magEnd; i++) - sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = magStart; i < magEnd; i++) - sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - default: - _mesa_problem(ctx, "Bad mag filter in sample_2d_array_texture"); - return; - } - } -} - - - - -/**********************************************************************/ -/* 1D Texture Array Sampling Functions */ -/**********************************************************************/ - -/** - * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. - */ -static void -sample_1d_array_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[4]) -{ - const GLint width = img->Width2; /* without border, power of two */ - const GLint height = img->Height; - GLint i; - GLint array; - (void) ctx; - - i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); - array = tex_array_slice(texcoord[1], height); - - if (i < 0 || i >= (GLint) img->Width || - array < 0 || array >= (GLint) img->Height) { - /* Need this test for GL_CLAMP_TO_BORDER mode */ - get_border_color(tObj, img, rgba); - } - else { - img->FetchTexelf(img, i, array, 0, rgba); - } -} - - -/** - * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. - */ -static void -sample_1d_array_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - const struct gl_texture_image *img, - const GLfloat texcoord[4], - GLfloat rgba[4]) -{ - const GLint width = img->Width2; - const GLint height = img->Height; - GLint i0, i1; - GLint array; - GLbitfield useBorderColor = 0x0; - GLfloat a; - GLfloat t0[4], t1[4]; - - linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); - array = tex_array_slice(texcoord[1], height); - - if (img->Border) { - i0 += img->Border; - i1 += img->Border; - } - else { - /* check if sampling texture border color */ - if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; - if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; - } - - if (array < 0 || array >= height) useBorderColor |= K0BIT; - - /* Fetch texels */ - if (useBorderColor & (I0BIT | K0BIT)) { - get_border_color(tObj, img, t0); - } - else { - img->FetchTexelf(img, i0, array, 0, t0); - } - if (useBorderColor & (I1BIT | K0BIT)) { - get_border_color(tObj, img, t1); - } - else { - img->FetchTexelf(img, i1, array, 0, t1); - } - - /* bilinear interpolation of samples */ - lerp_rgba(rgba, a, t0, t1); -} - - -static void -sample_1d_array_nearest_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], - rgba[i]); - } -} - - -static void -sample_1d_array_linear_mipmap_nearest(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = nearest_mipmap_level(tObj, lambda[i]); - sample_1d_array_linear(ctx, tObj, tObj->Image[0][level], - texcoord[i], rgba[i]); - } -} - - -static void -sample_1d_array_nearest_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -static void -sample_1d_array_linear_mipmap_linear(struct gl_context *ctx, - const struct gl_texture_object *tObj, - GLuint n, const GLfloat texcoord[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - ASSERT(lambda != NULL); - for (i = 0; i < n; i++) { - GLint level = linear_mipmap_level(tObj, lambda[i]); - if (level >= tObj->_MaxLevel) { - sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], - texcoord[i], rgba[i]); - } - else { - GLfloat t0[4], t1[4]; /* texels */ - const GLfloat f = FRAC(lambda[i]); - sample_1d_array_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); - sample_1d_array_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); - lerp_rgba(rgba[i], f, t0, t1); - } - } -} - - -/** Sample 1D Array texture, nearest filtering for both min/magnification */ -static void -sample_nearest_1d_array(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_1d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 1D Array texture, linear filtering for both min/magnification */ -static void -sample_linear_1d_array(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], - const GLfloat lambda[], GLfloat rgba[][4]) -{ - GLuint i; - struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; - (void) lambda; - for (i = 0; i < n; i++) { - sample_1d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]); - } -} - - -/** Sample 1D Array texture, using lambda to choose between min/magnification */ -static void -sample_lambda_1d_array(struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint minStart, minEnd; /* texels with minification */ - GLuint magStart, magEnd; /* texels with magnification */ - GLuint i; - - ASSERT(lambda != NULL); - compute_min_mag_ranges(tObj, n, lambda, - &minStart, &minEnd, &magStart, &magEnd); - - if (minStart < minEnd) { - /* do the minified texels */ - GLuint m = minEnd - minStart; - switch (tObj->Sampler.MinFilter) { - case GL_NEAREST: - for (i = minStart; i < minEnd; i++) - sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = minStart; i < minEnd; i++) - sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_NEAREST_MIPMAP_NEAREST: - sample_1d_array_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_NEAREST: - sample_1d_array_linear_mipmap_nearest(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, - rgba + minStart); - break; - case GL_NEAREST_MIPMAP_LINEAR: - sample_1d_array_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, - lambda + minStart, rgba + minStart); - break; - case GL_LINEAR_MIPMAP_LINEAR: - sample_1d_array_linear_mipmap_linear(ctx, tObj, m, - texcoords + minStart, - lambda + minStart, - rgba + minStart); - break; - default: - _mesa_problem(ctx, "Bad min filter in sample_1d_array_texture"); - return; - } - } - - if (magStart < magEnd) { - /* do the magnified texels */ - switch (tObj->Sampler.MagFilter) { - case GL_NEAREST: - for (i = magStart; i < magEnd; i++) - sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - case GL_LINEAR: - for (i = magStart; i < magEnd; i++) - sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], - texcoords[i], rgba[i]); - break; - default: - _mesa_problem(ctx, "Bad mag filter in sample_1d_array_texture"); - return; - } - } -} - - -/** - * Compare texcoord against depth sample. Return 1.0 or the ambient value. - */ -static INLINE GLfloat -shadow_compare(GLenum function, GLfloat coord, GLfloat depthSample, - GLfloat ambient) -{ - switch (function) { - case GL_LEQUAL: - return (coord <= depthSample) ? 1.0F : ambient; - case GL_GEQUAL: - return (coord >= depthSample) ? 1.0F : ambient; - case GL_LESS: - return (coord < depthSample) ? 1.0F : ambient; - case GL_GREATER: - return (coord > depthSample) ? 1.0F : ambient; - case GL_EQUAL: - return (coord == depthSample) ? 1.0F : ambient; - case GL_NOTEQUAL: - return (coord != depthSample) ? 1.0F : ambient; - case GL_ALWAYS: - return 1.0F; - case GL_NEVER: - return ambient; - case GL_NONE: - return depthSample; - default: - _mesa_problem(NULL, "Bad compare func in shadow_compare"); - return ambient; - } -} - - -/** - * Compare texcoord against four depth samples. - */ -static INLINE GLfloat -shadow_compare4(GLenum function, GLfloat coord, - GLfloat depth00, GLfloat depth01, - GLfloat depth10, GLfloat depth11, - GLfloat ambient, GLfloat wi, GLfloat wj) -{ - const GLfloat d = (1.0F - (GLfloat) ambient) * 0.25F; - GLfloat luminance = 1.0F; - - switch (function) { - case GL_LEQUAL: - if (coord > depth00) luminance -= d; - if (coord > depth01) luminance -= d; - if (coord > depth10) luminance -= d; - if (coord > depth11) luminance -= d; - return luminance; - case GL_GEQUAL: - if (coord < depth00) luminance -= d; - if (coord < depth01) luminance -= d; - if (coord < depth10) luminance -= d; - if (coord < depth11) luminance -= d; - return luminance; - case GL_LESS: - if (coord >= depth00) luminance -= d; - if (coord >= depth01) luminance -= d; - if (coord >= depth10) luminance -= d; - if (coord >= depth11) luminance -= d; - return luminance; - case GL_GREATER: - if (coord <= depth00) luminance -= d; - if (coord <= depth01) luminance -= d; - if (coord <= depth10) luminance -= d; - if (coord <= depth11) luminance -= d; - return luminance; - case GL_EQUAL: - if (coord != depth00) luminance -= d; - if (coord != depth01) luminance -= d; - if (coord != depth10) luminance -= d; - if (coord != depth11) luminance -= d; - return luminance; - case GL_NOTEQUAL: - if (coord == depth00) luminance -= d; - if (coord == depth01) luminance -= d; - if (coord == depth10) luminance -= d; - if (coord == depth11) luminance -= d; - return luminance; - case GL_ALWAYS: - return 1.0F; - case GL_NEVER: - return ambient; - case GL_NONE: - /* ordinary bilinear filtering */ - return lerp_2d(wi, wj, depth00, depth10, depth01, depth11); - default: - _mesa_problem(NULL, "Bad compare func in sample_compare4"); - return ambient; - } -} - - -/** - * Choose the mipmap level to use when sampling from a depth texture. - */ -static int -choose_depth_texture_level(const struct gl_texture_object *tObj, GLfloat lambda) -{ - GLint level; - - if (tObj->Sampler.MinFilter == GL_NEAREST || tObj->Sampler.MinFilter == GL_LINEAR) { - /* no mipmapping - use base level */ - level = tObj->BaseLevel; - } - else { - /* choose mipmap level */ - lambda = CLAMP(lambda, tObj->Sampler.MinLod, tObj->Sampler.MaxLod); - level = (GLint) lambda; - level = CLAMP(level, tObj->BaseLevel, tObj->_MaxLevel); - } - - return level; -} - - -/** - * Sample a shadow/depth texture. This function is incomplete. It doesn't - * check for minification vs. magnification, etc. - */ -static void -sample_depth_texture( struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat texel[][4] ) -{ - const GLint level = choose_depth_texture_level(tObj, lambda[0]); - const struct gl_texture_image *img = tObj->Image[0][level]; - const GLint width = img->Width; - const GLint height = img->Height; - const GLint depth = img->Depth; - const GLuint compare_coord = (tObj->Target == GL_TEXTURE_2D_ARRAY_EXT) - ? 3 : 2; - GLfloat ambient; - GLenum function; - GLfloat result; - - ASSERT(img->_BaseFormat == GL_DEPTH_COMPONENT || - img->_BaseFormat == GL_DEPTH_STENCIL_EXT); - - ASSERT(tObj->Target == GL_TEXTURE_1D || - tObj->Target == GL_TEXTURE_2D || - tObj->Target == GL_TEXTURE_RECTANGLE_NV || - tObj->Target == GL_TEXTURE_1D_ARRAY_EXT || - tObj->Target == GL_TEXTURE_2D_ARRAY_EXT); - - ambient = tObj->Sampler.CompareFailValue; - - /* XXXX if tObj->Sampler.MinFilter != tObj->Sampler.MagFilter, we're ignoring lambda */ - - function = (tObj->Sampler.CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) ? - tObj->Sampler.CompareFunc : GL_NONE; - - if (tObj->Sampler.MagFilter == GL_NEAREST) { - GLuint i; - for (i = 0; i < n; i++) { - GLfloat depthSample, depthRef; - GLint col, row, slice; - - nearest_texcoord(tObj, level, texcoords[i], &col, &row, &slice); - - if (col >= 0 && row >= 0 && col < width && row < height && - slice >= 0 && slice < depth) { - img->FetchTexelf(img, col, row, slice, &depthSample); - } - else { - depthSample = tObj->Sampler.BorderColor.f[0]; - } - - depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F); - - result = shadow_compare(function, depthRef, depthSample, ambient); - - switch (tObj->Sampler.DepthMode) { - case GL_LUMINANCE: - ASSIGN_4V(texel[i], result, result, result, 1.0F); - break; - case GL_INTENSITY: - ASSIGN_4V(texel[i], result, result, result, result); - break; - case GL_ALPHA: - ASSIGN_4V(texel[i], 0.0F, 0.0F, 0.0F, result); - break; - case GL_RED: - ASSIGN_4V(texel[i], result, 0.0F, 0.0F, 1.0F); - break; - default: - _mesa_problem(ctx, "Bad depth texture mode"); - } - } - } - else { - GLuint i; - ASSERT(tObj->Sampler.MagFilter == GL_LINEAR); - for (i = 0; i < n; i++) { - GLfloat depth00, depth01, depth10, depth11, depthRef; - GLint i0, i1, j0, j1; - GLint slice; - GLfloat wi, wj; - GLuint useBorderTexel; - - linear_texcoord(tObj, level, texcoords[i], &i0, &i1, &j0, &j1, &slice, - &wi, &wj); - - useBorderTexel = 0; - if (img->Border) { - i0 += img->Border; - i1 += img->Border; - if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) { - j0 += img->Border; - j1 += img->Border; - } - } - else { - if (i0 < 0 || i0 >= (GLint) width) useBorderTexel |= I0BIT; - if (i1 < 0 || i1 >= (GLint) width) useBorderTexel |= I1BIT; - if (j0 < 0 || j0 >= (GLint) height) useBorderTexel |= J0BIT; - if (j1 < 0 || j1 >= (GLint) height) useBorderTexel |= J1BIT; - } - - if (slice < 0 || slice >= (GLint) depth) { - depth00 = tObj->Sampler.BorderColor.f[0]; - depth01 = tObj->Sampler.BorderColor.f[0]; - depth10 = tObj->Sampler.BorderColor.f[0]; - depth11 = tObj->Sampler.BorderColor.f[0]; - } - else { - /* get four depth samples from the texture */ - if (useBorderTexel & (I0BIT | J0BIT)) { - depth00 = tObj->Sampler.BorderColor.f[0]; - } - else { - img->FetchTexelf(img, i0, j0, slice, &depth00); - } - if (useBorderTexel & (I1BIT | J0BIT)) { - depth10 = tObj->Sampler.BorderColor.f[0]; - } - else { - img->FetchTexelf(img, i1, j0, slice, &depth10); - } - - if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) { - if (useBorderTexel & (I0BIT | J1BIT)) { - depth01 = tObj->Sampler.BorderColor.f[0]; - } - else { - img->FetchTexelf(img, i0, j1, slice, &depth01); - } - if (useBorderTexel & (I1BIT | J1BIT)) { - depth11 = tObj->Sampler.BorderColor.f[0]; - } - else { - img->FetchTexelf(img, i1, j1, slice, &depth11); - } - } - else { - depth01 = depth00; - depth11 = depth10; - } - } - - depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F); - - result = shadow_compare4(function, depthRef, - depth00, depth01, depth10, depth11, - ambient, wi, wj); - - switch (tObj->Sampler.DepthMode) { - case GL_LUMINANCE: - ASSIGN_4V(texel[i], result, result, result, 1.0F); - break; - case GL_INTENSITY: - ASSIGN_4V(texel[i], result, result, result, result); - break; - case GL_ALPHA: - ASSIGN_4V(texel[i], 0.0F, 0.0F, 0.0F, result); - break; - default: - _mesa_problem(ctx, "Bad depth texture mode"); - } - - } /* for */ - } /* if filter */ -} - - -/** - * We use this function when a texture object is in an "incomplete" state. - * When a fragment program attempts to sample an incomplete texture we - * return black (see issue 23 in GL_ARB_fragment_program spec). - * Note: fragment programs don't observe the texture enable/disable flags. - */ -static void -null_sample_func( struct gl_context *ctx, - const struct gl_texture_object *tObj, GLuint n, - const GLfloat texcoords[][4], const GLfloat lambda[], - GLfloat rgba[][4]) -{ - GLuint i; - (void) ctx; - (void) tObj; - (void) texcoords; - (void) lambda; - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = 0; - rgba[i][GCOMP] = 0; - rgba[i][BCOMP] = 0; - rgba[i][ACOMP] = 1.0; - } -} - - -/** - * Choose the texture sampling function for the given texture object. - */ -texture_sample_func -_swrast_choose_texture_sample_func( struct gl_context *ctx, - const struct gl_texture_object *t ) -{ - if (!t || !t->_Complete) { - return &null_sample_func; - } - else { - const GLboolean needLambda = - (GLboolean) (t->Sampler.MinFilter != t->Sampler.MagFilter); - const GLenum format = t->Image[0][t->BaseLevel]->_BaseFormat; - - switch (t->Target) { - case GL_TEXTURE_1D: - if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { - return &sample_depth_texture; - } - else if (needLambda) { - return &sample_lambda_1d; - } - else if (t->Sampler.MinFilter == GL_LINEAR) { - return &sample_linear_1d; - } - else { - ASSERT(t->Sampler.MinFilter == GL_NEAREST); - return &sample_nearest_1d; - } - case GL_TEXTURE_2D: - if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { - return &sample_depth_texture; - } - else if (needLambda) { - /* Anisotropic filtering extension. Activated only if mipmaps are used */ - if (t->Sampler.MaxAnisotropy > 1.0 && - t->Sampler.MinFilter == GL_LINEAR_MIPMAP_LINEAR) { - return &sample_lambda_2d_aniso; - } - return &sample_lambda_2d; - } - else if (t->Sampler.MinFilter == GL_LINEAR) { - return &sample_linear_2d; - } - else { - /* check for a few optimized cases */ - const struct gl_texture_image *img = t->Image[0][t->BaseLevel]; - ASSERT(t->Sampler.MinFilter == GL_NEAREST); - if (t->Sampler.WrapS == GL_REPEAT && - t->Sampler.WrapT == GL_REPEAT && - img->_IsPowerOfTwo && - img->Border == 0 && - img->TexFormat == MESA_FORMAT_RGB888) { - return &opt_sample_rgb_2d; - } - else if (t->Sampler.WrapS == GL_REPEAT && - t->Sampler.WrapT == GL_REPEAT && - img->_IsPowerOfTwo && - img->Border == 0 && - img->TexFormat == MESA_FORMAT_RGBA8888) { - return &opt_sample_rgba_2d; - } - else { - return &sample_nearest_2d; - } - } - case GL_TEXTURE_3D: - if (needLambda) { - return &sample_lambda_3d; - } - else if (t->Sampler.MinFilter == GL_LINEAR) { - return &sample_linear_3d; - } - else { - ASSERT(t->Sampler.MinFilter == GL_NEAREST); - return &sample_nearest_3d; - } - case GL_TEXTURE_CUBE_MAP: - if (needLambda) { - return &sample_lambda_cube; - } - else if (t->Sampler.MinFilter == GL_LINEAR) { - return &sample_linear_cube; - } - else { - ASSERT(t->Sampler.MinFilter == GL_NEAREST); - return &sample_nearest_cube; - } - case GL_TEXTURE_RECTANGLE_NV: - if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { - return &sample_depth_texture; - } - else if (needLambda) { - return &sample_lambda_rect; - } - else if (t->Sampler.MinFilter == GL_LINEAR) { - return &sample_linear_rect; - } - else { - ASSERT(t->Sampler.MinFilter == GL_NEAREST); - return &sample_nearest_rect; - } - case GL_TEXTURE_1D_ARRAY_EXT: - if (needLambda) { - return &sample_lambda_1d_array; - } - else if (t->Sampler.MinFilter == GL_LINEAR) { - return &sample_linear_1d_array; - } - else { - ASSERT(t->Sampler.MinFilter == GL_NEAREST); - return &sample_nearest_1d_array; - } - case GL_TEXTURE_2D_ARRAY_EXT: - if (needLambda) { - return &sample_lambda_2d_array; - } - else if (t->Sampler.MinFilter == GL_LINEAR) { - return &sample_linear_2d_array; - } - else { - ASSERT(t->Sampler.MinFilter == GL_NEAREST); - return &sample_nearest_2d_array; - } - default: - _mesa_problem(ctx, - "invalid target in _swrast_choose_texture_sample_func"); - return &null_sample_func; - } - } -} +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * 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 + * BRIAN PAUL 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. + */ + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/colormac.h" +#include "main/imports.h" + +#include "s_context.h" +#include "s_texfilter.h" + + +/* + * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes + * see 1-pixel bands of improperly weighted linear-filtered textures. + * The tests/texwrap.c demo is a good test. + * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0. + * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x). + */ +#define FRAC(f) ((f) - IFLOOR(f)) + + + +/** + * Linear interpolation macro + */ +#define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) ) + + +/** + * Do 2D/biliner interpolation of float values. + * v00, v10, v01 and v11 are typically four texture samples in a square/box. + * a and b are the horizontal and vertical interpolants. + * It's important that this function is inlined when compiled with + * optimization! If we find that's not true on some systems, convert + * to a macro. + */ +static INLINE GLfloat +lerp_2d(GLfloat a, GLfloat b, + GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11) +{ + const GLfloat temp0 = LERP(a, v00, v10); + const GLfloat temp1 = LERP(a, v01, v11); + return LERP(b, temp0, temp1); +} + + +/** + * Do 3D/trilinear interpolation of float values. + * \sa lerp_2d + */ +static INLINE GLfloat +lerp_3d(GLfloat a, GLfloat b, GLfloat c, + GLfloat v000, GLfloat v100, GLfloat v010, GLfloat v110, + GLfloat v001, GLfloat v101, GLfloat v011, GLfloat v111) +{ + const GLfloat temp00 = LERP(a, v000, v100); + const GLfloat temp10 = LERP(a, v010, v110); + const GLfloat temp01 = LERP(a, v001, v101); + const GLfloat temp11 = LERP(a, v011, v111); + const GLfloat temp0 = LERP(b, temp00, temp10); + const GLfloat temp1 = LERP(b, temp01, temp11); + return LERP(c, temp0, temp1); +} + + +/** + * Do linear interpolation of colors. + */ +static INLINE void +lerp_rgba(GLfloat result[4], GLfloat t, const GLfloat a[4], const GLfloat b[4]) +{ + result[0] = LERP(t, a[0], b[0]); + result[1] = LERP(t, a[1], b[1]); + result[2] = LERP(t, a[2], b[2]); + result[3] = LERP(t, a[3], b[3]); +} + + +/** + * Do bilinear interpolation of colors. + */ +static INLINE void +lerp_rgba_2d(GLfloat result[4], GLfloat a, GLfloat b, + const GLfloat t00[4], const GLfloat t10[4], + const GLfloat t01[4], const GLfloat t11[4]) +{ + result[0] = lerp_2d(a, b, t00[0], t10[0], t01[0], t11[0]); + result[1] = lerp_2d(a, b, t00[1], t10[1], t01[1], t11[1]); + result[2] = lerp_2d(a, b, t00[2], t10[2], t01[2], t11[2]); + result[3] = lerp_2d(a, b, t00[3], t10[3], t01[3], t11[3]); +} + + +/** + * Do trilinear interpolation of colors. + */ +static INLINE void +lerp_rgba_3d(GLfloat result[4], GLfloat a, GLfloat b, GLfloat c, + const GLfloat t000[4], const GLfloat t100[4], + const GLfloat t010[4], const GLfloat t110[4], + const GLfloat t001[4], const GLfloat t101[4], + const GLfloat t011[4], const GLfloat t111[4]) +{ + GLuint k; + /* compiler should unroll these short loops */ + for (k = 0; k < 4; k++) { + result[k] = lerp_3d(a, b, c, t000[k], t100[k], t010[k], t110[k], + t001[k], t101[k], t011[k], t111[k]); + } +} + + +/** + * Used for GL_REPEAT wrap mode. Using A % B doesn't produce the + * right results for A<0. Casting to A to be unsigned only works if B + * is a power of two. Adding a bias to A (which is a multiple of B) + * avoids the problems with A < 0 (for reasonable A) without using a + * conditional. + */ +#define REMAINDER(A, B) (((A) + (B) * 1024) % (B)) + + +/** + * Used to compute texel locations for linear sampling. + * Input: + * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER + * s = texcoord in [0,1] + * size = width (or height or depth) of texture + * Output: + * i0, i1 = returns two nearest texel indexes + * weight = returns blend factor between texels + */ +static INLINE void +linear_texel_locations(GLenum wrapMode, + const struct gl_texture_image *img, + GLint size, GLfloat s, + GLint *i0, GLint *i1, GLfloat *weight) +{ + GLfloat u; + switch (wrapMode) { + case GL_REPEAT: + u = s * size - 0.5F; + if (img->_IsPowerOfTwo) { + *i0 = IFLOOR(u) & (size - 1); + *i1 = (*i0 + 1) & (size - 1); + } + else { + *i0 = REMAINDER(IFLOOR(u), size); + *i1 = REMAINDER(*i0 + 1, size); + } + break; + case GL_CLAMP_TO_EDGE: + if (s <= 0.0F) + u = 0.0F; + else if (s >= 1.0F) + u = (GLfloat) size; + else + u = s * size; + u -= 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + if (*i0 < 0) + *i0 = 0; + if (*i1 >= (GLint) size) + *i1 = size - 1; + break; + case GL_CLAMP_TO_BORDER: + { + const GLfloat min = -1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + if (s <= min) + u = min * size; + else if (s >= max) + u = max * size; + else + u = s * size; + u -= 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + } + break; + case GL_MIRRORED_REPEAT: + { + const GLint flr = IFLOOR(s); + if (flr & 1) + u = 1.0F - (s - (GLfloat) flr); + else + u = s - (GLfloat) flr; + u = (u * size) - 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + if (*i0 < 0) + *i0 = 0; + if (*i1 >= (GLint) size) + *i1 = size - 1; + } + break; + case GL_MIRROR_CLAMP_EXT: + u = FABSF(s); + if (u >= 1.0F) + u = (GLfloat) size; + else + u *= size; + u -= 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + break; + case GL_MIRROR_CLAMP_TO_EDGE_EXT: + u = FABSF(s); + if (u >= 1.0F) + u = (GLfloat) size; + else + u *= size; + u -= 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + if (*i0 < 0) + *i0 = 0; + if (*i1 >= (GLint) size) + *i1 = size - 1; + break; + case GL_MIRROR_CLAMP_TO_BORDER_EXT: + { + const GLfloat min = -1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + u = FABSF(s); + if (u <= min) + u = min * size; + else if (u >= max) + u = max * size; + else + u *= size; + u -= 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + } + break; + case GL_CLAMP: + if (s <= 0.0F) + u = 0.0F; + else if (s >= 1.0F) + u = (GLfloat) size; + else + u = s * size; + u -= 0.5F; + *i0 = IFLOOR(u); + *i1 = *i0 + 1; + break; + default: + _mesa_problem(NULL, "Bad wrap mode"); + u = 0.0F; + } + *weight = FRAC(u); +} + + +/** + * Used to compute texel location for nearest sampling. + */ +static INLINE GLint +nearest_texel_location(GLenum wrapMode, + const struct gl_texture_image *img, + GLint size, GLfloat s) +{ + GLint i; + + switch (wrapMode) { + case GL_REPEAT: + /* s limited to [0,1) */ + /* i limited to [0,size-1] */ + i = IFLOOR(s * size); + if (img->_IsPowerOfTwo) + i &= (size - 1); + else + i = REMAINDER(i, size); + return i; + case GL_CLAMP_TO_EDGE: + { + /* s limited to [min,max] */ + /* i limited to [0, size-1] */ + const GLfloat min = 1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + if (s < min) + i = 0; + else if (s > max) + i = size - 1; + else + i = IFLOOR(s * size); + } + return i; + case GL_CLAMP_TO_BORDER: + { + /* s limited to [min,max] */ + /* i limited to [-1, size] */ + const GLfloat min = -1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + if (s <= min) + i = -1; + else if (s >= max) + i = size; + else + i = IFLOOR(s * size); + } + return i; + case GL_MIRRORED_REPEAT: + { + const GLfloat min = 1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + const GLint flr = IFLOOR(s); + GLfloat u; + if (flr & 1) + u = 1.0F - (s - (GLfloat) flr); + else + u = s - (GLfloat) flr; + if (u < min) + i = 0; + else if (u > max) + i = size - 1; + else + i = IFLOOR(u * size); + } + return i; + case GL_MIRROR_CLAMP_EXT: + { + /* s limited to [0,1] */ + /* i limited to [0,size-1] */ + const GLfloat u = FABSF(s); + if (u <= 0.0F) + i = 0; + else if (u >= 1.0F) + i = size - 1; + else + i = IFLOOR(u * size); + } + return i; + case GL_MIRROR_CLAMP_TO_EDGE_EXT: + { + /* s limited to [min,max] */ + /* i limited to [0, size-1] */ + const GLfloat min = 1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + const GLfloat u = FABSF(s); + if (u < min) + i = 0; + else if (u > max) + i = size - 1; + else + i = IFLOOR(u * size); + } + return i; + case GL_MIRROR_CLAMP_TO_BORDER_EXT: + { + /* s limited to [min,max] */ + /* i limited to [0, size-1] */ + const GLfloat min = -1.0F / (2.0F * size); + const GLfloat max = 1.0F - min; + const GLfloat u = FABSF(s); + if (u < min) + i = -1; + else if (u > max) + i = size; + else + i = IFLOOR(u * size); + } + return i; + case GL_CLAMP: + /* s limited to [0,1] */ + /* i limited to [0,size-1] */ + if (s <= 0.0F) + i = 0; + else if (s >= 1.0F) + i = size - 1; + else + i = IFLOOR(s * size); + return i; + default: + _mesa_problem(NULL, "Bad wrap mode"); + return 0; + } +} + + +/* Power of two image sizes only */ +static INLINE void +linear_repeat_texel_location(GLuint size, GLfloat s, + GLint *i0, GLint *i1, GLfloat *weight) +{ + GLfloat u = s * size - 0.5F; + *i0 = IFLOOR(u) & (size - 1); + *i1 = (*i0 + 1) & (size - 1); + *weight = FRAC(u); +} + + +/** + * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode. + */ +static INLINE GLint +clamp_rect_coord_nearest(GLenum wrapMode, GLfloat coord, GLint max) +{ + switch (wrapMode) { + case GL_CLAMP: + return IFLOOR( CLAMP(coord, 0.0F, max - 1) ); + case GL_CLAMP_TO_EDGE: + return IFLOOR( CLAMP(coord, 0.5F, max - 0.5F) ); + case GL_CLAMP_TO_BORDER: + return IFLOOR( CLAMP(coord, -0.5F, max + 0.5F) ); + default: + _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_nearest"); + return 0; + } +} + + +/** + * As above, but GL_LINEAR filtering. + */ +static INLINE void +clamp_rect_coord_linear(GLenum wrapMode, GLfloat coord, GLint max, + GLint *i0out, GLint *i1out, GLfloat *weight) +{ + GLfloat fcol; + GLint i0, i1; + switch (wrapMode) { + case GL_CLAMP: + /* Not exactly what the spec says, but it matches NVIDIA output */ + fcol = CLAMP(coord - 0.5F, 0.0F, max - 1); + i0 = IFLOOR(fcol); + i1 = i0 + 1; + break; + case GL_CLAMP_TO_EDGE: + fcol = CLAMP(coord, 0.5F, max - 0.5F); + fcol -= 0.5F; + i0 = IFLOOR(fcol); + i1 = i0 + 1; + if (i1 > max - 1) + i1 = max - 1; + break; + case GL_CLAMP_TO_BORDER: + fcol = CLAMP(coord, -0.5F, max + 0.5F); + fcol -= 0.5F; + i0 = IFLOOR(fcol); + i1 = i0 + 1; + break; + default: + _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_linear"); + i0 = i1 = 0; + fcol = 0.0F; + } + *i0out = i0; + *i1out = i1; + *weight = FRAC(fcol); +} + + +/** + * Compute slice/image to use for 1D or 2D array texture. + */ +static INLINE GLint +tex_array_slice(GLfloat coord, GLsizei size) +{ + GLint slice = IFLOOR(coord + 0.5f); + slice = CLAMP(slice, 0, size - 1); + return slice; +} + + +/** + * Compute nearest integer texcoords for given texobj and coordinate. + * NOTE: only used for depth texture sampling. + */ +static INLINE void +nearest_texcoord(const struct gl_texture_object *texObj, + GLuint level, + const GLfloat texcoord[4], + GLint *i, GLint *j, GLint *k) +{ + const struct gl_texture_image *img = texObj->Image[0][level]; + const GLint width = img->Width; + const GLint height = img->Height; + const GLint depth = img->Depth; + + switch (texObj->Target) { + case GL_TEXTURE_RECTANGLE_ARB: + *i = clamp_rect_coord_nearest(texObj->Sampler.WrapS, texcoord[0], width); + *j = clamp_rect_coord_nearest(texObj->Sampler.WrapT, texcoord[1], height); + *k = 0; + break; + case GL_TEXTURE_1D: + *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]); + *j = 0; + *k = 0; + break; + case GL_TEXTURE_2D: + *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]); + *j = nearest_texel_location(texObj->Sampler.WrapT, img, height, texcoord[1]); + *k = 0; + break; + case GL_TEXTURE_1D_ARRAY_EXT: + *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]); + *j = tex_array_slice(texcoord[1], height); + *k = 0; + break; + case GL_TEXTURE_2D_ARRAY_EXT: + *i = nearest_texel_location(texObj->Sampler.WrapS, img, width, texcoord[0]); + *j = nearest_texel_location(texObj->Sampler.WrapT, img, height, texcoord[1]); + *k = tex_array_slice(texcoord[2], depth); + break; + default: + *i = *j = *k = 0; + } +} + + +/** + * Compute linear integer texcoords for given texobj and coordinate. + * NOTE: only used for depth texture sampling. + */ +static INLINE void +linear_texcoord(const struct gl_texture_object *texObj, + GLuint level, + const GLfloat texcoord[4], + GLint *i0, GLint *i1, GLint *j0, GLint *j1, GLint *slice, + GLfloat *wi, GLfloat *wj) +{ + const struct gl_texture_image *img = texObj->Image[0][level]; + const GLint width = img->Width; + const GLint height = img->Height; + const GLint depth = img->Depth; + + switch (texObj->Target) { + case GL_TEXTURE_RECTANGLE_ARB: + clamp_rect_coord_linear(texObj->Sampler.WrapS, texcoord[0], + width, i0, i1, wi); + clamp_rect_coord_linear(texObj->Sampler.WrapT, texcoord[1], + height, j0, j1, wj); + *slice = 0; + break; + + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + linear_texel_locations(texObj->Sampler.WrapS, img, width, + texcoord[0], i0, i1, wi); + linear_texel_locations(texObj->Sampler.WrapT, img, height, + texcoord[1], j0, j1, wj); + *slice = 0; + break; + + case GL_TEXTURE_1D_ARRAY_EXT: + linear_texel_locations(texObj->Sampler.WrapS, img, width, + texcoord[0], i0, i1, wi); + *j0 = tex_array_slice(texcoord[1], height); + *j1 = *j0; + *slice = 0; + break; + + case GL_TEXTURE_2D_ARRAY_EXT: + linear_texel_locations(texObj->Sampler.WrapS, img, width, + texcoord[0], i0, i1, wi); + linear_texel_locations(texObj->Sampler.WrapT, img, height, + texcoord[1], j0, j1, wj); + *slice = tex_array_slice(texcoord[2], depth); + break; + + default: + *slice = 0; + } +} + + + +/** + * For linear interpolation between mipmap levels N and N+1, this function + * computes N. + */ +static INLINE GLint +linear_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda) +{ + if (lambda < 0.0F) + return tObj->BaseLevel; + else if (lambda > tObj->_MaxLambda) + return (GLint) (tObj->BaseLevel + tObj->_MaxLambda); + else + return (GLint) (tObj->BaseLevel + lambda); +} + + +/** + * Compute the nearest mipmap level to take texels from. + */ +static INLINE GLint +nearest_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda) +{ + GLfloat l; + GLint level; + if (lambda <= 0.5F) + l = 0.0F; + else if (lambda > tObj->_MaxLambda + 0.4999F) + l = tObj->_MaxLambda + 0.4999F; + else + l = lambda; + level = (GLint) (tObj->BaseLevel + l + 0.5F); + if (level > tObj->_MaxLevel) + level = tObj->_MaxLevel; + return level; +} + + + +/* + * Bitflags for texture border color sampling. + */ +#define I0BIT 1 +#define I1BIT 2 +#define J0BIT 4 +#define J1BIT 8 +#define K0BIT 16 +#define K1BIT 32 + + + +/** + * The lambda[] array values are always monotonic. Either the whole span + * will be minified, magnified, or split between the two. This function + * determines the subranges in [0, n-1] that are to be minified or magnified. + */ +static INLINE void +compute_min_mag_ranges(const struct gl_texture_object *tObj, + GLuint n, const GLfloat lambda[], + GLuint *minStart, GLuint *minEnd, + GLuint *magStart, GLuint *magEnd) +{ + GLfloat minMagThresh; + + /* we shouldn't be here if minfilter == magfilter */ + ASSERT(tObj->Sampler.MinFilter != tObj->Sampler.MagFilter); + + /* This bit comes from the OpenGL spec: */ + if (tObj->Sampler.MagFilter == GL_LINEAR + && (tObj->Sampler.MinFilter == GL_NEAREST_MIPMAP_NEAREST || + tObj->Sampler.MinFilter == GL_NEAREST_MIPMAP_LINEAR)) { + minMagThresh = 0.5F; + } + else { + minMagThresh = 0.0F; + } + +#if 0 + /* DEBUG CODE: Verify that lambda[] is monotonic. + * We can't really use this because the inaccuracy in the LOG2 function + * causes this test to fail, yet the resulting texturing is correct. + */ + if (n > 1) { + GLuint i; + printf("lambda delta = %g\n", lambda[0] - lambda[n-1]); + if (lambda[0] >= lambda[n-1]) { /* decreasing */ + for (i = 0; i < n - 1; i++) { + ASSERT((GLint) (lambda[i] * 10) >= (GLint) (lambda[i+1] * 10)); + } + } + else { /* increasing */ + for (i = 0; i < n - 1; i++) { + ASSERT((GLint) (lambda[i] * 10) <= (GLint) (lambda[i+1] * 10)); + } + } + } +#endif /* DEBUG */ + + if (lambda[0] <= minMagThresh && (n <= 1 || lambda[n-1] <= minMagThresh)) { + /* magnification for whole span */ + *magStart = 0; + *magEnd = n; + *minStart = *minEnd = 0; + } + else if (lambda[0] > minMagThresh && (n <=1 || lambda[n-1] > minMagThresh)) { + /* minification for whole span */ + *minStart = 0; + *minEnd = n; + *magStart = *magEnd = 0; + } + else { + /* a mix of minification and magnification */ + GLuint i; + if (lambda[0] > minMagThresh) { + /* start with minification */ + for (i = 1; i < n; i++) { + if (lambda[i] <= minMagThresh) + break; + } + *minStart = 0; + *minEnd = i; + *magStart = i; + *magEnd = n; + } + else { + /* start with magnification */ + for (i = 1; i < n; i++) { + if (lambda[i] > minMagThresh) + break; + } + *magStart = 0; + *magEnd = i; + *minStart = i; + *minEnd = n; + } + } + +#if 0 + /* Verify the min/mag Start/End values + * We don't use this either (see above) + */ + { + GLint i; + for (i = 0; i < n; i++) { + if (lambda[i] > minMagThresh) { + /* minification */ + ASSERT(i >= *minStart); + ASSERT(i < *minEnd); + } + else { + /* magnification */ + ASSERT(i >= *magStart); + ASSERT(i < *magEnd); + } + } + } +#endif +} + + +/** + * When we sample the border color, it must be interpreted according to + * the base texture format. Ex: if the texture base format it GL_ALPHA, + * we return (0,0,0,BorderAlpha). + */ +static INLINE void +get_border_color(const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + GLfloat rgba[4]) +{ + switch (img->_BaseFormat) { + case GL_RGB: + rgba[0] = tObj->Sampler.BorderColor.f[0]; + rgba[1] = tObj->Sampler.BorderColor.f[1]; + rgba[2] = tObj->Sampler.BorderColor.f[2]; + rgba[3] = 1.0F; + break; + case GL_ALPHA: + rgba[0] = rgba[1] = rgba[2] = 0.0; + rgba[3] = tObj->Sampler.BorderColor.f[3]; + break; + case GL_LUMINANCE: + rgba[0] = rgba[1] = rgba[2] = tObj->Sampler.BorderColor.f[0]; + rgba[3] = 1.0; + break; + case GL_LUMINANCE_ALPHA: + rgba[0] = rgba[1] = rgba[2] = tObj->Sampler.BorderColor.f[0]; + rgba[3] = tObj->Sampler.BorderColor.f[3]; + break; + case GL_INTENSITY: + rgba[0] = rgba[1] = rgba[2] = rgba[3] = tObj->Sampler.BorderColor.f[0]; + break; + default: + COPY_4V(rgba, tObj->Sampler.BorderColor.f); + } +} + + +/**********************************************************************/ +/* 1-D Texture Sampling Functions */ +/**********************************************************************/ + +/** + * Return the texture sample for coordinate (s) using GL_NEAREST filter. + */ +static INLINE void +sample_1d_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], GLfloat rgba[4]) +{ + const GLint width = img->Width2; /* without border, power of two */ + GLint i; + i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); + /* skip over the border, if any */ + i += img->Border; + if (i < 0 || i >= (GLint) img->Width) { + /* Need this test for GL_CLAMP_TO_BORDER mode */ + get_border_color(tObj, img, rgba); + } + else { + img->FetchTexelf(img, i, 0, 0, rgba); + } +} + + +/** + * Return the texture sample for coordinate (s) using GL_LINEAR filter. + */ +static INLINE void +sample_1d_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], GLfloat rgba[4]) +{ + const GLint width = img->Width2; + GLint i0, i1; + GLbitfield useBorderColor = 0x0; + GLfloat a; + GLfloat t0[4], t1[4]; /* texels */ + + linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); + + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + } + else { + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + } + + /* fetch texel colors */ + if (useBorderColor & I0BIT) { + get_border_color(tObj, img, t0); + } + else { + img->FetchTexelf(img, i0, 0, 0, t0); + } + if (useBorderColor & I1BIT) { + get_border_color(tObj, img, t1); + } + else { + img->FetchTexelf(img, i1, 0, 0, t1); + } + + lerp_rgba(rgba, a, t0, t1); +} + + +static void +sample_1d_nearest_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_1d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); + } +} + + +static void +sample_1d_linear_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_1d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); + } +} + + +static void +sample_1d_nearest_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; + const GLfloat f = FRAC(lambda[i]); + sample_1d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_1d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_1d_linear_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; + const GLfloat f = FRAC(lambda[i]); + sample_1d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_1d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +/** Sample 1D texture, nearest filtering for both min/magnification */ +static void +sample_nearest_1d( struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4] ) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_1d_nearest(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 1D texture, linear filtering for both min/magnification */ +static void +sample_linear_1d( struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4] ) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_1d_linear(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 1D texture, using lambda to choose between min/magnification */ +static void +sample_lambda_1d( struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4] ) +{ + GLuint minStart, minEnd; /* texels with minification */ + GLuint magStart, magEnd; /* texels with magnification */ + GLuint i; + + ASSERT(lambda != NULL); + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + /* do the minified texels */ + const GLuint m = minEnd - minStart; + switch (tObj->Sampler.MinFilter) { + case GL_NEAREST: + for (i = minStart; i < minEnd; i++) + sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = minStart; i < minEnd; i++) + sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_1d_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_1d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_1d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_1d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + default: + _mesa_problem(ctx, "Bad min filter in sample_1d_texture"); + return; + } + } + + if (magStart < magEnd) { + /* do the magnified texels */ + switch (tObj->Sampler.MagFilter) { + case GL_NEAREST: + for (i = magStart; i < magEnd; i++) + sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = magStart; i < magEnd; i++) + sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + default: + _mesa_problem(ctx, "Bad mag filter in sample_1d_texture"); + return; + } + } +} + + +/**********************************************************************/ +/* 2-D Texture Sampling Functions */ +/**********************************************************************/ + + +/** + * Return the texture sample for coordinate (s,t) using GL_NEAREST filter. + */ +static INLINE void +sample_2d_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[]) +{ + const GLint width = img->Width2; /* without border, power of two */ + const GLint height = img->Height2; /* without border, power of two */ + GLint i, j; + (void) ctx; + + i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); + j = nearest_texel_location(tObj->Sampler.WrapT, img, height, texcoord[1]); + + /* skip over the border, if any */ + i += img->Border; + j += img->Border; + + if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height) { + /* Need this test for GL_CLAMP_TO_BORDER mode */ + get_border_color(tObj, img, rgba); + } + else { + img->FetchTexelf(img, i, j, 0, rgba); + } +} + + +/** + * Return the texture sample for coordinate (s,t) using GL_LINEAR filter. + * New sampling code contributed by Lynn Quam . + */ +static INLINE void +sample_2d_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[]) +{ + const GLint width = img->Width2; + const GLint height = img->Height2; + GLint i0, j0, i1, j1; + GLbitfield useBorderColor = 0x0; + GLfloat a, b; + GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */ + + linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); + linear_texel_locations(tObj->Sampler.WrapT, img, height, texcoord[1], &j0, &j1, &b); + + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + j0 += img->Border; + j1 += img->Border; + } + else { + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; + if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; + } + + /* fetch four texel colors */ + if (useBorderColor & (I0BIT | J0BIT)) { + get_border_color(tObj, img, t00); + } + else { + img->FetchTexelf(img, i0, j0, 0, t00); + } + if (useBorderColor & (I1BIT | J0BIT)) { + get_border_color(tObj, img, t10); + } + else { + img->FetchTexelf(img, i1, j0, 0, t10); + } + if (useBorderColor & (I0BIT | J1BIT)) { + get_border_color(tObj, img, t01); + } + else { + img->FetchTexelf(img, i0, j1, 0, t01); + } + if (useBorderColor & (I1BIT | J1BIT)) { + get_border_color(tObj, img, t11); + } + else { + img->FetchTexelf(img, i1, j1, 0, t11); + } + + lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11); +} + + +/** + * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT. + * We don't have to worry about the texture border. + */ +static INLINE void +sample_2d_linear_repeat(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[]) +{ + const GLint width = img->Width2; + const GLint height = img->Height2; + GLint i0, j0, i1, j1; + GLfloat wi, wj; + GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */ + + (void) ctx; + + ASSERT(tObj->Sampler.WrapS == GL_REPEAT); + ASSERT(tObj->Sampler.WrapT == GL_REPEAT); + ASSERT(img->Border == 0); + ASSERT(img->_IsPowerOfTwo); + + linear_repeat_texel_location(width, texcoord[0], &i0, &i1, &wi); + linear_repeat_texel_location(height, texcoord[1], &j0, &j1, &wj); + + img->FetchTexelf(img, i0, j0, 0, t00); + img->FetchTexelf(img, i1, j0, 0, t10); + img->FetchTexelf(img, i0, j1, 0, t01); + img->FetchTexelf(img, i1, j1, 0, t11); + + lerp_rgba_2d(rgba, wi, wj, t00, t10, t01, t11); +} + + +static void +sample_2d_nearest_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_2d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); + } +} + + +static void +sample_2d_linear_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_2d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); + } +} + + +static void +sample_2d_nearest_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_2d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_2d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_2d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_2d_linear_mipmap_linear( struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4] ) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_2d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_2d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_2d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_2d_linear_mipmap_linear_repeat(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + ASSERT(tObj->Sampler.WrapS == GL_REPEAT); + ASSERT(tObj->Sampler.WrapT == GL_REPEAT); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][level ], + texcoord[i], t0); + sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][level+1], + texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +/** Sample 2D texture, nearest filtering for both min/magnification */ +static void +sample_nearest_2d(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_2d_nearest(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 2D texture, linear filtering for both min/magnification */ +static void +sample_linear_2d(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + if (tObj->Sampler.WrapS == GL_REPEAT && + tObj->Sampler.WrapT == GL_REPEAT && + image->_IsPowerOfTwo && + image->Border == 0) { + for (i = 0; i < n; i++) { + sample_2d_linear_repeat(ctx, tObj, image, texcoords[i], rgba[i]); + } + } + else { + for (i = 0; i < n; i++) { + sample_2d_linear(ctx, tObj, image, texcoords[i], rgba[i]); + } + } +} + + +/** + * Optimized 2-D texture sampling: + * S and T wrap mode == GL_REPEAT + * GL_NEAREST min/mag filter + * No border, + * RowStride == Width, + * Format = GL_RGB + */ +static void +opt_sample_rgb_2d(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel]; + const GLfloat width = (GLfloat) img->Width; + const GLfloat height = (GLfloat) img->Height; + const GLint colMask = img->Width - 1; + const GLint rowMask = img->Height - 1; + const GLint shift = img->WidthLog2; + GLuint k; + (void) ctx; + (void) lambda; + ASSERT(tObj->Sampler.WrapS==GL_REPEAT); + ASSERT(tObj->Sampler.WrapT==GL_REPEAT); + ASSERT(img->Border==0); + ASSERT(img->TexFormat == MESA_FORMAT_RGB888); + ASSERT(img->_IsPowerOfTwo); + + for (k=0; kData) + 3*pos; + rgba[k][RCOMP] = UBYTE_TO_FLOAT(texel[2]); + rgba[k][GCOMP] = UBYTE_TO_FLOAT(texel[1]); + rgba[k][BCOMP] = UBYTE_TO_FLOAT(texel[0]); + rgba[k][ACOMP] = 1.0F; + } +} + + +/** + * Optimized 2-D texture sampling: + * S and T wrap mode == GL_REPEAT + * GL_NEAREST min/mag filter + * No border + * RowStride == Width, + * Format = GL_RGBA + */ +static void +opt_sample_rgba_2d(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel]; + const GLfloat width = (GLfloat) img->Width; + const GLfloat height = (GLfloat) img->Height; + const GLint colMask = img->Width - 1; + const GLint rowMask = img->Height - 1; + const GLint shift = img->WidthLog2; + GLuint i; + (void) ctx; + (void) lambda; + ASSERT(tObj->Sampler.WrapS==GL_REPEAT); + ASSERT(tObj->Sampler.WrapT==GL_REPEAT); + ASSERT(img->Border==0); + ASSERT(img->TexFormat == MESA_FORMAT_RGBA8888); + ASSERT(img->_IsPowerOfTwo); + + for (i = 0; i < n; i++) { + const GLint col = IFLOOR(texcoords[i][0] * width) & colMask; + const GLint row = IFLOOR(texcoords[i][1] * height) & rowMask; + const GLint pos = (row << shift) | col; + const GLuint texel = *((GLuint *) img->Data + pos); + rgba[i][RCOMP] = UBYTE_TO_FLOAT( (texel >> 24) ); + rgba[i][GCOMP] = UBYTE_TO_FLOAT( (texel >> 16) & 0xff ); + rgba[i][BCOMP] = UBYTE_TO_FLOAT( (texel >> 8) & 0xff ); + rgba[i][ACOMP] = UBYTE_TO_FLOAT( (texel ) & 0xff ); + } +} + + +/** Sample 2D texture, using lambda to choose between min/magnification */ +static void +sample_lambda_2d(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel]; + GLuint minStart, minEnd; /* texels with minification */ + GLuint magStart, magEnd; /* texels with magnification */ + + const GLboolean repeatNoBorderPOT = (tObj->Sampler.WrapS == GL_REPEAT) + && (tObj->Sampler.WrapT == GL_REPEAT) + && (tImg->Border == 0 && (tImg->Width == tImg->RowStride)) + && tImg->_IsPowerOfTwo; + + ASSERT(lambda != NULL); + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + /* do the minified texels */ + const GLuint m = minEnd - minStart; + switch (tObj->Sampler.MinFilter) { + case GL_NEAREST: + if (repeatNoBorderPOT) { + switch (tImg->TexFormat) { + case MESA_FORMAT_RGB888: + opt_sample_rgb_2d(ctx, tObj, m, texcoords + minStart, + NULL, rgba + minStart); + break; + case MESA_FORMAT_RGBA8888: + opt_sample_rgba_2d(ctx, tObj, m, texcoords + minStart, + NULL, rgba + minStart); + break; + default: + sample_nearest_2d(ctx, tObj, m, texcoords + minStart, + NULL, rgba + minStart ); + } + } + else { + sample_nearest_2d(ctx, tObj, m, texcoords + minStart, + NULL, rgba + minStart); + } + break; + case GL_LINEAR: + sample_linear_2d(ctx, tObj, m, texcoords + minStart, + NULL, rgba + minStart); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_2d_nearest_mipmap_nearest(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_2d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_2d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_LINEAR: + if (repeatNoBorderPOT) + sample_2d_linear_mipmap_linear_repeat(ctx, tObj, m, + texcoords + minStart, lambda + minStart, rgba + minStart); + else + sample_2d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + default: + _mesa_problem(ctx, "Bad min filter in sample_2d_texture"); + return; + } + } + + if (magStart < magEnd) { + /* do the magnified texels */ + const GLuint m = magEnd - magStart; + + switch (tObj->Sampler.MagFilter) { + case GL_NEAREST: + if (repeatNoBorderPOT) { + switch (tImg->TexFormat) { + case MESA_FORMAT_RGB888: + opt_sample_rgb_2d(ctx, tObj, m, texcoords + magStart, + NULL, rgba + magStart); + break; + case MESA_FORMAT_RGBA8888: + opt_sample_rgba_2d(ctx, tObj, m, texcoords + magStart, + NULL, rgba + magStart); + break; + default: + sample_nearest_2d(ctx, tObj, m, texcoords + magStart, + NULL, rgba + magStart ); + } + } + else { + sample_nearest_2d(ctx, tObj, m, texcoords + magStart, + NULL, rgba + magStart); + } + break; + case GL_LINEAR: + sample_linear_2d(ctx, tObj, m, texcoords + magStart, + NULL, rgba + magStart); + break; + default: + _mesa_problem(ctx, "Bad mag filter in sample_lambda_2d"); + } + } +} + + +/* For anisotropic filtering */ +#define WEIGHT_LUT_SIZE 1024 + +static GLfloat *weightLut = NULL; + +/** + * Creates the look-up table used to speed-up EWA sampling + */ +static void +create_filter_table(void) +{ + GLuint i; + if (!weightLut) { + weightLut = (GLfloat *) malloc(WEIGHT_LUT_SIZE * sizeof(GLfloat)); + + for (i = 0; i < WEIGHT_LUT_SIZE; ++i) { + GLfloat alpha = 2; + GLfloat r2 = (GLfloat) i / (GLfloat) (WEIGHT_LUT_SIZE - 1); + GLfloat weight = (GLfloat) exp(-alpha * r2); + weightLut[i] = weight; + } + } +} + + +/** + * Elliptical weighted average (EWA) filter for producing high quality + * anisotropic filtered results. + * Based on the Higher Quality Elliptical Weighted Avarage Filter + * published by Paul S. Heckbert in his Master's Thesis + * "Fundamentals of Texture Mapping and Image Warping" (1989) + */ +static void +sample_2d_ewa(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const GLfloat texcoord[4], + const GLfloat dudx, const GLfloat dvdx, + const GLfloat dudy, const GLfloat dvdy, const GLint lod, + GLfloat rgba[]) +{ + GLint level = lod > 0 ? lod : 0; + GLfloat scaling = 1.0 / (1 << level); + const struct gl_texture_image *img = tObj->Image[0][level]; + const struct gl_texture_image *mostDetailedImage = + tObj->Image[0][tObj->BaseLevel]; + GLfloat tex_u=-0.5 + texcoord[0] * mostDetailedImage->WidthScale * scaling; + GLfloat tex_v=-0.5 + texcoord[1] * mostDetailedImage->HeightScale * scaling; + + GLfloat ux = dudx * scaling; + GLfloat vx = dvdx * scaling; + GLfloat uy = dudy * scaling; + GLfloat vy = dvdy * scaling; + + /* compute ellipse coefficients to bound the region: + * A*x*x + B*x*y + C*y*y = F. + */ + GLfloat A = vx*vx+vy*vy+1; + GLfloat B = -2*(ux*vx+uy*vy); + GLfloat C = ux*ux+uy*uy+1; + GLfloat F = A*C-B*B/4.0; + + /* check if it is an ellipse */ + /* ASSERT(F > 0.0); */ + + /* Compute the ellipse's (u,v) bounding box in texture space */ + GLfloat d = -B*B+4.0*C*A; + GLfloat box_u = 2.0 / d * sqrt(d*C*F); /* box_u -> half of bbox with */ + GLfloat box_v = 2.0 / d * sqrt(A*d*F); /* box_v -> half of bbox height */ + + GLint u0 = floor(tex_u - box_u); + GLint u1 = ceil (tex_u + box_u); + GLint v0 = floor(tex_v - box_v); + GLint v1 = ceil (tex_v + box_v); + + GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F}; + GLfloat newCoord[2]; + GLfloat den = 0.0F; + GLfloat ddq; + GLfloat U = u0 - tex_u; + GLint v; + + /* Scale ellipse formula to directly index the Filter Lookup Table. + * i.e. scale so that F = WEIGHT_LUT_SIZE-1 + */ + double formScale = (double) (WEIGHT_LUT_SIZE - 1) / F; + A *= formScale; + B *= formScale; + C *= formScale; + /* F *= formScale; */ /* no need to scale F as we don't use it below here */ + + /* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse + * and incrementally update the value of Ax^2+Bxy*Cy^2; when this + * value, q, is less than F, we're inside the ellipse + */ + ddq = 2 * A; + for (v = v0; v <= v1; ++v) { + GLfloat V = v - tex_v; + GLfloat dq = A * (2 * U + 1) + B * V; + GLfloat q = (C * V + B * U) * V + A * U * U; + + GLint u; + for (u = u0; u <= u1; ++u) { + /* Note that the ellipse has been pre-scaled so F = WEIGHT_LUT_SIZE - 1 */ + if (q < WEIGHT_LUT_SIZE) { + /* as a LUT is used, q must never be negative; + * should not happen, though + */ + const GLint qClamped = q >= 0.0F ? q : 0; + GLfloat weight = weightLut[qClamped]; + + newCoord[0] = u / ((GLfloat) img->Width2); + newCoord[1] = v / ((GLfloat) img->Height2); + + sample_2d_nearest(ctx, tObj, img, newCoord, rgba); + num[0] += weight * rgba[0]; + num[1] += weight * rgba[1]; + num[2] += weight * rgba[2]; + num[3] += weight * rgba[3]; + + den += weight; + } + q += dq; + dq += ddq; + } + } + + if (den <= 0.0F) { + /* Reaching this place would mean + * that no pixels intersected the ellipse. + * This should never happen because + * the filter we use always + * intersects at least one pixel. + */ + + /*rgba[0]=0; + rgba[1]=0; + rgba[2]=0; + rgba[3]=0;*/ + /* not enough pixels in resampling, resort to direct interpolation */ + sample_2d_linear(ctx, tObj, img, texcoord, rgba); + return; + } + + rgba[0] = num[0] / den; + rgba[1] = num[1] / den; + rgba[2] = num[2] / den; + rgba[3] = num[3] / den; +} + + +/** + * Anisotropic filtering using footprint assembly as outlined in the + * EXT_texture_filter_anisotropic spec: + * http://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt + * Faster than EWA but has less quality (more aliasing effects) + */ +static void +sample_2d_footprint(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const GLfloat texcoord[4], + const GLfloat dudx, const GLfloat dvdx, + const GLfloat dudy, const GLfloat dvdy, const GLint lod, + GLfloat rgba[]) +{ + GLint level = lod > 0 ? lod : 0; + GLfloat scaling = 1.0F / (1 << level); + const struct gl_texture_image *img = tObj->Image[0][level]; + + GLfloat ux = dudx * scaling; + GLfloat vx = dvdx * scaling; + GLfloat uy = dudy * scaling; + GLfloat vy = dvdy * scaling; + + GLfloat Px2 = ux * ux + vx * vx; /* squared length of dx */ + GLfloat Py2 = uy * uy + vy * vy; /* squared length of dy */ + + GLint numSamples; + GLfloat ds; + GLfloat dt; + + GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F}; + GLfloat newCoord[2]; + GLint s; + + /* Calculate the per anisotropic sample offsets in s,t space. */ + if (Px2 > Py2) { + numSamples = ceil(SQRTF(Px2)); + ds = ux / ((GLfloat) img->Width2); + dt = vx / ((GLfloat) img->Height2); + } + else { + numSamples = ceil(SQRTF(Py2)); + ds = uy / ((GLfloat) img->Width2); + dt = vy / ((GLfloat) img->Height2); + } + + for (s = 0; sTexture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1; + GLuint u; + + /* XXX CoordUnits vs. ImageUnits */ + for (u = 0; u < maxUnit; u++) { + if (ctx->Texture.Unit[u]._Current == tObj) + break; /* found */ + } + if (u >= maxUnit) + u = 0; /* not found, use 1st one; should never happen */ + + return u; +} + + +/** + * Sample 2D texture using an anisotropic filter. + * NOTE: the const GLfloat lambda_iso[] parameter does *NOT* contain + * the lambda float array but a "hidden" SWspan struct which is required + * by this function but is not available in the texture_sample_func signature. + * See _swrast_texture_span( struct gl_context *ctx, SWspan *span ) on how + * this function is called. + */ +static void +sample_lambda_2d_aniso(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoords[][4], + const GLfloat lambda_iso[], GLfloat rgba[][4]) +{ + const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel]; + const GLfloat maxEccentricity = + tObj->Sampler.MaxAnisotropy * tObj->Sampler.MaxAnisotropy; + + /* re-calculate the lambda values so that they are usable with anisotropic + * filtering + */ + SWspan *span = (SWspan *)lambda_iso; /* access the "hidden" SWspan struct */ + + /* based on interpolate_texcoords(struct gl_context *ctx, SWspan *span) + * in swrast/s_span.c + */ + + /* find the texture unit index by looking up the current texture object + * from the context list of available texture objects. + */ + const GLuint u = texture_unit_index(ctx, tObj); + const GLuint attr = FRAG_ATTRIB_TEX0 + u; + GLfloat texW, texH; + + const GLfloat dsdx = span->attrStepX[attr][0]; + const GLfloat dsdy = span->attrStepY[attr][0]; + const GLfloat dtdx = span->attrStepX[attr][1]; + const GLfloat dtdy = span->attrStepY[attr][1]; + const GLfloat dqdx = span->attrStepX[attr][3]; + const GLfloat dqdy = span->attrStepY[attr][3]; + GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx; + GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx; + GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx; + + /* from swrast/s_texcombine.c _swrast_texture_span */ + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[u]; + const GLboolean adjustLOD = + (texUnit->LodBias + tObj->Sampler.LodBias != 0.0F) + || (tObj->Sampler.MinLod != -1000.0 || tObj->Sampler.MaxLod != 1000.0); + + GLuint i; + + /* on first access create the lookup table containing the filter weights. */ + if (!weightLut) { + create_filter_table(); + } + + texW = tImg->WidthScale; + texH = tImg->HeightScale; + + for (i = 0; i < n; i++) { + const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q); + + GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ); + GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ); + GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ); + GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ); + + /* note: instead of working with Px and Py, we will use the + * squared length instead, to avoid sqrt. + */ + GLfloat Px2 = dudx * dudx + dvdx * dvdx; + GLfloat Py2 = dudy * dudy + dvdy * dvdy; + + GLfloat Pmax2; + GLfloat Pmin2; + GLfloat e; + GLfloat lod; + + s += dsdx; + t += dtdx; + q += dqdx; + + if (Px2 < Py2) { + Pmax2 = Py2; + Pmin2 = Px2; + } + else { + Pmax2 = Px2; + Pmin2 = Py2; + } + + /* if the eccentricity of the ellipse is too big, scale up the shorter + * of the two vectors to limit the maximum amount of work per pixel + */ + e = Pmax2 / Pmin2; + if (e > maxEccentricity) { + /* GLfloat s=e / maxEccentricity; + minor[0] *= s; + minor[1] *= s; + Pmin2 *= s; */ + Pmin2 = Pmax2 / maxEccentricity; + } + + /* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid + * this since 0.5*log(x) = log(sqrt(x)) + */ + lod = 0.5 * LOG2(Pmin2); + + if (adjustLOD) { + /* from swrast/s_texcombine.c _swrast_texture_span */ + if (texUnit->LodBias + tObj->Sampler.LodBias != 0.0F) { + /* apply LOD bias, but don't clamp yet */ + const GLfloat bias = + CLAMP(texUnit->LodBias + tObj->Sampler.LodBias, + -ctx->Const.MaxTextureLodBias, + ctx->Const.MaxTextureLodBias); + lod += bias; + + if (tObj->Sampler.MinLod != -1000.0 || + tObj->Sampler.MaxLod != 1000.0) { + /* apply LOD clamping to lambda */ + lod = CLAMP(lod, tObj->Sampler.MinLod, tObj->Sampler.MaxLod); + } + } + } + + /* If the ellipse covers the whole image, we can + * simply return the average of the whole image. + */ + if (lod >= tObj->_MaxLevel) { + sample_2d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoords[i], rgba[i]); + } + else { + /* don't bother interpolating between multiple LODs; it doesn't + * seem to be worth the extra running time. + */ + sample_2d_ewa(ctx, tObj, texcoords[i], + dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]); + + /* unused: */ + (void) sample_2d_footprint; + /* + sample_2d_footprint(ctx, tObj, texcoords[i], + dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]); + */ + } + } +} + + + +/**********************************************************************/ +/* 3-D Texture Sampling Functions */ +/**********************************************************************/ + +/** + * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. + */ +static INLINE void +sample_3d_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[4]) +{ + const GLint width = img->Width2; /* without border, power of two */ + const GLint height = img->Height2; /* without border, power of two */ + const GLint depth = img->Depth2; /* without border, power of two */ + GLint i, j, k; + (void) ctx; + + i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); + j = nearest_texel_location(tObj->Sampler.WrapT, img, height, texcoord[1]); + k = nearest_texel_location(tObj->Sampler.WrapR, img, depth, texcoord[2]); + + if (i < 0 || i >= (GLint) img->Width || + j < 0 || j >= (GLint) img->Height || + k < 0 || k >= (GLint) img->Depth) { + /* Need this test for GL_CLAMP_TO_BORDER mode */ + get_border_color(tObj, img, rgba); + } + else { + img->FetchTexelf(img, i, j, k, rgba); + } +} + + +/** + * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. + */ +static void +sample_3d_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[4]) +{ + const GLint width = img->Width2; + const GLint height = img->Height2; + const GLint depth = img->Depth2; + GLint i0, j0, k0, i1, j1, k1; + GLbitfield useBorderColor = 0x0; + GLfloat a, b, c; + GLfloat t000[4], t010[4], t001[4], t011[4]; + GLfloat t100[4], t110[4], t101[4], t111[4]; + + linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); + linear_texel_locations(tObj->Sampler.WrapT, img, height, texcoord[1], &j0, &j1, &b); + linear_texel_locations(tObj->Sampler.WrapR, img, depth, texcoord[2], &k0, &k1, &c); + + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + j0 += img->Border; + j1 += img->Border; + k0 += img->Border; + k1 += img->Border; + } + else { + /* check if sampling texture border color */ + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; + if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; + if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT; + if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT; + } + + /* Fetch texels */ + if (useBorderColor & (I0BIT | J0BIT | K0BIT)) { + get_border_color(tObj, img, t000); + } + else { + img->FetchTexelf(img, i0, j0, k0, t000); + } + if (useBorderColor & (I1BIT | J0BIT | K0BIT)) { + get_border_color(tObj, img, t100); + } + else { + img->FetchTexelf(img, i1, j0, k0, t100); + } + if (useBorderColor & (I0BIT | J1BIT | K0BIT)) { + get_border_color(tObj, img, t010); + } + else { + img->FetchTexelf(img, i0, j1, k0, t010); + } + if (useBorderColor & (I1BIT | J1BIT | K0BIT)) { + get_border_color(tObj, img, t110); + } + else { + img->FetchTexelf(img, i1, j1, k0, t110); + } + + if (useBorderColor & (I0BIT | J0BIT | K1BIT)) { + get_border_color(tObj, img, t001); + } + else { + img->FetchTexelf(img, i0, j0, k1, t001); + } + if (useBorderColor & (I1BIT | J0BIT | K1BIT)) { + get_border_color(tObj, img, t101); + } + else { + img->FetchTexelf(img, i1, j0, k1, t101); + } + if (useBorderColor & (I0BIT | J1BIT | K1BIT)) { + get_border_color(tObj, img, t011); + } + else { + img->FetchTexelf(img, i0, j1, k1, t011); + } + if (useBorderColor & (I1BIT | J1BIT | K1BIT)) { + get_border_color(tObj, img, t111); + } + else { + img->FetchTexelf(img, i1, j1, k1, t111); + } + + /* trilinear interpolation of samples */ + lerp_rgba_3d(rgba, a, b, c, t000, t100, t010, t110, t001, t101, t011, t111); +} + + +static void +sample_3d_nearest_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4] ) +{ + GLuint i; + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_3d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); + } +} + + +static void +sample_3d_linear_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_3d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]); + } +} + + +static void +sample_3d_nearest_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_3d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_3d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_3d_linear_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_3d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_3d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +/** Sample 3D texture, nearest filtering for both min/magnification */ +static void +sample_nearest_3d(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_3d_nearest(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 3D texture, linear filtering for both min/magnification */ +static void +sample_linear_3d(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_3d_linear(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 3D texture, using lambda to choose between min/magnification */ +static void +sample_lambda_3d(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint minStart, minEnd; /* texels with minification */ + GLuint magStart, magEnd; /* texels with magnification */ + GLuint i; + + ASSERT(lambda != NULL); + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + /* do the minified texels */ + GLuint m = minEnd - minStart; + switch (tObj->Sampler.MinFilter) { + case GL_NEAREST: + for (i = minStart; i < minEnd; i++) + sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = minStart; i < minEnd; i++) + sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_3d_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_3d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_3d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_3d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + default: + _mesa_problem(ctx, "Bad min filter in sample_3d_texture"); + return; + } + } + + if (magStart < magEnd) { + /* do the magnified texels */ + switch (tObj->Sampler.MagFilter) { + case GL_NEAREST: + for (i = magStart; i < magEnd; i++) + sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = magStart; i < magEnd; i++) + sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + default: + _mesa_problem(ctx, "Bad mag filter in sample_3d_texture"); + return; + } + } +} + + +/**********************************************************************/ +/* Texture Cube Map Sampling Functions */ +/**********************************************************************/ + +/** + * Choose one of six sides of a texture cube map given the texture + * coord (rx,ry,rz). Return pointer to corresponding array of texture + * images. + */ +static const struct gl_texture_image ** +choose_cube_face(const struct gl_texture_object *texObj, + const GLfloat texcoord[4], GLfloat newCoord[4]) +{ + /* + major axis + direction target sc tc ma + ---------- ------------------------------- --- --- --- + +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx + -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx + +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry + -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry + +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz + -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz + */ + const GLfloat rx = texcoord[0]; + const GLfloat ry = texcoord[1]; + const GLfloat rz = texcoord[2]; + const GLfloat arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz); + GLuint face; + GLfloat sc, tc, ma; + + if (arx >= ary && arx >= arz) { + if (rx >= 0.0F) { + face = FACE_POS_X; + sc = -rz; + tc = -ry; + ma = arx; + } + else { + face = FACE_NEG_X; + sc = rz; + tc = -ry; + ma = arx; + } + } + else if (ary >= arx && ary >= arz) { + if (ry >= 0.0F) { + face = FACE_POS_Y; + sc = rx; + tc = rz; + ma = ary; + } + else { + face = FACE_NEG_Y; + sc = rx; + tc = -rz; + ma = ary; + } + } + else { + if (rz > 0.0F) { + face = FACE_POS_Z; + sc = rx; + tc = -ry; + ma = arz; + } + else { + face = FACE_NEG_Z; + sc = -rx; + tc = -ry; + ma = arz; + } + } + + { + const float ima = 1.0F / ma; + newCoord[0] = ( sc * ima + 1.0F ) * 0.5F; + newCoord[1] = ( tc * ima + 1.0F ) * 0.5F; + } + + return (const struct gl_texture_image **) texObj->Image[face]; +} + + +static void +sample_nearest_cube(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint i; + (void) lambda; + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newCoord[4]; + images = choose_cube_face(tObj, texcoords[i], newCoord); + sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel], + newCoord, rgba[i]); + } +} + + +static void +sample_linear_cube(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + (void) lambda; + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newCoord[4]; + images = choose_cube_face(tObj, texcoords[i], newCoord); + sample_2d_linear(ctx, tObj, images[tObj->BaseLevel], + newCoord, rgba[i]); + } +} + + +static void +sample_cube_nearest_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newCoord[4]; + GLint level; + images = choose_cube_face(tObj, texcoord[i], newCoord); + + /* XXX we actually need to recompute lambda here based on the newCoords. + * But we would need the texcoords of adjacent fragments to compute that + * properly, and we don't have those here. + * For now, do an approximation: subtracting 1 from the chosen mipmap + * level seems to work in some test cases. + * The same adjustment is done in the next few functions. + */ + level = nearest_mipmap_level(tObj, lambda[i]); + level = MAX2(level - 1, 0); + + sample_2d_nearest(ctx, tObj, images[level], newCoord, rgba[i]); + } +} + + +static void +sample_cube_linear_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newCoord[4]; + GLint level = nearest_mipmap_level(tObj, lambda[i]); + level = MAX2(level - 1, 0); /* see comment above */ + images = choose_cube_face(tObj, texcoord[i], newCoord); + sample_2d_linear(ctx, tObj, images[level], newCoord, rgba[i]); + } +} + + +static void +sample_cube_nearest_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newCoord[4]; + GLint level = linear_mipmap_level(tObj, lambda[i]); + level = MAX2(level - 1, 0); /* see comment above */ + images = choose_cube_face(tObj, texcoord[i], newCoord); + if (level >= tObj->_MaxLevel) { + sample_2d_nearest(ctx, tObj, images[tObj->_MaxLevel], + newCoord, rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_2d_nearest(ctx, tObj, images[level ], newCoord, t0); + sample_2d_nearest(ctx, tObj, images[level+1], newCoord, t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_cube_linear_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newCoord[4]; + GLint level = linear_mipmap_level(tObj, lambda[i]); + level = MAX2(level - 1, 0); /* see comment above */ + images = choose_cube_face(tObj, texcoord[i], newCoord); + if (level >= tObj->_MaxLevel) { + sample_2d_linear(ctx, tObj, images[tObj->_MaxLevel], + newCoord, rgba[i]); + } + else { + GLfloat t0[4], t1[4]; + const GLfloat f = FRAC(lambda[i]); + sample_2d_linear(ctx, tObj, images[level ], newCoord, t0); + sample_2d_linear(ctx, tObj, images[level+1], newCoord, t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +/** Sample cube texture, using lambda to choose between min/magnification */ +static void +sample_lambda_cube(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint minStart, minEnd; /* texels with minification */ + GLuint magStart, magEnd; /* texels with magnification */ + + ASSERT(lambda != NULL); + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + /* do the minified texels */ + const GLuint m = minEnd - minStart; + switch (tObj->Sampler.MinFilter) { + case GL_NEAREST: + sample_nearest_cube(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR: + sample_linear_cube(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_cube_nearest_mipmap_nearest(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_cube_linear_mipmap_nearest(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_cube_nearest_mipmap_linear(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_cube_linear_mipmap_linear(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + default: + _mesa_problem(ctx, "Bad min filter in sample_lambda_cube"); + } + } + + if (magStart < magEnd) { + /* do the magnified texels */ + const GLuint m = magEnd - magStart; + switch (tObj->Sampler.MagFilter) { + case GL_NEAREST: + sample_nearest_cube(ctx, tObj, m, texcoords + magStart, + lambda + magStart, rgba + magStart); + break; + case GL_LINEAR: + sample_linear_cube(ctx, tObj, m, texcoords + magStart, + lambda + magStart, rgba + magStart); + break; + default: + _mesa_problem(ctx, "Bad mag filter in sample_lambda_cube"); + } + } +} + + +/**********************************************************************/ +/* Texture Rectangle Sampling Functions */ +/**********************************************************************/ + + +static void +sample_nearest_rect(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + const struct gl_texture_image *img = tObj->Image[0][0]; + const GLint width = img->Width; + const GLint height = img->Height; + GLuint i; + + (void) ctx; + (void) lambda; + + ASSERT(tObj->Sampler.WrapS == GL_CLAMP || + tObj->Sampler.WrapS == GL_CLAMP_TO_EDGE || + tObj->Sampler.WrapS == GL_CLAMP_TO_BORDER); + ASSERT(tObj->Sampler.WrapT == GL_CLAMP || + tObj->Sampler.WrapT == GL_CLAMP_TO_EDGE || + tObj->Sampler.WrapT == GL_CLAMP_TO_BORDER); + + for (i = 0; i < n; i++) { + GLint row, col; + col = clamp_rect_coord_nearest(tObj->Sampler.WrapS, texcoords[i][0], width); + row = clamp_rect_coord_nearest(tObj->Sampler.WrapT, texcoords[i][1], height); + if (col < 0 || col >= width || row < 0 || row >= height) + get_border_color(tObj, img, rgba[i]); + else + img->FetchTexelf(img, col, row, 0, rgba[i]); + } +} + + +static void +sample_linear_rect(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + const struct gl_texture_image *img = tObj->Image[0][0]; + const GLint width = img->Width; + const GLint height = img->Height; + GLuint i; + + (void) ctx; + (void) lambda; + + ASSERT(tObj->Sampler.WrapS == GL_CLAMP || + tObj->Sampler.WrapS == GL_CLAMP_TO_EDGE || + tObj->Sampler.WrapS == GL_CLAMP_TO_BORDER); + ASSERT(tObj->Sampler.WrapT == GL_CLAMP || + tObj->Sampler.WrapT == GL_CLAMP_TO_EDGE || + tObj->Sampler.WrapT == GL_CLAMP_TO_BORDER); + + for (i = 0; i < n; i++) { + GLint i0, j0, i1, j1; + GLfloat t00[4], t01[4], t10[4], t11[4]; + GLfloat a, b; + GLbitfield useBorderColor = 0x0; + + clamp_rect_coord_linear(tObj->Sampler.WrapS, texcoords[i][0], width, + &i0, &i1, &a); + clamp_rect_coord_linear(tObj->Sampler.WrapT, texcoords[i][1], height, + &j0, &j1, &b); + + /* compute integer rows/columns */ + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; + if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; + + /* get four texel samples */ + if (useBorderColor & (I0BIT | J0BIT)) + get_border_color(tObj, img, t00); + else + img->FetchTexelf(img, i0, j0, 0, t00); + + if (useBorderColor & (I1BIT | J0BIT)) + get_border_color(tObj, img, t10); + else + img->FetchTexelf(img, i1, j0, 0, t10); + + if (useBorderColor & (I0BIT | J1BIT)) + get_border_color(tObj, img, t01); + else + img->FetchTexelf(img, i0, j1, 0, t01); + + if (useBorderColor & (I1BIT | J1BIT)) + get_border_color(tObj, img, t11); + else + img->FetchTexelf(img, i1, j1, 0, t11); + + lerp_rgba_2d(rgba[i], a, b, t00, t10, t01, t11); + } +} + + +/** Sample Rect texture, using lambda to choose between min/magnification */ +static void +sample_lambda_rect(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint minStart, minEnd, magStart, magEnd; + + /* We only need lambda to decide between minification and magnification. + * There is no mipmapping with rectangular textures. + */ + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + if (tObj->Sampler.MinFilter == GL_NEAREST) { + sample_nearest_rect(ctx, tObj, minEnd - minStart, + texcoords + minStart, NULL, rgba + minStart); + } + else { + sample_linear_rect(ctx, tObj, minEnd - minStart, + texcoords + minStart, NULL, rgba + minStart); + } + } + if (magStart < magEnd) { + if (tObj->Sampler.MagFilter == GL_NEAREST) { + sample_nearest_rect(ctx, tObj, magEnd - magStart, + texcoords + magStart, NULL, rgba + magStart); + } + else { + sample_linear_rect(ctx, tObj, magEnd - magStart, + texcoords + magStart, NULL, rgba + magStart); + } + } +} + + +/**********************************************************************/ +/* 2D Texture Array Sampling Functions */ +/**********************************************************************/ + +/** + * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. + */ +static void +sample_2d_array_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[4]) +{ + const GLint width = img->Width2; /* without border, power of two */ + const GLint height = img->Height2; /* without border, power of two */ + const GLint depth = img->Depth; + GLint i, j; + GLint array; + (void) ctx; + + i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); + j = nearest_texel_location(tObj->Sampler.WrapT, img, height, texcoord[1]); + array = tex_array_slice(texcoord[2], depth); + + if (i < 0 || i >= (GLint) img->Width || + j < 0 || j >= (GLint) img->Height || + array < 0 || array >= (GLint) img->Depth) { + /* Need this test for GL_CLAMP_TO_BORDER mode */ + get_border_color(tObj, img, rgba); + } + else { + img->FetchTexelf(img, i, j, array, rgba); + } +} + + +/** + * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. + */ +static void +sample_2d_array_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[4]) +{ + const GLint width = img->Width2; + const GLint height = img->Height2; + const GLint depth = img->Depth; + GLint i0, j0, i1, j1; + GLint array; + GLbitfield useBorderColor = 0x0; + GLfloat a, b; + GLfloat t00[4], t01[4], t10[4], t11[4]; + + linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); + linear_texel_locations(tObj->Sampler.WrapT, img, height, texcoord[1], &j0, &j1, &b); + array = tex_array_slice(texcoord[2], depth); + + if (array < 0 || array >= depth) { + COPY_4V(rgba, tObj->Sampler.BorderColor.f); + } + else { + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + j0 += img->Border; + j1 += img->Border; + } + else { + /* check if sampling texture border color */ + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; + if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; + } + + /* Fetch texels */ + if (useBorderColor & (I0BIT | J0BIT)) { + get_border_color(tObj, img, t00); + } + else { + img->FetchTexelf(img, i0, j0, array, t00); + } + if (useBorderColor & (I1BIT | J0BIT)) { + get_border_color(tObj, img, t10); + } + else { + img->FetchTexelf(img, i1, j0, array, t10); + } + if (useBorderColor & (I0BIT | J1BIT)) { + get_border_color(tObj, img, t01); + } + else { + img->FetchTexelf(img, i0, j1, array, t01); + } + if (useBorderColor & (I1BIT | J1BIT)) { + get_border_color(tObj, img, t11); + } + else { + img->FetchTexelf(img, i1, j1, array, t11); + } + + /* trilinear interpolation of samples */ + lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11); + } +} + + +static void +sample_2d_array_nearest_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], + rgba[i]); + } +} + + +static void +sample_2d_array_linear_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_2d_array_linear(ctx, tObj, tObj->Image[0][level], + texcoord[i], rgba[i]); + } +} + + +static void +sample_2d_array_nearest_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level ], + texcoord[i], t0); + sample_2d_array_nearest(ctx, tObj, tObj->Image[0][level+1], + texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_2d_array_linear_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_2d_array_linear(ctx, tObj, tObj->Image[0][level ], + texcoord[i], t0); + sample_2d_array_linear(ctx, tObj, tObj->Image[0][level+1], + texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +/** Sample 2D Array texture, nearest filtering for both min/magnification */ +static void +sample_nearest_2d_array(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_2d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + + +/** Sample 2D Array texture, linear filtering for both min/magnification */ +static void +sample_linear_2d_array(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_2d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 2D Array texture, using lambda to choose between min/magnification */ +static void +sample_lambda_2d_array(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint minStart, minEnd; /* texels with minification */ + GLuint magStart, magEnd; /* texels with magnification */ + GLuint i; + + ASSERT(lambda != NULL); + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + /* do the minified texels */ + GLuint m = minEnd - minStart; + switch (tObj->Sampler.MinFilter) { + case GL_NEAREST: + for (i = minStart; i < minEnd; i++) + sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = minStart; i < minEnd; i++) + sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_2d_array_nearest_mipmap_nearest(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, + rgba + minStart); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_2d_array_linear_mipmap_nearest(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, + rgba + minStart); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_2d_array_nearest_mipmap_linear(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, + rgba + minStart); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_2d_array_linear_mipmap_linear(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, + rgba + minStart); + break; + default: + _mesa_problem(ctx, "Bad min filter in sample_2d_array_texture"); + return; + } + } + + if (magStart < magEnd) { + /* do the magnified texels */ + switch (tObj->Sampler.MagFilter) { + case GL_NEAREST: + for (i = magStart; i < magEnd; i++) + sample_2d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = magStart; i < magEnd; i++) + sample_2d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + default: + _mesa_problem(ctx, "Bad mag filter in sample_2d_array_texture"); + return; + } + } +} + + + + +/**********************************************************************/ +/* 1D Texture Array Sampling Functions */ +/**********************************************************************/ + +/** + * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. + */ +static void +sample_1d_array_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[4]) +{ + const GLint width = img->Width2; /* without border, power of two */ + const GLint height = img->Height; + GLint i; + GLint array; + (void) ctx; + + i = nearest_texel_location(tObj->Sampler.WrapS, img, width, texcoord[0]); + array = tex_array_slice(texcoord[1], height); + + if (i < 0 || i >= (GLint) img->Width || + array < 0 || array >= (GLint) img->Height) { + /* Need this test for GL_CLAMP_TO_BORDER mode */ + get_border_color(tObj, img, rgba); + } + else { + img->FetchTexelf(img, i, array, 0, rgba); + } +} + + +/** + * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. + */ +static void +sample_1d_array_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + const GLfloat texcoord[4], + GLfloat rgba[4]) +{ + const GLint width = img->Width2; + const GLint height = img->Height; + GLint i0, i1; + GLint array; + GLbitfield useBorderColor = 0x0; + GLfloat a; + GLfloat t0[4], t1[4]; + + linear_texel_locations(tObj->Sampler.WrapS, img, width, texcoord[0], &i0, &i1, &a); + array = tex_array_slice(texcoord[1], height); + + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + } + else { + /* check if sampling texture border color */ + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + } + + if (array < 0 || array >= height) useBorderColor |= K0BIT; + + /* Fetch texels */ + if (useBorderColor & (I0BIT | K0BIT)) { + get_border_color(tObj, img, t0); + } + else { + img->FetchTexelf(img, i0, array, 0, t0); + } + if (useBorderColor & (I1BIT | K0BIT)) { + get_border_color(tObj, img, t1); + } + else { + img->FetchTexelf(img, i1, array, 0, t1); + } + + /* bilinear interpolation of samples */ + lerp_rgba(rgba, a, t0, t1); +} + + +static void +sample_1d_array_nearest_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], + rgba[i]); + } +} + + +static void +sample_1d_array_linear_mipmap_nearest(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = nearest_mipmap_level(tObj, lambda[i]); + sample_1d_array_linear(ctx, tObj, tObj->Image[0][level], + texcoord[i], rgba[i]); + } +} + + +static void +sample_1d_array_nearest_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_1d_array_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +static void +sample_1d_array_linear_mipmap_linear(struct gl_context *ctx, + const struct gl_texture_object *tObj, + GLuint n, const GLfloat texcoord[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + ASSERT(lambda != NULL); + for (i = 0; i < n; i++) { + GLint level = linear_mipmap_level(tObj, lambda[i]); + if (level >= tObj->_MaxLevel) { + sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel], + texcoord[i], rgba[i]); + } + else { + GLfloat t0[4], t1[4]; /* texels */ + const GLfloat f = FRAC(lambda[i]); + sample_1d_array_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0); + sample_1d_array_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1); + lerp_rgba(rgba[i], f, t0, t1); + } + } +} + + +/** Sample 1D Array texture, nearest filtering for both min/magnification */ +static void +sample_nearest_1d_array(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_1d_array_nearest(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 1D Array texture, linear filtering for both min/magnification */ +static void +sample_linear_1d_array(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], + const GLfloat lambda[], GLfloat rgba[][4]) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; + (void) lambda; + for (i = 0; i < n; i++) { + sample_1d_array_linear(ctx, tObj, image, texcoords[i], rgba[i]); + } +} + + +/** Sample 1D Array texture, using lambda to choose between min/magnification */ +static void +sample_lambda_1d_array(struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint minStart, minEnd; /* texels with minification */ + GLuint magStart, magEnd; /* texels with magnification */ + GLuint i; + + ASSERT(lambda != NULL); + compute_min_mag_ranges(tObj, n, lambda, + &minStart, &minEnd, &magStart, &magEnd); + + if (minStart < minEnd) { + /* do the minified texels */ + GLuint m = minEnd - minStart; + switch (tObj->Sampler.MinFilter) { + case GL_NEAREST: + for (i = minStart; i < minEnd; i++) + sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = minStart; i < minEnd; i++) + sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_1d_array_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_1d_array_linear_mipmap_nearest(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, + rgba + minStart); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_1d_array_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart, + lambda + minStart, rgba + minStart); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_1d_array_linear_mipmap_linear(ctx, tObj, m, + texcoords + minStart, + lambda + minStart, + rgba + minStart); + break; + default: + _mesa_problem(ctx, "Bad min filter in sample_1d_array_texture"); + return; + } + } + + if (magStart < magEnd) { + /* do the magnified texels */ + switch (tObj->Sampler.MagFilter) { + case GL_NEAREST: + for (i = magStart; i < magEnd; i++) + sample_1d_array_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + case GL_LINEAR: + for (i = magStart; i < magEnd; i++) + sample_1d_array_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel], + texcoords[i], rgba[i]); + break; + default: + _mesa_problem(ctx, "Bad mag filter in sample_1d_array_texture"); + return; + } + } +} + + +/** + * Compare texcoord against depth sample. Return 1.0 or the ambient value. + */ +static INLINE GLfloat +shadow_compare(GLenum function, GLfloat coord, GLfloat depthSample, + GLfloat ambient) +{ + switch (function) { + case GL_LEQUAL: + return (coord <= depthSample) ? 1.0F : ambient; + case GL_GEQUAL: + return (coord >= depthSample) ? 1.0F : ambient; + case GL_LESS: + return (coord < depthSample) ? 1.0F : ambient; + case GL_GREATER: + return (coord > depthSample) ? 1.0F : ambient; + case GL_EQUAL: + return (coord == depthSample) ? 1.0F : ambient; + case GL_NOTEQUAL: + return (coord != depthSample) ? 1.0F : ambient; + case GL_ALWAYS: + return 1.0F; + case GL_NEVER: + return ambient; + case GL_NONE: + return depthSample; + default: + _mesa_problem(NULL, "Bad compare func in shadow_compare"); + return ambient; + } +} + + +/** + * Compare texcoord against four depth samples. + */ +static INLINE GLfloat +shadow_compare4(GLenum function, GLfloat coord, + GLfloat depth00, GLfloat depth01, + GLfloat depth10, GLfloat depth11, + GLfloat ambient, GLfloat wi, GLfloat wj) +{ + const GLfloat d = (1.0F - (GLfloat) ambient) * 0.25F; + GLfloat luminance = 1.0F; + + switch (function) { + case GL_LEQUAL: + if (coord > depth00) luminance -= d; + if (coord > depth01) luminance -= d; + if (coord > depth10) luminance -= d; + if (coord > depth11) luminance -= d; + return luminance; + case GL_GEQUAL: + if (coord < depth00) luminance -= d; + if (coord < depth01) luminance -= d; + if (coord < depth10) luminance -= d; + if (coord < depth11) luminance -= d; + return luminance; + case GL_LESS: + if (coord >= depth00) luminance -= d; + if (coord >= depth01) luminance -= d; + if (coord >= depth10) luminance -= d; + if (coord >= depth11) luminance -= d; + return luminance; + case GL_GREATER: + if (coord <= depth00) luminance -= d; + if (coord <= depth01) luminance -= d; + if (coord <= depth10) luminance -= d; + if (coord <= depth11) luminance -= d; + return luminance; + case GL_EQUAL: + if (coord != depth00) luminance -= d; + if (coord != depth01) luminance -= d; + if (coord != depth10) luminance -= d; + if (coord != depth11) luminance -= d; + return luminance; + case GL_NOTEQUAL: + if (coord == depth00) luminance -= d; + if (coord == depth01) luminance -= d; + if (coord == depth10) luminance -= d; + if (coord == depth11) luminance -= d; + return luminance; + case GL_ALWAYS: + return 1.0F; + case GL_NEVER: + return ambient; + case GL_NONE: + /* ordinary bilinear filtering */ + return lerp_2d(wi, wj, depth00, depth10, depth01, depth11); + default: + _mesa_problem(NULL, "Bad compare func in sample_compare4"); + return ambient; + } +} + + +/** + * Choose the mipmap level to use when sampling from a depth texture. + */ +static int +choose_depth_texture_level(const struct gl_texture_object *tObj, GLfloat lambda) +{ + GLint level; + + if (tObj->Sampler.MinFilter == GL_NEAREST || tObj->Sampler.MinFilter == GL_LINEAR) { + /* no mipmapping - use base level */ + level = tObj->BaseLevel; + } + else { + /* choose mipmap level */ + lambda = CLAMP(lambda, tObj->Sampler.MinLod, tObj->Sampler.MaxLod); + level = (GLint) lambda; + level = CLAMP(level, tObj->BaseLevel, tObj->_MaxLevel); + } + + return level; +} + + +/** + * Sample a shadow/depth texture. This function is incomplete. It doesn't + * check for minification vs. magnification, etc. + */ +static void +sample_depth_texture( struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat texel[][4] ) +{ + const GLint level = choose_depth_texture_level(tObj, lambda[0]); + const struct gl_texture_image *img = tObj->Image[0][level]; + const GLint width = img->Width; + const GLint height = img->Height; + const GLint depth = img->Depth; + const GLuint compare_coord = (tObj->Target == GL_TEXTURE_2D_ARRAY_EXT) + ? 3 : 2; + GLfloat ambient; + GLenum function; + GLfloat result; + + ASSERT(img->_BaseFormat == GL_DEPTH_COMPONENT || + img->_BaseFormat == GL_DEPTH_STENCIL_EXT); + + ASSERT(tObj->Target == GL_TEXTURE_1D || + tObj->Target == GL_TEXTURE_2D || + tObj->Target == GL_TEXTURE_RECTANGLE_NV || + tObj->Target == GL_TEXTURE_1D_ARRAY_EXT || + tObj->Target == GL_TEXTURE_2D_ARRAY_EXT); + + ambient = tObj->Sampler.CompareFailValue; + + /* XXXX if tObj->Sampler.MinFilter != tObj->Sampler.MagFilter, we're ignoring lambda */ + + function = (tObj->Sampler.CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) ? + tObj->Sampler.CompareFunc : GL_NONE; + + if (tObj->Sampler.MagFilter == GL_NEAREST) { + GLuint i; + for (i = 0; i < n; i++) { + GLfloat depthSample, depthRef; + GLint col, row, slice; + + nearest_texcoord(tObj, level, texcoords[i], &col, &row, &slice); + + if (col >= 0 && row >= 0 && col < width && row < height && + slice >= 0 && slice < depth) { + img->FetchTexelf(img, col, row, slice, &depthSample); + } + else { + depthSample = tObj->Sampler.BorderColor.f[0]; + } + + depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F); + + result = shadow_compare(function, depthRef, depthSample, ambient); + + switch (tObj->Sampler.DepthMode) { + case GL_LUMINANCE: + ASSIGN_4V(texel[i], result, result, result, 1.0F); + break; + case GL_INTENSITY: + ASSIGN_4V(texel[i], result, result, result, result); + break; + case GL_ALPHA: + ASSIGN_4V(texel[i], 0.0F, 0.0F, 0.0F, result); + break; + case GL_RED: + ASSIGN_4V(texel[i], result, 0.0F, 0.0F, 1.0F); + break; + default: + _mesa_problem(ctx, "Bad depth texture mode"); + } + } + } + else { + GLuint i; + ASSERT(tObj->Sampler.MagFilter == GL_LINEAR); + for (i = 0; i < n; i++) { + GLfloat depth00, depth01, depth10, depth11, depthRef; + GLint i0, i1, j0, j1; + GLint slice; + GLfloat wi, wj; + GLuint useBorderTexel; + + linear_texcoord(tObj, level, texcoords[i], &i0, &i1, &j0, &j1, &slice, + &wi, &wj); + + useBorderTexel = 0; + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) { + j0 += img->Border; + j1 += img->Border; + } + } + else { + if (i0 < 0 || i0 >= (GLint) width) useBorderTexel |= I0BIT; + if (i1 < 0 || i1 >= (GLint) width) useBorderTexel |= I1BIT; + if (j0 < 0 || j0 >= (GLint) height) useBorderTexel |= J0BIT; + if (j1 < 0 || j1 >= (GLint) height) useBorderTexel |= J1BIT; + } + + if (slice < 0 || slice >= (GLint) depth) { + depth00 = tObj->Sampler.BorderColor.f[0]; + depth01 = tObj->Sampler.BorderColor.f[0]; + depth10 = tObj->Sampler.BorderColor.f[0]; + depth11 = tObj->Sampler.BorderColor.f[0]; + } + else { + /* get four depth samples from the texture */ + if (useBorderTexel & (I0BIT | J0BIT)) { + depth00 = tObj->Sampler.BorderColor.f[0]; + } + else { + img->FetchTexelf(img, i0, j0, slice, &depth00); + } + if (useBorderTexel & (I1BIT | J0BIT)) { + depth10 = tObj->Sampler.BorderColor.f[0]; + } + else { + img->FetchTexelf(img, i1, j0, slice, &depth10); + } + + if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) { + if (useBorderTexel & (I0BIT | J1BIT)) { + depth01 = tObj->Sampler.BorderColor.f[0]; + } + else { + img->FetchTexelf(img, i0, j1, slice, &depth01); + } + if (useBorderTexel & (I1BIT | J1BIT)) { + depth11 = tObj->Sampler.BorderColor.f[0]; + } + else { + img->FetchTexelf(img, i1, j1, slice, &depth11); + } + } + else { + depth01 = depth00; + depth11 = depth10; + } + } + + depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F); + + result = shadow_compare4(function, depthRef, + depth00, depth01, depth10, depth11, + ambient, wi, wj); + + switch (tObj->Sampler.DepthMode) { + case GL_LUMINANCE: + ASSIGN_4V(texel[i], result, result, result, 1.0F); + break; + case GL_INTENSITY: + ASSIGN_4V(texel[i], result, result, result, result); + break; + case GL_ALPHA: + ASSIGN_4V(texel[i], 0.0F, 0.0F, 0.0F, result); + break; + default: + _mesa_problem(ctx, "Bad depth texture mode"); + } + + } /* for */ + } /* if filter */ +} + + +/** + * We use this function when a texture object is in an "incomplete" state. + * When a fragment program attempts to sample an incomplete texture we + * return black (see issue 23 in GL_ARB_fragment_program spec). + * Note: fragment programs don't observe the texture enable/disable flags. + */ +static void +null_sample_func( struct gl_context *ctx, + const struct gl_texture_object *tObj, GLuint n, + const GLfloat texcoords[][4], const GLfloat lambda[], + GLfloat rgba[][4]) +{ + GLuint i; + (void) ctx; + (void) tObj; + (void) texcoords; + (void) lambda; + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = 0; + rgba[i][GCOMP] = 0; + rgba[i][BCOMP] = 0; + rgba[i][ACOMP] = 1.0; + } +} + + +/** + * Choose the texture sampling function for the given texture object. + */ +texture_sample_func +_swrast_choose_texture_sample_func( struct gl_context *ctx, + const struct gl_texture_object *t ) +{ + if (!t || !t->_Complete) { + return &null_sample_func; + } + else { + const GLboolean needLambda = + (GLboolean) (t->Sampler.MinFilter != t->Sampler.MagFilter); + const GLenum format = t->Image[0][t->BaseLevel]->_BaseFormat; + + switch (t->Target) { + case GL_TEXTURE_1D: + if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { + return &sample_depth_texture; + } + else if (needLambda) { + return &sample_lambda_1d; + } + else if (t->Sampler.MinFilter == GL_LINEAR) { + return &sample_linear_1d; + } + else { + ASSERT(t->Sampler.MinFilter == GL_NEAREST); + return &sample_nearest_1d; + } + case GL_TEXTURE_2D: + if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { + return &sample_depth_texture; + } + else if (needLambda) { + /* Anisotropic filtering extension. Activated only if mipmaps are used */ + if (t->Sampler.MaxAnisotropy > 1.0 && + t->Sampler.MinFilter == GL_LINEAR_MIPMAP_LINEAR) { + return &sample_lambda_2d_aniso; + } + return &sample_lambda_2d; + } + else if (t->Sampler.MinFilter == GL_LINEAR) { + return &sample_linear_2d; + } + else { + /* check for a few optimized cases */ + const struct gl_texture_image *img = t->Image[0][t->BaseLevel]; + ASSERT(t->Sampler.MinFilter == GL_NEAREST); + if (t->Sampler.WrapS == GL_REPEAT && + t->Sampler.WrapT == GL_REPEAT && + img->_IsPowerOfTwo && + img->Border == 0 && + img->TexFormat == MESA_FORMAT_RGB888) { + return &opt_sample_rgb_2d; + } + else if (t->Sampler.WrapS == GL_REPEAT && + t->Sampler.WrapT == GL_REPEAT && + img->_IsPowerOfTwo && + img->Border == 0 && + img->TexFormat == MESA_FORMAT_RGBA8888) { + return &opt_sample_rgba_2d; + } + else { + return &sample_nearest_2d; + } + } + case GL_TEXTURE_3D: + if (needLambda) { + return &sample_lambda_3d; + } + else if (t->Sampler.MinFilter == GL_LINEAR) { + return &sample_linear_3d; + } + else { + ASSERT(t->Sampler.MinFilter == GL_NEAREST); + return &sample_nearest_3d; + } + case GL_TEXTURE_CUBE_MAP: + if (needLambda) { + return &sample_lambda_cube; + } + else if (t->Sampler.MinFilter == GL_LINEAR) { + return &sample_linear_cube; + } + else { + ASSERT(t->Sampler.MinFilter == GL_NEAREST); + return &sample_nearest_cube; + } + case GL_TEXTURE_RECTANGLE_NV: + if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { + return &sample_depth_texture; + } + else if (needLambda) { + return &sample_lambda_rect; + } + else if (t->Sampler.MinFilter == GL_LINEAR) { + return &sample_linear_rect; + } + else { + ASSERT(t->Sampler.MinFilter == GL_NEAREST); + return &sample_nearest_rect; + } + case GL_TEXTURE_1D_ARRAY_EXT: + if (needLambda) { + return &sample_lambda_1d_array; + } + else if (t->Sampler.MinFilter == GL_LINEAR) { + return &sample_linear_1d_array; + } + else { + ASSERT(t->Sampler.MinFilter == GL_NEAREST); + return &sample_nearest_1d_array; + } + case GL_TEXTURE_2D_ARRAY_EXT: + if (needLambda) { + return &sample_lambda_2d_array; + } + else if (t->Sampler.MinFilter == GL_LINEAR) { + return &sample_linear_2d_array; + } + else { + ASSERT(t->Sampler.MinFilter == GL_NEAREST); + return &sample_nearest_2d_array; + } + default: + _mesa_problem(ctx, + "invalid target in _swrast_choose_texture_sample_func"); + return &null_sample_func; + } + } +} diff --git a/mesalib/src/mesa/vbo/vbo_attrib_tmp.h b/mesalib/src/mesa/vbo/vbo_attrib_tmp.h index d6448dfb6..65717eb45 100644 --- a/mesalib/src/mesa/vbo/vbo_attrib_tmp.h +++ b/mesalib/src/mesa/vbo/vbo_attrib_tmp.h @@ -59,12 +59,12 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #define MAT_ATTR( A, N, V ) ATTR( A, N, (V)[0], (V)[1], (V)[2], (V)[3] ) -static inline float conv_ui10_to_norm_float(unsigned ui10) +static INLINE float conv_ui10_to_norm_float(unsigned ui10) { return (float)(ui10) / 1023.0; } -static inline float conv_ui2_to_norm_float(unsigned ui2) +static INLINE float conv_ui2_to_norm_float(unsigned ui2) { return (float)(ui2) / 3.0; } @@ -91,28 +91,28 @@ static inline float conv_ui2_to_norm_float(unsigned ui2) struct attr_bits_10 {signed int x:10;}; struct attr_bits_2 {signed int x:2;}; -static inline float conv_i10_to_i(int i10) +static INLINE float conv_i10_to_i(int i10) { struct attr_bits_10 val; val.x = i10; return (float)val.x; } -static inline float conv_i2_to_i(int i2) +static INLINE float conv_i2_to_i(int i2) { struct attr_bits_2 val; val.x = i2; return (float)val.x; } -static inline float conv_i10_to_norm_float(int i10) +static INLINE float conv_i10_to_norm_float(int i10) { struct attr_bits_10 val; val.x = i10; return (2.0F * (float)val.x + 1.0F) * (1.0F / 511.0F); } -static inline float conv_i2_to_norm_float(int i2) +static INLINE float conv_i2_to_norm_float(int i2) { struct attr_bits_2 val; val.x = i2; -- cgit v1.2.3