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