From 15319963fa45ae3fa8b6a097fa9ed0b8751807cc Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Wed, 13 Feb 2019 10:23:32 -0800 Subject: [PATCH] turnip: fix VkClearValue packing Add tu_pack_clear_value to correctly pack VkClearValue according to VkFormat. It ignores the component order defined by VkFormat, and always packs to WZYX order. --- src/freedreno/vulkan/tu_cmd_buffer.c | 23 ++-- src/freedreno/vulkan/tu_formats.c | 210 +++++++++++++++++++++++++++++++++++ src/freedreno/vulkan/tu_private.h | 37 +----- 3 files changed, 224 insertions(+), 46 deletions(-) diff --git a/src/freedreno/vulkan/tu_cmd_buffer.c b/src/freedreno/vulkan/tu_cmd_buffer.c index 59e31b39b7b..51f97971335 100644 --- a/src/freedreno/vulkan/tu_cmd_buffer.c +++ b/src/freedreno/vulkan/tu_cmd_buffer.c @@ -617,17 +617,21 @@ tu6_emit_blit_info(struct tu_cmd_buffer *cmd, static void tu6_emit_blit_clear(struct tu_cmd_buffer *cmd, struct tu_cs *cs, + const struct tu_image_view *iview, uint32_t gmem_offset, const VkClearValue *clear_value) { const enum a6xx_tile_mode tile_mode = TILE6_LINEAR; const enum a3xx_msaa_samples samples = tu6_msaa_samples(1); const enum a6xx_color_fmt format = RB6_R8G8B8A8_UNORM; + /* must be WZYX; other values are ignored */ + const enum a3xx_color_swap swap = WZYX; tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_DST_INFO, 1); tu_cs_emit(cs, A6XX_RB_BLIT_DST_INFO_TILE_MODE(tile_mode) | A6XX_RB_BLIT_DST_INFO_SAMPLES(samples) | - A6XX_RB_BLIT_DST_INFO_COLOR_FORMAT(format)); + A6XX_RB_BLIT_DST_INFO_COLOR_FORMAT(format) | + A6XX_RB_BLIT_DST_INFO_COLOR_SWAP(swap)); tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_INFO, 1); tu_cs_emit(cs, A6XX_RB_BLIT_INFO_GMEM | A6XX_RB_BLIT_INFO_CLEAR_MASK(0xf)); @@ -638,14 +642,10 @@ tu6_emit_blit_clear(struct tu_cmd_buffer *cmd, tu_cs_emit_pkt4(cs, REG_A6XX_RB_UNKNOWN_88D0, 1); tu_cs_emit(cs, 0); - /* att->clear_value? */ - uint32_t clear_vals[4] = { - ((int) (clear_value->color.float32[0] * 255) << 24) | - ((int) (clear_value->color.float32[1] * 255) << 16) | - ((int) (clear_value->color.float32[2] * 255) << 8) | - ((int) (clear_value->color.float32[3] * 255) << 0), - 0, 0, 0 - }; + /* pack clear_value into WZYX order */ + uint32_t clear_vals[4] = { 0 }; + tu_pack_clear_value(clear_value, iview->vk_format, clear_vals); + tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_CLEAR_COLOR_DW0, 4); tu_cs_emit(cs, clear_vals[0]); tu_cs_emit(cs, clear_vals[1]); @@ -753,13 +753,14 @@ tu6_emit_tile_load(struct tu_cmd_buffer *cmd, struct tu_cs *cs) if (a == VK_ATTACHMENT_UNUSED) continue; + const struct tu_image_view *iview = fb->attachments[a].attachment; const struct tu_attachment_state *att = attachments + a; if (att->pending_clear_aspects) { assert(att->pending_clear_aspects == VK_IMAGE_ASPECT_COLOR_BIT); - tu6_emit_blit_clear(cmd, cs, tiling->gmem_offsets[gmem_index++], + tu6_emit_blit_clear(cmd, cs, iview, + tiling->gmem_offsets[gmem_index++], &att->clear_value); } else { - const struct tu_image_view *iview = fb->attachments[a].attachment; tu6_emit_blit_info(cmd, cs, iview, tiling->gmem_offsets[gmem_index++], A6XX_RB_BLIT_INFO_UNK0 | A6XX_RB_BLIT_INFO_GMEM); diff --git a/src/freedreno/vulkan/tu_formats.c b/src/freedreno/vulkan/tu_formats.c index 7f936f5f114..00a45aaac01 100644 --- a/src/freedreno/vulkan/tu_formats.c +++ b/src/freedreno/vulkan/tu_formats.c @@ -337,6 +337,216 @@ tu6_get_native_format(VkFormat format) return (fmt && fmt->present) ? fmt : NULL; } +static uint32_t +tu_pack_mask(int bits) +{ + assert(bits <= 32); + return (1ull << bits) - 1; +} + +static uint32_t +tu_pack_float32_for_unorm(float val, int bits) +{ + const uint32_t max = tu_pack_mask(bits); + if (val < 0.0f) + return 0; + else if (val > 1.0f) + return max; + else + return _mesa_lroundevenf(val * (float) max); +} + +static uint32_t +tu_pack_float32_for_snorm(float val, int bits) +{ + const int32_t max = tu_pack_mask(bits - 1); + int32_t tmp; + if (val < -1.0f) + tmp = -max; + else if (val > 1.0f) + tmp = max; + else + tmp = _mesa_lroundevenf(val * (float) max); + + return tmp & tu_pack_mask(bits); +} + +static uint32_t +tu_pack_float32_for_uscaled(float val, int bits) +{ + const uint32_t max = tu_pack_mask(bits); + if (val < 0.0f) + return 0; + else if (val > (float) max) + return max; + else + return (uint32_t) val; +} + +static uint32_t +tu_pack_float32_for_sscaled(float val, int bits) +{ + const int32_t max = tu_pack_mask(bits - 1); + const int32_t min = -max - 1; + int32_t tmp; + if (val < (float) min) + tmp = min; + else if (val > (float) max) + tmp = max; + else + tmp = (int32_t) val; + + return tmp & tu_pack_mask(bits); +} + +static uint32_t +tu_pack_uint32_for_uint(uint32_t val, int bits) +{ + return val & tu_pack_mask(bits); +} + +static uint32_t +tu_pack_int32_for_sint(int32_t val, int bits) +{ + return val & tu_pack_mask(bits); +} + +static uint32_t +tu_pack_float32_for_sfloat(float val, int bits) +{ + assert(bits == 16 || bits == 32); + return bits == 16 ? util_float_to_half(val) : fui(val); +} + +union tu_clear_component_value { + float float32; + int32_t int32; + uint32_t uint32; +}; + +static uint32_t +tu_pack_clear_component_value(union tu_clear_component_value val, + const struct vk_format_channel_description *ch) +{ + uint32_t packed; + + switch (ch->type) { + case VK_FORMAT_TYPE_UNSIGNED: + /* normalized, scaled, or pure integer */ + assert(ch->normalized + ch->scaled + ch->pure_integer == 1); + if (ch->normalized) + packed = tu_pack_float32_for_unorm(val.float32, ch->size); + else if (ch->scaled) + packed = tu_pack_float32_for_uscaled(val.float32, ch->size); + else + packed = tu_pack_uint32_for_uint(val.uint32, ch->size); + break; + case VK_FORMAT_TYPE_SIGNED: + /* normalized, scaled, or pure integer */ + assert(ch->normalized + ch->scaled + ch->pure_integer == 1); + if (ch->normalized) + packed = tu_pack_float32_for_snorm(val.float32, ch->size); + else if (ch->scaled) + packed = tu_pack_float32_for_sscaled(val.float32, ch->size); + else + packed = tu_pack_int32_for_sint(val.int32, ch->size); + break; + case VK_FORMAT_TYPE_FLOAT: + packed = tu_pack_float32_for_sfloat(val.float32, ch->size); + break; + default: + unreachable("unexpected channel type"); + packed = 0; + break; + } + + assert((packed & tu_pack_mask(ch->size)) == packed); + return packed; +} + +static const struct vk_format_channel_description * +tu_get_format_channel_description(const struct vk_format_description *desc, + int comp) +{ + switch (desc->swizzle[comp]) { + case VK_SWIZZLE_X: + return &desc->channel[0]; + case VK_SWIZZLE_Y: + return &desc->channel[1]; + case VK_SWIZZLE_Z: + return &desc->channel[2]; + case VK_SWIZZLE_W: + return &desc->channel[3]; + default: + return NULL; + } +} + +static union tu_clear_component_value +tu_get_clear_component_value(const VkClearValue *val, int comp, bool color) +{ + union tu_clear_component_value tmp; + if (color) { + assert(comp < 4); + tmp.uint32 = val->color.uint32[comp]; + } else { + assert(comp < 2); + if (comp == 0) + tmp.float32 = val->depthStencil.depth; + else + tmp.uint32 = val->depthStencil.stencil; + } + + return tmp; +} + +/** + * Pack a VkClearValue into a 128-bit buffer. \a format is respected except + * for the component order. The components are always packed in WZYX order + * (i.e., msb is white and lsb is red). + * + * Return the number of uint32_t's used. + */ +int +tu_pack_clear_value(const VkClearValue *val, VkFormat format, uint32_t buf[4]) +{ + const struct vk_format_description *desc = vk_format_description(format); + assert(desc && desc->layout == VK_FORMAT_LAYOUT_PLAIN); + + /* S8_UINT is special and has no depth */ + const int max_components = + format == VK_FORMAT_S8_UINT ? 2 : desc->nr_channels; + + int buf_offset = 0; + int bit_shift = 0; + for (int comp = 0; comp < max_components; comp++) { + const struct vk_format_channel_description *ch = + tu_get_format_channel_description(desc, comp); + if (!ch) { + assert(format == VK_FORMAT_S8_UINT && comp == 0); + continue; + } + + union tu_clear_component_value v = tu_get_clear_component_value( + val, comp, desc->colorspace != VK_FORMAT_COLORSPACE_ZS); + + /* move to the next uint32_t when there is not enough space */ + assert(ch->size <= 32); + if (bit_shift + ch->size > 32) { + buf_offset++; + bit_shift = 0; + } + + if (bit_shift == 0) + buf[buf_offset] = 0; + + buf[buf_offset] |= tu_pack_clear_component_value(v, ch) << bit_shift; + bit_shift += ch->size; + } + + return buf_offset + 1; +} + static void tu_physical_device_get_format_properties( struct tu_physical_device *physical_device, diff --git a/src/freedreno/vulkan/tu_private.h b/src/freedreno/vulkan/tu_private.h index 62f7cf28004..808fee6cbe8 100644 --- a/src/freedreno/vulkan/tu_private.h +++ b/src/freedreno/vulkan/tu_private.h @@ -983,41 +983,8 @@ tu_graphics_pipeline_create( const VkAllocationCallbacks *alloc, VkPipeline *pPipeline); -struct vk_format_description; -uint32_t -tu_translate_buffer_dataformat(const struct vk_format_description *desc, - int first_non_void); -uint32_t -tu_translate_buffer_numformat(const struct vk_format_description *desc, - int first_non_void); -uint32_t -tu_translate_colorformat(VkFormat format); -uint32_t -tu_translate_color_numformat(VkFormat format, - const struct vk_format_description *desc, - int first_non_void); -uint32_t -tu_colorformat_endian_swap(uint32_t colorformat); -unsigned -tu_translate_colorswap(VkFormat format, bool do_endian_swap); -uint32_t -tu_translate_dbformat(VkFormat format); -uint32_t -tu_translate_tex_dataformat(VkFormat format, - const struct vk_format_description *desc, - int first_non_void); -uint32_t -tu_translate_tex_numformat(VkFormat format, - const struct vk_format_description *desc, - int first_non_void); -bool -tu_format_pack_clear_color(VkFormat format, - uint32_t clear_vals[2], - VkClearColorValue *value); -bool -tu_is_colorbuffer_format_supported(VkFormat format, bool *blendable); -bool -tu_dcc_formats_compatible(VkFormat format1, VkFormat format2); +int +tu_pack_clear_value(const VkClearValue *val, VkFormat format, uint32_t buf[4]); struct tu_image_level { -- 2.11.0