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 #include "imports.h" 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 */ 48 GLboolean 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 */ 100 GLboolean 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 _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM 125 : MESA_FORMAT_A8B8G8R8_UNORM, 126 rgbaRowStride, tempImageSlices, 127 srcWidth, srcHeight, srcDepth, 128 srcFormat, srcType, srcAddr, 129 srcPacking); 130 pixels = tempImage; 131 srcFormat = GL_RGBA; 132 } 133 else { 134 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 135 srcFormat, srcType, 0, 0); 136 } 137 138 dst = dstSlices[0]; 139 140 tx_compress_dxtn(4, srcWidth, srcHeight, pixels, 141 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 142 dst, dstRowStride); 143 144 free((void*) tempImage); 145 146 return GL_TRUE; 147 } 148 149 150 /** 151 * Store user's image in rgba_dxt3 format. 152 */ 153 GLboolean 154 _mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS) 155 { 156 const GLubyte *pixels; 157 GLubyte *dst; 158 const GLubyte *tempImage = NULL; 159 160 assert(dstFormat == MESA_FORMAT_RGBA_DXT3 || 161 dstFormat == MESA_FORMAT_SRGBA_DXT3); 162 163 if (srcFormat != GL_RGBA || 164 srcType != GL_UNSIGNED_BYTE || 165 ctx->_ImageTransferState || 166 ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth || 167 srcPacking->SwapBytes) { 168 /* convert image to RGBA/GLubyte */ 169 GLubyte *tempImageSlices[1]; 170 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte); 171 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte)); 172 if (!tempImage) 173 return GL_FALSE; /* out of memory */ 174 tempImageSlices[0] = (GLubyte *) tempImage; 175 _mesa_texstore(ctx, dims, 176 baseInternalFormat, 177 _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM 178 : MESA_FORMAT_A8B8G8R8_UNORM, 179 rgbaRowStride, tempImageSlices, 180 srcWidth, srcHeight, srcDepth, 181 srcFormat, srcType, srcAddr, 182 srcPacking); 183 pixels = tempImage; 184 } 185 else { 186 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 187 srcFormat, srcType, 0, 0); 188 } 189 190 dst = dstSlices[0]; 191 192 tx_compress_dxtn(4, srcWidth, srcHeight, pixels, 193 GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 194 dst, dstRowStride); 195 196 free((void *) tempImage); 197 198 return GL_TRUE; 199 } 200 201 202 /** 203 * Store user's image in rgba_dxt5 format. 204 */ 205 GLboolean 206 _mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS) 207 { 208 const GLubyte *pixels; 209 GLubyte *dst; 210 const GLubyte *tempImage = NULL; 211 212 assert(dstFormat == MESA_FORMAT_RGBA_DXT5 || 213 dstFormat == MESA_FORMAT_SRGBA_DXT5); 214 215 if (srcFormat != GL_RGBA || 216 srcType != GL_UNSIGNED_BYTE || 217 ctx->_ImageTransferState || 218 ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth || 219 srcPacking->SwapBytes) { 220 /* convert image to RGBA/GLubyte */ 221 GLubyte *tempImageSlices[1]; 222 int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte); 223 tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte)); 224 if (!tempImage) 225 return GL_FALSE; /* out of memory */ 226 tempImageSlices[0] = (GLubyte *) tempImage; 227 _mesa_texstore(ctx, dims, 228 baseInternalFormat, 229 _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM 230 : MESA_FORMAT_A8B8G8R8_UNORM, 231 rgbaRowStride, tempImageSlices, 232 srcWidth, srcHeight, srcDepth, 233 srcFormat, srcType, srcAddr, 234 srcPacking); 235 pixels = tempImage; 236 } 237 else { 238 pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 239 srcFormat, srcType, 0, 0); 240 } 241 242 dst = dstSlices[0]; 243 244 tx_compress_dxtn(4, srcWidth, srcHeight, pixels, 245 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 246 dst, dstRowStride); 247 248 free((void *) tempImage); 249 250 return GL_TRUE; 251 } 252 253 254 static void 255 fetch_rgb_dxt1(const GLubyte *map, 256 GLint rowStride, GLint i, GLint j, GLfloat *texel) 257 { 258 GLubyte tex[4]; 259 fetch_2d_texel_rgb_dxt1(rowStride, map, i, j, tex); 260 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 261 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 262 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 263 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 264 } 265 266 static void 267 fetch_rgba_dxt1(const GLubyte *map, 268 GLint rowStride, GLint i, GLint j, GLfloat *texel) 269 { 270 GLubyte tex[4]; 271 fetch_2d_texel_rgba_dxt1(rowStride, map, i, j, tex); 272 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 273 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 274 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 275 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 276 } 277 278 static void 279 fetch_rgba_dxt3(const GLubyte *map, 280 GLint rowStride, GLint i, GLint j, GLfloat *texel) 281 { 282 GLubyte tex[4]; 283 fetch_2d_texel_rgba_dxt3(rowStride, map, i, j, tex); 284 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 285 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 286 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 287 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 288 } 289 290 static void 291 fetch_rgba_dxt5(const GLubyte *map, 292 GLint rowStride, GLint i, GLint j, GLfloat *texel) 293 { 294 GLubyte tex[4]; 295 fetch_2d_texel_rgba_dxt5(rowStride, map, i, j, tex); 296 texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 297 texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 298 texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 299 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 300 } 301 302 303 static void 304 fetch_srgb_dxt1(const GLubyte *map, 305 GLint rowStride, GLint i, GLint j, GLfloat *texel) 306 { 307 GLubyte tex[4]; 308 fetch_2d_texel_rgb_dxt1(rowStride, map, i, j, tex); 309 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 310 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 311 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 312 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 313 } 314 315 static void 316 fetch_srgba_dxt1(const GLubyte *map, 317 GLint rowStride, GLint i, GLint j, GLfloat *texel) 318 { 319 GLubyte tex[4]; 320 fetch_2d_texel_rgba_dxt1(rowStride, map, i, j, tex); 321 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 322 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 323 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 324 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 325 } 326 327 static void 328 fetch_srgba_dxt3(const GLubyte *map, 329 GLint rowStride, GLint i, GLint j, GLfloat *texel) 330 { 331 GLubyte tex[4]; 332 fetch_2d_texel_rgba_dxt3(rowStride, map, i, j, tex); 333 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 334 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 335 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 336 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 337 } 338 339 static void 340 fetch_srgba_dxt5(const GLubyte *map, 341 GLint rowStride, GLint i, GLint j, GLfloat *texel) 342 { 343 GLubyte tex[4]; 344 fetch_2d_texel_rgba_dxt5(rowStride, map, i, j, tex); 345 texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 346 texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 347 texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 348 texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 349 } 350 351 352 353 compressed_fetch_func 354 _mesa_get_dxt_fetch_func(mesa_format format) 355 { 356 switch (format) { 357 case MESA_FORMAT_RGB_DXT1: 358 return fetch_rgb_dxt1; 359 case MESA_FORMAT_RGBA_DXT1: 360 return fetch_rgba_dxt1; 361 case MESA_FORMAT_RGBA_DXT3: 362 return fetch_rgba_dxt3; 363 case MESA_FORMAT_RGBA_DXT5: 364 return fetch_rgba_dxt5; 365 case MESA_FORMAT_SRGB_DXT1: 366 return fetch_srgb_dxt1; 367 case MESA_FORMAT_SRGBA_DXT1: 368 return fetch_srgba_dxt1; 369 case MESA_FORMAT_SRGBA_DXT3: 370 return fetch_srgba_dxt3; 371 case MESA_FORMAT_SRGBA_DXT5: 372 return fetch_srgba_dxt5; 373 default: 374 return NULL; 375 } 376 } 377