texcompress_s3tc.c revision 01e04c3f
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 */
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                     _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 */
153GLboolean
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 */
205GLboolean
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
254static void
255fetch_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
266static void
267fetch_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
278static void
279fetch_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
290static void
291fetch_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
303static void
304fetch_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
315static void
316fetch_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
327static void
328fetch_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
339static void
340fetch_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
353compressed_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