1 /**************************************************************************
2 *
3 * Copyright 2010 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /**
29 * @file
30 * Pixel format accessor functions.
31 *
32 * @author Jose Fonseca <jfonseca@vmware.com>
33 */
34
35 #include "u_math.h"
36 #include "u_memory.h"
37 #include "u_format.h"
38 #include "u_format_s3tc.h"
39 #include "u_surface.h"
40
41 #include "pipe/p_defines.h"
42
43 boolean util_format_s3tc_enabled = FALSE;
44
45 boolean
util_format_is_float(enum pipe_format format)46 util_format_is_float(enum pipe_format format)
47 {
48 const struct util_format_description *desc = util_format_description(format);
49 int i;
50
51 assert(desc);
52 if (!desc) {
53 return FALSE;
54 }
55
56 i = util_format_get_first_non_void_channel(format);
57 if (i == -1) {
58 return FALSE;
59 }
60
61 return desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT ? TRUE : FALSE;
62 }
63
64
65 /** Test if the format contains RGB, but not alpha */
66 boolean
util_format_has_alpha(enum pipe_format format)67 util_format_has_alpha(enum pipe_format format)
68 {
69 const struct util_format_description *desc =
70 util_format_description(format);
71
72 return (desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
73 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
74 desc->swizzle[3] != UTIL_FORMAT_SWIZZLE_1;
75 }
76
77
78 boolean
util_format_is_luminance(enum pipe_format format)79 util_format_is_luminance(enum pipe_format format)
80 {
81 const struct util_format_description *desc =
82 util_format_description(format);
83
84 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
85 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
86 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X &&
87 desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X &&
88 desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X &&
89 desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1) {
90 return TRUE;
91 }
92 return FALSE;
93 }
94
95 boolean
util_format_is_alpha(enum pipe_format format)96 util_format_is_alpha(enum pipe_format format)
97 {
98 const struct util_format_description *desc =
99 util_format_description(format);
100
101 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
102 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
103 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_0 &&
104 desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_0 &&
105 desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_0 &&
106 desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_X) {
107 return TRUE;
108 }
109 return FALSE;
110 }
111
112 boolean
util_format_is_pure_integer(enum pipe_format format)113 util_format_is_pure_integer(enum pipe_format format)
114 {
115 const struct util_format_description *desc = util_format_description(format);
116 int i;
117
118 /* Find the first non-void channel. */
119 i = util_format_get_first_non_void_channel(format);
120 if (i == -1)
121 return FALSE;
122
123 return desc->channel[i].pure_integer ? TRUE : FALSE;
124 }
125
126 boolean
util_format_is_pure_sint(enum pipe_format format)127 util_format_is_pure_sint(enum pipe_format format)
128 {
129 const struct util_format_description *desc = util_format_description(format);
130 int i;
131
132 i = util_format_get_first_non_void_channel(format);
133 if (i == -1)
134 return FALSE;
135
136 return (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED && desc->channel[i].pure_integer) ? TRUE : FALSE;
137 }
138
139 boolean
util_format_is_pure_uint(enum pipe_format format)140 util_format_is_pure_uint(enum pipe_format format)
141 {
142 const struct util_format_description *desc = util_format_description(format);
143 int i;
144
145 i = util_format_get_first_non_void_channel(format);
146 if (i == -1)
147 return FALSE;
148
149 return (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED && desc->channel[i].pure_integer) ? TRUE : FALSE;
150 }
151
152 /**
153 * Returns true if all non-void channels are normalized signed.
154 */
155 boolean
util_format_is_snorm(enum pipe_format format)156 util_format_is_snorm(enum pipe_format format)
157 {
158 const struct util_format_description *desc = util_format_description(format);
159 int i;
160
161 if (desc->is_mixed)
162 return FALSE;
163
164 i = util_format_get_first_non_void_channel(format);
165 if (i == -1)
166 return FALSE;
167
168 return desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED &&
169 !desc->channel[i].pure_integer &&
170 desc->channel[i].normalized;
171 }
172
173 boolean
util_format_is_luminance_alpha(enum pipe_format format)174 util_format_is_luminance_alpha(enum pipe_format format)
175 {
176 const struct util_format_description *desc =
177 util_format_description(format);
178
179 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
180 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
181 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X &&
182 desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X &&
183 desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X &&
184 desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_Y) {
185 return TRUE;
186 }
187 return FALSE;
188 }
189
190
191 boolean
util_format_is_intensity(enum pipe_format format)192 util_format_is_intensity(enum pipe_format format)
193 {
194 const struct util_format_description *desc =
195 util_format_description(format);
196
197 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
198 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
199 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X &&
200 desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X &&
201 desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X &&
202 desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_X) {
203 return TRUE;
204 }
205 return FALSE;
206 }
207
208 boolean
util_format_is_subsampled_422(enum pipe_format format)209 util_format_is_subsampled_422(enum pipe_format format)
210 {
211 const struct util_format_description *desc =
212 util_format_description(format);
213
214 return desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED &&
215 desc->block.width == 2 &&
216 desc->block.height == 1 &&
217 desc->block.bits == 32;
218 }
219
220 boolean
util_format_is_supported(enum pipe_format format,unsigned bind)221 util_format_is_supported(enum pipe_format format, unsigned bind)
222 {
223 if (util_format_is_s3tc(format) && !util_format_s3tc_enabled) {
224 return FALSE;
225 }
226
227 #ifndef TEXTURE_FLOAT_ENABLED
228 if ((bind & PIPE_BIND_RENDER_TARGET) &&
229 format != PIPE_FORMAT_R9G9B9E5_FLOAT &&
230 format != PIPE_FORMAT_R11G11B10_FLOAT &&
231 util_format_is_float(format)) {
232 return FALSE;
233 }
234 #endif
235
236 return TRUE;
237 }
238
239
240 /**
241 * Calculates the MRD for the depth format. MRD is used in depth bias
242 * for UNORM and unbound depth buffers. When the depth buffer is floating
243 * point, the depth bias calculation does not use the MRD. However, the
244 * default MRD will be 1.0 / ((1 << 24) - 1).
245 */
246 double
util_get_depth_format_mrd(const struct util_format_description * desc)247 util_get_depth_format_mrd(const struct util_format_description *desc)
248 {
249 /*
250 * Depth buffer formats without a depth component OR scenarios
251 * without a bound depth buffer default to D24.
252 */
253 double mrd = 1.0 / ((1 << 24) - 1);
254 unsigned depth_channel;
255
256 assert(desc);
257
258 /*
259 * Some depth formats do not store the depth component in the first
260 * channel, detect the format and adjust the depth channel. Get the
261 * swizzled depth component channel.
262 */
263 depth_channel = desc->swizzle[0];
264
265 if (desc->channel[depth_channel].type == UTIL_FORMAT_TYPE_UNSIGNED &&
266 desc->channel[depth_channel].normalized) {
267 int depth_bits;
268
269 depth_bits = desc->channel[depth_channel].size;
270 mrd = 1.0 / ((1ULL << depth_bits) - 1);
271 }
272
273 return mrd;
274 }
275
276 boolean
util_is_format_compatible(const struct util_format_description * src_desc,const struct util_format_description * dst_desc)277 util_is_format_compatible(const struct util_format_description *src_desc,
278 const struct util_format_description *dst_desc)
279 {
280 unsigned chan;
281
282 if (src_desc->format == dst_desc->format) {
283 return TRUE;
284 }
285
286 if (src_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN ||
287 dst_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) {
288 return FALSE;
289 }
290
291 if (src_desc->block.bits != dst_desc->block.bits ||
292 src_desc->nr_channels != dst_desc->nr_channels ||
293 src_desc->colorspace != dst_desc->colorspace) {
294 return FALSE;
295 }
296
297 for (chan = 0; chan < 4; ++chan) {
298 if (src_desc->channel[chan].size !=
299 dst_desc->channel[chan].size) {
300 return FALSE;
301 }
302 }
303
304 for (chan = 0; chan < 4; ++chan) {
305 enum util_format_swizzle swizzle = dst_desc->swizzle[chan];
306
307 if (swizzle < 4) {
308 if (src_desc->swizzle[chan] != swizzle) {
309 return FALSE;
310 }
311 if ((src_desc->channel[swizzle].type !=
312 dst_desc->channel[swizzle].type) ||
313 (src_desc->channel[swizzle].normalized !=
314 dst_desc->channel[swizzle].normalized)) {
315 return FALSE;
316 }
317 }
318 }
319
320 return TRUE;
321 }
322
323
324 boolean
util_format_fits_8unorm(const struct util_format_description * format_desc)325 util_format_fits_8unorm(const struct util_format_description *format_desc)
326 {
327 unsigned chan;
328
329 /*
330 * After linearized sRGB values require more than 8bits.
331 */
332
333 if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
334 return FALSE;
335 }
336
337 switch (format_desc->layout) {
338
339 case UTIL_FORMAT_LAYOUT_S3TC:
340 /*
341 * These are straight forward.
342 */
343 return TRUE;
344 case UTIL_FORMAT_LAYOUT_RGTC:
345 if (format_desc->format == PIPE_FORMAT_RGTC1_SNORM ||
346 format_desc->format == PIPE_FORMAT_RGTC2_SNORM ||
347 format_desc->format == PIPE_FORMAT_LATC1_SNORM ||
348 format_desc->format == PIPE_FORMAT_LATC2_SNORM)
349 return FALSE;
350 return TRUE;
351 case UTIL_FORMAT_LAYOUT_BPTC:
352 if (format_desc->format == PIPE_FORMAT_BPTC_RGBA_UNORM)
353 return TRUE;
354 return FALSE;
355
356 case UTIL_FORMAT_LAYOUT_PLAIN:
357 /*
358 * For these we can find a generic rule.
359 */
360
361 for (chan = 0; chan < format_desc->nr_channels; ++chan) {
362 switch (format_desc->channel[chan].type) {
363 case UTIL_FORMAT_TYPE_VOID:
364 break;
365 case UTIL_FORMAT_TYPE_UNSIGNED:
366 if (!format_desc->channel[chan].normalized ||
367 format_desc->channel[chan].size > 8) {
368 return FALSE;
369 }
370 break;
371 default:
372 return FALSE;
373 }
374 }
375 return TRUE;
376
377 default:
378 /*
379 * Handle all others on a case by case basis.
380 */
381
382 switch (format_desc->format) {
383 case PIPE_FORMAT_R1_UNORM:
384 case PIPE_FORMAT_UYVY:
385 case PIPE_FORMAT_YUYV:
386 case PIPE_FORMAT_R8G8_B8G8_UNORM:
387 case PIPE_FORMAT_G8R8_G8B8_UNORM:
388 return TRUE;
389
390 default:
391 return FALSE;
392 }
393 }
394 }
395
396
util_format_compose_swizzles(const unsigned char swz1[4],const unsigned char swz2[4],unsigned char dst[4])397 void util_format_compose_swizzles(const unsigned char swz1[4],
398 const unsigned char swz2[4],
399 unsigned char dst[4])
400 {
401 unsigned i;
402
403 for (i = 0; i < 4; i++) {
404 dst[i] = swz2[i] <= UTIL_FORMAT_SWIZZLE_W ?
405 swz1[swz2[i]] : swz2[i];
406 }
407 }
408
util_format_apply_color_swizzle(union pipe_color_union * dst,const union pipe_color_union * src,const unsigned char swz[4],const boolean is_integer)409 void util_format_apply_color_swizzle(union pipe_color_union *dst,
410 const union pipe_color_union *src,
411 const unsigned char swz[4],
412 const boolean is_integer)
413 {
414 unsigned c;
415
416 if (is_integer) {
417 for (c = 0; c < 4; ++c) {
418 switch (swz[c]) {
419 case PIPE_SWIZZLE_RED: dst->ui[c] = src->ui[0]; break;
420 case PIPE_SWIZZLE_GREEN: dst->ui[c] = src->ui[1]; break;
421 case PIPE_SWIZZLE_BLUE: dst->ui[c] = src->ui[2]; break;
422 case PIPE_SWIZZLE_ALPHA: dst->ui[c] = src->ui[3]; break;
423 default:
424 dst->ui[c] = (swz[c] == PIPE_SWIZZLE_ONE) ? 1 : 0;
425 break;
426 }
427 }
428 } else {
429 for (c = 0; c < 4; ++c) {
430 switch (swz[c]) {
431 case PIPE_SWIZZLE_RED: dst->f[c] = src->f[0]; break;
432 case PIPE_SWIZZLE_GREEN: dst->f[c] = src->f[1]; break;
433 case PIPE_SWIZZLE_BLUE: dst->f[c] = src->f[2]; break;
434 case PIPE_SWIZZLE_ALPHA: dst->f[c] = src->f[3]; break;
435 default:
436 dst->f[c] = (swz[c] == PIPE_SWIZZLE_ONE) ? 1.0f : 0.0f;
437 break;
438 }
439 }
440 }
441 }
442
util_format_swizzle_4f(float * dst,const float * src,const unsigned char swz[4])443 void util_format_swizzle_4f(float *dst, const float *src,
444 const unsigned char swz[4])
445 {
446 unsigned i;
447
448 for (i = 0; i < 4; i++) {
449 if (swz[i] <= UTIL_FORMAT_SWIZZLE_W)
450 dst[i] = src[swz[i]];
451 else if (swz[i] == UTIL_FORMAT_SWIZZLE_0)
452 dst[i] = 0;
453 else if (swz[i] == UTIL_FORMAT_SWIZZLE_1)
454 dst[i] = 1;
455 }
456 }
457
util_format_unswizzle_4f(float * dst,const float * src,const unsigned char swz[4])458 void util_format_unswizzle_4f(float *dst, const float *src,
459 const unsigned char swz[4])
460 {
461 unsigned i;
462
463 for (i = 0; i < 4; i++) {
464 switch (swz[i]) {
465 case UTIL_FORMAT_SWIZZLE_X:
466 dst[0] = src[i];
467 break;
468 case UTIL_FORMAT_SWIZZLE_Y:
469 dst[1] = src[i];
470 break;
471 case UTIL_FORMAT_SWIZZLE_Z:
472 dst[2] = src[i];
473 break;
474 case UTIL_FORMAT_SWIZZLE_W:
475 dst[3] = src[i];
476 break;
477 }
478 }
479 }
480