#include "u_math.h"
#include "u_memory.h"
-#include "u_rect.h"
#include "u_format.h"
+#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);
+ unsigned i;
+
+ assert(desc);
+ if (!desc) {
+ return FALSE;
+ }
+
+ i = util_format_get_first_non_void_channel(format);
+ if (i == -1) {
+ 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] != UTIL_FORMAT_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] == UTIL_FORMAT_SWIZZLE_X &&
+ desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X &&
+ desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X &&
+ desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1) {
+ 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_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] == UTIL_FORMAT_SWIZZLE_X &&
+ desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X &&
+ desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X &&
+ desc->swizzle[3] == UTIL_FORMAT_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] == UTIL_FORMAT_SWIZZLE_X &&
+ desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X &&
+ desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X &&
+ desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_X) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+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
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);
-static INLINE boolean
+ 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);
+}
+
+void
+util_format_read_4i(enum pipe_format format,
+ int *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;
+ int32_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_sint(dst_row, dst_stride, src_row, src_stride, w, h);
+}
+
+void
+util_format_write_4i(enum pipe_format format,
+ const 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 int32_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_sint(dst_row, dst_stride, src_row, src_stride, w, h);
+}
+
+boolean
+util_is_format_compatible(const struct util_format_description *src_desc,
+ const struct util_format_description *dst_desc)
+{
+ unsigned chan;
+
+ if (src_desc->format == dst_desc->format) {
+ return TRUE;
+ }
+
+ if (src_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN ||
+ dst_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) {
+ return FALSE;
+ }
+
+ if (src_desc->block.bits != dst_desc->block.bits ||
+ src_desc->nr_channels != dst_desc->nr_channels ||
+ src_desc->colorspace != dst_desc->colorspace) {
+ return FALSE;
+ }
+
+ for (chan = 0; chan < 4; ++chan) {
+ if (src_desc->channel[chan].size !=
+ dst_desc->channel[chan].size) {
+ return FALSE;
+ }
+ }
+
+ for (chan = 0; chan < 4; ++chan) {
+ enum util_format_swizzle swizzle = dst_desc->swizzle[chan];
+
+ if (swizzle < 4) {
+ if (src_desc->swizzle[chan] != swizzle) {
+ return FALSE;
+ }
+ if ((src_desc->channel[swizzle].type !=
+ dst_desc->channel[swizzle].type) ||
+ (src_desc->channel[swizzle].normalized !=
+ dst_desc->channel[swizzle].normalized)) {
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+boolean
util_format_fits_8unorm(const struct util_format_description *format_desc)
{
unsigned chan;
+ /*
+ * After linearized sRGB values require more than 8bits.
+ */
+
+ if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
+ return FALSE;
+ }
+
switch (format_desc->layout) {
case UTIL_FORMAT_LAYOUT_S3TC:
- case UTIL_FORMAT_LAYOUT_RGTC:
/*
* These are straight forward.
*/
-
+ return TRUE;
+ case UTIL_FORMAT_LAYOUT_RGTC:
+ if (format_desc->format == PIPE_FORMAT_RGTC1_SNORM ||
+ format_desc->format == PIPE_FORMAT_RGTC2_SNORM ||
+ format_desc->format == PIPE_FORMAT_LATC1_SNORM ||
+ format_desc->format == PIPE_FORMAT_LATC2_SNORM)
+ return FALSE;
return TRUE;
case UTIL_FORMAT_LAYOUT_PLAIN:
const struct util_format_description *src_format_desc;
uint8_t *dst_row;
const uint8_t *src_row;
- unsigned y_step;
+ unsigned x_step, y_step;
unsigned dst_step;
unsigned src_step;
- if (dst_format == src_format) {
+ dst_format_desc = util_format_description(dst_format);
+ src_format_desc = util_format_description(src_format);
+
+ if (util_is_format_compatible(src_format_desc, dst_format_desc)) {
/*
* Trivial case.
*/
return;
}
- dst_format_desc = util_format_description(dst_format);
- src_format_desc = util_format_description(src_format);
-
assert(dst_x % dst_format_desc->block.width == 0);
assert(dst_y % dst_format_desc->block.height == 0);
assert(src_x % src_format_desc->block.width == 0);
*/
y_step = MAX2(dst_format_desc->block.height, src_format_desc->block.height);
+ x_step = MAX2(dst_format_desc->block.width, src_format_desc->block.width);
assert(y_step % dst_format_desc->block.height == 0);
assert(y_step % src_format_desc->block.height == 0);
* TODO: Add a special case for formats that are mere swizzles of each other
*/
+ if (src_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS ||
+ dst_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {
+ float *tmp_z = NULL;
+ uint8_t *tmp_s = NULL;
+
+ assert(x_step == 1);
+ assert(y_step == 1);
+
+ if (src_format_desc->unpack_z_float &&
+ dst_format_desc->pack_z_float) {
+ tmp_z = MALLOC(width * sizeof *tmp_z);
+ }
+
+ if (src_format_desc->unpack_s_8uint &&
+ dst_format_desc->pack_s_8uint) {
+ tmp_s = MALLOC(width * sizeof *tmp_s);
+ }
+
+ while (height--) {
+ if (tmp_z) {
+ src_format_desc->unpack_z_float(tmp_z, 0, src_row, src_stride, width, 1);
+ dst_format_desc->pack_z_float(dst_row, dst_stride, tmp_z, 0, width, 1);
+ }
+
+ if (tmp_s) {
+ src_format_desc->unpack_s_8uint(tmp_s, 0, src_row, src_stride, width, 1);
+ dst_format_desc->pack_s_8uint(dst_row, dst_stride, tmp_s, 0, width, 1);
+ }
+
+ dst_row += dst_step;
+ src_row += src_step;
+ }
+
+ FREE(tmp_s);
+
+ FREE(tmp_z);
+
+ return;
+ }
+
if (util_format_fits_8unorm(src_format_desc) ||
util_format_fits_8unorm(dst_format_desc)) {
unsigned tmp_stride;
uint8_t *tmp_row;
- tmp_stride = width * 4 * sizeof *tmp_row;
+ tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row;
tmp_row = MALLOC(y_step * tmp_stride);
if (!tmp_row)
return;
unsigned tmp_stride;
float *tmp_row;
- tmp_stride = width * 4 * sizeof *tmp_row;
+ tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row;
tmp_row = MALLOC(y_step * tmp_stride);
if (!tmp_row)
return;
FREE(tmp_row);
}
}
+
+void util_format_compose_swizzles(const unsigned char swz1[4],
+ const unsigned char swz2[4],
+ unsigned char dst[4])
+{
+ unsigned i;
+
+ for (i = 0; i < 4; i++) {
+ dst[i] = swz2[i] <= UTIL_FORMAT_SWIZZLE_W ?
+ swz1[swz2[i]] : swz2[i];
+ }
+}
+
+void 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)
+{
+ unsigned c;
+
+ if (is_integer) {
+ for (c = 0; c < 4; ++c) {
+ switch (swz[c]) {
+ case PIPE_SWIZZLE_RED: dst->ui[c] = src->ui[0]; break;
+ case PIPE_SWIZZLE_GREEN: dst->ui[c] = src->ui[1]; break;
+ case PIPE_SWIZZLE_BLUE: dst->ui[c] = src->ui[2]; break;
+ case PIPE_SWIZZLE_ALPHA: dst->ui[c] = src->ui[3]; break;
+ default:
+ dst->ui[c] = (swz[c] == PIPE_SWIZZLE_ONE) ? 1 : 0;
+ break;
+ }
+ }
+ } else {
+ for (c = 0; c < 4; ++c) {
+ switch (swz[c]) {
+ case PIPE_SWIZZLE_RED: dst->f[c] = src->f[0]; break;
+ case PIPE_SWIZZLE_GREEN: dst->f[c] = src->f[1]; break;
+ case PIPE_SWIZZLE_BLUE: dst->f[c] = src->f[2]; break;
+ case PIPE_SWIZZLE_ALPHA: dst->f[c] = src->f[3]; break;
+ default:
+ dst->f[c] = (swz[c] == PIPE_SWIZZLE_ONE) ? 1.0f : 0.0f;
+ break;
+ }
+ }
+ }
+}
+
+void util_format_swizzle_4f(float *dst, const float *src,
+ const unsigned char swz[4])
+{
+ unsigned i;
+
+ for (i = 0; i < 4; i++) {
+ if (swz[i] <= UTIL_FORMAT_SWIZZLE_W)
+ dst[i] = src[swz[i]];
+ else if (swz[i] == UTIL_FORMAT_SWIZZLE_0)
+ dst[i] = 0;
+ else if (swz[i] == UTIL_FORMAT_SWIZZLE_1)
+ dst[i] = 1;
+ }
+}
+
+void util_format_unswizzle_4f(float *dst, const float *src,
+ const unsigned char swz[4])
+{
+ unsigned i;
+
+ for (i = 0; i < 4; i++) {
+ switch (swz[i]) {
+ case UTIL_FORMAT_SWIZZLE_X:
+ dst[0] = src[i];
+ break;
+ case UTIL_FORMAT_SWIZZLE_Y:
+ dst[1] = src[i];
+ break;
+ case UTIL_FORMAT_SWIZZLE_Z:
+ dst[2] = src[i];
+ break;
+ case UTIL_FORMAT_SWIZZLE_W:
+ dst[3] = src[i];
+ break;
+ }
+ }
+}