util: Handle conversion between depth stencil formats.
[mesa.git] / src / gallium / auxiliary / util / u_format.c
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_rect.h"
38 #include "u_format.h"
39 #include "u_format_s3tc.h"
40
41 #include "pipe/p_defines.h"
42
43
44 boolean
45 util_format_is_float(enum pipe_format format)
46 {
47 const struct util_format_description *desc = util_format_description(format);
48 unsigned i;
49
50 assert(desc);
51 if (!desc) {
52 return FALSE;
53 }
54
55 /* Find the first non-void channel. */
56 for (i = 0; i < 4; i++) {
57 if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) {
58 break;
59 }
60 }
61
62 if (i == 4) {
63 return FALSE;
64 }
65
66 return desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT ? TRUE : FALSE;
67 }
68
69
70 /**
71 * Return the number of logical channels in the given format by
72 * examining swizzles.
73 * XXX this could be made into a public function if useful elsewhere.
74 */
75 static unsigned
76 nr_logical_channels(const struct util_format_description *desc)
77 {
78 boolean swizzle_used[UTIL_FORMAT_SWIZZLE_MAX];
79
80 memset(swizzle_used, 0, sizeof(swizzle_used));
81
82 swizzle_used[desc->swizzle[0]] = TRUE;
83 swizzle_used[desc->swizzle[1]] = TRUE;
84 swizzle_used[desc->swizzle[2]] = TRUE;
85 swizzle_used[desc->swizzle[3]] = TRUE;
86
87 return (swizzle_used[UTIL_FORMAT_SWIZZLE_X] +
88 swizzle_used[UTIL_FORMAT_SWIZZLE_Y] +
89 swizzle_used[UTIL_FORMAT_SWIZZLE_Z] +
90 swizzle_used[UTIL_FORMAT_SWIZZLE_W]);
91 }
92
93
94 /** Test if the format contains RGB, but not alpha */
95 boolean
96 util_format_is_rgb_no_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 nr_logical_channels(desc) == 3) {
104 return TRUE;
105 }
106 return FALSE;
107 }
108
109
110 boolean
111 util_format_is_luminance(enum pipe_format format)
112 {
113 const struct util_format_description *desc =
114 util_format_description(format);
115
116 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
117 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
118 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X &&
119 desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X &&
120 desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X &&
121 desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1) {
122 return TRUE;
123 }
124 return FALSE;
125 }
126
127
128 boolean
129 util_format_is_luminance_alpha(enum pipe_format format)
130 {
131 const struct util_format_description *desc =
132 util_format_description(format);
133
134 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
135 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
136 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X &&
137 desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X &&
138 desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X &&
139 desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_Y) {
140 return TRUE;
141 }
142 return FALSE;
143 }
144
145
146 boolean
147 util_format_is_intensity(enum pipe_format format)
148 {
149 const struct util_format_description *desc =
150 util_format_description(format);
151
152 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
153 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
154 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X &&
155 desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X &&
156 desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X &&
157 desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_X) {
158 return TRUE;
159 }
160 return FALSE;
161 }
162
163
164 boolean
165 util_format_is_supported(enum pipe_format format, unsigned bind)
166 {
167 if (util_format_is_s3tc(format) && !util_format_s3tc_enabled) {
168 return FALSE;
169 }
170
171 #ifndef TEXTURE_FLOAT_ENABLED
172 if ((bind & PIPE_BIND_RENDER_TARGET) &&
173 format != PIPE_FORMAT_R9G9B9E5_FLOAT &&
174 format != PIPE_FORMAT_R11G11B10_FLOAT &&
175 util_format_is_float(format)) {
176 return FALSE;
177 }
178 #endif
179
180 return TRUE;
181 }
182
183
184 void
185 util_format_read_4f(enum pipe_format format,
186 float *dst, unsigned dst_stride,
187 const void *src, unsigned src_stride,
188 unsigned x, unsigned y, unsigned w, unsigned h)
189 {
190 const struct util_format_description *format_desc;
191 const uint8_t *src_row;
192 float *dst_row;
193
194 format_desc = util_format_description(format);
195
196 assert(x % format_desc->block.width == 0);
197 assert(y % format_desc->block.height == 0);
198
199 src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8);
200 dst_row = dst;
201
202 format_desc->unpack_rgba_float(dst_row, dst_stride, src_row, src_stride, w, h);
203 }
204
205
206 void
207 util_format_write_4f(enum pipe_format format,
208 const float *src, unsigned src_stride,
209 void *dst, unsigned dst_stride,
210 unsigned x, unsigned y, unsigned w, unsigned h)
211 {
212 const struct util_format_description *format_desc;
213 uint8_t *dst_row;
214 const float *src_row;
215
216 format_desc = util_format_description(format);
217
218 assert(x % format_desc->block.width == 0);
219 assert(y % format_desc->block.height == 0);
220
221 dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8);
222 src_row = src;
223
224 format_desc->pack_rgba_float(dst_row, dst_stride, src_row, src_stride, w, h);
225 }
226
227
228 void
229 util_format_read_4ub(enum pipe_format format, uint8_t *dst, unsigned dst_stride, const void *src, unsigned src_stride, unsigned x, unsigned y, unsigned w, unsigned h)
230 {
231 const struct util_format_description *format_desc;
232 const uint8_t *src_row;
233 uint8_t *dst_row;
234
235 format_desc = util_format_description(format);
236
237 assert(x % format_desc->block.width == 0);
238 assert(y % format_desc->block.height == 0);
239
240 src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8);
241 dst_row = dst;
242
243 format_desc->unpack_rgba_8unorm(dst_row, dst_stride, src_row, src_stride, w, h);
244 }
245
246
247 void
248 util_format_write_4ub(enum pipe_format format, const uint8_t *src, unsigned src_stride, void *dst, unsigned dst_stride, unsigned x, unsigned y, unsigned w, unsigned h)
249 {
250 const struct util_format_description *format_desc;
251 uint8_t *dst_row;
252 const uint8_t *src_row;
253
254 format_desc = util_format_description(format);
255
256 assert(x % format_desc->block.width == 0);
257 assert(y % format_desc->block.height == 0);
258
259 dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8);
260 src_row = src;
261
262 format_desc->pack_rgba_8unorm(dst_row, dst_stride, src_row, src_stride, w, h);
263 }
264
265
266 boolean
267 util_is_format_compatible(const struct util_format_description *src_desc,
268 const struct util_format_description *dst_desc)
269 {
270 unsigned chan;
271
272 if (src_desc->format == dst_desc->format) {
273 return TRUE;
274 }
275
276 if (src_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN ||
277 dst_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) {
278 return FALSE;
279 }
280
281 if (src_desc->block.bits != dst_desc->block.bits ||
282 src_desc->nr_channels != dst_desc->nr_channels ||
283 src_desc->colorspace != dst_desc->colorspace) {
284 return FALSE;
285 }
286
287 for (chan = 0; chan < 4; ++chan) {
288 if (src_desc->channel[chan].size !=
289 dst_desc->channel[chan].size) {
290 return FALSE;
291 }
292 }
293
294 for (chan = 0; chan < 4; ++chan) {
295 enum util_format_swizzle swizzle = dst_desc->swizzle[chan];
296
297 if (swizzle < 4) {
298 if (src_desc->swizzle[chan] != swizzle) {
299 return FALSE;
300 }
301 if ((src_desc->channel[swizzle].type !=
302 dst_desc->channel[swizzle].type) ||
303 (src_desc->channel[swizzle].normalized !=
304 dst_desc->channel[swizzle].normalized)) {
305 return FALSE;
306 }
307 }
308 }
309
310 return TRUE;
311 }
312
313
314 boolean
315 util_format_fits_8unorm(const struct util_format_description *format_desc)
316 {
317 unsigned chan;
318
319 /*
320 * After linearized sRGB values require more than 8bits.
321 */
322
323 if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
324 return FALSE;
325 }
326
327 switch (format_desc->layout) {
328
329 case UTIL_FORMAT_LAYOUT_S3TC:
330 case UTIL_FORMAT_LAYOUT_RGTC:
331 /*
332 * These are straight forward.
333 */
334
335 return TRUE;
336
337 case UTIL_FORMAT_LAYOUT_PLAIN:
338 /*
339 * For these we can find a generic rule.
340 */
341
342 for (chan = 0; chan < format_desc->nr_channels; ++chan) {
343 switch (format_desc->channel[chan].type) {
344 case UTIL_FORMAT_TYPE_VOID:
345 break;
346 case UTIL_FORMAT_TYPE_UNSIGNED:
347 if (!format_desc->channel[chan].normalized ||
348 format_desc->channel[chan].size > 8) {
349 return FALSE;
350 }
351 break;
352 default:
353 return FALSE;
354 }
355 }
356 return TRUE;
357
358 default:
359 /*
360 * Handle all others on a case by case basis.
361 */
362
363 switch (format_desc->format) {
364 case PIPE_FORMAT_R1_UNORM:
365 case PIPE_FORMAT_UYVY:
366 case PIPE_FORMAT_YUYV:
367 case PIPE_FORMAT_R8G8_B8G8_UNORM:
368 case PIPE_FORMAT_G8R8_G8B8_UNORM:
369 return TRUE;
370
371 default:
372 return FALSE;
373 }
374 }
375 }
376
377
378 void
379 util_format_translate(enum pipe_format dst_format,
380 void *dst, unsigned dst_stride,
381 unsigned dst_x, unsigned dst_y,
382 enum pipe_format src_format,
383 const void *src, unsigned src_stride,
384 unsigned src_x, unsigned src_y,
385 unsigned width, unsigned height)
386 {
387 const struct util_format_description *dst_format_desc;
388 const struct util_format_description *src_format_desc;
389 uint8_t *dst_row;
390 const uint8_t *src_row;
391 unsigned x_step, y_step;
392 unsigned dst_step;
393 unsigned src_step;
394
395 dst_format_desc = util_format_description(dst_format);
396 src_format_desc = util_format_description(src_format);
397
398 if (util_is_format_compatible(src_format_desc, dst_format_desc)) {
399 /*
400 * Trivial case.
401 */
402
403 util_copy_rect(dst, dst_format, dst_stride, dst_x, dst_y,
404 width, height, src, (int)src_stride,
405 src_x, src_y);
406 return;
407 }
408
409 assert(dst_x % dst_format_desc->block.width == 0);
410 assert(dst_y % dst_format_desc->block.height == 0);
411 assert(src_x % src_format_desc->block.width == 0);
412 assert(src_y % src_format_desc->block.height == 0);
413
414 dst_row = (uint8_t *)dst + dst_y*dst_stride + dst_x*(dst_format_desc->block.bits/8);
415 src_row = (const uint8_t *)src + src_y*src_stride + src_x*(src_format_desc->block.bits/8);
416
417 /*
418 * This works because all pixel formats have pixel blocks with power of two
419 * sizes.
420 */
421
422 y_step = MAX2(dst_format_desc->block.height, src_format_desc->block.height);
423 x_step = MAX2(dst_format_desc->block.width, src_format_desc->block.width);
424 assert(y_step % dst_format_desc->block.height == 0);
425 assert(y_step % src_format_desc->block.height == 0);
426
427 dst_step = y_step / dst_format_desc->block.height * dst_stride;
428 src_step = y_step / src_format_desc->block.height * src_stride;
429
430 /*
431 * TODO: double formats will loose precision
432 * TODO: Add a special case for formats that are mere swizzles of each other
433 */
434
435 if (src_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS ||
436 dst_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {
437 float *tmp_z = NULL;
438 uint8_t *tmp_s = NULL;
439
440 assert(x_step == 1);
441 assert(y_step == 1);
442
443 if (src_format_desc->unpack_z_float &&
444 dst_format_desc->pack_z_float) {
445 tmp_z = MALLOC(width * sizeof *tmp_z);
446 }
447
448 if (src_format_desc->unpack_s_8uscaled &&
449 dst_format_desc->pack_s_8uscaled) {
450 tmp_s = MALLOC(width * sizeof *tmp_s);
451 }
452
453 while (height--) {
454 if (tmp_z) {
455 src_format_desc->unpack_z_float(tmp_z, 0, src_row, src_stride, width, 1);
456 dst_format_desc->pack_z_float(dst_row, dst_stride, tmp_z, 0, width, 1);
457 }
458
459 if (tmp_s) {
460 src_format_desc->unpack_s_8uscaled(tmp_s, 0, src_row, src_stride, width, 1);
461 dst_format_desc->pack_s_8uscaled(dst_row, dst_stride, tmp_s, 0, width, 1);
462 }
463
464 dst_row += dst_step;
465 src_row += src_step;
466 }
467
468 if (tmp_s) {
469 FREE(tmp_s);
470 }
471
472 if (tmp_z) {
473 FREE(tmp_z);
474 }
475
476 return;
477 }
478
479 if (util_format_fits_8unorm(src_format_desc) ||
480 util_format_fits_8unorm(dst_format_desc)) {
481 unsigned tmp_stride;
482 uint8_t *tmp_row;
483
484 tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row;
485 tmp_row = MALLOC(y_step * tmp_stride);
486 if (!tmp_row)
487 return;
488
489 while (height >= y_step) {
490 src_format_desc->unpack_rgba_8unorm(tmp_row, tmp_stride, src_row, src_stride, width, y_step);
491 dst_format_desc->pack_rgba_8unorm(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step);
492
493 dst_row += dst_step;
494 src_row += src_step;
495 height -= y_step;
496 }
497
498 if (height) {
499 src_format_desc->unpack_rgba_8unorm(tmp_row, tmp_stride, src_row, src_stride, width, height);
500 dst_format_desc->pack_rgba_8unorm(dst_row, dst_stride, tmp_row, tmp_stride, width, height);
501 }
502
503 FREE(tmp_row);
504 }
505 else {
506 unsigned tmp_stride;
507 float *tmp_row;
508
509 tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row;
510 tmp_row = MALLOC(y_step * tmp_stride);
511 if (!tmp_row)
512 return;
513
514 while (height >= y_step) {
515 src_format_desc->unpack_rgba_float(tmp_row, tmp_stride, src_row, src_stride, width, y_step);
516 dst_format_desc->pack_rgba_float(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step);
517
518 dst_row += dst_step;
519 src_row += src_step;
520 height -= y_step;
521 }
522
523 if (height) {
524 src_format_desc->unpack_rgba_float(tmp_row, tmp_stride, src_row, src_stride, width, height);
525 dst_format_desc->pack_rgba_float(dst_row, dst_stride, tmp_row, tmp_stride, width, height);
526 }
527
528 FREE(tmp_row);
529 }
530 }
531
532 void util_format_compose_swizzles(const unsigned char swz1[4],
533 const unsigned char swz2[4],
534 unsigned char dst[4])
535 {
536 unsigned i;
537
538 for (i = 0; i < 4; i++) {
539 dst[i] = swz2[i] <= UTIL_FORMAT_SWIZZLE_W ?
540 swz1[swz2[i]] : swz2[i];
541 }
542 }
543
544 void util_format_swizzle_4f(float *dst, const float *src,
545 const unsigned char swz[4])
546 {
547 unsigned i;
548
549 for (i = 0; i < 4; i++) {
550 if (swz[i] <= UTIL_FORMAT_SWIZZLE_W)
551 dst[i] = src[swz[i]];
552 else if (swz[i] == UTIL_FORMAT_SWIZZLE_0)
553 dst[i] = 0;
554 else if (swz[i] == UTIL_FORMAT_SWIZZLE_1)
555 dst[i] = 1;
556 }
557 }
558
559 void util_format_unswizzle_4f(float *dst, const float *src,
560 const unsigned char swz[4])
561 {
562 unsigned i;
563
564 for (i = 0; i < 4; i++) {
565 switch (swz[i]) {
566 case UTIL_FORMAT_SWIZZLE_X:
567 dst[0] = src[i];
568 break;
569 case UTIL_FORMAT_SWIZZLE_Y:
570 dst[1] = src[i];
571 break;
572 case UTIL_FORMAT_SWIZZLE_Z:
573 dst[2] = src[i];
574 break;
575 case UTIL_FORMAT_SWIZZLE_W:
576 dst[3] = src[i];
577 break;
578 }
579 }
580 }