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