+#include "u_format_s3tc.h"
+#include "u_surface.h"
+
+#include "pipe/p_defines.h"
+
+
+boolean
+util_format_is_float(enum pipe_format format)
+{
+ const struct util_format_description *desc = util_format_description(format);
+ int i;
+
+ assert(desc);
+ if (!desc) {
+ return FALSE;
+ }
+
+ i = util_format_get_first_non_void_channel(format);
+ if (i < 0) {
+ return FALSE;
+ }
+
+ return desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT ? TRUE : FALSE;
+}
+
+
+/** Test if the format contains RGB, but not alpha */
+boolean
+util_format_has_alpha(enum pipe_format format)
+{
+ const struct util_format_description *desc =
+ util_format_description(format);
+
+ return (desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
+ desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
+ desc->swizzle[3] != PIPE_SWIZZLE_1;
+}
+
+
+boolean
+util_format_is_luminance(enum pipe_format format)
+{
+ const struct util_format_description *desc =
+ util_format_description(format);
+
+ if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
+ desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
+ desc->swizzle[0] == PIPE_SWIZZLE_X &&
+ desc->swizzle[1] == PIPE_SWIZZLE_X &&
+ desc->swizzle[2] == PIPE_SWIZZLE_X &&
+ desc->swizzle[3] == PIPE_SWIZZLE_1) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+boolean
+util_format_is_alpha(enum pipe_format format)
+{
+ const struct util_format_description *desc =
+ util_format_description(format);
+
+ if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
+ desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
+ desc->swizzle[0] == PIPE_SWIZZLE_0 &&
+ desc->swizzle[1] == PIPE_SWIZZLE_0 &&
+ desc->swizzle[2] == PIPE_SWIZZLE_0 &&
+ desc->swizzle[3] == PIPE_SWIZZLE_X) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+boolean
+util_format_is_pure_integer(enum pipe_format format)
+{
+ const struct util_format_description *desc = util_format_description(format);
+ int i;
+
+ /* Find the first non-void channel. */
+ i = util_format_get_first_non_void_channel(format);
+ if (i == -1)
+ return FALSE;
+
+ return desc->channel[i].pure_integer ? TRUE : FALSE;
+}
+
+boolean
+util_format_is_pure_sint(enum pipe_format format)
+{
+ const struct util_format_description *desc = util_format_description(format);
+ int i;
+
+ i = util_format_get_first_non_void_channel(format);
+ if (i == -1)
+ return FALSE;
+
+ return (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED && desc->channel[i].pure_integer) ? TRUE : FALSE;
+}
+
+boolean
+util_format_is_pure_uint(enum pipe_format format)
+{
+ const struct util_format_description *desc = util_format_description(format);
+ int i;
+
+ i = util_format_get_first_non_void_channel(format);
+ if (i == -1)
+ return FALSE;
+
+ return (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED && desc->channel[i].pure_integer) ? TRUE : FALSE;
+}
+
+/**
+ * Returns true if all non-void channels are normalized signed.
+ */
+boolean
+util_format_is_snorm(enum pipe_format format)
+{
+ const struct util_format_description *desc = util_format_description(format);
+ int i;
+
+ if (desc->is_mixed)
+ return FALSE;
+
+ i = util_format_get_first_non_void_channel(format);
+ if (i == -1)
+ return FALSE;
+
+ return desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED &&
+ !desc->channel[i].pure_integer &&
+ desc->channel[i].normalized;
+}
+
+boolean
+util_format_is_snorm8(enum pipe_format format)
+{
+ const struct util_format_description *desc = util_format_description(format);
+ int i;
+
+ if (desc->is_mixed)
+ return FALSE;
+
+ i = util_format_get_first_non_void_channel(format);
+ if (i == -1)
+ return FALSE;
+
+ return desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED &&
+ !desc->channel[i].pure_integer &&
+ desc->channel[i].normalized &&
+ desc->channel[i].size == 8;
+}
+
+boolean
+util_format_is_luminance_alpha(enum pipe_format format)
+{
+ const struct util_format_description *desc =
+ util_format_description(format);
+
+ if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
+ desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
+ desc->swizzle[0] == PIPE_SWIZZLE_X &&
+ desc->swizzle[1] == PIPE_SWIZZLE_X &&
+ desc->swizzle[2] == PIPE_SWIZZLE_X &&
+ desc->swizzle[3] == PIPE_SWIZZLE_Y) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+boolean
+util_format_is_intensity(enum pipe_format format)
+{
+ const struct util_format_description *desc =
+ util_format_description(format);
+
+ if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
+ desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
+ desc->swizzle[0] == PIPE_SWIZZLE_X &&
+ desc->swizzle[1] == PIPE_SWIZZLE_X &&
+ desc->swizzle[2] == PIPE_SWIZZLE_X &&
+ desc->swizzle[3] == PIPE_SWIZZLE_X) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+boolean
+util_format_is_subsampled_422(enum pipe_format format)
+{
+ const struct util_format_description *desc =
+ util_format_description(format);
+
+ return desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED &&
+ desc->block.width == 2 &&
+ desc->block.height == 1 &&
+ desc->block.bits == 32;
+}
+
+boolean
+util_format_is_supported(enum pipe_format format, unsigned bind)
+{
+ if (util_format_is_s3tc(format) && !util_format_s3tc_enabled) {
+ return FALSE;
+ }
+
+#ifndef TEXTURE_FLOAT_ENABLED
+ if ((bind & PIPE_BIND_RENDER_TARGET) &&
+ format != PIPE_FORMAT_R9G9B9E5_FLOAT &&
+ format != PIPE_FORMAT_R11G11B10_FLOAT &&
+ util_format_is_float(format)) {
+ return FALSE;
+ }
+#endif
+
+ return TRUE;
+}
+
+
+/**
+ * Calculates the MRD for the depth format. MRD is used in depth bias
+ * for UNORM and unbound depth buffers. When the depth buffer is floating
+ * point, the depth bias calculation does not use the MRD. However, the
+ * default MRD will be 1.0 / ((1 << 24) - 1).
+ */
+double
+util_get_depth_format_mrd(const struct util_format_description *desc)
+{
+ /*
+ * Depth buffer formats without a depth component OR scenarios
+ * without a bound depth buffer default to D24.
+ */
+ double mrd = 1.0 / ((1 << 24) - 1);
+ unsigned depth_channel;
+
+ assert(desc);
+
+ /*
+ * Some depth formats do not store the depth component in the first
+ * channel, detect the format and adjust the depth channel. Get the
+ * swizzled depth component channel.
+ */
+ depth_channel = desc->swizzle[0];
+
+ if (desc->channel[depth_channel].type == UTIL_FORMAT_TYPE_UNSIGNED &&
+ desc->channel[depth_channel].normalized) {
+ int depth_bits;
+
+ depth_bits = desc->channel[depth_channel].size;
+ mrd = 1.0 / ((1ULL << depth_bits) - 1);
+ }
+
+ return mrd;
+}
+
+
+void
+util_format_read_4f(enum pipe_format format,
+ float *dst, unsigned dst_stride,
+ const void *src, unsigned src_stride,
+ unsigned x, unsigned y, unsigned w, unsigned h)
+{
+ const struct util_format_description *format_desc;
+ const uint8_t *src_row;
+ float *dst_row;
+
+ format_desc = util_format_description(format);
+
+ assert(x % format_desc->block.width == 0);
+ assert(y % format_desc->block.height == 0);
+
+ src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8);
+ dst_row = dst;
+
+ format_desc->unpack_rgba_float(dst_row, dst_stride, src_row, src_stride, w, h);
+}
+
+
+void
+util_format_write_4f(enum pipe_format format,
+ const float *src, unsigned src_stride,
+ void *dst, unsigned dst_stride,
+ unsigned x, unsigned y, unsigned w, unsigned h)
+{
+ const struct util_format_description *format_desc;
+ uint8_t *dst_row;
+ const float *src_row;
+
+ format_desc = util_format_description(format);
+
+ assert(x % format_desc->block.width == 0);
+ assert(y % format_desc->block.height == 0);
+
+ dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8);
+ src_row = src;
+
+ format_desc->pack_rgba_float(dst_row, dst_stride, src_row, src_stride, w, h);
+}
+
+
+void
+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)
+{
+ const struct util_format_description *format_desc;
+ const uint8_t *src_row;
+ uint8_t *dst_row;
+
+ format_desc = util_format_description(format);
+
+ assert(x % format_desc->block.width == 0);
+ assert(y % format_desc->block.height == 0);
+
+ src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8);
+ dst_row = dst;
+
+ format_desc->unpack_rgba_8unorm(dst_row, dst_stride, src_row, src_stride, w, h);
+}
+
+
+void
+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)
+{
+ const struct util_format_description *format_desc;
+ uint8_t *dst_row;
+ const uint8_t *src_row;
+
+ format_desc = util_format_description(format);
+
+ assert(x % format_desc->block.width == 0);
+ assert(y % format_desc->block.height == 0);
+
+ dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8);
+ src_row = src;
+
+ format_desc->pack_rgba_8unorm(dst_row, dst_stride, src_row, src_stride, w, h);
+}
+
+void
+util_format_read_4ui(enum pipe_format format,
+ unsigned *dst, unsigned dst_stride,
+ const void *src, unsigned src_stride,
+ unsigned x, unsigned y, unsigned w, unsigned h)
+{
+ const struct util_format_description *format_desc;
+ const uint8_t *src_row;
+ uint32_t *dst_row;
+
+ format_desc = util_format_description(format);
+
+ assert(x % format_desc->block.width == 0);
+ assert(y % format_desc->block.height == 0);
+
+ src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8);
+ dst_row = dst;
+
+ format_desc->unpack_rgba_uint(dst_row, dst_stride, src_row, src_stride, w, h);
+}
+
+void
+util_format_write_4ui(enum pipe_format format,
+ const unsigned int *src, unsigned src_stride,
+ void *dst, unsigned dst_stride,
+ unsigned x, unsigned y, unsigned w, unsigned h)
+{
+ const struct util_format_description *format_desc;
+ uint8_t *dst_row;
+ const uint32_t *src_row;
+
+ format_desc = util_format_description(format);
+
+ assert(x % format_desc->block.width == 0);
+ assert(y % format_desc->block.height == 0);
+
+ dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8);
+ src_row = src;
+
+ format_desc->pack_rgba_uint(dst_row, dst_stride, src_row, src_stride, w, h);
+}