texcompress_rgtc.c revision 531c336fa39d8e823d05728cb7ddb3cc8a44d199
1/*
2 * Copyright (C) 2011 Red Hat Inc.
3 *
4 * block compression parts are:
5 * Copyright (C) 2004  Roland Scheidegger   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 (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
16 * Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 * Author:
27 *    Dave Airlie
28 */
29
30/**
31 * \file texcompress_rgtc.c
32 * GL_EXT_texture_compression_rgtc support.
33 */
34
35
36#include "glheader.h"
37#include "imports.h"
38#include "colormac.h"
39#include "image.h"
40#include "macros.h"
41#include "mfeatures.h"
42#include "mipmap.h"
43#include "texcompress.h"
44#include "texcompress_rgtc.h"
45#include "texstore.h"
46
47#define RGTC_DEBUG 0
48
49static void unsigned_encode_rgtc_chan(GLubyte *blkaddr, GLubyte srccolors[4][4],
50					GLint numxpixels, GLint numypixels);
51static void signed_encode_rgtc_chan(GLbyte *blkaddr, GLbyte srccolors[4][4],
52			     GLint numxpixels, GLint numypixels);
53
54static void unsigned_fetch_texel_rgtc(unsigned srcRowStride, const GLubyte *pixdata,
55				      unsigned i, unsigned j, GLubyte *value, unsigned comps);
56
57static void signed_fetch_texel_rgtc(unsigned srcRowStride, const GLbyte *pixdata,
58				      unsigned i, unsigned j, GLbyte *value, unsigned comps);
59
60static void extractsrc_u( GLubyte srcpixels[4][4], const GLchan *srcaddr,
61			  GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps)
62{
63   GLubyte i, j;
64   const GLchan *curaddr;
65   for (j = 0; j < numypixels; j++) {
66      curaddr = srcaddr + j * srcRowStride * comps;
67      for (i = 0; i < numxpixels; i++) {
68	 srcpixels[j][i] = *curaddr / (CHAN_MAX / 255);
69	 curaddr += comps;
70      }
71   }
72}
73
74static void extractsrc_s( GLbyte srcpixels[4][4], const GLfloat *srcaddr,
75			  GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps)
76{
77   GLubyte i, j;
78   const GLfloat *curaddr;
79   for (j = 0; j < numypixels; j++) {
80      curaddr = srcaddr + j * srcRowStride * comps;
81      for (i = 0; i < numxpixels; i++) {
82	 srcpixels[j][i] = FLOAT_TO_BYTE_TEX(*curaddr);
83	 curaddr += comps;
84      }
85   }
86}
87
88
89GLboolean
90_mesa_texstore_red_rgtc1(TEXSTORE_PARAMS)
91{
92   GLubyte *dst;
93   const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */
94   const GLchan *tempImage = NULL;
95   int i, j;
96   int numxpixels, numypixels;
97   const GLchan *srcaddr;
98   GLubyte srcpixels[4][4];
99   GLubyte *blkaddr;
100   GLint dstRowDiff;
101   ASSERT(dstFormat == MESA_FORMAT_RED_RGTC1);
102   ASSERT(dstXoffset % 4 == 0);
103   ASSERT(dstYoffset % 4 == 0);
104   ASSERT(dstZoffset % 4 == 0);
105   (void) dstZoffset;
106   (void) dstImageOffsets;
107
108
109   tempImage = _mesa_make_temp_chan_image(ctx, dims,
110					  baseInternalFormat,
111					  _mesa_get_format_base_format(dstFormat),
112					  srcWidth, srcHeight, srcDepth,
113					  srcFormat, srcType, srcAddr,
114					  srcPacking);
115   if (!tempImage)
116      return GL_FALSE; /* out of memory */
117
118   dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
119                                        dstFormat,
120                                        texWidth, (GLubyte *) dstAddr);
121
122   blkaddr = dst;
123   dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0;
124   for (j = 0; j < srcHeight; j+=4) {
125      if (srcHeight > j + 3) numypixels = 4;
126      else numypixels = srcHeight - j;
127      srcaddr = tempImage + j * srcWidth;
128      for (i = 0; i < srcWidth; i += 4) {
129	 if (srcWidth > i + 3) numxpixels = 4;
130	 else numxpixels = srcWidth - i;
131	 extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1);
132	 unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
133	 srcaddr += numxpixels;
134	 blkaddr += 8;
135      }
136      blkaddr += dstRowDiff;
137   }
138   if (tempImage)
139      free((void *) tempImage);
140
141   return GL_TRUE;
142}
143
144GLboolean
145_mesa_texstore_signed_red_rgtc1(TEXSTORE_PARAMS)
146{
147   GLbyte *dst;
148   const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */
149   const GLfloat *tempImage = NULL;
150   int i, j;
151   int numxpixels, numypixels;
152   const GLfloat *srcaddr;
153   GLbyte srcpixels[4][4];
154   GLbyte *blkaddr;
155   GLint dstRowDiff;
156   ASSERT(dstFormat == MESA_FORMAT_SIGNED_RED_RGTC1);
157   ASSERT(dstXoffset % 4 == 0);
158   ASSERT(dstYoffset % 4 == 0);
159   ASSERT(dstZoffset % 4 == 0);
160   (void) dstZoffset;
161   (void) dstImageOffsets;
162
163   tempImage = _mesa_make_temp_float_image(ctx, dims,
164					   baseInternalFormat,
165					   _mesa_get_format_base_format(dstFormat),
166					   srcWidth, srcHeight, srcDepth,
167					   srcFormat, srcType, srcAddr,
168					   srcPacking, 0x0);
169   if (!tempImage)
170      return GL_FALSE; /* out of memory */
171
172   dst = (GLbyte *)_mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
173						  dstFormat,
174						  texWidth, (GLubyte *) dstAddr);
175
176   blkaddr = dst;
177   dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0;
178   for (j = 0; j < srcHeight; j+=4) {
179      if (srcHeight > j + 3) numypixels = 4;
180      else numypixels = srcHeight - j;
181      srcaddr = tempImage + j * srcWidth;
182      for (i = 0; i < srcWidth; i += 4) {
183	 if (srcWidth > i + 3) numxpixels = 4;
184	 else numxpixels = srcWidth - i;
185	 extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1);
186	 signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
187	 srcaddr += numxpixels;
188	 blkaddr += 8;
189      }
190      blkaddr += dstRowDiff;
191   }
192   if (tempImage)
193      free((void *) tempImage);
194
195   return GL_TRUE;
196}
197
198GLboolean
199_mesa_texstore_rg_rgtc2(TEXSTORE_PARAMS)
200{
201   GLubyte *dst;
202   const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */
203   const GLchan *tempImage = NULL;
204   int i, j;
205   int numxpixels, numypixels;
206   const GLchan *srcaddr;
207   GLubyte srcpixels[4][4];
208   GLubyte *blkaddr;
209   GLint dstRowDiff;
210
211   ASSERT(dstFormat == MESA_FORMAT_RG_RGTC2);
212   ASSERT(dstXoffset % 4 == 0);
213   ASSERT(dstYoffset % 4 == 0);
214   ASSERT(dstZoffset % 4 == 0);
215   (void) dstZoffset;
216   (void) dstImageOffsets;
217
218   tempImage = _mesa_make_temp_chan_image(ctx, dims,
219					  baseInternalFormat,
220					  _mesa_get_format_base_format(dstFormat),
221					  srcWidth, srcHeight, srcDepth,
222					  srcFormat, srcType, srcAddr,
223					  srcPacking);
224   if (!tempImage)
225      return GL_FALSE; /* out of memory */
226
227   dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
228                                        dstFormat,
229                                        texWidth, (GLubyte *) dstAddr);
230
231   blkaddr = dst;
232   dstRowDiff = dstRowStride >= (srcWidth * 8) ? dstRowStride - (((srcWidth + 7) & ~7) * 8) : 0;
233   for (j = 0; j < srcHeight; j+=4) {
234      if (srcHeight > j + 3) numypixels = 4;
235      else numypixels = srcHeight - j;
236      srcaddr = tempImage + j * srcWidth * 2;
237      for (i = 0; i < srcWidth; i += 4) {
238	 if (srcWidth > i + 3) numxpixels = 4;
239	 else numxpixels = srcWidth - i;
240	 extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2);
241	 unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
242
243	 blkaddr += 8;
244	 extractsrc_u(srcpixels, (GLchan *)srcaddr + 1, srcWidth, numxpixels, numypixels, 2);
245	 unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
246
247	 blkaddr += 8;
248
249	 srcaddr += numxpixels * 2;
250      }
251      blkaddr += dstRowDiff;
252   }
253   if (tempImage)
254      free((void *) tempImage);
255
256   return GL_TRUE;
257}
258
259GLboolean
260_mesa_texstore_signed_rg_rgtc2(TEXSTORE_PARAMS)
261{
262   GLbyte *dst;
263   const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */
264   const GLfloat *tempImage = NULL;
265   int i, j;
266   int numxpixels, numypixels;
267   const GLfloat *srcaddr;
268   GLbyte srcpixels[4][4];
269   GLbyte *blkaddr;
270   GLint dstRowDiff;
271
272   ASSERT(dstFormat == MESA_FORMAT_SIGNED_RG_RGTC2);
273   ASSERT(dstXoffset % 4 == 0);
274   ASSERT(dstYoffset % 4 == 0);
275   ASSERT(dstZoffset % 4 == 0);
276   (void) dstZoffset;
277   (void) dstImageOffsets;
278
279   tempImage = _mesa_make_temp_float_image(ctx, dims,
280					   baseInternalFormat,
281					   _mesa_get_format_base_format(dstFormat),
282					   srcWidth, srcHeight, srcDepth,
283					   srcFormat, srcType, srcAddr,
284					   srcPacking, 0x0);
285   if (!tempImage)
286      return GL_FALSE; /* out of memory */
287
288   dst = (GLbyte *)_mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
289						  dstFormat,
290						  texWidth, (GLubyte *) dstAddr);
291
292   blkaddr = dst;
293   dstRowDiff = dstRowStride >= (srcWidth * 8) ? dstRowStride - (((srcWidth + 7) & ~7) * 8) : 0;
294   for (j = 0; j < srcHeight; j += 4) {
295      if (srcHeight > j + 3) numypixels = 4;
296      else numypixels = srcHeight - j;
297      srcaddr = tempImage + j * srcWidth * 2;
298      for (i = 0; i < srcWidth; i += 4) {
299	 if (srcWidth > i + 3) numxpixels = 4;
300	 else numxpixels = srcWidth - i;
301
302	 extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2);
303	 signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
304	 blkaddr += 8;
305
306	 extractsrc_s(srcpixels, srcaddr + 1, srcWidth, numxpixels, numypixels, 2);
307	 signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
308	 blkaddr += 8;
309
310	 srcaddr += numxpixels * 2;
311
312      }
313      blkaddr += dstRowDiff;
314   }
315   if (tempImage)
316      free((void *) tempImage);
317
318   return GL_TRUE;
319}
320
321void
322_mesa_fetch_texel_2d_f_red_rgtc1(const struct gl_texture_image *texImage,
323				 GLint i, GLint j, GLint k, GLfloat *texel)
324{
325   GLubyte red;
326   unsigned_fetch_texel_rgtc(texImage->RowStride, (GLubyte *)(texImage->Data),
327		       i, j, &red, 1);
328   texel[RCOMP] = UBYTE_TO_FLOAT(red);
329   texel[GCOMP] = 0.0;
330   texel[BCOMP] = 0.0;
331   texel[ACOMP] = 1.0;
332}
333
334void
335_mesa_fetch_texel_2d_f_signed_red_rgtc1(const struct gl_texture_image *texImage,
336					GLint i, GLint j, GLint k, GLfloat *texel)
337{
338   GLbyte red;
339   signed_fetch_texel_rgtc(texImage->RowStride, (GLbyte *)(texImage->Data),
340		       i, j, &red, 1);
341   texel[RCOMP] = BYTE_TO_FLOAT_TEX(red);
342   texel[GCOMP] = 0.0;
343   texel[BCOMP] = 0.0;
344   texel[ACOMP] = 1.0;
345}
346
347void
348_mesa_fetch_texel_2d_f_rg_rgtc2(const struct gl_texture_image *texImage,
349				 GLint i, GLint j, GLint k, GLfloat *texel)
350{
351   GLubyte red, green;
352   unsigned_fetch_texel_rgtc(texImage->RowStride, (GLubyte *)(texImage->Data),
353		     i, j, &red, 2);
354   unsigned_fetch_texel_rgtc(texImage->RowStride, (GLubyte *)(texImage->Data) + 8,
355		     i, j, &green, 2);
356   texel[RCOMP] = UBYTE_TO_FLOAT(red);
357   texel[GCOMP] = UBYTE_TO_FLOAT(green);
358   texel[BCOMP] = 0.0;
359   texel[ACOMP] = 1.0;
360}
361
362void
363_mesa_fetch_texel_2d_f_signed_rg_rgtc2(const struct gl_texture_image *texImage,
364				       GLint i, GLint j, GLint k, GLfloat *texel)
365{
366   GLbyte red, green;
367   signed_fetch_texel_rgtc(texImage->RowStride, (GLbyte *)(texImage->Data),
368		     i, j, &red, 2);
369   signed_fetch_texel_rgtc(texImage->RowStride, (GLbyte *)(texImage->Data) + 8,
370		     i, j, &green, 2);
371   texel[RCOMP] = BYTE_TO_FLOAT_TEX(red);
372   texel[GCOMP] = BYTE_TO_FLOAT_TEX(green);
373   texel[BCOMP] = 0.0;
374   texel[ACOMP] = 1.0;
375}
376
377#define TAG(x) unsigned_##x
378
379#define TYPE GLubyte
380#define T_MIN 0
381#define T_MAX 0xff
382
383#include "texcompress_rgtc_tmp.h"
384
385#undef TAG
386#undef TYPE
387#undef T_MIN
388#undef T_MAX
389
390#define TAG(x) signed_##x
391#define TYPE GLbyte
392#define T_MIN (GLbyte)-128
393#define T_MAX (GLbyte)127
394
395#include "texcompress_rgtc_tmp.h"
396
397#undef TAG
398#undef TYPE
399#undef T_MIN
400#undef T_MAX
401