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