texcompress.c revision 33fa5e4bfad8005f09ad3c9fc92c40fa863935d1
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.5.1
4 *
5 * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
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 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26/**
27 * \file texcompress.c
28 * Helper functions for texture compression.
29 */
30
31
32#include "glheader.h"
33#include "imports.h"
34#include "colormac.h"
35#include "context.h"
36#include "image.h"
37#include "mipmap.h"
38#include "texcompress.h"
39#include "texformat.h"
40#include "texstore.h"
41
42
43/**
44 * Return list of (and count of) all specific texture compression
45 * formats that are supported.
46 *
47 * \param ctx  the GL context
48 * \param formats  the resulting format list (may be NULL).
49 * \param all  if true return all formats, even those with  some kind
50 *             of restrictions/limitations (See GL_ARB_texture_compression
51 *             spec for more info).
52 *
53 * \return number of formats.
54 */
55GLuint
56_mesa_get_compressed_formats(GLcontext *ctx, GLint *formats, GLboolean all)
57{
58   GLuint n = 0;
59   if (ctx->Extensions.TDFX_texture_compression_FXT1) {
60      if (formats) {
61         formats[n++] = GL_COMPRESSED_RGB_FXT1_3DFX;
62         formats[n++] = GL_COMPRESSED_RGBA_FXT1_3DFX;
63      }
64      else {
65         n += 2;
66      }
67   }
68   if (ctx->Extensions.EXT_texture_compression_s3tc) {
69      if (formats) {
70         formats[n++] = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
71         /* This format has some restrictions/limitations and so should
72          * not be returned via the GL_COMPRESSED_TEXTURE_FORMATS query.
73          * Specifically, all transparent pixels become black.  NVIDIA
74          * omits this format too.
75          */
76         if (all)
77             formats[n++] = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
78         formats[n++] = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
79         formats[n++] = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
80      }
81      else {
82         n += 3;
83         if (all)
84             n += 1;
85      }
86   }
87   if (ctx->Extensions.S3_s3tc) {
88      if (formats) {
89         formats[n++] = GL_RGB_S3TC;
90         formats[n++] = GL_RGB4_S3TC;
91         formats[n++] = GL_RGBA_S3TC;
92         formats[n++] = GL_RGBA4_S3TC;
93      }
94      else {
95         n += 4;
96      }
97   }
98#if FEATURE_EXT_texture_sRGB
99   if (ctx->Extensions.EXT_texture_sRGB) {
100      if (formats) {
101         formats[n++] = GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
102         formats[n++] = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
103         formats[n++] = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
104         formats[n++] = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
105      }
106      else {
107         n += 4;
108      }
109   }
110#endif /* FEATURE_EXT_texture_sRGB */
111   return n;
112}
113
114
115
116/**
117 * Return number of bytes needed to store a texture of the given size
118 * using the specified compressed format.
119 * This is called via the ctx->Driver.CompressedTextureSize function,
120 * unless a device driver overrides it.
121 *
122 * \param width texture width in texels.
123 * \param height texture height in texels.
124 * \param depth texture depth in texels.
125 * \param mesaFormat  one of the MESA_FORMAT_* compressed formats
126 *
127 * \return size in bytes, or zero if bad format
128 */
129GLuint
130_mesa_compressed_texture_size( GLcontext *ctx,
131                               GLsizei width, GLsizei height, GLsizei depth,
132                               GLuint mesaFormat )
133{
134   GLuint size;
135
136   ASSERT(depth == 1);
137   (void) depth;
138
139   switch (mesaFormat) {
140   case MESA_FORMAT_RGB_FXT1:
141   case MESA_FORMAT_RGBA_FXT1:
142      /* round up width to next multiple of 8, height to next multiple of 4 */
143      width = (width + 7) & ~7;
144      height = (height + 3) & ~3;
145      /* 16 bytes per 8x4 tile of RGB[A] texels */
146      size = width * height / 2;
147      /* Textures smaller than 8x4 will effectively be made into 8x4 and
148       * take 16 bytes.
149       */
150      return size;
151   case MESA_FORMAT_RGB_DXT1:
152   case MESA_FORMAT_RGBA_DXT1:
153      /* round up width, height to next multiple of 4 */
154      width = (width + 3) & ~3;
155      height = (height + 3) & ~3;
156      /* 8 bytes per 4x4 tile of RGB[A] texels */
157      size = width * height / 2;
158      /* Textures smaller than 4x4 will effectively be made into 4x4 and
159       * take 8 bytes.
160       */
161      return size;
162   case MESA_FORMAT_RGBA_DXT3:
163   case MESA_FORMAT_RGBA_DXT5:
164      /* round up width, height to next multiple of 4 */
165      width = (width + 3) & ~3;
166      height = (height + 3) & ~3;
167      /* 16 bytes per 4x4 tile of RGBA texels */
168      size = width * height; /* simple! */
169      /* Textures smaller than 4x4 will effectively be made into 4x4 and
170       * take 16 bytes.
171       */
172      return size;
173   default:
174      _mesa_problem(ctx, "bad mesaFormat in _mesa_compressed_texture_size");
175      return 0;
176   }
177}
178
179
180/**
181 * As above, but format is specified by a GLenum (GL_COMPRESSED_*) token.
182 *
183 * Note: This function CAN NOT return a padded hardware texture size.
184 * That's why we don't call the ctx->Driver.CompressedTextureSize() function.
185 *
186 * We use this function to validate the <imageSize> parameter
187 * of glCompressedTex[Sub]Image1/2/3D(), which must be an exact match.
188 */
189GLuint
190_mesa_compressed_texture_size_glenum(GLcontext *ctx,
191                                     GLsizei width, GLsizei height,
192                                     GLsizei depth, GLenum glformat)
193{
194   GLuint mesaFormat;
195
196   switch (glformat) {
197   case GL_COMPRESSED_RGB_FXT1_3DFX:
198      mesaFormat = MESA_FORMAT_RGB_FXT1;
199      break;
200   case GL_COMPRESSED_RGBA_FXT1_3DFX:
201      mesaFormat = MESA_FORMAT_RGBA_FXT1;
202      break;
203   case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
204   case GL_RGB_S3TC:
205      mesaFormat = MESA_FORMAT_RGB_DXT1;
206      break;
207   case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
208   case GL_RGB4_S3TC:
209      mesaFormat = MESA_FORMAT_RGBA_DXT1;
210      break;
211   case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
212   case GL_RGBA_S3TC:
213      mesaFormat = MESA_FORMAT_RGBA_DXT3;
214      break;
215   case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
216   case GL_RGBA4_S3TC:
217      mesaFormat = MESA_FORMAT_RGBA_DXT5;
218      break;
219   default:
220      return 0;
221   }
222
223   return _mesa_compressed_texture_size(ctx, width, height, depth, mesaFormat);
224}
225
226
227/*
228 * Compute the bytes per row in a compressed texture image.
229 * We use this for computing the destination address for sub-texture updates.
230 * \param mesaFormat  one of the MESA_FORMAT_* compressed formats
231 * \param width  image width in pixels
232 * \return stride, in bytes, between rows for compressed image
233 */
234GLint
235_mesa_compressed_row_stride(GLuint mesaFormat, GLsizei width)
236{
237   GLint stride;
238
239   switch (mesaFormat) {
240   case MESA_FORMAT_RGB_FXT1:
241   case MESA_FORMAT_RGBA_FXT1:
242      stride = ((width + 7) / 8) * 16; /* 16 bytes per 8x4 tile */
243      break;
244   case MESA_FORMAT_RGB_DXT1:
245   case MESA_FORMAT_RGBA_DXT1:
246      stride = ((width + 3) / 4) * 8; /* 8 bytes per 4x4 tile */
247      break;
248   case MESA_FORMAT_RGBA_DXT3:
249   case MESA_FORMAT_RGBA_DXT5:
250      stride = ((width + 3) / 4) * 16; /* 16 bytes per 4x4 tile */
251      break;
252   default:
253      _mesa_problem(NULL, "bad mesaFormat in _mesa_compressed_row_stride");
254      return 0;
255   }
256
257   return stride;
258}
259
260
261/*
262 * Return the address of the pixel at (col, row, img) in a
263 * compressed texture image.
264 * \param col, row, img - image position (3D)
265 * \param format - compressed image format
266 * \param width - image width
267 * \param image - the image address
268 * \return address of pixel at (row, col)
269 */
270GLubyte *
271_mesa_compressed_image_address(GLint col, GLint row, GLint img,
272                               GLuint mesaFormat,
273                               GLsizei width, const GLubyte *image)
274{
275   GLubyte *addr;
276
277   (void) img;
278
279   /* We try to spot a "complete" subtexture "above" ROW, COL;
280    * this texture is given by appropriate rounding of WIDTH x ROW.
281    * Then we just add the amount left (usually on the left).
282    *
283    * Example for X*Y microtiles (Z bytes each)
284    * offset = Z * (((width + X - 1) / X) * (row / Y) + col / X);
285    */
286
287   switch (mesaFormat) {
288   case MESA_FORMAT_RGB_FXT1:
289   case MESA_FORMAT_RGBA_FXT1:
290      addr = (GLubyte *) image + 16 * (((width + 7) / 8) * (row / 4) + col / 8);
291      break;
292   case MESA_FORMAT_RGB_DXT1:
293   case MESA_FORMAT_RGBA_DXT1:
294      addr = (GLubyte *) image + 8 * (((width + 3) / 4) * (row / 4) + col / 4);
295      break;
296   case MESA_FORMAT_RGBA_DXT3:
297   case MESA_FORMAT_RGBA_DXT5:
298      addr = (GLubyte *) image + 16 * (((width + 3) / 4) * (row / 4) + col / 4);
299      break;
300   default:
301      _mesa_problem(NULL, "bad mesaFormat in _mesa_compressed_image_address");
302      addr = NULL;
303   }
304
305   return addr;
306}
307