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