texcompress_rgtc.c revision 521394a204bd8073846acc7f9861081d29fa24c9
1/* 2 * Copyright (C) 2011 Red Hat Inc. 3 * 4 * block compression parts are: 5 * Copyright (C) 2004 Roland Scheidegger All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the next 15 * paragraph) shall be included in all copies or substantial portions of the 16 * Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 * DEALINGS IN THE SOFTWARE. 25 * 26 * Author: 27 * Dave Airlie 28 */ 29 30/** 31 * \file texcompress_rgtc.c 32 * GL_EXT_texture_compression_rgtc support. 33 */ 34 35 36#include "glheader.h" 37#include "imports.h" 38#include "colormac.h" 39#include "image.h" 40#include "macros.h" 41#include "mfeatures.h" 42#include "mipmap.h" 43#include "texcompress.h" 44#include "texcompress_rgtc.h" 45#include "texstore.h" 46 47#define RGTC_DEBUG 0 48 49static void unsigned_encode_rgtc_chan(GLubyte *blkaddr, GLubyte srccolors[4][4], 50 GLint numxpixels, GLint numypixels); 51static void signed_encode_rgtc_chan(GLbyte *blkaddr, GLbyte srccolors[4][4], 52 GLint numxpixels, GLint numypixels); 53 54static void extractsrc_u( GLubyte srcpixels[4][4], const GLchan *srcaddr, 55 GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps) 56{ 57 GLubyte i, j; 58 const GLchan *curaddr; 59 for (j = 0; j < numypixels; j++) { 60 curaddr = srcaddr + j * srcRowStride * comps; 61 for (i = 0; i < numxpixels; i++) { 62 srcpixels[j][i] = *curaddr / (CHAN_MAX / 255); 63 curaddr += comps; 64 } 65 } 66} 67 68static void extractsrc_s( GLbyte srcpixels[4][4], const GLfloat *srcaddr, 69 GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps) 70{ 71 GLubyte i, j; 72 const GLfloat *curaddr; 73 for (j = 0; j < numypixels; j++) { 74 curaddr = srcaddr + j * srcRowStride * comps; 75 for (i = 0; i < numxpixels; i++) { 76 srcpixels[j][i] = FLOAT_TO_BYTE_TEX(*curaddr); 77 curaddr += comps; 78 } 79 } 80} 81 82 83GLboolean 84_mesa_texstore_red_rgtc1(TEXSTORE_PARAMS) 85{ 86 GLubyte *dst; 87 const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */ 88 const GLchan *tempImage = NULL; 89 int i, j; 90 int numxpixels, numypixels; 91 const GLchan *srcaddr; 92 GLubyte srcpixels[4][4]; 93 GLubyte *blkaddr; 94 GLint dstRowDiff; 95 ASSERT(dstFormat == MESA_FORMAT_RED_RGTC1); 96 ASSERT(dstXoffset % 4 == 0); 97 ASSERT(dstYoffset % 4 == 0); 98 ASSERT(dstZoffset % 4 == 0); 99 (void) dstZoffset; 100 (void) dstImageOffsets; 101 102 103 tempImage = _mesa_make_temp_chan_image(ctx, dims, 104 baseInternalFormat, 105 _mesa_get_format_base_format(dstFormat), 106 srcWidth, srcHeight, srcDepth, 107 srcFormat, srcType, srcAddr, 108 srcPacking); 109 if (!tempImage) 110 return GL_FALSE; /* out of memory */ 111 112 dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, 113 dstFormat, 114 texWidth, (GLubyte *) dstAddr); 115 116 blkaddr = dst; 117 dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0; 118 for (j = 0; j < srcHeight; j+=4) { 119 if (srcHeight > j + 3) numypixels = 4; 120 else numypixels = srcHeight - j; 121 srcaddr = tempImage + j * srcWidth; 122 for (i = 0; i < srcWidth; i += 4) { 123 if (srcWidth > i + 3) numxpixels = 4; 124 else numxpixels = srcWidth - i; 125 extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1); 126 unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); 127 srcaddr += numxpixels; 128 blkaddr += 8; 129 } 130 blkaddr += dstRowDiff; 131 } 132 if (tempImage) 133 free((void *) tempImage); 134 135 return GL_TRUE; 136} 137 138GLboolean 139_mesa_texstore_signed_red_rgtc1(TEXSTORE_PARAMS) 140{ 141 GLbyte *dst; 142 const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */ 143 const GLfloat *tempImage = NULL; 144 int i, j; 145 int numxpixels, numypixels; 146 const GLfloat *srcaddr; 147 GLbyte srcpixels[4][4]; 148 GLbyte *blkaddr; 149 GLint dstRowDiff; 150 ASSERT(dstFormat == MESA_FORMAT_SIGNED_RED_RGTC1); 151 ASSERT(dstXoffset % 4 == 0); 152 ASSERT(dstYoffset % 4 == 0); 153 ASSERT(dstZoffset % 4 == 0); 154 (void) dstZoffset; 155 (void) dstImageOffsets; 156 157 tempImage = _mesa_make_temp_float_image(ctx, dims, 158 baseInternalFormat, 159 _mesa_get_format_base_format(dstFormat), 160 srcWidth, srcHeight, srcDepth, 161 srcFormat, srcType, srcAddr, 162 srcPacking, 0x0); 163 if (!tempImage) 164 return GL_FALSE; /* out of memory */ 165 166 dst = (GLbyte *)_mesa_compressed_image_address(dstXoffset, dstYoffset, 0, 167 dstFormat, 168 texWidth, (GLubyte *) dstAddr); 169 170 blkaddr = dst; 171 dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0; 172 for (j = 0; j < srcHeight; j+=4) { 173 if (srcHeight > j + 3) numypixels = 4; 174 else numypixels = srcHeight - j; 175 srcaddr = tempImage + j * srcWidth; 176 for (i = 0; i < srcWidth; i += 4) { 177 if (srcWidth > i + 3) numxpixels = 4; 178 else numxpixels = srcWidth - i; 179 extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1); 180 signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); 181 srcaddr += numxpixels; 182 blkaddr += 8; 183 } 184 blkaddr += dstRowDiff; 185 } 186 if (tempImage) 187 free((void *) tempImage); 188 189 return GL_TRUE; 190} 191 192GLboolean 193_mesa_texstore_rg_rgtc2(TEXSTORE_PARAMS) 194{ 195 GLubyte *dst; 196 const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */ 197 const GLchan *tempImage = NULL; 198 int i, j; 199 int numxpixels, numypixels; 200 const GLchan *srcaddr; 201 GLubyte srcpixels[4][4]; 202 GLubyte *blkaddr; 203 GLint dstRowDiff; 204 205 ASSERT(dstFormat == MESA_FORMAT_RG_RGTC2); 206 ASSERT(dstXoffset % 4 == 0); 207 ASSERT(dstYoffset % 4 == 0); 208 ASSERT(dstZoffset % 4 == 0); 209 (void) dstZoffset; 210 (void) dstImageOffsets; 211 212 tempImage = _mesa_make_temp_chan_image(ctx, dims, 213 baseInternalFormat, 214 _mesa_get_format_base_format(dstFormat), 215 srcWidth, srcHeight, srcDepth, 216 srcFormat, srcType, srcAddr, 217 srcPacking); 218 if (!tempImage) 219 return GL_FALSE; /* out of memory */ 220 221 dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0, 222 dstFormat, 223 texWidth, (GLubyte *) dstAddr); 224 225 blkaddr = dst; 226 dstRowDiff = dstRowStride >= (srcWidth * 8) ? dstRowStride - (((srcWidth + 7) & ~7) * 8) : 0; 227 for (j = 0; j < srcHeight; j+=4) { 228 if (srcHeight > j + 3) numypixels = 4; 229 else numypixels = srcHeight - j; 230 srcaddr = tempImage + j * srcWidth * 2; 231 for (i = 0; i < srcWidth; i += 4) { 232 if (srcWidth > i + 3) numxpixels = 4; 233 else numxpixels = srcWidth - i; 234 extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2); 235 unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); 236 237 blkaddr += 8; 238 extractsrc_u(srcpixels, (GLchan *)srcaddr + 1, srcWidth, numxpixels, numypixels, 2); 239 unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); 240 241 blkaddr += 8; 242 243 srcaddr += numxpixels * 2; 244 } 245 blkaddr += dstRowDiff; 246 } 247 if (tempImage) 248 free((void *) tempImage); 249 250 return GL_TRUE; 251} 252 253GLboolean 254_mesa_texstore_signed_rg_rgtc2(TEXSTORE_PARAMS) 255{ 256 GLbyte *dst; 257 const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */ 258 const GLfloat *tempImage = NULL; 259 int i, j; 260 int numxpixels, numypixels; 261 const GLfloat *srcaddr; 262 GLbyte srcpixels[4][4]; 263 GLbyte *blkaddr; 264 GLint dstRowDiff; 265 266 ASSERT(dstFormat == MESA_FORMAT_SIGNED_RG_RGTC2); 267 ASSERT(dstXoffset % 4 == 0); 268 ASSERT(dstYoffset % 4 == 0); 269 ASSERT(dstZoffset % 4 == 0); 270 (void) dstZoffset; 271 (void) dstImageOffsets; 272 273 tempImage = _mesa_make_temp_float_image(ctx, dims, 274 baseInternalFormat, 275 _mesa_get_format_base_format(dstFormat), 276 srcWidth, srcHeight, srcDepth, 277 srcFormat, srcType, srcAddr, 278 srcPacking, 0x0); 279 if (!tempImage) 280 return GL_FALSE; /* out of memory */ 281 282 dst = (GLbyte *)_mesa_compressed_image_address(dstXoffset, dstYoffset, 0, 283 dstFormat, 284 texWidth, (GLubyte *) dstAddr); 285 286 blkaddr = dst; 287 dstRowDiff = dstRowStride >= (srcWidth * 8) ? dstRowStride - (((srcWidth + 7) & ~7) * 8) : 0; 288 for (j = 0; j < srcHeight; j += 4) { 289 if (srcHeight > j + 3) numypixels = 4; 290 else numypixels = srcHeight - j; 291 srcaddr = tempImage + j * srcWidth * 2; 292 for (i = 0; i < srcWidth; i += 4) { 293 if (srcWidth > i + 3) numxpixels = 4; 294 else numxpixels = srcWidth - i; 295 296 extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2); 297 signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); 298 blkaddr += 8; 299 300 extractsrc_s(srcpixels, srcaddr + 1, srcWidth, numxpixels, numypixels, 2); 301 signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels); 302 blkaddr += 8; 303 304 srcaddr += numxpixels * 2; 305 306 } 307 blkaddr += dstRowDiff; 308 } 309 if (tempImage) 310 free((void *) tempImage); 311 312 return GL_TRUE; 313} 314 315static void _fetch_texel_rgtc_u(GLint srcRowStride, const GLubyte *pixdata, 316 GLint i, GLint j, GLubyte *value, int comps) 317{ 318 GLubyte decode; 319 const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 8 * comps); 320 const GLubyte alpha0 = blksrc[0]; 321 const GLubyte alpha1 = blksrc[1]; 322 const GLubyte bit_pos = ((j&3) * 4 + (i&3)) * 3; 323 const GLubyte acodelow = blksrc[2 + bit_pos / 8]; 324 const uint8_t acodehigh = (3 + bit_pos / 8) < 8 ? blksrc[3 + bit_pos / 8] : 0; 325 const GLubyte code = (acodelow >> (bit_pos & 0x7) | 326 (acodehigh << (8 - (bit_pos & 0x7)))) & 0x7; 327 328 if (code == 0) 329 decode = alpha0; 330 else if (code == 1) 331 decode = alpha1; 332 else if (alpha0 > alpha1) 333 decode = ((alpha0 * (8 - code) + (alpha1 * (code - 1))) / 7); 334 else if (code < 6) 335 decode = ((alpha0 * (6 - code) + (alpha1 * (code - 1))) / 5); 336 else if (code == 6) 337 decode = 0; 338 else 339 decode = 255; 340 341 *value = decode; 342} 343 344 345static void _fetch_texel_rgtc_s(GLint srcRowStride, const GLbyte *pixdata, 346 GLint i, GLint j, GLbyte *value, int comps) 347{ 348 GLbyte decode; 349 const GLbyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 8 * comps); 350 const GLbyte alpha0 = blksrc[0]; 351 const GLbyte alpha1 = blksrc[1]; 352 const GLbyte bit_pos = ((j&3) * 4 + (i&3)) * 3; 353 const GLbyte acodelow = blksrc[2 + bit_pos / 8]; 354 const uint8_t acodehigh = (3 + bit_pos / 8) < 8 ? blksrc[3 + bit_pos / 8] : 0; 355 const GLbyte code = (acodelow >> (bit_pos & 0x7) | 356 (acodehigh << (8 - (bit_pos & 0x7)))) & 0x7; 357 358 if (code == 0) 359 decode = alpha0; 360 else if (code == 1) 361 decode = alpha1; 362 else if (alpha0 > alpha1) 363 decode = ((alpha0 * (8 - code) + (alpha1 * (code - 1))) / 7); 364 else if (code < 6) 365 decode = ((alpha0 * (6 - code) + (alpha1 * (code - 1))) / 5); 366 else if (code == 6) 367 decode = -127; 368 else 369 decode = 127; 370 371 *value = decode; 372} 373 374void 375_mesa_fetch_texel_2d_f_red_rgtc1(const struct gl_texture_image *texImage, 376 GLint i, GLint j, GLint k, GLfloat *texel) 377{ 378 GLubyte red; 379 _fetch_texel_rgtc_u(texImage->RowStride, (GLubyte *)(texImage->Data), 380 i, j, &red, 1); 381 texel[RCOMP] = UBYTE_TO_FLOAT(red); 382 texel[GCOMP] = 0.0; 383 texel[BCOMP] = 0.0; 384 texel[ACOMP] = 1.0; 385} 386 387void 388_mesa_fetch_texel_2d_f_signed_red_rgtc1(const struct gl_texture_image *texImage, 389 GLint i, GLint j, GLint k, GLfloat *texel) 390{ 391 GLbyte red; 392 _fetch_texel_rgtc_s(texImage->RowStride, (GLbyte *)(texImage->Data), 393 i, j, &red, 1); 394 texel[RCOMP] = BYTE_TO_FLOAT_TEX(red); 395 texel[GCOMP] = 0.0; 396 texel[BCOMP] = 0.0; 397 texel[ACOMP] = 1.0; 398} 399 400void 401_mesa_fetch_texel_2d_f_rg_rgtc2(const struct gl_texture_image *texImage, 402 GLint i, GLint j, GLint k, GLfloat *texel) 403{ 404 GLubyte red, green; 405 _fetch_texel_rgtc_u(texImage->RowStride, (GLubyte *)(texImage->Data), 406 i, j, &red, 2); 407 _fetch_texel_rgtc_u(texImage->RowStride, (GLubyte *)(texImage->Data) + 8, 408 i, j, &green, 2); 409 texel[RCOMP] = UBYTE_TO_FLOAT(red); 410 texel[GCOMP] = UBYTE_TO_FLOAT(green); 411 texel[BCOMP] = 0.0; 412 texel[ACOMP] = 1.0; 413} 414 415void 416_mesa_fetch_texel_2d_f_signed_rg_rgtc2(const struct gl_texture_image *texImage, 417 GLint i, GLint j, GLint k, GLfloat *texel) 418{ 419 GLbyte red, green; 420 _fetch_texel_rgtc_s(texImage->RowStride, (GLbyte *)(texImage->Data), 421 i, j, &red, 2); 422 _fetch_texel_rgtc_s(texImage->RowStride, (GLbyte *)(texImage->Data) + 8, 423 i, j, &green, 2); 424 texel[RCOMP] = BYTE_TO_FLOAT_TEX(red); 425 texel[GCOMP] = BYTE_TO_FLOAT_TEX(green); 426 texel[BCOMP] = 0.0; 427 texel[ACOMP] = 1.0; 428} 429 430#define TAG(x) unsigned_##x 431 432#define TYPE GLubyte 433#define T_MIN 0 434#define T_MAX 0xff 435 436#include "texcompress_rgtc_tmp.h" 437 438#undef TAG 439#undef TYPE 440#undef T_MIN 441#undef T_MAX 442 443#define TAG(x) signed_##x 444#define TYPE GLbyte 445#define T_MIN (GLbyte)-127 446#define T_MAX (GLbyte)128 447 448#include "texcompress_rgtc_tmp.h" 449 450#undef TAG 451#undef TYPE 452#undef T_MIN 453#undef T_MAX 454