u_format.c revision f2a2ba9c6cdef99e1dc12209ac06d4e817368bfd
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
44boolean
45util_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 */
75static unsigned
76nr_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 */
95boolean
96util_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
110boolean
111util_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
128boolean
129util_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
146boolean
147util_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
164boolean
165util_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
184void
185util_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
206void
207util_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
228void
229util_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
247void
248util_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
266boolean
267util_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
314boolean
315util_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
378void
379util_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
532void 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
544void 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
559void 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}
581