texcompress_rgtc.c revision 521394a204bd8073846acc7f9861081d29fa24c9
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 extractsrc_u( GLubyte srcpixels[4][4], const GLchan *srcaddr,
55			  GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps)
56{
57   GLubyte i, j;
58   const GLchan *curaddr;
59   for (j = 0; j < numypixels; j++) {
60      curaddr = srcaddr + j * srcRowStride * comps;
61      for (i = 0; i < numxpixels; i++) {
62	 srcpixels[j][i] = *curaddr / (CHAN_MAX / 255);
63	 curaddr += comps;
64      }
65   }
66}
67
68static void extractsrc_s( GLbyte srcpixels[4][4], const GLfloat *srcaddr,
69			  GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps)
70{
71   GLubyte i, j;
72   const GLfloat *curaddr;
73   for (j = 0; j < numypixels; j++) {
74      curaddr = srcaddr + j * srcRowStride * comps;
75      for (i = 0; i < numxpixels; i++) {
76	 srcpixels[j][i] = FLOAT_TO_BYTE_TEX(*curaddr);
77	 curaddr += comps;
78      }
79   }
80}
81
82
83GLboolean
84_mesa_texstore_red_rgtc1(TEXSTORE_PARAMS)
85{
86   GLubyte *dst;
87   const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */
88   const GLchan *tempImage = NULL;
89   int i, j;
90   int numxpixels, numypixels;
91   const GLchan *srcaddr;
92   GLubyte srcpixels[4][4];
93   GLubyte *blkaddr;
94   GLint dstRowDiff;
95   ASSERT(dstFormat == MESA_FORMAT_RED_RGTC1);
96   ASSERT(dstXoffset % 4 == 0);
97   ASSERT(dstYoffset % 4 == 0);
98   ASSERT(dstZoffset % 4 == 0);
99   (void) dstZoffset;
100   (void) dstImageOffsets;
101
102
103   tempImage = _mesa_make_temp_chan_image(ctx, dims,
104					  baseInternalFormat,
105					  _mesa_get_format_base_format(dstFormat),
106					  srcWidth, srcHeight, srcDepth,
107					  srcFormat, srcType, srcAddr,
108					  srcPacking);
109   if (!tempImage)
110      return GL_FALSE; /* out of memory */
111
112   dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
113                                        dstFormat,
114                                        texWidth, (GLubyte *) dstAddr);
115
116   blkaddr = dst;
117   dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0;
118   for (j = 0; j < srcHeight; j+=4) {
119      if (srcHeight > j + 3) numypixels = 4;
120      else numypixels = srcHeight - j;
121      srcaddr = tempImage + j * srcWidth;
122      for (i = 0; i < srcWidth; i += 4) {
123	 if (srcWidth > i + 3) numxpixels = 4;
124	 else numxpixels = srcWidth - i;
125	 extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1);
126	 unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
127	 srcaddr += numxpixels;
128	 blkaddr += 8;
129      }
130      blkaddr += dstRowDiff;
131   }
132   if (tempImage)
133      free((void *) tempImage);
134
135   return GL_TRUE;
136}
137
138GLboolean
139_mesa_texstore_signed_red_rgtc1(TEXSTORE_PARAMS)
140{
141   GLbyte *dst;
142   const GLint texWidth = dstRowStride * 4 / 8; /* a bit of a hack */
143   const GLfloat *tempImage = NULL;
144   int i, j;
145   int numxpixels, numypixels;
146   const GLfloat *srcaddr;
147   GLbyte srcpixels[4][4];
148   GLbyte *blkaddr;
149   GLint dstRowDiff;
150   ASSERT(dstFormat == MESA_FORMAT_SIGNED_RED_RGTC1);
151   ASSERT(dstXoffset % 4 == 0);
152   ASSERT(dstYoffset % 4 == 0);
153   ASSERT(dstZoffset % 4 == 0);
154   (void) dstZoffset;
155   (void) dstImageOffsets;
156
157   tempImage = _mesa_make_temp_float_image(ctx, dims,
158					   baseInternalFormat,
159					   _mesa_get_format_base_format(dstFormat),
160					   srcWidth, srcHeight, srcDepth,
161					   srcFormat, srcType, srcAddr,
162					   srcPacking, 0x0);
163   if (!tempImage)
164      return GL_FALSE; /* out of memory */
165
166   dst = (GLbyte *)_mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
167						  dstFormat,
168						  texWidth, (GLubyte *) dstAddr);
169
170   blkaddr = dst;
171   dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0;
172   for (j = 0; j < srcHeight; j+=4) {
173      if (srcHeight > j + 3) numypixels = 4;
174      else numypixels = srcHeight - j;
175      srcaddr = tempImage + j * srcWidth;
176      for (i = 0; i < srcWidth; i += 4) {
177	 if (srcWidth > i + 3) numxpixels = 4;
178	 else numxpixels = srcWidth - i;
179	 extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1);
180	 signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
181	 srcaddr += numxpixels;
182	 blkaddr += 8;
183      }
184      blkaddr += dstRowDiff;
185   }
186   if (tempImage)
187      free((void *) tempImage);
188
189   return GL_TRUE;
190}
191
192GLboolean
193_mesa_texstore_rg_rgtc2(TEXSTORE_PARAMS)
194{
195   GLubyte *dst;
196   const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */
197   const GLchan *tempImage = NULL;
198   int i, j;
199   int numxpixels, numypixels;
200   const GLchan *srcaddr;
201   GLubyte srcpixels[4][4];
202   GLubyte *blkaddr;
203   GLint dstRowDiff;
204
205   ASSERT(dstFormat == MESA_FORMAT_RG_RGTC2);
206   ASSERT(dstXoffset % 4 == 0);
207   ASSERT(dstYoffset % 4 == 0);
208   ASSERT(dstZoffset % 4 == 0);
209   (void) dstZoffset;
210   (void) dstImageOffsets;
211
212   tempImage = _mesa_make_temp_chan_image(ctx, dims,
213					  baseInternalFormat,
214					  _mesa_get_format_base_format(dstFormat),
215					  srcWidth, srcHeight, srcDepth,
216					  srcFormat, srcType, srcAddr,
217					  srcPacking);
218   if (!tempImage)
219      return GL_FALSE; /* out of memory */
220
221   dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
222                                        dstFormat,
223                                        texWidth, (GLubyte *) dstAddr);
224
225   blkaddr = dst;
226   dstRowDiff = dstRowStride >= (srcWidth * 8) ? dstRowStride - (((srcWidth + 7) & ~7) * 8) : 0;
227   for (j = 0; j < srcHeight; j+=4) {
228      if (srcHeight > j + 3) numypixels = 4;
229      else numypixels = srcHeight - j;
230      srcaddr = tempImage + j * srcWidth * 2;
231      for (i = 0; i < srcWidth; i += 4) {
232	 if (srcWidth > i + 3) numxpixels = 4;
233	 else numxpixels = srcWidth - i;
234	 extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2);
235	 unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
236
237	 blkaddr += 8;
238	 extractsrc_u(srcpixels, (GLchan *)srcaddr + 1, srcWidth, numxpixels, numypixels, 2);
239	 unsigned_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
240
241	 blkaddr += 8;
242
243	 srcaddr += numxpixels * 2;
244      }
245      blkaddr += dstRowDiff;
246   }
247   if (tempImage)
248      free((void *) tempImage);
249
250   return GL_TRUE;
251}
252
253GLboolean
254_mesa_texstore_signed_rg_rgtc2(TEXSTORE_PARAMS)
255{
256   GLbyte *dst;
257   const GLint texWidth = dstRowStride * 4 / 16; /* a bit of a hack */
258   const GLfloat *tempImage = NULL;
259   int i, j;
260   int numxpixels, numypixels;
261   const GLfloat *srcaddr;
262   GLbyte srcpixels[4][4];
263   GLbyte *blkaddr;
264   GLint dstRowDiff;
265
266   ASSERT(dstFormat == MESA_FORMAT_SIGNED_RG_RGTC2);
267   ASSERT(dstXoffset % 4 == 0);
268   ASSERT(dstYoffset % 4 == 0);
269   ASSERT(dstZoffset % 4 == 0);
270   (void) dstZoffset;
271   (void) dstImageOffsets;
272
273   tempImage = _mesa_make_temp_float_image(ctx, dims,
274					   baseInternalFormat,
275					   _mesa_get_format_base_format(dstFormat),
276					   srcWidth, srcHeight, srcDepth,
277					   srcFormat, srcType, srcAddr,
278					   srcPacking, 0x0);
279   if (!tempImage)
280      return GL_FALSE; /* out of memory */
281
282   dst = (GLbyte *)_mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
283						  dstFormat,
284						  texWidth, (GLubyte *) dstAddr);
285
286   blkaddr = dst;
287   dstRowDiff = dstRowStride >= (srcWidth * 8) ? dstRowStride - (((srcWidth + 7) & ~7) * 8) : 0;
288   for (j = 0; j < srcHeight; j += 4) {
289      if (srcHeight > j + 3) numypixels = 4;
290      else numypixels = srcHeight - j;
291      srcaddr = tempImage + j * srcWidth * 2;
292      for (i = 0; i < srcWidth; i += 4) {
293	 if (srcWidth > i + 3) numxpixels = 4;
294	 else numxpixels = srcWidth - i;
295
296	 extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2);
297	 signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
298	 blkaddr += 8;
299
300	 extractsrc_s(srcpixels, srcaddr + 1, srcWidth, numxpixels, numypixels, 2);
301	 signed_encode_rgtc_chan(blkaddr, srcpixels, numxpixels, numypixels);
302	 blkaddr += 8;
303
304	 srcaddr += numxpixels * 2;
305
306      }
307      blkaddr += dstRowDiff;
308   }
309   if (tempImage)
310      free((void *) tempImage);
311
312   return GL_TRUE;
313}
314
315static void _fetch_texel_rgtc_u(GLint srcRowStride, const GLubyte *pixdata,
316				GLint i, GLint j, GLubyte *value, int comps)
317{
318   GLubyte decode;
319   const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 8 * comps);
320   const GLubyte alpha0 = blksrc[0];
321   const GLubyte alpha1 = blksrc[1];
322   const GLubyte bit_pos = ((j&3) * 4 + (i&3)) * 3;
323   const GLubyte acodelow = blksrc[2 + bit_pos / 8];
324   const uint8_t acodehigh = (3 + bit_pos / 8) < 8 ? blksrc[3 + bit_pos / 8] : 0;
325   const GLubyte code = (acodelow >> (bit_pos & 0x7) |
326      (acodehigh  << (8 - (bit_pos & 0x7)))) & 0x7;
327
328   if (code == 0)
329      decode =  alpha0;
330   else if (code == 1)
331      decode =  alpha1;
332   else if (alpha0 > alpha1)
333      decode =  ((alpha0 * (8 - code) + (alpha1 * (code - 1))) / 7);
334   else if (code < 6)
335      decode =  ((alpha0 * (6 - code) + (alpha1 * (code - 1))) / 5);
336   else if (code == 6)
337      decode = 0;
338   else
339      decode = 255;
340
341   *value = decode;
342}
343
344
345static void _fetch_texel_rgtc_s(GLint srcRowStride, const GLbyte *pixdata,
346				GLint i, GLint j, GLbyte *value, int comps)
347{
348   GLbyte decode;
349   const GLbyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 8 * comps);
350   const GLbyte alpha0 = blksrc[0];
351   const GLbyte alpha1 = blksrc[1];
352   const GLbyte bit_pos = ((j&3) * 4 + (i&3)) * 3;
353   const GLbyte acodelow = blksrc[2 + bit_pos / 8];
354   const uint8_t acodehigh = (3 + bit_pos / 8) < 8 ? blksrc[3 + bit_pos / 8] : 0;
355   const GLbyte code = (acodelow >> (bit_pos & 0x7) |
356      (acodehigh  << (8 - (bit_pos & 0x7)))) & 0x7;
357
358   if (code == 0)
359      decode = alpha0;
360   else if (code == 1)
361      decode = alpha1;
362   else if (alpha0 > alpha1)
363      decode = ((alpha0 * (8 - code) + (alpha1 * (code - 1))) / 7);
364   else if (code < 6)
365      decode = ((alpha0 * (6 - code) + (alpha1 * (code - 1))) / 5);
366   else if (code == 6)
367      decode = -127;
368   else
369      decode = 127;
370
371   *value = decode;
372}
373
374void
375_mesa_fetch_texel_2d_f_red_rgtc1(const struct gl_texture_image *texImage,
376				 GLint i, GLint j, GLint k, GLfloat *texel)
377{
378   GLubyte red;
379   _fetch_texel_rgtc_u(texImage->RowStride, (GLubyte *)(texImage->Data),
380		       i, j, &red, 1);
381   texel[RCOMP] = UBYTE_TO_FLOAT(red);
382   texel[GCOMP] = 0.0;
383   texel[BCOMP] = 0.0;
384   texel[ACOMP] = 1.0;
385}
386
387void
388_mesa_fetch_texel_2d_f_signed_red_rgtc1(const struct gl_texture_image *texImage,
389					GLint i, GLint j, GLint k, GLfloat *texel)
390{
391   GLbyte red;
392   _fetch_texel_rgtc_s(texImage->RowStride, (GLbyte *)(texImage->Data),
393		       i, j, &red, 1);
394   texel[RCOMP] = BYTE_TO_FLOAT_TEX(red);
395   texel[GCOMP] = 0.0;
396   texel[BCOMP] = 0.0;
397   texel[ACOMP] = 1.0;
398}
399
400void
401_mesa_fetch_texel_2d_f_rg_rgtc2(const struct gl_texture_image *texImage,
402				 GLint i, GLint j, GLint k, GLfloat *texel)
403{
404   GLubyte red, green;
405   _fetch_texel_rgtc_u(texImage->RowStride, (GLubyte *)(texImage->Data),
406		     i, j, &red, 2);
407   _fetch_texel_rgtc_u(texImage->RowStride, (GLubyte *)(texImage->Data) + 8,
408		     i, j, &green, 2);
409   texel[RCOMP] = UBYTE_TO_FLOAT(red);
410   texel[GCOMP] = UBYTE_TO_FLOAT(green);
411   texel[BCOMP] = 0.0;
412   texel[ACOMP] = 1.0;
413}
414
415void
416_mesa_fetch_texel_2d_f_signed_rg_rgtc2(const struct gl_texture_image *texImage,
417				       GLint i, GLint j, GLint k, GLfloat *texel)
418{
419   GLbyte red, green;
420   _fetch_texel_rgtc_s(texImage->RowStride, (GLbyte *)(texImage->Data),
421		     i, j, &red, 2);
422   _fetch_texel_rgtc_s(texImage->RowStride, (GLbyte *)(texImage->Data) + 8,
423		     i, j, &green, 2);
424   texel[RCOMP] = BYTE_TO_FLOAT_TEX(red);
425   texel[GCOMP] = BYTE_TO_FLOAT_TEX(green);
426   texel[BCOMP] = 0.0;
427   texel[ACOMP] = 1.0;
428}
429
430#define TAG(x) unsigned_##x
431
432#define TYPE GLubyte
433#define T_MIN 0
434#define T_MAX 0xff
435
436#include "texcompress_rgtc_tmp.h"
437
438#undef TAG
439#undef TYPE
440#undef T_MIN
441#undef T_MAX
442
443#define TAG(x) signed_##x
444#define TYPE GLbyte
445#define T_MIN (GLbyte)-127
446#define T_MAX (GLbyte)128
447
448#include "texcompress_rgtc_tmp.h"
449
450#undef TAG
451#undef TYPE
452#undef T_MIN
453#undef T_MAX
454