1/*
2 * Copyright (C) 2014 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24/**
25 * \file texcompress_bptc.c
26 * GL_ARB_texture_compression_bptc support.
27 */
28
29#include <stdbool.h>
30#include "texcompress.h"
31#include "texcompress_bptc.h"
32#include "texcompress_bptc_tmp.h"
33#include "texstore.h"
34#include "image.h"
35#include "mtypes.h"
36
37static void
38fetch_bptc_rgb_float(const GLubyte *map,
39                     GLint rowStride, GLint i, GLint j,
40                     GLfloat *texel,
41                     bool is_signed)
42{
43   const GLubyte *block;
44
45   block = map + (((rowStride + 3) / 4) * (j / 4) + (i / 4)) * 16;
46
47   fetch_rgb_float_from_block(block, texel, (i % 4) + (j % 4) * 4, is_signed);
48}
49
50static void
51fetch_bptc_rgb_signed_float(const GLubyte *map,
52                            GLint rowStride, GLint i, GLint j,
53                            GLfloat *texel)
54{
55   fetch_bptc_rgb_float(map, rowStride, i, j, texel, true);
56}
57
58static void
59fetch_bptc_rgb_unsigned_float(const GLubyte *map,
60                              GLint rowStride, GLint i, GLint j,
61                              GLfloat *texel)
62{
63   fetch_bptc_rgb_float(map, rowStride, i, j, texel, false);
64}
65
66static void
67fetch_bptc_rgba_unorm_bytes(const GLubyte *map,
68                            GLint rowStride, GLint i, GLint j,
69                            GLubyte *texel)
70{
71   const GLubyte *block;
72
73   block = map + (((rowStride + 3) / 4) * (j / 4) + (i / 4)) * 16;
74
75   fetch_rgba_unorm_from_block(block, texel, (i % 4) + (j % 4) * 4);
76}
77
78static void
79fetch_bptc_rgba_unorm(const GLubyte *map,
80                      GLint rowStride, GLint i, GLint j,
81                      GLfloat *texel)
82{
83   GLubyte texel_bytes[4];
84
85   fetch_bptc_rgba_unorm_bytes(map, rowStride, i, j, texel_bytes);
86
87   texel[RCOMP] = UBYTE_TO_FLOAT(texel_bytes[0]);
88   texel[GCOMP] = UBYTE_TO_FLOAT(texel_bytes[1]);
89   texel[BCOMP] = UBYTE_TO_FLOAT(texel_bytes[2]);
90   texel[ACOMP] = UBYTE_TO_FLOAT(texel_bytes[3]);
91}
92
93static void
94fetch_bptc_srgb_alpha_unorm(const GLubyte *map,
95                            GLint rowStride, GLint i, GLint j,
96                            GLfloat *texel)
97{
98   GLubyte texel_bytes[4];
99
100   fetch_bptc_rgba_unorm_bytes(map, rowStride, i, j, texel_bytes);
101
102   texel[RCOMP] = util_format_srgb_8unorm_to_linear_float(texel_bytes[0]);
103   texel[GCOMP] = util_format_srgb_8unorm_to_linear_float(texel_bytes[1]);
104   texel[BCOMP] = util_format_srgb_8unorm_to_linear_float(texel_bytes[2]);
105   texel[ACOMP] = UBYTE_TO_FLOAT(texel_bytes[3]);
106}
107
108compressed_fetch_func
109_mesa_get_bptc_fetch_func(mesa_format format)
110{
111   switch (format) {
112   case MESA_FORMAT_BPTC_RGBA_UNORM:
113      return fetch_bptc_rgba_unorm;
114   case MESA_FORMAT_BPTC_SRGB_ALPHA_UNORM:
115      return fetch_bptc_srgb_alpha_unorm;
116   case MESA_FORMAT_BPTC_RGB_SIGNED_FLOAT:
117      return fetch_bptc_rgb_signed_float;
118   case MESA_FORMAT_BPTC_RGB_UNSIGNED_FLOAT:
119      return fetch_bptc_rgb_unsigned_float;
120   default:
121      return NULL;
122   }
123}
124
125GLboolean
126_mesa_texstore_bptc_rgba_unorm(TEXSTORE_PARAMS)
127{
128   const GLubyte *pixels;
129   const GLubyte *tempImage = NULL;
130   int rowstride;
131
132   if (srcFormat != GL_RGBA ||
133       srcType != GL_UNSIGNED_BYTE ||
134       ctx->_ImageTransferState ||
135       srcPacking->SwapBytes) {
136      /* convert image to RGBA/ubyte */
137      GLubyte *tempImageSlices[1];
138      int rgbaRowStride = 4 * srcWidth * sizeof(GLubyte);
139      tempImage = malloc(srcWidth * srcHeight * 4 * sizeof(GLubyte));
140      if (!tempImage)
141         return GL_FALSE; /* out of memory */
142      tempImageSlices[0] = (GLubyte *) tempImage;
143      _mesa_texstore(ctx, dims,
144                     baseInternalFormat,
145                     _mesa_little_endian() ? MESA_FORMAT_R8G8B8A8_UNORM
146                                           : MESA_FORMAT_A8B8G8R8_UNORM,
147                     rgbaRowStride, tempImageSlices,
148                     srcWidth, srcHeight, srcDepth,
149                     srcFormat, srcType, srcAddr,
150                     srcPacking);
151
152      pixels = tempImage;
153      rowstride = srcWidth * 4;
154   } else {
155      pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
156                                     srcFormat, srcType, 0, 0);
157      rowstride = _mesa_image_row_stride(srcPacking, srcWidth,
158                                         srcFormat, srcType);
159   }
160
161   compress_rgba_unorm(srcWidth, srcHeight,
162                       pixels, rowstride,
163                       dstSlices[0], dstRowStride);
164
165   free((void *) tempImage);
166
167   return GL_TRUE;
168}
169
170static GLboolean
171texstore_bptc_rgb_float(TEXSTORE_PARAMS,
172                        bool is_signed)
173{
174   const float *pixels;
175   const float *tempImage = NULL;
176   int rowstride;
177
178   if (srcFormat != GL_RGB ||
179       srcType != GL_FLOAT ||
180       ctx->_ImageTransferState ||
181       srcPacking->SwapBytes) {
182      /* convert image to RGB/float */
183      GLfloat *tempImageSlices[1];
184      int rgbRowStride = 3 * srcWidth * sizeof(GLfloat);
185      tempImage = malloc(srcWidth * srcHeight * 3 * sizeof(GLfloat));
186      if (!tempImage)
187         return GL_FALSE; /* out of memory */
188      tempImageSlices[0] = (GLfloat *) tempImage;
189      _mesa_texstore(ctx, dims,
190                     baseInternalFormat,
191                     MESA_FORMAT_RGB_FLOAT32,
192                     rgbRowStride, (GLubyte **)tempImageSlices,
193                     srcWidth, srcHeight, srcDepth,
194                     srcFormat, srcType, srcAddr,
195                     srcPacking);
196
197      pixels = tempImage;
198      rowstride = srcWidth * sizeof(float) * 3;
199   } else {
200      pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
201                                     srcFormat, srcType, 0, 0);
202      rowstride = _mesa_image_row_stride(srcPacking, srcWidth,
203                                         srcFormat, srcType);
204   }
205
206   compress_rgb_float(srcWidth, srcHeight,
207                      pixels, rowstride,
208                      dstSlices[0], dstRowStride,
209                      is_signed);
210
211   free((void *) tempImage);
212
213   return GL_TRUE;
214}
215
216GLboolean
217_mesa_texstore_bptc_rgb_signed_float(TEXSTORE_PARAMS)
218{
219   assert(dstFormat == MESA_FORMAT_BPTC_RGB_SIGNED_FLOAT);
220
221   return texstore_bptc_rgb_float(ctx, dims, baseInternalFormat,
222                                  dstFormat, dstRowStride, dstSlices,
223                                  srcWidth, srcHeight, srcDepth,
224                                  srcFormat, srcType,
225                                  srcAddr, srcPacking,
226                                  true /* signed */);
227}
228
229GLboolean
230_mesa_texstore_bptc_rgb_unsigned_float(TEXSTORE_PARAMS)
231{
232   assert(dstFormat == MESA_FORMAT_BPTC_RGB_UNSIGNED_FLOAT);
233
234   return texstore_bptc_rgb_float(ctx, dims, baseInternalFormat,
235                                  dstFormat, dstRowStride, dstSlices,
236                                  srcWidth, srcHeight, srcDepth,
237                                  srcFormat, srcType,
238                                  srcAddr, srcPacking,
239                                  false /* unsigned */);
240}
241