1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5 * Copyright (c) 2008 VMware, Inc. 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 shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 * OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27/** 28 * \file texcompress_s3tc.c 29 * GL_EXT_texture_compression_s3tc support. 30 */ 31 32#include "glheader.h" 33 34#include "image.h" 35#include "macros.h" 36#include "mtypes.h" 37#include "texcompress.h" 38#include "texcompress_s3tc.h" 39#include "texcompress_s3tc_tmp.h" 40#include "texstore.h" 41#include "format_unpack.h" 42#include "util/format_srgb.h" 43 44 45/** 46 * Store user's image in rgb_dxt1 format. 47 */ 48GLboolean 49_mesa_texstore_rgb_dxt1(TEXSTORE_PARAMS) 50{ 51 const GLubyte *pixels; 52 GLubyte *dst; 53 const GLubyte *tempImage = NULL; 54 55 assert(dstFormat == MESA_FORMAT_RGB_DXT1 || 56 dstFormat == MESA_FORMAT_SRGB_DXT1); 57 58 if (srcFormat != GL_RGB || 59 srcType != GL_UNSIGNED_BYTE || 60 ctx->_ImageTransferState || 61 ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth || 62 srcPacking->SwapBytes) { 63 /* convert image to RGB/GLubyte */ 64 GLubyte *tempImageSlices[1]; 65 int rgbRowStride = 3 * srcWidth * sizeof(GLubyte); 66 tempImage = malloc(srcWidth * srcHeight * 3 * sizeof(GLubyte)); 67 if (!tempImage) 68 return GL_FALSE; /* out of memory */ 69 tempImageSlices[0] = (GLubyte *) tempImage; 70 _mesa_texstore(ctx, dims, 71 baseInternalFormat, 72 MESA_FORMAT_RGB_UNORM8, 73 rgbRowStride, tempImageSlices, 74 srcWidth, srcHeight, srcDepth, 75 srcFormat, srcType, srcAddr, 76 srcPacking); 77 pixels = tempImage; 78 srcFormat = GL_RGB; 79 } 80 else { 81 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 82 srcFormat, srcType, 0, 0); 83 } 84 85 dst = dstSlices[0]; 86 87 tx_compress_dxtn(3, srcWidth, srcHeight, pixels, 88 GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 89 dst, dstRowStride); 90 91 free((void *) tempImage); 92 93 return GL_TRUE; 94} 95 96 97/** 98 * Store user's image in rgba_dxt1 format. 99 */ 100GLboolean 101_mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS) 102{ 103 const GLubyte *pixels; 104 GLubyte *dst; 105 const GLubyte *tempImage = NULL; 106 107 assert(dstFormat == MESA_FORMAT_RGBA_DXT1 || 108 dstFormat == MESA_FORMAT_SRGBA_DXT1); 109 110 if (srcFormat != GL_RGBA || 111 srcType != GL_UNSIGNED_BYTE || 112 ctx->_ImageTransferState || 113 ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth || 114 srcPacking->SwapBytes) { 115 /* convert image to RGBA/GLubyte */ 116 GLubyte *tempImageSlices[1]; 117 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte); 118 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte)); 119 if (!tempImage) 120 return GL_FALSE; /* out of memory */ 121 tempImageSlices[0] = (GLubyte *) tempImage; 122 _mesa_texstore(ctx, dims, 123 baseInternalFormat, 124#if UTIL_ARCH_LITTLE_ENDIAN 125 MESA_FORMAT_R8G8B8A8_UNORM, 126#else 127 MESA_FORMAT_A8B8G8R8_UNORM, 128#endif 129 rgbaRowStride, tempImageSlices, 130 srcWidth, srcHeight, srcDepth, 131 srcFormat, srcType, srcAddr, 132 srcPacking); 133 pixels = tempImage; 134 srcFormat = GL_RGBA; 135 } 136 else { 137 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 138 srcFormat, srcType, 0, 0); 139 } 140 141 dst = dstSlices[0]; 142 143 tx_compress_dxtn(4, srcWidth, srcHeight, pixels, 144 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 145 dst, dstRowStride); 146 147 free((void*) tempImage); 148 149 return GL_TRUE; 150} 151 152 153/** 154 * Store user's image in rgba_dxt3 format. 155 */ 156GLboolean 157_mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS) 158{ 159 const GLubyte *pixels; 160 GLubyte *dst; 161 const GLubyte *tempImage = NULL; 162 163 assert(dstFormat == MESA_FORMAT_RGBA_DXT3 || 164 dstFormat == MESA_FORMAT_SRGBA_DXT3); 165 166 if (srcFormat != GL_RGBA || 167 srcType != GL_UNSIGNED_BYTE || 168 ctx->_ImageTransferState || 169 ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth || 170 srcPacking->SwapBytes) { 171 /* convert image to RGBA/GLubyte */ 172 GLubyte *tempImageSlices[1]; 173 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte); 174 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte)); 175 if (!tempImage) 176 return GL_FALSE; /* out of memory */ 177 tempImageSlices[0] = (GLubyte *) tempImage; 178 _mesa_texstore(ctx, dims, 179 baseInternalFormat, 180#if UTIL_ARCH_LITTLE_ENDIAN 181 MESA_FORMAT_R8G8B8A8_UNORM, 182#else 183 MESA_FORMAT_A8B8G8R8_UNORM, 184#endif 185 rgbaRowStride, tempImageSlices, 186 srcWidth, srcHeight, srcDepth, 187 srcFormat, srcType, srcAddr, 188 srcPacking); 189 pixels = tempImage; 190 } 191 else { 192 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 193 srcFormat, srcType, 0, 0); 194 } 195 196 dst = dstSlices[0]; 197 198 tx_compress_dxtn(4, srcWidth, srcHeight, pixels, 199 GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 200 dst, dstRowStride); 201 202 free((void *) tempImage); 203 204 return GL_TRUE; 205} 206 207 208/** 209 * Store user's image in rgba_dxt5 format. 210 */ 211GLboolean 212_mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS) 213{ 214 const GLubyte *pixels; 215 GLubyte *dst; 216 const GLubyte *tempImage = NULL; 217 218 assert(dstFormat == MESA_FORMAT_RGBA_DXT5 || 219 dstFormat == MESA_FORMAT_SRGBA_DXT5); 220 221 if (srcFormat != GL_RGBA || 222 srcType != GL_UNSIGNED_BYTE || 223 ctx->_ImageTransferState || 224 ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth || 225 srcPacking->SwapBytes) { 226 /* convert image to RGBA/GLubyte */ 227 GLubyte *tempImageSlices[1]; 228 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte); 229 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte)); 230 if (!tempImage) 231 return GL_FALSE; /* out of memory */ 232 tempImageSlices[0] = (GLubyte *) tempImage; 233 _mesa_texstore(ctx, dims, 234 baseInternalFormat, 235#if UTIL_ARCH_LITTLE_ENDIAN 236 MESA_FORMAT_R8G8B8A8_UNORM, 237#else 238 MESA_FORMAT_A8B8G8R8_UNORM, 239#endif 240 rgbaRowStride, tempImageSlices, 241 srcWidth, srcHeight, srcDepth, 242 srcFormat, srcType, srcAddr, 243 srcPacking); 244 pixels = tempImage; 245 } 246 else { 247 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 248 srcFormat, srcType, 0, 0); 249 } 250 251 dst = dstSlices[0]; 252 253 tx_compress_dxtn(4, srcWidth, srcHeight, pixels, 254 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 255 dst, dstRowStride); 256 257 free((void *) tempImage); 258 259 return GL_TRUE; 260} 261 262 263static void 264fetch_rgb_dxt1(const GLubyte *map, 265 GLint rowStride, GLint i, GLint j, GLfloat *texel) 266{ 267 GLubyte tex[4]; 268 fetch_2d_texel_rgb_dxt1(rowStride, map, i, j, tex); 269 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 270 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 271 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 272 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 273} 274 275static void 276fetch_rgba_dxt1(const GLubyte *map, 277 GLint rowStride, GLint i, GLint j, GLfloat *texel) 278{ 279 GLubyte tex[4]; 280 fetch_2d_texel_rgba_dxt1(rowStride, map, i, j, tex); 281 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 282 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 283 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 284 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 285} 286 287static void 288fetch_rgba_dxt3(const GLubyte *map, 289 GLint rowStride, GLint i, GLint j, GLfloat *texel) 290{ 291 GLubyte tex[4]; 292 fetch_2d_texel_rgba_dxt3(rowStride, map, i, j, tex); 293 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 294 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 295 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 296 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 297} 298 299static void 300fetch_rgba_dxt5(const GLubyte *map, 301 GLint rowStride, GLint i, GLint j, GLfloat *texel) 302{ 303 GLubyte tex[4]; 304 fetch_2d_texel_rgba_dxt5(rowStride, map, i, j, tex); 305 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 306 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 307 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 308 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 309} 310 311 312static void 313fetch_srgb_dxt1(const GLubyte *map, 314 GLint rowStride, GLint i, GLint j, GLfloat *texel) 315{ 316 GLubyte tex[4]; 317 fetch_2d_texel_rgb_dxt1(rowStride, map, i, j, tex); 318 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 319 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 320 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 321 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 322} 323 324static void 325fetch_srgba_dxt1(const GLubyte *map, 326 GLint rowStride, GLint i, GLint j, GLfloat *texel) 327{ 328 GLubyte tex[4]; 329 fetch_2d_texel_rgba_dxt1(rowStride, map, i, j, tex); 330 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 331 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 332 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 333 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 334} 335 336static void 337fetch_srgba_dxt3(const GLubyte *map, 338 GLint rowStride, GLint i, GLint j, GLfloat *texel) 339{ 340 GLubyte tex[4]; 341 fetch_2d_texel_rgba_dxt3(rowStride, map, i, j, tex); 342 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 343 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 344 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 345 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 346} 347 348static void 349fetch_srgba_dxt5(const GLubyte *map, 350 GLint rowStride, GLint i, GLint j, GLfloat *texel) 351{ 352 GLubyte tex[4]; 353 fetch_2d_texel_rgba_dxt5(rowStride, map, i, j, tex); 354 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 355 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 356 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 357 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 358} 359 360 361 362compressed_fetch_func 363_mesa_get_dxt_fetch_func(mesa_format format) 364{ 365 switch (format) { 366 case MESA_FORMAT_RGB_DXT1: 367 return fetch_rgb_dxt1; 368 case MESA_FORMAT_RGBA_DXT1: 369 return fetch_rgba_dxt1; 370 case MESA_FORMAT_RGBA_DXT3: 371 return fetch_rgba_dxt3; 372 case MESA_FORMAT_RGBA_DXT5: 373 return fetch_rgba_dxt5; 374 case MESA_FORMAT_SRGB_DXT1: 375 return fetch_srgb_dxt1; 376 case MESA_FORMAT_SRGBA_DXT1: 377 return fetch_srgba_dxt1; 378 case MESA_FORMAT_SRGBA_DXT3: 379 return fetch_srgba_dxt3; 380 case MESA_FORMAT_SRGBA_DXT5: 381 return fetch_srgba_dxt5; 382 default: 383 return NULL; 384 } 385} 386