[Mesa-dev] [PATCH 1/2] vulkan/util: Introduce format utilities
alexandros.frantzis at collabora.com
alexandros.frantzis at collabora.com
Fri Jun 23 15:50:50 UTC 2017
From: Alexandros Frantzis <alexandros.frantzis at collabora.com>
Introduce utilities to describe, find and compare Vulkan formats based
on their color component masks, taking into account system endianness.
---
src/vulkan/Makefile.sources | 2 +
src/vulkan/util/vk_format_util.c | 173 +++++++++++++++++++++++++++++++++++++++
src/vulkan/util/vk_format_util.h | 100 ++++++++++++++++++++++
3 files changed, 275 insertions(+)
create mode 100644 src/vulkan/util/vk_format_util.c
create mode 100644 src/vulkan/util/vk_format_util.h
diff --git a/src/vulkan/Makefile.sources b/src/vulkan/Makefile.sources
index 2cf7218e92..f4f1f14d5a 100644
--- a/src/vulkan/Makefile.sources
+++ b/src/vulkan/Makefile.sources
@@ -17,6 +17,8 @@ VULKAN_WSI_X11_FILES := \
VULKAN_UTIL_FILES := \
util/vk_alloc.h \
+ util/vk_format_util.c \
+ util/vk_format_util.h \
util/vk_util.c \
util/vk_util.h
diff --git a/src/vulkan/util/vk_format_util.c b/src/vulkan/util/vk_format_util.c
new file mode 100644
index 0000000000..aa6d403e84
--- /dev/null
+++ b/src/vulkan/util/vk_format_util.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright © 2017 Collabora Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "vk_format_util.h"
+
+#include "util/u_vector.h"
+#include "util/u_math.h"
+
+#include <assert.h>
+
+static inline uint32_t
+bswap24(uint32_t n)
+{
+ return (n & 0xff000000) |
+ ((n >> 16) & 0x000000ff) |
+ (n & 0x0000ff00) |
+ ((n << 16) & 0x00ff0000);
+}
+
+static inline uint32_t
+bswap(uint32_t n, int bits)
+{
+ switch (bits)
+ {
+ case 8:
+ return n;
+ case 16:
+ return util_bswap16(n);
+ case 24:
+ return bswap24(n);
+ case 32:
+ return util_bswap32(n);
+ default:
+ assert(!"Invalid bswap bits");
+ return n;
+ }
+}
+
+struct format_spec {
+ VkFormat format;
+ struct vk_format_util_spec spec;
+};
+
+#define VF(FMT, BPP, R, G, B, A, E, S) \
+ {VK_FORMAT_##FMT, {BPP, R, G, B, A, VK_FORMAT_UTIL_ENDIANNESS_##E, VK_FORMAT_UTIL_##S}}
+
+// SRGB formats are presented to the user before the UNORM ones.
+static const struct format_spec format_specs[] = {
+ VF(R8_SRGB, 8, 0x000000ff, 0x00000000, 0x00000000, 0x00000000, BIG, SWAPPABLE),
+ VF(R8G8_SRGB, 16, 0x0000ff00, 0x000000ff, 0x00000000, 0x00000000, BIG, SWAPPABLE),
+ VF(R8G8B8_SRGB, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, BIG, SWAPPABLE),
+ VF(B8G8R8_SRGB, 24, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000, BIG, SWAPPABLE),
+ VF(R8G8B8A8_SRGB, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, BIG, SWAPPABLE),
+ VF(B8G8R8A8_SRGB, 32, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff, BIG, SWAPPABLE),
+ VF(A8B8G8R8_SRGB_PACK32, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000, NATIVE, SWAPPABLE),
+
+ VF(R8_UNORM, 8, 0x000000ff, 0x00000000, 0x00000000, 0x00000000, BIG, SWAPPABLE),
+ VF(R8G8_UNORM, 16, 0x0000ff00, 0x000000ff, 0x00000000, 0x00000000, BIG, SWAPPABLE),
+ VF(R8G8B8_UNORM, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, BIG, SWAPPABLE),
+ VF(B8G8R8_UNORM, 24, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000, BIG, SWAPPABLE),
+ VF(R8G8B8A8_UNORM, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, BIG, SWAPPABLE),
+ VF(B8G8R8A8_UNORM, 32, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff, BIG, SWAPPABLE),
+ VF(R4G4_UNORM_PACK8, 8, 0x000000f0, 0x0000000f, 0x00000000, 0x00000000, NATIVE, NON_SWAPPABLE),
+ VF(R4G4B4A4_UNORM_PACK16, 16, 0x0000f000, 0x00000f00, 0x000000f0, 0x0000000f, NATIVE, NON_SWAPPABLE),
+ VF(B4G4R4A4_UNORM_PACK16, 16, 0x000000f0, 0x00000f00, 0x0000f000, 0x0000000f, NATIVE, NON_SWAPPABLE),
+ VF(R5G6B5_UNORM_PACK16, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000, NATIVE, NON_SWAPPABLE),
+ VF(B5G6R5_UNORM_PACK16, 16, 0x0000001f, 0x000007e0, 0x0000f800, 0x00000000, NATIVE, NON_SWAPPABLE),
+ VF(R5G5B5A1_UNORM_PACK16, 16, 0x0000f800, 0x000007c0, 0x0000003e, 0x00000001, NATIVE, NON_SWAPPABLE),
+ VF(B5G5R5A1_UNORM_PACK16, 16, 0x0000003e, 0x000007c0, 0x0000f800, 0x00000001, NATIVE, NON_SWAPPABLE),
+ VF(A1R5G5B5_UNORM_PACK16, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000, NATIVE, NON_SWAPPABLE),
+ VF(A8B8G8R8_UNORM_PACK32, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000, NATIVE, SWAPPABLE),
+ VF(A2R10G10B10_UNORM_PACK32, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000, NATIVE, NON_SWAPPABLE),
+ VF(A2B10G10R10_UNORM_PACK32, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000, NATIVE, NON_SWAPPABLE),
+};
+
+#undef VF
+
+static inline vk_format_util_endianness
+native_endianness()
+{
+ const unsigned ui = 1;
+ return *((const char *) &ui) == 1 ? VK_FORMAT_UTIL_ENDIANNESS_LITTLE :
+ VK_FORMAT_UTIL_ENDIANNESS_BIG;
+}
+
+void
+vk_get_format_spec(VkFormat format,
+ struct vk_format_util_spec *spec)
+{
+ static const struct vk_format_util_spec empty_spec =
+ {0, 0x0, 0x0, 0x0, 0x0, VK_FORMAT_UTIL_ENDIANNESS_NATIVE, VK_FORMAT_UTIL_NON_SWAPPABLE};
+
+ for (size_t i = 0; i < ARRAY_SIZE(format_specs); i++) {
+ if (format_specs[i].format == format) {
+ *spec = format_specs[i].spec;
+ return;
+ }
+ }
+
+ *spec = empty_spec;
+}
+
+bool
+vk_compare_format_specs(const struct vk_format_util_spec* spec1,
+ const struct vk_format_util_spec* spec2)
+{
+ const vk_format_util_endianness endianness1 =
+ spec1->endianness == VK_FORMAT_UTIL_ENDIANNESS_NATIVE ?
+ native_endianness() : spec1->endianness;
+
+ const vk_format_util_endianness endianness2 =
+ spec2->endianness == VK_FORMAT_UTIL_ENDIANNESS_NATIVE ?
+ native_endianness() : spec2->endianness;
+
+ if (endianness1 == endianness2) {
+ return spec1->bits_per_pixel == spec2->bits_per_pixel &&
+ spec1->red_mask == spec2->red_mask &&
+ spec1->green_mask == spec2->green_mask &&
+ spec1->blue_mask == spec2->blue_mask &&
+ spec1->alpha_mask == spec2->alpha_mask;
+ }
+ else {
+ if (spec1->swappable == VK_FORMAT_UTIL_SWAPPABLE) {
+ return spec1->bits_per_pixel == spec2->bits_per_pixel &&
+ bswap(spec1->red_mask, spec1->bits_per_pixel) == spec2->red_mask &&
+ bswap(spec1->green_mask, spec1->bits_per_pixel) == spec2->green_mask &&
+ bswap(spec1->blue_mask, spec1->bits_per_pixel) == spec2->blue_mask &&
+ bswap(spec1->alpha_mask, spec1->bits_per_pixel) == spec2->alpha_mask;
+ }
+ else if (spec2->swappable == VK_FORMAT_UTIL_SWAPPABLE) {
+ return spec1->bits_per_pixel == spec2->bits_per_pixel &&
+ spec1->red_mask == bswap(spec2->red_mask, spec2->bits_per_pixel) &&
+ spec1->green_mask == bswap(spec2->green_mask, spec2->bits_per_pixel) &&
+ spec1->blue_mask == bswap(spec2->blue_mask, spec2->bits_per_pixel) &&
+ spec1->alpha_mask == bswap(spec2->alpha_mask, spec2->bits_per_pixel);
+ }
+ }
+
+ return false;
+}
+
+void
+vk_find_matching_formats(const struct vk_format_util_spec *spec,
+ struct u_vector *formats)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(format_specs); i++) {
+ if (vk_compare_format_specs(spec, &format_specs[i].spec)) {
+ VkFormat *f = u_vector_add(formats);
+ if (f)
+ *f = format_specs[i].format;
+ }
+ }
+}
diff --git a/src/vulkan/util/vk_format_util.h b/src/vulkan/util/vk_format_util.h
new file mode 100644
index 0000000000..a1f9d87abe
--- /dev/null
+++ b/src/vulkan/util/vk_format_util.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright © 2017 Collabora Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef VK_FORMAT_UTIL_H
+#define VK_FORMAT_UTIL_H
+
+#include <vulkan/vulkan.h>
+#include <stdbool.h>
+
+struct u_vector;
+
+typedef enum vk_format_util_endianness {
+ VK_FORMAT_UTIL_ENDIANNESS_NATIVE,
+ VK_FORMAT_UTIL_ENDIANNESS_LITTLE,
+ VK_FORMAT_UTIL_ENDIANNESS_BIG,
+} vk_format_util_endianness;
+
+typedef enum vk_format_util_swappable {
+ VK_FORMAT_UTIL_NON_SWAPPABLE,
+ VK_FORMAT_UTIL_SWAPPABLE,
+} vk_format_util_swappable;
+
+/*
+ * Structure describing a pixel format.
+ *
+ * The masks express the bit positions of the components in an native integer
+ * storing a pixel of this format.
+ *
+ * Examples:
+ *
+ * * A pixel format which is always stored as a 0xR8G8B8A8 32-bit integer:
+ *
+ * {32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, NATIVE, SWAPPABLE}
+ *
+ * * A pixel format which is always stored as R8,G8,B8,A8 in memory order,
+ * with R at the lowest address:
+ *
+ * {32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, BIG, SWAPPABLE}
+ * or
+ * {32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000, LITTLE, SWAPPABLE}
+ *
+ * * A pixel format which is always stored as a 0xR5G6B5 16-bit integer,
+ * and cannot change endianness by byte-swapping:
+ *
+ * {16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000, NATIVE, NON_SWAPPABLE},
+ *
+ */
+struct vk_format_util_spec {
+ int bits_per_pixel;
+ uint32_t red_mask;
+ uint32_t green_mask;
+ uint32_t blue_mask;
+ uint32_t alpha_mask;
+ /* The endianness for which the masks are correct */
+ vk_format_util_endianness endianness;
+ /* Whether the masks can be byte-swapped to switch endianness */
+ vk_format_util_swappable swappable;
+};
+
+
+/* Fill a vk_format_util_spec structure to describe a Vulkan format. */
+void
+vk_get_format_spec(VkFormat format,
+ struct vk_format_util_spec *spec);
+
+/* Compare two pixel formats described by vk_format_util_spec structures. */
+bool
+vk_compare_format_specs(const struct vk_format_util_spec *spec1,
+ const struct vk_format_util_spec *spec2);
+
+/*
+ * Find Vulkan pixel formats that match a vk_format_util_spec.
+ *
+ * Note that, at the moment, only UNORM and SRGB formats are considered.
+ */
+void
+vk_find_matching_formats(const struct vk_format_util_spec *spec,
+ struct u_vector *formats);
+
+#endif
--
2.11.0
More information about the mesa-dev
mailing list