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