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 "util/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 "util/format/u_format_rgtc.h"
46 #include "texcompress_rgtc.h"
47 #include "texstore.h"
48
extractsrc_u(GLubyte srcpixels[4][4],const GLubyte * srcaddr,GLint srcRowStride,GLint numxpixels,GLint numypixels,GLint comps)49 static void extractsrc_u( GLubyte srcpixels[4][4], const GLubyte *srcaddr,
50 GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps)
51 {
52 GLubyte i, j;
53 const GLubyte *curaddr;
54 for (j = 0; j < numypixels; j++) {
55 curaddr = srcaddr + j * srcRowStride * comps;
56 for (i = 0; i < numxpixels; i++) {
57 srcpixels[j][i] = *curaddr;
58 curaddr += comps;
59 }
60 }
61 }
62
extractsrc_s(GLbyte srcpixels[4][4],const GLbyte * srcaddr,GLint srcRowStride,GLint numxpixels,GLint numypixels,GLint comps)63 static void extractsrc_s( GLbyte srcpixels[4][4], const GLbyte *srcaddr,
64 GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps)
65 {
66 GLubyte i, j;
67 const GLbyte *curaddr;
68 for (j = 0; j < numypixels; j++) {
69 curaddr = srcaddr + j * srcRowStride * comps;
70 for (i = 0; i < numxpixels; i++) {
71 srcpixels[j][i] = *curaddr;
72 curaddr += comps;
73 }
74 }
75 }
76
77
78 GLboolean
_mesa_texstore_red_rgtc1(TEXSTORE_PARAMS)79 _mesa_texstore_red_rgtc1(TEXSTORE_PARAMS)
80 {
81 GLubyte *dst;
82 const GLubyte *tempImage = NULL;
83 int i, j;
84 int numxpixels, numypixels;
85 const GLubyte *srcaddr;
86 GLubyte srcpixels[4][4];
87 GLubyte *blkaddr;
88 GLint dstRowDiff, redRowStride;
89 GLubyte *tempImageSlices[1];
90
91 assert(dstFormat == MESA_FORMAT_R_RGTC1_UNORM ||
92 dstFormat == MESA_FORMAT_L_LATC1_UNORM);
93
94 tempImage = malloc(srcWidth * srcHeight * 1 * sizeof(GLubyte));
95 if (!tempImage)
96 return GL_FALSE; /* out of memory */
97 redRowStride = 1 * srcWidth * sizeof(GLubyte);
98 tempImageSlices[0] = (GLubyte *) tempImage;
99 _mesa_texstore(ctx, dims,
100 baseInternalFormat,
101 MESA_FORMAT_R_UNORM8,
102 redRowStride, tempImageSlices,
103 srcWidth, srcHeight, srcDepth,
104 srcFormat, srcType, srcAddr,
105 srcPacking);
106
107 dst = dstSlices[0];
108
109 blkaddr = dst;
110 dstRowDiff = dstRowStride >= (srcWidth * 2) ? dstRowStride - (((srcWidth + 3) & ~3) * 2) : 0;
111 for (j = 0; j < srcHeight; j+=4) {
112 if (srcHeight > j + 3) numypixels = 4;
113 else numypixels = srcHeight - j;
114 srcaddr = tempImage + j * srcWidth;
115 for (i = 0; i < srcWidth; i += 4) {
116 if (srcWidth > i + 3) numxpixels = 4;
117 else numxpixels = srcWidth - i;
118 extractsrc_u(srcpixels, srcaddr, srcWidth, numxpixels, numypixels, 1);
119 util_format_unsigned_encode_rgtc_ubyte(blkaddr, srcpixels, numxpixels, numypixels);
120 srcaddr += numxpixels;
121 blkaddr += 8;
122 }
123 blkaddr += dstRowDiff;
124 }
125
126 free((void *) tempImage);
127
128 return GL_TRUE;
129 }
130
131 GLboolean
_mesa_texstore_signed_red_rgtc1(TEXSTORE_PARAMS)132 _mesa_texstore_signed_red_rgtc1(TEXSTORE_PARAMS)
133 {
134 GLbyte *dst;
135 const GLbyte *tempImage = NULL;
136 int i, j;
137 int numxpixels, numypixels;
138 const GLbyte *srcaddr;
139 GLbyte srcpixels[4][4];
140 GLbyte *blkaddr;
141 GLint dstRowDiff, redRowStride;
142 GLbyte *tempImageSlices[1];
143
144 assert(dstFormat == MESA_FORMAT_R_RGTC1_SNORM ||
145 dstFormat == MESA_FORMAT_L_LATC1_SNORM);
146
147 redRowStride = 1 * srcWidth * sizeof(GLbyte);
148 tempImage = malloc(srcWidth * srcHeight * 1 * sizeof(GLbyte));
149 if (!tempImage)
150 return GL_FALSE; /* out of memory */
151 tempImageSlices[0] = (GLbyte *) tempImage;
152 _mesa_texstore(ctx, dims,
153 baseInternalFormat,
154 MESA_FORMAT_R_SNORM8,
155 redRowStride, (GLubyte **)tempImageSlices,
156 srcWidth, srcHeight, srcDepth,
157 srcFormat, srcType, srcAddr,
158 srcPacking);
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 util_format_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
184 GLboolean
_mesa_texstore_rg_rgtc2(TEXSTORE_PARAMS)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, rgRowStride;
195 mesa_format tempFormat;
196 GLubyte *tempImageSlices[1];
197
198 assert(dstFormat == MESA_FORMAT_RG_RGTC2_UNORM ||
199 dstFormat == MESA_FORMAT_LA_LATC2_UNORM);
200
201 if (baseInternalFormat == GL_RG)
202 tempFormat = MESA_FORMAT_RG_UNORM8;
203 else
204 tempFormat = MESA_FORMAT_LA_UNORM8;
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
249 GLboolean
_mesa_texstore_signed_rg_rgtc2(TEXSTORE_PARAMS)250 _mesa_texstore_signed_rg_rgtc2(TEXSTORE_PARAMS)
251 {
252 GLbyte *dst;
253 const GLbyte *tempImage = NULL;
254 int i, j;
255 int numxpixels, numypixels;
256 const GLbyte *srcaddr;
257 GLbyte srcpixels[4][4];
258 GLbyte *blkaddr;
259 GLint dstRowDiff, rgRowStride;
260 mesa_format tempFormat;
261 GLbyte *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_SNORM8;
268 else
269 tempFormat = MESA_FORMAT_LA_SNORM8;
270
271 rgRowStride = 2 * srcWidth * sizeof(GLbyte);
272 tempImage = malloc(srcWidth * srcHeight * 2 * sizeof(GLbyte));
273 if (!tempImage)
274 return GL_FALSE; /* out of memory */
275 tempImageSlices[0] = (GLbyte *) 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 blkaddr += dstRowDiff;
307 }
308
309 free((void *) tempImage);
310
311 return GL_TRUE;
312 }
313
314 static void
fetch_red_rgtc1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)315 fetch_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
326 static void
fetch_l_latc1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)327 fetch_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
338 static void
fetch_signed_red_rgtc1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)339 fetch_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
351 static void
fetch_signed_l_latc1(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)352 fetch_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
364 static void
fetch_rg_rgtc2(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)365 fetch_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
381 static void
fetch_la_latc2(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)382 fetch_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
399 static void
fetch_signed_rg_rgtc2(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)400 fetch_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
417 static void
fetch_signed_la_latc2(const GLubyte * map,GLint rowStride,GLint i,GLint j,GLfloat * texel)418 fetch_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
435 compressed_fetch_func
_mesa_get_compressed_rgtc_func(mesa_format format)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
460 void
_mesa_unpack_rgtc(uint8_t * dst_row,unsigned dst_stride,const uint8_t * src_row,unsigned src_stride,unsigned src_width,unsigned src_height,mesa_format format)461 _mesa_unpack_rgtc(uint8_t *dst_row,
462 unsigned dst_stride,
463 const uint8_t *src_row,
464 unsigned src_stride,
465 unsigned src_width,
466 unsigned src_height,
467 mesa_format format)
468 {
469 switch (format) {
470 case MESA_FORMAT_R_RGTC1_UNORM:
471 case MESA_FORMAT_L_LATC1_UNORM:
472 util_format_rgtc1_unorm_unpack_r_8unorm(dst_row, dst_stride,
473 src_row, src_stride,
474 src_width, src_height);
475 break;
476
477 case MESA_FORMAT_R_RGTC1_SNORM:
478 case MESA_FORMAT_L_LATC1_SNORM:
479 util_format_rgtc1_snorm_unpack_r_8snorm((int8_t *)dst_row, dst_stride,
480 src_row, src_stride,
481 src_width, src_height);
482 break;
483
484 case MESA_FORMAT_RG_RGTC2_UNORM:
485 case MESA_FORMAT_LA_LATC2_UNORM:
486 util_format_rgtc2_unorm_unpack_rg_8unorm(dst_row, dst_stride,
487 src_row, src_stride,
488 src_width, src_height);
489 break;
490
491 case MESA_FORMAT_RG_RGTC2_SNORM:
492 case MESA_FORMAT_LA_LATC2_SNORM:
493 util_format_rgtc2_snorm_unpack_rg_8snorm((int8_t *)dst_row, dst_stride,
494 src_row, src_stride,
495 src_width, src_height);
496 break;
497
498 default:
499 unreachable("unexpected format");
500 }
501 }
502