/* * Copyright (C) 2011 Red Hat Inc. * * block compression parts are: * Copyright (C) 2004 Roland Scheidegger 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 (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 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. * * Author: * Dave Airlie */ /** * \file texcompress_rgtc.c * GL_EXT_texture_compression_rgtc support. */ #include "config.h" #include "glheader.h" #include "util/imports.h" #include "image.h" #include "macros.h" #include "mipmap.h" #include "texcompress.h" #include "util/rgtc.h" #include "texcompress_rgtc.h" #include "texstore.h" static void extractsrc_u( GLubyte srcpixels[4][4], const GLubyte *srcaddr, GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps) { GLubyte i, j; const GLubyte *curaddr; for (j = 0; j < numypixels; j++) { curaddr = srcaddr + j * srcRowStride * comps; for (i = 0; i < numxpixels; i++) { srcpixels[j][i] = *curaddr; curaddr += comps; } } } static void extractsrc_s( GLbyte srcpixels[4][4], const GLfloat *srcaddr, GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps) { GLubyte i, j; const GLfloat *curaddr; for (j = 0; j < numypixels; j++) { curaddr = srcaddr + j * srcRowStride * comps; for (i = 0; i < numxpixels; i++) { srcpixels[j][i] = FLOAT_TO_BYTE_TEX(*curaddr); curaddr += comps; } } } GLboolean _mesa_texstore_red_rgtc1(TEXSTORE_PARAMS) { GLubyte *dst; const GLubyte *tempImage = NULL; int i, j; int numxpixels, numypixels; const GLubyte *srcaddr; GLubyte srcpixels[4][4]; GLubyte *blkaddr; GLint dstRowDiff, redRowStride; GLubyte *tempImageSlices[1]; assert(dstFormat == MESA_FORMAT_R_RGTC1_UNORM || dstFormat == MESA_FORMAT_L_LATC1_UNORM); tempImage = malloc(srcWidth * srcHeight * 1 * sizeof(GLubyte)); if (!tempImage) return GL_FALSE; /* out of memory */ redRowStride = 1 * srcWidth * sizeof(GLubyte); tempImageSlices[0] = (GLubyte *) tempImage; _mesa_texstore(ctx, dims, baseInternalFormat, MESA_FORMAT_R_UNORM8, redRowStride, tempImageSlices, srcWidth, srcHeight, srcDepth, srcFormat, srcType, srcAddr, srcPacking); dst = dstSlices[0]; blkaddr = dst; dstRowDiff = dstRowStride >= (srcWidth * 2) ? dstRowStride - (((srcWidth + 3) & ~3) * 2) : 0; for (j = 0; j < srcHeight; j+=4) { if (srcHeight > j + 3) numypixels = 4; else numypixels = srcHeight - j; srcaddr = tempImage + j * srcWidth; for (i = 0; i < srcWidth; i += 4) { if (srcWidth > i + 3) numxpixels = 4; else numxpixels = srcWidth - i; extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1); util_format_unsigned_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels); srcaddr += numxpixels; blkaddr += 8; } blkaddr += dstRowDiff; } free((void *) tempImage); return GL_TRUE; } GLboolean _mesa_texstore_signed_red_rgtc1(TEXSTORE_PARAMS) { GLbyte *dst; const GLfloat *tempImage = NULL; int i, j; int numxpixels, numypixels; const GLfloat *srcaddr; GLbyte srcpixels[4][4]; GLbyte *blkaddr; GLint dstRowDiff, redRowStride; GLfloat *tempImageSlices[1]; assert(dstFormat == MESA_FORMAT_R_RGTC1_SNORM || dstFormat == MESA_FORMAT_L_LATC1_SNORM); redRowStride = 1 * srcWidth * sizeof(GLfloat); tempImage = malloc(srcWidth * srcHeight * 1 * sizeof(GLfloat)); if (!tempImage) return GL_FALSE; /* out of memory */ tempImageSlices[0] = (GLfloat *) tempImage; _mesa_texstore(ctx, dims, baseInternalFormat, MESA_FORMAT_R_FLOAT32, redRowStride, (GLubyte **)tempImageSlices, srcWidth, srcHeight, srcDepth, srcFormat, srcType, srcAddr, srcPacking); dst = (GLbyte *) dstSlices[0]; blkaddr = dst; dstRowDiff = dstRowStride >= (srcWidth * 2) ? dstRowStride - (((srcWidth + 3) & ~3) * 2) : 0; for (j = 0; j < srcHeight; j+=4) { if (srcHeight > j + 3) numypixels = 4; else numypixels = srcHeight - j; srcaddr = tempImage + j * srcWidth; for (i = 0; i < srcWidth; i += 4) { if (srcWidth > i + 3) numxpixels = 4; else numxpixels = srcWidth - i; extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1); util_format_signed_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels); srcaddr += numxpixels; blkaddr += 8; } blkaddr += dstRowDiff; } free((void *) tempImage); return GL_TRUE; } GLboolean _mesa_texstore_rg_rgtc2(TEXSTORE_PARAMS) { GLubyte *dst; const GLubyte *tempImage = NULL; int i, j; int numxpixels, numypixels; const GLubyte *srcaddr; GLubyte srcpixels[4][4]; GLubyte *blkaddr; GLint dstRowDiff, rgRowStride; mesa_format tempFormat; GLubyte *tempImageSlices[1]; assert(dstFormat == MESA_FORMAT_RG_RGTC2_UNORM || dstFormat == MESA_FORMAT_LA_LATC2_UNORM); if (baseInternalFormat == GL_RG) tempFormat = MESA_FORMAT_RG_UNORM8; else tempFormat = MESA_FORMAT_LA_UNORM8; rgRowStride = 2 * srcWidth * sizeof(GLubyte); tempImage = malloc(srcWidth * srcHeight * 2 * sizeof(GLubyte)); if (!tempImage) return GL_FALSE; /* out of memory */ tempImageSlices[0] = (GLubyte *) tempImage; _mesa_texstore(ctx, dims, baseInternalFormat, tempFormat, rgRowStride, tempImageSlices, srcWidth, srcHeight, srcDepth, srcFormat, srcType, srcAddr, srcPacking); dst = dstSlices[0]; blkaddr = dst; dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0; for (j = 0; j < srcHeight; j+=4) { if (srcHeight > j + 3) numypixels = 4; else numypixels = srcHeight - j; srcaddr = tempImage + j * srcWidth * 2; for (i = 0; i < srcWidth; i += 4) { if (srcWidth > i + 3) numxpixels = 4; else numxpixels = srcWidth - i; extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2); util_format_unsigned_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; extractsrc_u(srcpixels, (GLubyte *)srcaddr + 1, srcWidth, numxpixels, numypixels, 2); util_format_unsigned_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; srcaddr += numxpixels * 2; } blkaddr += dstRowDiff; } free((void *) tempImage); return GL_TRUE; } GLboolean _mesa_texstore_signed_rg_rgtc2(TEXSTORE_PARAMS) { GLbyte *dst; const GLfloat *tempImage = NULL; int i, j; int numxpixels, numypixels; const GLfloat *srcaddr; GLbyte srcpixels[4][4]; GLbyte *blkaddr; GLint dstRowDiff, rgRowStride; mesa_format tempFormat; GLfloat *tempImageSlices[1]; assert(dstFormat == MESA_FORMAT_RG_RGTC2_SNORM || dstFormat == MESA_FORMAT_LA_LATC2_SNORM); if (baseInternalFormat == GL_RG) tempFormat = MESA_FORMAT_RG_FLOAT32; else tempFormat = MESA_FORMAT_LA_FLOAT32; rgRowStride = 2 * srcWidth * sizeof(GLfloat); tempImage = malloc(srcWidth * srcHeight * 2 * sizeof(GLfloat)); if (!tempImage) return GL_FALSE; /* out of memory */ tempImageSlices[0] = (GLfloat *) tempImage; _mesa_texstore(ctx, dims, baseInternalFormat, tempFormat, rgRowStride, (GLubyte **)tempImageSlices, srcWidth, srcHeight, srcDepth, srcFormat, srcType, srcAddr, srcPacking); dst = (GLbyte *) dstSlices[0]; blkaddr = dst; dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0; for (j = 0; j < srcHeight; j += 4) { if (srcHeight > j + 3) numypixels = 4; else numypixels = srcHeight - j; srcaddr = tempImage + j * srcWidth * 2; for (i = 0; i < srcWidth; i += 4) { if (srcWidth > i + 3) numxpixels = 4; else numxpixels = srcWidth - i; extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2); util_format_signed_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; extractsrc_s(srcpixels, srcaddr + 1, srcWidth, numxpixels, numypixels, 2); util_format_signed_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels); blkaddr += 8; srcaddr += numxpixels * 2; } blkaddr += dstRowDiff; } free((void *) tempImage); return GL_TRUE; } static void fetch_red_rgtc1(const GLubyte *map, GLint rowStride, GLint i, GLint j, GLfloat *texel) { GLubyte red; util_format_unsigned_fetch_texel_rgtc(rowStride, map, i, j, &red, 1); texel[RCOMP] = UBYTE_TO_FLOAT(red); texel[GCOMP] = 0.0; texel[BCOMP] = 0.0; texel[ACOMP] = 1.0; } static void fetch_l_latc1(const GLubyte *map, GLint rowStride, GLint i, GLint j, GLfloat *texel) { GLubyte red; util_format_unsigned_fetch_texel_rgtc(rowStride, map, i, j, &red, 1); texel[RCOMP] = texel[GCOMP] = texel[BCOMP] = UBYTE_TO_FLOAT(red); texel[ACOMP] = 1.0; } static void fetch_signed_red_rgtc1(const GLubyte *map, GLint rowStride, GLint i, GLint j, GLfloat *texel) { GLbyte red; util_format_signed_fetch_texel_rgtc(rowStride, (const GLbyte *) map, i, j, &red, 1); texel[RCOMP] = BYTE_TO_FLOAT_TEX(red); texel[GCOMP] = 0.0; texel[BCOMP] = 0.0; texel[ACOMP] = 1.0; } static void fetch_signed_l_latc1(const GLubyte *map, GLint rowStride, GLint i, GLint j, GLfloat *texel) { GLbyte red; util_format_signed_fetch_texel_rgtc(rowStride, (GLbyte *) map, i, j, &red, 1); texel[RCOMP] = texel[GCOMP] = texel[BCOMP] = BYTE_TO_FLOAT(red); texel[ACOMP] = 1.0; } static void fetch_rg_rgtc2(const GLubyte *map, GLint rowStride, GLint i, GLint j, GLfloat *texel) { GLubyte red, green; util_format_unsigned_fetch_texel_rgtc(rowStride, map, i, j, &red, 2); util_format_unsigned_fetch_texel_rgtc(rowStride, map + 8, i, j, &green, 2); texel[RCOMP] = UBYTE_TO_FLOAT(red); texel[GCOMP] = UBYTE_TO_FLOAT(green); texel[BCOMP] = 0.0; texel[ACOMP] = 1.0; } static void fetch_la_latc2(const GLubyte *map, GLint rowStride, GLint i, GLint j, GLfloat *texel) { GLubyte red, green; util_format_unsigned_fetch_texel_rgtc(rowStride, map, i, j, &red, 2); util_format_unsigned_fetch_texel_rgtc(rowStride, map + 8, i, j, &green, 2); texel[RCOMP] = texel[GCOMP] = texel[BCOMP] = UBYTE_TO_FLOAT(red); texel[ACOMP] = UBYTE_TO_FLOAT(green); } static void fetch_signed_rg_rgtc2(const GLubyte *map, GLint rowStride, GLint i, GLint j, GLfloat *texel) { GLbyte red, green; util_format_signed_fetch_texel_rgtc(rowStride, (GLbyte *) map, i, j, &red, 2); util_format_signed_fetch_texel_rgtc(rowStride, (GLbyte *) map + 8, i, j, &green, 2); texel[RCOMP] = BYTE_TO_FLOAT_TEX(red); texel[GCOMP] = BYTE_TO_FLOAT_TEX(green); texel[BCOMP] = 0.0; texel[ACOMP] = 1.0; } static void fetch_signed_la_latc2(const GLubyte *map, GLint rowStride, GLint i, GLint j, GLfloat *texel) { GLbyte red, green; util_format_signed_fetch_texel_rgtc(rowStride, (GLbyte *) map, i, j, &red, 2); util_format_signed_fetch_texel_rgtc(rowStride, (GLbyte *) map + 8, i, j, &green, 2); texel[RCOMP] = texel[GCOMP] = texel[BCOMP] = BYTE_TO_FLOAT_TEX(red); texel[ACOMP] = BYTE_TO_FLOAT_TEX(green); } compressed_fetch_func _mesa_get_compressed_rgtc_func(mesa_format format) { switch (format) { case MESA_FORMAT_R_RGTC1_UNORM: return fetch_red_rgtc1; case MESA_FORMAT_L_LATC1_UNORM: return fetch_l_latc1; case MESA_FORMAT_R_RGTC1_SNORM: return fetch_signed_red_rgtc1; case MESA_FORMAT_L_LATC1_SNORM: return fetch_signed_l_latc1; case MESA_FORMAT_RG_RGTC2_UNORM: return fetch_rg_rgtc2; case MESA_FORMAT_LA_LATC2_UNORM: return fetch_la_latc2; case MESA_FORMAT_RG_RGTC2_SNORM: return fetch_signed_rg_rgtc2; case MESA_FORMAT_LA_LATC2_SNORM: return fetch_signed_la_latc2; default: return NULL; } }