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 "config.h"
37#include "glheader.h"
38#include "imports.h"
39#include "image.h"
40#include "macros.h"
41#include "mipmap.h"
42#include "texcompress.h"
43#include "util/rgtc.h"
44#include "texcompress_rgtc.h"
45#include "texstore.h"
46
47static void extractsrc_u( GLubyte srcpixels[4][4], const GLubyte *srcaddr,
48			  GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps)
49{
50   GLubyte i, j;
51   const GLubyte *curaddr;
52   for (j = 0; j < numypixels; j++) {
53      curaddr = srcaddr + j * srcRowStride * comps;
54      for (i = 0; i < numxpixels; i++) {
55	 srcpixels[j][i] = *curaddr;
56	 curaddr += comps;
57      }
58   }
59}
60
61static void extractsrc_s( GLbyte srcpixels[4][4], const GLfloat *srcaddr,
62			  GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps)
63{
64   GLubyte i, j;
65   const GLfloat *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] = FLOAT_TO_BYTE_TEX(*curaddr);
70	 curaddr += comps;
71      }
72   }
73}
74
75
76GLboolean
77_mesa_texstore_red_rgtc1(TEXSTORE_PARAMS)
78{
79   GLubyte *dst;
80   const GLubyte *tempImage = NULL;
81   int i, j;
82   int numxpixels, numypixels;
83   const GLubyte *srcaddr;
84   GLubyte srcpixels[4][4];
85   GLubyte *blkaddr;
86   GLint dstRowDiff, redRowStride;
87   GLubyte *tempImageSlices[1];
88
89   assert(dstFormat == MESA_FORMAT_R_RGTC1_UNORM ||
90          dstFormat == MESA_FORMAT_L_LATC1_UNORM);
91
92   tempImage = malloc(srcWidth * srcHeight * 1 * sizeof(GLubyte));
93   if (!tempImage)
94      return GL_FALSE; /* out of memory */
95   redRowStride = 1 * srcWidth * sizeof(GLubyte);
96   tempImageSlices[0] = (GLubyte *) tempImage;
97   _mesa_texstore(ctx, dims,
98                  baseInternalFormat,
99                  MESA_FORMAT_R_UNORM8,
100                  redRowStride, tempImageSlices,
101                  srcWidth, srcHeight, srcDepth,
102                  srcFormat, srcType, srcAddr,
103                  srcPacking);
104
105   dst = dstSlices[0];
106
107   blkaddr = dst;
108   dstRowDiff = dstRowStride >= (srcWidth * 2) ? dstRowStride - (((srcWidth + 3) & ~3) * 2) : 0;
109   for (j = 0; j < srcHeight; j+=4) {
110      if (srcHeight > j + 3) numypixels = 4;
111      else numypixels = srcHeight - j;
112      srcaddr = tempImage + j * srcWidth;
113      for (i = 0; i < srcWidth; i += 4) {
114	 if (srcWidth > i + 3) numxpixels = 4;
115	 else numxpixels = srcWidth - i;
116	 extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1);
117	 util_format_unsigned_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels);
118	 srcaddr += numxpixels;
119	 blkaddr += 8;
120      }
121      blkaddr += dstRowDiff;
122   }
123
124   free((void *) tempImage);
125
126   return GL_TRUE;
127}
128
129GLboolean
130_mesa_texstore_signed_red_rgtc1(TEXSTORE_PARAMS)
131{
132   GLbyte *dst;
133   const GLfloat *tempImage = NULL;
134   int i, j;
135   int numxpixels, numypixels;
136   const GLfloat *srcaddr;
137   GLbyte srcpixels[4][4];
138   GLbyte *blkaddr;
139   GLint dstRowDiff, redRowStride;
140   GLfloat *tempImageSlices[1];
141
142   assert(dstFormat == MESA_FORMAT_R_RGTC1_SNORM ||
143          dstFormat == MESA_FORMAT_L_LATC1_SNORM);
144
145   redRowStride = 1 * srcWidth * sizeof(GLfloat);
146   tempImage = malloc(srcWidth * srcHeight * 1 * sizeof(GLfloat));
147   if (!tempImage)
148      return GL_FALSE; /* out of memory */
149   tempImageSlices[0] = (GLfloat *) tempImage;
150   _mesa_texstore(ctx, dims,
151                  baseInternalFormat,
152                  MESA_FORMAT_R_FLOAT32,
153                  redRowStride, (GLubyte **)tempImageSlices,
154                  srcWidth, srcHeight, srcDepth,
155                  srcFormat, srcType, srcAddr,
156                  srcPacking);
157
158   dst = (GLbyte *) dstSlices[0];
159
160   blkaddr = dst;
161   dstRowDiff = dstRowStride >= (srcWidth * 2) ? dstRowStride - (((srcWidth + 3) & ~3) * 2) : 0;
162   for (j = 0; j < srcHeight; j+=4) {
163      if (srcHeight > j + 3) numypixels = 4;
164      else numypixels = srcHeight - j;
165      srcaddr = tempImage + j * srcWidth;
166      for (i = 0; i < srcWidth; i += 4) {
167	 if (srcWidth > i + 3) numxpixels = 4;
168	 else numxpixels = srcWidth - i;
169	 extractsrc_s(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1);
170	 util_format_signed_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels);
171	 srcaddr += numxpixels;
172	 blkaddr += 8;
173      }
174      blkaddr += dstRowDiff;
175   }
176
177   free((void *) tempImage);
178
179   return GL_TRUE;
180}
181
182GLboolean
183_mesa_texstore_rg_rgtc2(TEXSTORE_PARAMS)
184{
185   GLubyte *dst;
186   const GLubyte *tempImage = NULL;
187   int i, j;
188   int numxpixels, numypixels;
189   const GLubyte *srcaddr;
190   GLubyte srcpixels[4][4];
191   GLubyte *blkaddr;
192   GLint dstRowDiff, rgRowStride;
193   mesa_format tempFormat;
194   GLubyte *tempImageSlices[1];
195
196   assert(dstFormat == MESA_FORMAT_RG_RGTC2_UNORM ||
197          dstFormat == MESA_FORMAT_LA_LATC2_UNORM);
198
199   if (baseInternalFormat == GL_RG)
200      tempFormat = _mesa_little_endian() ? MESA_FORMAT_R8G8_UNORM
201                                         : MESA_FORMAT_G8R8_UNORM;
202   else
203      tempFormat = _mesa_little_endian() ? MESA_FORMAT_L8A8_UNORM
204                                         : MESA_FORMAT_A8L8_UNORM;
205
206   rgRowStride = 2 * srcWidth * sizeof(GLubyte);
207   tempImage = malloc(srcWidth * srcHeight * 2 * sizeof(GLubyte));
208   if (!tempImage)
209      return GL_FALSE; /* out of memory */
210   tempImageSlices[0] = (GLubyte *) tempImage;
211   _mesa_texstore(ctx, dims,
212                  baseInternalFormat,
213                  tempFormat,
214                  rgRowStride, tempImageSlices,
215                  srcWidth, srcHeight, srcDepth,
216                  srcFormat, srcType, srcAddr,
217                  srcPacking);
218
219   dst = dstSlices[0];
220
221   blkaddr = dst;
222   dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 0;
223   for (j = 0; j < srcHeight; j+=4) {
224      if (srcHeight > j + 3) numypixels = 4;
225      else numypixels = srcHeight - j;
226      srcaddr = tempImage + j * srcWidth * 2;
227      for (i = 0; i < srcWidth; i += 4) {
228	 if (srcWidth > i + 3) numxpixels = 4;
229	 else numxpixels = srcWidth - i;
230	 extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 2);
231	 util_format_unsigned_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels);
232
233	 blkaddr += 8;
234	 extractsrc_u(srcpixels, (GLubyte *)srcaddr + 1, srcWidth, numxpixels, numypixels, 2);
235	 util_format_unsigned_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels);
236
237	 blkaddr += 8;
238
239	 srcaddr += numxpixels * 2;
240      }
241      blkaddr += dstRowDiff;
242   }
243
244   free((void *) tempImage);
245
246   return GL_TRUE;
247}
248
249GLboolean
250_mesa_texstore_signed_rg_rgtc2(TEXSTORE_PARAMS)
251{
252   GLbyte *dst;
253   const GLfloat *tempImage = NULL;
254   int i, j;
255   int numxpixels, numypixels;
256   const GLfloat *srcaddr;
257   GLbyte srcpixels[4][4];
258   GLbyte *blkaddr;
259   GLint dstRowDiff, rgRowStride;
260   mesa_format tempFormat;
261   GLfloat *tempImageSlices[1];
262
263   assert(dstFormat == MESA_FORMAT_RG_RGTC2_SNORM ||
264          dstFormat == MESA_FORMAT_LA_LATC2_SNORM);
265
266   if (baseInternalFormat == GL_RG)
267      tempFormat = MESA_FORMAT_RG_FLOAT32;
268   else
269      tempFormat = MESA_FORMAT_LA_FLOAT32;
270
271   rgRowStride = 2 * srcWidth * sizeof(GLfloat);
272   tempImage = malloc(srcWidth * srcHeight * 2 * sizeof(GLfloat));
273   if (!tempImage)
274      return GL_FALSE; /* out of memory */
275   tempImageSlices[0] = (GLfloat *) tempImage;
276   _mesa_texstore(ctx, dims,
277                  baseInternalFormat,
278                  tempFormat,
279                  rgRowStride, (GLubyte **)tempImageSlices,
280                  srcWidth, srcHeight, srcDepth,
281                  srcFormat, srcType, srcAddr,
282                  srcPacking);
283
284   dst = (GLbyte *) dstSlices[0];
285
286   blkaddr = dst;
287   dstRowDiff = dstRowStride >= (srcWidth * 4) ? dstRowStride - (((srcWidth + 3) & ~3) * 4) : 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	 util_format_signed_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels);
298	 blkaddr += 8;
299
300	 extractsrc_s(srcpixels, srcaddr + 1, srcWidth, numxpixels, numypixels, 2);
301	 util_format_signed_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels);
302	 blkaddr += 8;
303
304	 srcaddr += numxpixels * 2;
305
306      }
307      blkaddr += dstRowDiff;
308   }
309
310   free((void *) tempImage);
311
312   return GL_TRUE;
313}
314
315static void
316fetch_red_rgtc1(const GLubyte *map,
317                GLint rowStride, GLint i, GLint j, GLfloat *texel)
318{
319   GLubyte red;
320   util_format_unsigned_fetch_texel_rgtc(rowStride, map, i, j, &red, 1);
321   texel[RCOMP] = UBYTE_TO_FLOAT(red);
322   texel[GCOMP] = 0.0;
323   texel[BCOMP] = 0.0;
324   texel[ACOMP] = 1.0;
325}
326
327static void
328fetch_l_latc1(const GLubyte *map,
329              GLint rowStride, GLint i, GLint j, GLfloat *texel)
330{
331   GLubyte red;
332   util_format_unsigned_fetch_texel_rgtc(rowStride, map, i, j, &red, 1);
333   texel[RCOMP] =
334   texel[GCOMP] =
335   texel[BCOMP] = UBYTE_TO_FLOAT(red);
336   texel[ACOMP] = 1.0;
337}
338
339static void
340fetch_signed_red_rgtc1(const GLubyte *map,
341                       GLint rowStride, GLint i, GLint j, GLfloat *texel)
342{
343   GLbyte red;
344   util_format_signed_fetch_texel_rgtc(rowStride, (const GLbyte *) map,
345                           i, j, &red, 1);
346   texel[RCOMP] = BYTE_TO_FLOAT_TEX(red);
347   texel[GCOMP] = 0.0;
348   texel[BCOMP] = 0.0;
349   texel[ACOMP] = 1.0;
350}
351
352static void
353fetch_signed_l_latc1(const GLubyte *map,
354                     GLint rowStride, GLint i, GLint j, GLfloat *texel)
355{
356   GLbyte red;
357   util_format_signed_fetch_texel_rgtc(rowStride, (GLbyte *) map,
358                           i, j, &red, 1);
359   texel[RCOMP] =
360   texel[GCOMP] =
361   texel[BCOMP] = BYTE_TO_FLOAT(red);
362   texel[ACOMP] = 1.0;
363}
364
365static void
366fetch_rg_rgtc2(const GLubyte *map,
367               GLint rowStride, GLint i, GLint j, GLfloat *texel)
368{
369   GLubyte red, green;
370   util_format_unsigned_fetch_texel_rgtc(rowStride,
371                             map,
372                             i, j, &red, 2);
373   util_format_unsigned_fetch_texel_rgtc(rowStride,
374                             map + 8,
375                             i, j, &green, 2);
376   texel[RCOMP] = UBYTE_TO_FLOAT(red);
377   texel[GCOMP] = UBYTE_TO_FLOAT(green);
378   texel[BCOMP] = 0.0;
379   texel[ACOMP] = 1.0;
380}
381
382static void
383fetch_la_latc2(const GLubyte *map,
384               GLint rowStride, GLint i, GLint j, GLfloat *texel)
385{
386   GLubyte red, green;
387   util_format_unsigned_fetch_texel_rgtc(rowStride,
388                             map,
389                             i, j, &red, 2);
390   util_format_unsigned_fetch_texel_rgtc(rowStride,
391                             map + 8,
392                             i, j, &green, 2);
393   texel[RCOMP] =
394   texel[GCOMP] =
395   texel[BCOMP] = UBYTE_TO_FLOAT(red);
396   texel[ACOMP] = UBYTE_TO_FLOAT(green);
397}
398
399
400static void
401fetch_signed_rg_rgtc2(const GLubyte *map,
402                      GLint rowStride, GLint i, GLint j, GLfloat *texel)
403{
404   GLbyte red, green;
405   util_format_signed_fetch_texel_rgtc(rowStride,
406                           (GLbyte *) map,
407                           i, j, &red, 2);
408   util_format_signed_fetch_texel_rgtc(rowStride,
409                           (GLbyte *) map + 8,
410                           i, j, &green, 2);
411   texel[RCOMP] = BYTE_TO_FLOAT_TEX(red);
412   texel[GCOMP] = BYTE_TO_FLOAT_TEX(green);
413   texel[BCOMP] = 0.0;
414   texel[ACOMP] = 1.0;
415}
416
417
418static void
419fetch_signed_la_latc2(const GLubyte *map,
420                      GLint rowStride, GLint i, GLint j, GLfloat *texel)
421{
422   GLbyte red, green;
423   util_format_signed_fetch_texel_rgtc(rowStride,
424                           (GLbyte *) map,
425                           i, j, &red, 2);
426   util_format_signed_fetch_texel_rgtc(rowStride,
427                           (GLbyte *) map + 8,
428                           i, j, &green, 2);
429   texel[RCOMP] =
430   texel[GCOMP] =
431   texel[BCOMP] = BYTE_TO_FLOAT_TEX(red);
432   texel[ACOMP] = BYTE_TO_FLOAT_TEX(green);
433}
434
435
436compressed_fetch_func
437_mesa_get_compressed_rgtc_func(mesa_format format)
438{
439   switch (format) {
440   case MESA_FORMAT_R_RGTC1_UNORM:
441      return fetch_red_rgtc1;
442   case MESA_FORMAT_L_LATC1_UNORM:
443      return fetch_l_latc1;
444   case MESA_FORMAT_R_RGTC1_SNORM:
445      return fetch_signed_red_rgtc1;
446   case MESA_FORMAT_L_LATC1_SNORM:
447      return fetch_signed_l_latc1;
448   case MESA_FORMAT_RG_RGTC2_UNORM:
449      return fetch_rg_rgtc2;
450   case MESA_FORMAT_LA_LATC2_UNORM:
451      return fetch_la_latc2;
452   case MESA_FORMAT_RG_RGTC2_SNORM:
453      return fetch_signed_rg_rgtc2;
454   case MESA_FORMAT_LA_LATC2_SNORM:
455      return fetch_signed_la_latc2;
456   default:
457      return NULL;
458   }
459}
460