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 int srccomps = srcFormat == GL_RGB ? 3 : 4; 55 56 assert(dstFormat == MESA_FORMAT_RGB_DXT1 || 57 dstFormat == MESA_FORMAT_SRGB_DXT1); 58 59 if (!(srcFormat == GL_RGB || srcFormat == GL_RGBA) || 60 srcType != GL_UNSIGNED_BYTE || 61 ctx->_ImageTransferState || 62 _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType) != srccomps * srcWidth * sizeof(GLubyte) || 63 srcPacking->SkipImages || 64 srcPacking->SwapBytes) { 65 /* convert image to RGB/GLubyte */ 66 GLubyte *tempImageSlices[1]; 67 int rgbRowStride = 3 * srcWidth * sizeof(GLubyte); 68 tempImage = malloc(srcWidth * srcHeight * 3 * sizeof(GLubyte)); 69 if (!tempImage) 70 return GL_FALSE; /* out of memory */ 71 tempImageSlices[0] = (GLubyte *) tempImage; 72 _mesa_texstore(ctx, dims, 73 baseInternalFormat, 74 MESA_FORMAT_RGB_UNORM8, 75 rgbRowStride, tempImageSlices, 76 srcWidth, srcHeight, srcDepth, 77 srcFormat, srcType, srcAddr, 78 srcPacking); 79 pixels = tempImage; 80 srcFormat = GL_RGB; 81 srccomps = 3; 82 } 83 else { 84 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 85 srcFormat, srcType, 0, 0); 86 } 87 88 dst = dstSlices[0]; 89 90 tx_compress_dxt1(srccomps, srcWidth, srcHeight, pixels, 91 dst, dstRowStride, 3); 92 93 free((void *) tempImage); 94 95 return GL_TRUE; 96} 97 98 99/** 100 * Store user's image in rgba_dxt1 format. 101 */ 102GLboolean 103_mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS) 104{ 105 const GLubyte *pixels; 106 GLubyte *dst; 107 const GLubyte *tempImage = NULL; 108 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte); 109 110 assert(dstFormat == MESA_FORMAT_RGBA_DXT1 || 111 dstFormat == MESA_FORMAT_SRGBA_DXT1); 112 113 if (srcFormat != GL_RGBA || 114 srcType != GL_UNSIGNED_BYTE || 115 ctx->_ImageTransferState || 116 _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType) != rgbaRowStride || 117 srcPacking->SkipImages || 118 srcPacking->SwapBytes) { 119 /* convert image to RGBA/GLubyte */ 120 GLubyte *tempImageSlices[1]; 121 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte)); 122 if (!tempImage) 123 return GL_FALSE; /* out of memory */ 124 tempImageSlices[0] = (GLubyte *) tempImage; 125 _mesa_texstore(ctx, dims, 126 baseInternalFormat, 127#if UTIL_ARCH_LITTLE_ENDIAN 128 MESA_FORMAT_R8G8B8A8_UNORM, 129#else 130 MESA_FORMAT_A8B8G8R8_UNORM, 131#endif 132 rgbaRowStride, tempImageSlices, 133 srcWidth, srcHeight, srcDepth, 134 srcFormat, srcType, srcAddr, 135 srcPacking); 136 pixels = tempImage; 137 srcFormat = GL_RGBA; 138 } 139 else { 140 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 141 srcFormat, srcType, 0, 0); 142 } 143 144 dst = dstSlices[0]; 145 146 tx_compress_dxt1(4, srcWidth, srcHeight, pixels, dst, dstRowStride, 4); 147 148 free((void*) tempImage); 149 150 return GL_TRUE; 151} 152 153 154/** 155 * Store user's image in rgba_dxt3 format. 156 */ 157GLboolean 158_mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS) 159{ 160 const GLubyte *pixels; 161 GLubyte *dst; 162 const GLubyte *tempImage = NULL; 163 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte); 164 165 assert(dstFormat == MESA_FORMAT_RGBA_DXT3 || 166 dstFormat == MESA_FORMAT_SRGBA_DXT3); 167 168 if (srcFormat != GL_RGBA || 169 srcType != GL_UNSIGNED_BYTE || 170 ctx->_ImageTransferState || 171 _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType) != rgbaRowStride || 172 srcPacking->SkipImages || 173 srcPacking->SwapBytes) { 174 /* convert image to RGBA/GLubyte */ 175 GLubyte *tempImageSlices[1]; 176 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte)); 177 if (!tempImage) 178 return GL_FALSE; /* out of memory */ 179 tempImageSlices[0] = (GLubyte *) tempImage; 180 _mesa_texstore(ctx, dims, 181 baseInternalFormat, 182#if UTIL_ARCH_LITTLE_ENDIAN 183 MESA_FORMAT_R8G8B8A8_UNORM, 184#else 185 MESA_FORMAT_A8B8G8R8_UNORM, 186#endif 187 rgbaRowStride, tempImageSlices, 188 srcWidth, srcHeight, srcDepth, 189 srcFormat, srcType, srcAddr, 190 srcPacking); 191 pixels = tempImage; 192 } 193 else { 194 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 195 srcFormat, srcType, 0, 0); 196 } 197 198 dst = dstSlices[0]; 199 200 tx_compress_dxt3(4, srcWidth, srcHeight, pixels, 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 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte); 218 219 assert(dstFormat == MESA_FORMAT_RGBA_DXT5 || 220 dstFormat == MESA_FORMAT_SRGBA_DXT5); 221 222 if (srcFormat != GL_RGBA || 223 srcType != GL_UNSIGNED_BYTE || 224 ctx->_ImageTransferState || 225 _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType) != rgbaRowStride || 226 srcPacking->SkipImages || 227 srcPacking->SwapBytes) { 228 /* convert image to RGBA/GLubyte */ 229 GLubyte *tempImageSlices[1]; 230 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte)); 231 if (!tempImage) 232 return GL_FALSE; /* out of memory */ 233 tempImageSlices[0] = (GLubyte *) tempImage; 234 _mesa_texstore(ctx, dims, 235 baseInternalFormat, 236#if UTIL_ARCH_LITTLE_ENDIAN 237 MESA_FORMAT_R8G8B8A8_UNORM, 238#else 239 MESA_FORMAT_A8B8G8R8_UNORM, 240#endif 241 rgbaRowStride, tempImageSlices, 242 srcWidth, srcHeight, srcDepth, 243 srcFormat, srcType, srcAddr, 244 srcPacking); 245 pixels = tempImage; 246 } 247 else { 248 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 249 srcFormat, srcType, 0, 0); 250 } 251 252 dst = dstSlices[0]; 253 254 tx_compress_dxt5(4, srcWidth, srcHeight, pixels, dst, dstRowStride); 255 256 free((void *) tempImage); 257 258 return GL_TRUE; 259} 260 261 262static void 263fetch_rgb_dxt1(const GLubyte *map, 264 GLint rowStride, GLint i, GLint j, GLfloat *texel) 265{ 266 GLubyte tex[4]; 267 fetch_2d_texel_rgb_dxt1(rowStride, map, i, j, tex); 268 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 269 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 270 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 271 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 272} 273 274static void 275fetch_rgba_dxt1(const GLubyte *map, 276 GLint rowStride, GLint i, GLint j, GLfloat *texel) 277{ 278 GLubyte tex[4]; 279 fetch_2d_texel_rgba_dxt1(rowStride, map, i, j, tex); 280 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 281 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 282 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 283 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 284} 285 286static void 287fetch_rgba_dxt3(const GLubyte *map, 288 GLint rowStride, GLint i, GLint j, GLfloat *texel) 289{ 290 GLubyte tex[4]; 291 fetch_2d_texel_rgba_dxt3(rowStride, map, i, j, tex); 292 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 293 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 294 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 295 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 296} 297 298static void 299fetch_rgba_dxt5(const GLubyte *map, 300 GLint rowStride, GLint i, GLint j, GLfloat *texel) 301{ 302 GLubyte tex[4]; 303 fetch_2d_texel_rgba_dxt5(rowStride, map, i, j, tex); 304 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 305 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 306 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 307 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 308} 309 310 311static void 312fetch_srgb_dxt1(const GLubyte *map, 313 GLint rowStride, GLint i, GLint j, GLfloat *texel) 314{ 315 GLubyte tex[4]; 316 fetch_2d_texel_rgb_dxt1(rowStride, map, i, j, tex); 317 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 318 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 319 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 320 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 321} 322 323static void 324fetch_srgba_dxt1(const GLubyte *map, 325 GLint rowStride, GLint i, GLint j, GLfloat *texel) 326{ 327 GLubyte tex[4]; 328 fetch_2d_texel_rgba_dxt1(rowStride, map, i, j, tex); 329 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 330 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 331 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 332 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 333} 334 335static void 336fetch_srgba_dxt3(const GLubyte *map, 337 GLint rowStride, GLint i, GLint j, GLfloat *texel) 338{ 339 GLubyte tex[4]; 340 fetch_2d_texel_rgba_dxt3(rowStride, map, i, j, tex); 341 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 342 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 343 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 344 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 345} 346 347static void 348fetch_srgba_dxt5(const GLubyte *map, 349 GLint rowStride, GLint i, GLint j, GLfloat *texel) 350{ 351 GLubyte tex[4]; 352 fetch_2d_texel_rgba_dxt5(rowStride, map, i, j, tex); 353 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 354 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 355 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 356 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 357} 358 359 360 361compressed_fetch_func 362_mesa_get_dxt_fetch_func(mesa_format format) 363{ 364 switch (format) { 365 case MESA_FORMAT_RGB_DXT1: 366 return fetch_rgb_dxt1; 367 case MESA_FORMAT_RGBA_DXT1: 368 return fetch_rgba_dxt1; 369 case MESA_FORMAT_RGBA_DXT3: 370 return fetch_rgba_dxt3; 371 case MESA_FORMAT_RGBA_DXT5: 372 return fetch_rgba_dxt5; 373 case MESA_FORMAT_SRGB_DXT1: 374 return fetch_srgb_dxt1; 375 case MESA_FORMAT_SRGBA_DXT1: 376 return fetch_srgba_dxt1; 377 case MESA_FORMAT_SRGBA_DXT3: 378 return fetch_srgba_dxt3; 379 case MESA_FORMAT_SRGBA_DXT5: 380 return fetch_srgba_dxt5; 381 default: 382 return NULL; 383 } 384} 385