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