1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5848b8605Smrg * Copyright (c) 2008 VMware, Inc. 6848b8605Smrg * 7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 8848b8605Smrg * copy of this software and associated documentation files (the "Software"), 9848b8605Smrg * to deal in the Software without restriction, including without limitation 10848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 12848b8605Smrg * Software is furnished to do so, subject to the following conditions: 13848b8605Smrg * 14848b8605Smrg * The above copyright notice and this permission notice shall be included 15848b8605Smrg * in all copies or substantial portions of the Software. 16848b8605Smrg * 17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 24848b8605Smrg */ 25848b8605Smrg 26848b8605Smrg 27848b8605Smrg/** 28848b8605Smrg * \file texcompress_s3tc.c 29848b8605Smrg * GL_EXT_texture_compression_s3tc support. 30848b8605Smrg */ 31848b8605Smrg 32848b8605Smrg#include "glheader.h" 33848b8605Smrg#include "imports.h" 34848b8605Smrg#include "image.h" 35848b8605Smrg#include "macros.h" 36848b8605Smrg#include "mtypes.h" 37848b8605Smrg#include "texcompress.h" 38848b8605Smrg#include "texcompress_s3tc.h" 39b8e80941Smrg#include "texcompress_s3tc_tmp.h" 40848b8605Smrg#include "texstore.h" 41848b8605Smrg#include "format_unpack.h" 42848b8605Smrg#include "util/format_srgb.h" 43848b8605Smrg 44848b8605Smrg 45848b8605Smrg/** 46848b8605Smrg * Store user's image in rgb_dxt1 format. 47848b8605Smrg */ 48848b8605SmrgGLboolean 49848b8605Smrg_mesa_texstore_rgb_dxt1(TEXSTORE_PARAMS) 50848b8605Smrg{ 51848b8605Smrg const GLubyte *pixels; 52848b8605Smrg GLubyte *dst; 53848b8605Smrg const GLubyte *tempImage = NULL; 54848b8605Smrg 55b8e80941Smrg assert(dstFormat == MESA_FORMAT_RGB_DXT1 || 56848b8605Smrg dstFormat == MESA_FORMAT_SRGB_DXT1); 57848b8605Smrg 58848b8605Smrg if (srcFormat != GL_RGB || 59848b8605Smrg srcType != GL_UNSIGNED_BYTE || 60848b8605Smrg ctx->_ImageTransferState || 61b8e80941Smrg ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth || 62848b8605Smrg srcPacking->SwapBytes) { 63848b8605Smrg /* convert image to RGB/GLubyte */ 64b8e80941Smrg GLubyte *tempImageSlices[1]; 65b8e80941Smrg int rgbRowStride = 3 * srcWidth * sizeof(GLubyte); 66b8e80941Smrg tempImage = malloc(srcWidth * srcHeight * 3 * sizeof(GLubyte)); 67848b8605Smrg if (!tempImage) 68848b8605Smrg return GL_FALSE; /* out of memory */ 69b8e80941Smrg tempImageSlices[0] = (GLubyte *) tempImage; 70b8e80941Smrg _mesa_texstore(ctx, dims, 71b8e80941Smrg baseInternalFormat, 72b8e80941Smrg MESA_FORMAT_RGB_UNORM8, 73b8e80941Smrg rgbRowStride, tempImageSlices, 74b8e80941Smrg srcWidth, srcHeight, srcDepth, 75b8e80941Smrg srcFormat, srcType, srcAddr, 76b8e80941Smrg srcPacking); 77848b8605Smrg pixels = tempImage; 78848b8605Smrg srcFormat = GL_RGB; 79848b8605Smrg } 80848b8605Smrg else { 81848b8605Smrg pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 82848b8605Smrg srcFormat, srcType, 0, 0); 83848b8605Smrg } 84848b8605Smrg 85848b8605Smrg dst = dstSlices[0]; 86848b8605Smrg 87b8e80941Smrg tx_compress_dxtn(3, srcWidth, srcHeight, pixels, 88b8e80941Smrg GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 89b8e80941Smrg dst, dstRowStride); 90848b8605Smrg 91848b8605Smrg free((void *) tempImage); 92848b8605Smrg 93848b8605Smrg return GL_TRUE; 94848b8605Smrg} 95848b8605Smrg 96848b8605Smrg 97848b8605Smrg/** 98848b8605Smrg * Store user's image in rgba_dxt1 format. 99848b8605Smrg */ 100848b8605SmrgGLboolean 101848b8605Smrg_mesa_texstore_rgba_dxt1(TEXSTORE_PARAMS) 102848b8605Smrg{ 103848b8605Smrg const GLubyte *pixels; 104848b8605Smrg GLubyte *dst; 105848b8605Smrg const GLubyte *tempImage = NULL; 106848b8605Smrg 107b8e80941Smrg assert(dstFormat == MESA_FORMAT_RGBA_DXT1 || 108848b8605Smrg dstFormat == MESA_FORMAT_SRGBA_DXT1); 109848b8605Smrg 110848b8605Smrg if (srcFormat != GL_RGBA || 111848b8605Smrg srcType != GL_UNSIGNED_BYTE || 112848b8605Smrg ctx->_ImageTransferState || 113b8e80941Smrg ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth || 114848b8605Smrg srcPacking->SwapBytes) { 115848b8605Smrg /* convert image to RGBA/GLubyte */ 116b8e80941Smrg GLubyte *tempImageSlices[1]; 117b8e80941Smrg int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte); 118b8e80941Smrg tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte)); 119848b8605Smrg if (!tempImage) 120848b8605Smrg return GL_FALSE; /* out of memory */ 121b8e80941Smrg tempImageSlices[0] = (GLubyte *) tempImage; 122b8e80941Smrg _mesa_texstore(ctx, dims, 123b8e80941Smrg baseInternalFormat, 124b8e80941Smrg _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM 125b8e80941Smrg : MESA_FORMAT_A8B8G8R8_UNORM, 126b8e80941Smrg rgbaRowStride, tempImageSlices, 127b8e80941Smrg srcWidth, srcHeight, srcDepth, 128b8e80941Smrg srcFormat, srcType, srcAddr, 129b8e80941Smrg srcPacking); 130848b8605Smrg pixels = tempImage; 131848b8605Smrg srcFormat = GL_RGBA; 132848b8605Smrg } 133848b8605Smrg else { 134848b8605Smrg pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 135848b8605Smrg srcFormat, srcType, 0, 0); 136848b8605Smrg } 137848b8605Smrg 138848b8605Smrg dst = dstSlices[0]; 139848b8605Smrg 140b8e80941Smrg tx_compress_dxtn(4, srcWidth, srcHeight, pixels, 141b8e80941Smrg GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 142b8e80941Smrg dst, dstRowStride); 143848b8605Smrg 144848b8605Smrg free((void*) tempImage); 145848b8605Smrg 146848b8605Smrg return GL_TRUE; 147848b8605Smrg} 148848b8605Smrg 149848b8605Smrg 150848b8605Smrg/** 151848b8605Smrg * Store user's image in rgba_dxt3 format. 152848b8605Smrg */ 153848b8605SmrgGLboolean 154848b8605Smrg_mesa_texstore_rgba_dxt3(TEXSTORE_PARAMS) 155848b8605Smrg{ 156848b8605Smrg const GLubyte *pixels; 157848b8605Smrg GLubyte *dst; 158848b8605Smrg const GLubyte *tempImage = NULL; 159848b8605Smrg 160b8e80941Smrg assert(dstFormat == MESA_FORMAT_RGBA_DXT3 || 161848b8605Smrg dstFormat == MESA_FORMAT_SRGBA_DXT3); 162848b8605Smrg 163848b8605Smrg if (srcFormat != GL_RGBA || 164848b8605Smrg srcType != GL_UNSIGNED_BYTE || 165848b8605Smrg ctx->_ImageTransferState || 166b8e80941Smrg ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth || 167848b8605Smrg srcPacking->SwapBytes) { 168848b8605Smrg /* convert image to RGBA/GLubyte */ 169b8e80941Smrg GLubyte *tempImageSlices[1]; 170b8e80941Smrg int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte); 171b8e80941Smrg tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte)); 172848b8605Smrg if (!tempImage) 173848b8605Smrg return GL_FALSE; /* out of memory */ 174b8e80941Smrg tempImageSlices[0] = (GLubyte *) tempImage; 175b8e80941Smrg _mesa_texstore(ctx, dims, 176b8e80941Smrg baseInternalFormat, 177b8e80941Smrg _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM 178b8e80941Smrg : MESA_FORMAT_A8B8G8R8_UNORM, 179b8e80941Smrg rgbaRowStride, tempImageSlices, 180b8e80941Smrg srcWidth, srcHeight, srcDepth, 181b8e80941Smrg srcFormat, srcType, srcAddr, 182b8e80941Smrg srcPacking); 183848b8605Smrg pixels = tempImage; 184848b8605Smrg } 185848b8605Smrg else { 186848b8605Smrg pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 187848b8605Smrg srcFormat, srcType, 0, 0); 188848b8605Smrg } 189848b8605Smrg 190848b8605Smrg dst = dstSlices[0]; 191848b8605Smrg 192b8e80941Smrg tx_compress_dxtn(4, srcWidth, srcHeight, pixels, 193b8e80941Smrg GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 194b8e80941Smrg dst, dstRowStride); 195848b8605Smrg 196848b8605Smrg free((void *) tempImage); 197848b8605Smrg 198848b8605Smrg return GL_TRUE; 199848b8605Smrg} 200848b8605Smrg 201848b8605Smrg 202848b8605Smrg/** 203848b8605Smrg * Store user's image in rgba_dxt5 format. 204848b8605Smrg */ 205848b8605SmrgGLboolean 206848b8605Smrg_mesa_texstore_rgba_dxt5(TEXSTORE_PARAMS) 207848b8605Smrg{ 208848b8605Smrg const GLubyte *pixels; 209848b8605Smrg GLubyte *dst; 210848b8605Smrg const GLubyte *tempImage = NULL; 211848b8605Smrg 212b8e80941Smrg assert(dstFormat == MESA_FORMAT_RGBA_DXT5 || 213848b8605Smrg dstFormat == MESA_FORMAT_SRGBA_DXT5); 214848b8605Smrg 215848b8605Smrg if (srcFormat != GL_RGBA || 216848b8605Smrg srcType != GL_UNSIGNED_BYTE || 217848b8605Smrg ctx->_ImageTransferState || 218b8e80941Smrg ALIGN(srcPacking->RowLength, srcPacking->Alignment) != srcWidth || 219848b8605Smrg srcPacking->SwapBytes) { 220848b8605Smrg /* convert image to RGBA/GLubyte */ 221b8e80941Smrg GLubyte *tempImageSlices[1]; 222b8e80941Smrg int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte); 223b8e80941Smrg tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte)); 224848b8605Smrg if (!tempImage) 225848b8605Smrg return GL_FALSE; /* out of memory */ 226b8e80941Smrg tempImageSlices[0] = (GLubyte *) tempImage; 227b8e80941Smrg _mesa_texstore(ctx, dims, 228b8e80941Smrg baseInternalFormat, 229b8e80941Smrg _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM 230b8e80941Smrg : MESA_FORMAT_A8B8G8R8_UNORM, 231b8e80941Smrg rgbaRowStride, tempImageSlices, 232b8e80941Smrg srcWidth, srcHeight, srcDepth, 233b8e80941Smrg srcFormat, srcType, srcAddr, 234b8e80941Smrg srcPacking); 235848b8605Smrg pixels = tempImage; 236848b8605Smrg } 237848b8605Smrg else { 238848b8605Smrg pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight, 239848b8605Smrg srcFormat, srcType, 0, 0); 240848b8605Smrg } 241848b8605Smrg 242848b8605Smrg dst = dstSlices[0]; 243848b8605Smrg 244b8e80941Smrg tx_compress_dxtn(4, srcWidth, srcHeight, pixels, 245b8e80941Smrg GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 246b8e80941Smrg dst, dstRowStride); 247848b8605Smrg 248848b8605Smrg free((void *) tempImage); 249848b8605Smrg 250848b8605Smrg return GL_TRUE; 251848b8605Smrg} 252848b8605Smrg 253848b8605Smrg 254848b8605Smrgstatic void 255848b8605Smrgfetch_rgb_dxt1(const GLubyte *map, 256848b8605Smrg GLint rowStride, GLint i, GLint j, GLfloat *texel) 257848b8605Smrg{ 258b8e80941Smrg GLubyte tex[4]; 259b8e80941Smrg fetch_2d_texel_rgb_dxt1(rowStride, map, i, j, tex); 260b8e80941Smrg texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 261b8e80941Smrg texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 262b8e80941Smrg texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 263b8e80941Smrg texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 264848b8605Smrg} 265848b8605Smrg 266848b8605Smrgstatic void 267848b8605Smrgfetch_rgba_dxt1(const GLubyte *map, 268848b8605Smrg GLint rowStride, GLint i, GLint j, GLfloat *texel) 269848b8605Smrg{ 270b8e80941Smrg GLubyte tex[4]; 271b8e80941Smrg fetch_2d_texel_rgba_dxt1(rowStride, map, i, j, tex); 272b8e80941Smrg texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 273b8e80941Smrg texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 274b8e80941Smrg texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 275b8e80941Smrg texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 276848b8605Smrg} 277848b8605Smrg 278848b8605Smrgstatic void 279848b8605Smrgfetch_rgba_dxt3(const GLubyte *map, 280848b8605Smrg GLint rowStride, GLint i, GLint j, GLfloat *texel) 281848b8605Smrg{ 282b8e80941Smrg GLubyte tex[4]; 283b8e80941Smrg fetch_2d_texel_rgba_dxt3(rowStride, map, i, j, tex); 284b8e80941Smrg texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 285b8e80941Smrg texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 286b8e80941Smrg texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 287b8e80941Smrg texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 288848b8605Smrg} 289848b8605Smrg 290848b8605Smrgstatic void 291848b8605Smrgfetch_rgba_dxt5(const GLubyte *map, 292848b8605Smrg GLint rowStride, GLint i, GLint j, GLfloat *texel) 293848b8605Smrg{ 294b8e80941Smrg GLubyte tex[4]; 295b8e80941Smrg fetch_2d_texel_rgba_dxt5(rowStride, map, i, j, tex); 296b8e80941Smrg texel[RCOMP] = UBYTE_TO_FLOAT(tex[RCOMP]); 297b8e80941Smrg texel[GCOMP] = UBYTE_TO_FLOAT(tex[GCOMP]); 298b8e80941Smrg texel[BCOMP] = UBYTE_TO_FLOAT(tex[BCOMP]); 299b8e80941Smrg texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 300848b8605Smrg} 301848b8605Smrg 302848b8605Smrg 303848b8605Smrgstatic void 304848b8605Smrgfetch_srgb_dxt1(const GLubyte *map, 305848b8605Smrg GLint rowStride, GLint i, GLint j, GLfloat *texel) 306848b8605Smrg{ 307b8e80941Smrg GLubyte tex[4]; 308b8e80941Smrg fetch_2d_texel_rgb_dxt1(rowStride, map, i, j, tex); 309b8e80941Smrg texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 310b8e80941Smrg texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 311b8e80941Smrg texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 312b8e80941Smrg texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 313848b8605Smrg} 314848b8605Smrg 315848b8605Smrgstatic void 316848b8605Smrgfetch_srgba_dxt1(const GLubyte *map, 317848b8605Smrg GLint rowStride, GLint i, GLint j, GLfloat *texel) 318848b8605Smrg{ 319b8e80941Smrg GLubyte tex[4]; 320b8e80941Smrg fetch_2d_texel_rgba_dxt1(rowStride, map, i, j, tex); 321b8e80941Smrg texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 322b8e80941Smrg texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 323b8e80941Smrg texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 324b8e80941Smrg texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 325848b8605Smrg} 326848b8605Smrg 327848b8605Smrgstatic void 328848b8605Smrgfetch_srgba_dxt3(const GLubyte *map, 329848b8605Smrg GLint rowStride, GLint i, GLint j, GLfloat *texel) 330848b8605Smrg{ 331b8e80941Smrg GLubyte tex[4]; 332b8e80941Smrg fetch_2d_texel_rgba_dxt3(rowStride, map, i, j, tex); 333b8e80941Smrg texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 334b8e80941Smrg texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 335b8e80941Smrg texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 336b8e80941Smrg texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 337848b8605Smrg} 338848b8605Smrg 339848b8605Smrgstatic void 340848b8605Smrgfetch_srgba_dxt5(const GLubyte *map, 341848b8605Smrg GLint rowStride, GLint i, GLint j, GLfloat *texel) 342848b8605Smrg{ 343b8e80941Smrg GLubyte tex[4]; 344b8e80941Smrg fetch_2d_texel_rgba_dxt5(rowStride, map, i, j, tex); 345b8e80941Smrg texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(tex[RCOMP]); 346b8e80941Smrg texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(tex[GCOMP]); 347b8e80941Smrg texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(tex[BCOMP]); 348b8e80941Smrg texel[ACOMP] = UBYTE_TO_FLOAT(tex[ACOMP]); 349848b8605Smrg} 350848b8605Smrg 351848b8605Smrg 352848b8605Smrg 353848b8605Smrgcompressed_fetch_func 354848b8605Smrg_mesa_get_dxt_fetch_func(mesa_format format) 355848b8605Smrg{ 356848b8605Smrg switch (format) { 357848b8605Smrg case MESA_FORMAT_RGB_DXT1: 358848b8605Smrg return fetch_rgb_dxt1; 359848b8605Smrg case MESA_FORMAT_RGBA_DXT1: 360848b8605Smrg return fetch_rgba_dxt1; 361848b8605Smrg case MESA_FORMAT_RGBA_DXT3: 362848b8605Smrg return fetch_rgba_dxt3; 363848b8605Smrg case MESA_FORMAT_RGBA_DXT5: 364848b8605Smrg return fetch_rgba_dxt5; 365848b8605Smrg case MESA_FORMAT_SRGB_DXT1: 366848b8605Smrg return fetch_srgb_dxt1; 367848b8605Smrg case MESA_FORMAT_SRGBA_DXT1: 368848b8605Smrg return fetch_srgba_dxt1; 369848b8605Smrg case MESA_FORMAT_SRGBA_DXT3: 370848b8605Smrg return fetch_srgba_dxt3; 371848b8605Smrg case MESA_FORMAT_SRGBA_DXT5: 372848b8605Smrg return fetch_srgba_dxt5; 373848b8605Smrg default: 374848b8605Smrg return NULL; 375848b8605Smrg } 376848b8605Smrg} 377