diff options
author | Chia-I Wu <[email protected]> | 2009-11-24 12:21:03 +0800 |
---|---|---|
committer | Brian Paul <[email protected]> | 2010-01-04 14:15:16 -0700 |
commit | a316b700effd615fcc895d0a2e015356854c6f44 (patch) | |
tree | 6eb9e69876ef9a8744009c8253289caf104dd2ad | |
parent | c4b9e1aa1a2f1fda9e5764e3f7dd1a268216df09 (diff) |
mesa/es: Improve support for GL_OES_compressed_paletted_texture.
Add error checking and fix handling of level (it should be negative).
Besides, always use the palette entry format/type when calling
_mesa_TexImage2D. It respects the base internal formats of the cpal
formats, and is simpler and faster, except for cases where the unpack
alignment needs to be changed.
Signed-off-by: Chia-I Wu <[email protected]>
-rw-r--r-- | src/mesa/es/main/es_cpaltex.c | 275 |
1 files changed, 133 insertions, 142 deletions
diff --git a/src/mesa/es/main/es_cpaltex.c b/src/mesa/es/main/es_cpaltex.c index 15b6ad36173..0c497774ff8 100644 --- a/src/mesa/es/main/es_cpaltex.c +++ b/src/mesa/es/main/es_cpaltex.c @@ -7,210 +7,201 @@ /** - * Code to convert compressed/paletted texture images to ordinary 4-byte RGBA. + * Code to convert compressed/paletted texture images to ordinary images. * See the GL_OES_compressed_paletted_texture spec at * http://khronos.org/registry/gles/extensions/OES/OES_compressed_paletted_texture.txt + * + * XXX this makes it impossible to add hardware support... */ -#include <stdlib.h> -#include <assert.h> #include "GLES/gl.h" #include "GLES/glext.h" +#include "main/compiler.h" /* for ASSERT */ + void GL_APIENTRY _es_CompressedTexImage2DARB(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +void GL_APIENTRY _mesa_GetIntegerv(GLenum pname, GLint *params); +void GL_APIENTRY _mesa_PixelStorei(GLenum pname, GLint param); void GL_APIENTRY _mesa_TexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); void GL_APIENTRY _mesa_CompressedTexImage2DARB(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +void *_mesa_get_current_context(void); +void _mesa_error(void *ctx, GLenum error, const char *fmtString, ... ); + -static const struct { +static const struct cpal_format_info { + GLenum cpal_format; GLenum format; + GLenum type; GLuint palette_size; GLuint size; } formats[] = { - { GL_PALETTE4_RGB8_OES, 16, 3 }, - { GL_PALETTE4_RGBA8_OES, 16, 4 }, - { GL_PALETTE4_R5_G6_B5_OES, 16, 2 }, - { GL_PALETTE4_RGBA4_OES, 16, 2 }, - { GL_PALETTE4_RGB5_A1_OES, 16, 2 }, - { GL_PALETTE8_RGB8_OES, 256, 3 }, - { GL_PALETTE8_RGBA8_OES, 256, 4 }, - { GL_PALETTE8_R5_G6_B5_OES, 256, 2 }, - { GL_PALETTE8_RGBA4_OES, 256, 2 }, - { GL_PALETTE8_RGB5_A1_OES, 256, 2 } + { GL_PALETTE4_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE, 16, 3 }, + { GL_PALETTE4_RGBA8_OES, GL_RGBA, GL_UNSIGNED_BYTE, 16, 4 }, + { GL_PALETTE4_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16, 2 }, + { GL_PALETTE4_RGBA4_OES, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 16, 2 }, + { GL_PALETTE4_RGB5_A1_OES, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 16, 2 }, + { GL_PALETTE8_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE, 256, 3 }, + { GL_PALETTE8_RGBA8_OES, GL_RGBA, GL_UNSIGNED_BYTE, 256, 4 }, + { GL_PALETTE8_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 256, 2 }, + { GL_PALETTE8_RGBA4_OES, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 256, 2 }, + { GL_PALETTE8_RGB5_A1_OES, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 256, 2 } }; /** - * Get a color/entry from the palette. Convert to GLubyte/RGBA format. + * Get a color/entry from the palette. */ -static void -get_palette_entry(GLenum format, const void *palette, GLuint index, - GLubyte rgba[4]) +static GLuint +get_palette_entry(const struct cpal_format_info *info, const GLubyte *palette, + GLuint index, GLubyte *pixel) { - switch (format) { - case GL_PALETTE4_RGB8_OES: - case GL_PALETTE8_RGB8_OES: - { - const GLubyte *pal = (const GLubyte *) palette; - rgba[0] = pal[index * 3 + 0]; - rgba[1] = pal[index * 3 + 1]; - rgba[2] = pal[index * 3 + 2]; - rgba[3] = 255; - } - break; - case GL_PALETTE4_RGBA8_OES: - case GL_PALETTE8_RGBA8_OES: - { - const GLubyte *pal = (const GLubyte *) palette; - rgba[0] = pal[index * 4 + 0]; - rgba[1] = pal[index * 4 + 1]; - rgba[2] = pal[index * 4 + 2]; - rgba[3] = pal[index * 4 + 3]; - } - break; - case GL_PALETTE4_R5_G6_B5_OES: - case GL_PALETTE8_R5_G6_B5_OES: - { - const GLushort *pal = (const GLushort *) palette; - const GLushort color = pal[index]; - rgba[0] = ((color >> 8) & 0xf8) | ((color >> 11) & 0x3); - rgba[1] = ((color >> 3) & 0xfc) | ((color >> 1 ) & 0x3); - rgba[2] = ((color << 3) & 0xf8) | ((color ) & 0x7); - rgba[3] = 255; - } - break; - case GL_PALETTE4_RGBA4_OES: - case GL_PALETTE8_RGBA4_OES: - { - const GLushort *pal = (const GLushort *) palette; - const GLushort color = pal[index]; - rgba[0] = ((color & 0xf000) >> 8) | ((color & 0xf000) >> 12); - rgba[1] = ((color & 0x0f00) >> 4) | ((color & 0x0f00) >> 8); - rgba[2] = ((color & 0x00f0) ) | ((color & 0x00f0) >> 4); - rgba[3] = ((color & 0x000f) << 4) | ((color & 0x000f) ); - } - break; - case GL_PALETTE4_RGB5_A1_OES: - case GL_PALETTE8_RGB5_A1_OES: - { - const GLushort *pal = (const GLushort *) palette; - const GLushort color = pal[index]; - rgba[0] = ((color >> 8) & 0xf8) | ((color >> 11) & 0x7); - rgba[1] = ((color >> 3) & 0xf8) | ((color >> 6) & 0x7); - rgba[2] = ((color << 2) & 0xf8) | ((color >> 1) & 0x7); - rgba[3] = (color & 0x1) * 255; - } - break; - default: - assert(0); - } + memcpy(pixel, palette + info->size * index, info->size); + return info->size; } /** - * Convert paletted texture to simple GLubyte/RGBA format. + * Convert paletted texture to color texture. */ static void -paletted_to_rgba(GLenum src_format, - const void *palette, - const void *indexes, - GLsizei width, GLsizei height, - GLubyte *rgba) +paletted_to_color(const struct cpal_format_info *info, const GLubyte *palette, + const void *indices, GLuint num_pixels, GLubyte *image) { - GLuint pal_ents, i; - - assert(src_format >= GL_PALETTE4_RGB8_OES); - assert(src_format <= GL_PALETTE8_RGB5_A1_OES); - assert(formats[src_format - GL_PALETTE4_RGB8_OES].format == src_format); + GLubyte *pix = image; + GLuint remain, i; - pal_ents = formats[src_format - GL_PALETTE4_RGB8_OES].palette_size; - - if (pal_ents == 16) { + if (info->palette_size == 16) { /* 4 bits per index */ - const GLubyte *ind = (const GLubyte *) indexes; + const GLubyte *ind = (const GLubyte *) indices; - if (width * height == 1) { - /* special case the only odd-sized image */ - GLuint index0 = ind[0] >> 4; - get_palette_entry(src_format, palette, index0, rgba); - return; - } /* two pixels per iteration */ - for (i = 0; i < width * height / 2; i++) { - GLuint index0 = ind[i] >> 4; - GLuint index1 = ind[i] & 0xf; - get_palette_entry(src_format, palette, index0, rgba + i * 8); - get_palette_entry(src_format, palette, index1, rgba + i * 8 + 4); + remain = num_pixels % 2; + for (i = 0; i < num_pixels / 2; i++) { + pix += get_palette_entry(info, palette, (ind[i] >> 4) & 0xf, pix); + pix += get_palette_entry(info, palette, ind[i] & 0xf, pix); + } + if (remain) { + get_palette_entry(info, palette, (ind[i] >> 4) & 0xf, pix); } } else { /* 8 bits per index */ - const GLubyte *ind = (const GLubyte *) indexes; - for (i = 0; i < width * height; i++) { - GLuint index = ind[i]; - get_palette_entry(src_format, palette, index, rgba + i * 4); - } + const GLubyte *ind = (const GLubyte *) indices; + for (i = 0; i < num_pixels; i++) + pix += get_palette_entry(info, palette, ind[i], pix); } } +static const struct cpal_format_info * +cpal_get_info(GLint level, GLenum internalFormat, + GLsizei width, GLsizei height, GLsizei imageSize) +{ + const struct cpal_format_info *info; + GLint lvl, num_levels; + GLsizei w, h, expect_size; + + info = &formats[internalFormat - GL_PALETTE4_RGB8_OES]; + ASSERT(info->cpal_format == internalFormat); + + if (level > 0) { + _mesa_error(_mesa_get_current_context(), GL_INVALID_VALUE, + "glCompressedTexImage2D(level=%d)", level); + return NULL; + } + + num_levels = -level + 1; + expect_size = info->palette_size * info->size; + for (lvl = 0; lvl < num_levels; lvl++) { + w = width >> lvl; + if (!w) + w = 1; + h = height >> lvl; + if (!h) + h = 1; + + if (info->palette_size == 16) + expect_size += (w * h + 1) / 2; + else + expect_size += w * h; + } + if (expect_size > imageSize) { + _mesa_error(_mesa_get_current_context(), GL_INVALID_VALUE, + "glCompressedTexImage2D(imageSize=%d)", imageSize); + return NULL; + } + return info; +} + /** * Convert a call to glCompressedTexImage2D() where internalFormat is a * compressed palette format into a regular GLubyte/RGBA glTexImage2D() call. */ static void -cpal_compressed_teximage2d(GLenum target, GLint level, - GLenum internalFormat, - GLsizei width, GLsizei height, - const void *pixels) +cpal_compressed_teximage2d(GLenum target, GLint level, GLenum internalFormat, + GLsizei width, GLsizei height, GLsizei imageSize, + const void *palette) { - GLuint pal_ents, pal_ent_size, pal_bytes; - const GLint num_levels = level + 1; - GLint lvl; - const GLubyte *indexes; + const struct cpal_format_info *info; + GLint lvl, num_levels; + const GLubyte *indices; + GLint saved_align, align; - assert(internalFormat >= GL_PALETTE4_RGB8_OES); - assert(internalFormat <= GL_PALETTE8_RGB5_A1_OES); - assert(formats[internalFormat - GL_PALETTE4_RGB8_OES].format == internalFormat); + info = cpal_get_info(level, internalFormat, width, height, imageSize); + if (!info) + return; - pal_ents = formats[internalFormat - GL_PALETTE4_RGB8_OES].palette_size; - pal_ent_size = formats[internalFormat - GL_PALETTE4_RGB8_OES].size; - pal_bytes = pal_ents * pal_ent_size; + info = &formats[internalFormat - GL_PALETTE4_RGB8_OES]; + ASSERT(info->cpal_format == internalFormat); + num_levels = -level + 1; /* first image follows the palette */ - indexes = (const GLubyte *) pixels + pal_bytes; + indices = (const GLubyte *) palette + info->palette_size * info->size; - /* No worries about glPixelStore state since the only supported parameter is - * GL_UNPACK_ALIGNMENT and it doesn't matter when unpacking GLubyte/RGBA. - */ + _mesa_GetIntegerv(GL_UNPACK_ALIGNMENT, &saved_align); + align = saved_align; for (lvl = 0; lvl < num_levels; lvl++) { - /* Allocate GLubyte/RGBA dest image buffer */ - GLubyte *rgba = (GLubyte *) malloc(width * height * 4); - - if (pixels) - paletted_to_rgba(internalFormat, pixels, indexes, width, height, rgba); + GLsizei w, h; + GLuint num_texels; + GLubyte *image = NULL; + + w = width >> lvl; + if (!w) + w = 1; + h = height >> lvl; + if (!h) + h = 1; + num_texels = w * h; + if (w * info->size % align) { + _mesa_PixelStorei(GL_UNPACK_ALIGNMENT, 1); + align = 1; + } - _mesa_TexImage2D(target, lvl, GL_RGBA, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, rgba); + /* allocate and fill dest image buffer */ + if (palette) { + image = (GLubyte *) malloc(num_texels * info->size); + paletted_to_color(info, palette, indices, num_texels, image); + } - free(rgba); + _mesa_TexImage2D(target, lvl, info->format, w, h, 0, + info->format, info->type, image); + if (image) + free(image); /* advance index pointer to point to next src mipmap */ - if (pal_ents == 4) - indexes += width * height / 2; + if (info->palette_size == 16) + indices += (num_texels + 1) / 2; else - indexes += width * height; - - /* next mipmap level size */ - if (width > 1) - width /= 2; - if (height > 1) - height /= 2; + indices += num_texels; } + + if (saved_align != align) + _mesa_PixelStorei(GL_UNPACK_ALIGNMENT, saved_align); } @@ -231,7 +222,7 @@ _es_CompressedTexImage2DARB(GLenum target, GLint level, GLenum internalFormat, case GL_PALETTE8_RGBA4_OES: case GL_PALETTE8_RGB5_A1_OES: cpal_compressed_teximage2d(target, level, internalFormat, - width, height, data); + width, height, imageSize, data); break; default: _mesa_CompressedTexImage2DARB(target, level, internalFormat, |