pvr: Change pvr_get_hw_clear_color() to pack based on accum formats.

`pvr_get_hw_clear_color()` now packs formats based on the accum
format which is how the hw deals with the formats internally and
might not line up exactly with the vk format representation.

E.g. R5G6B5_UNORM_PACK16 uses the U8 accum format so the USC will
internally use 3 bytes (1 per component) to deal with it instead
of 2 bytes which the vk format specifies. On USC EMITPIX, the PBE
will pack the results to 2 bytes using PACKMODE_R5G6B5 resulting
in the final value being in the vk format representation.

Signed-off-by: Karmjit Mahil <Karmjit.Mahil@imgtec.com>
Reviewed-by: Frank Binns <frank.binns@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19218>
This commit is contained in:
Karmjit Mahil 2022-10-10 10:26:24 +01:00 committed by Marge Bot
parent 81a90c1e48
commit 6a9364f4bc
3 changed files with 165 additions and 24 deletions

View file

@ -545,27 +545,6 @@ err_free_usc_pixel_program:
return result;
}
static uint32_t pvr_get_hw_clear_color(VkFormat vk_format,
const VkClearValue *clear_value)
{
union util_color uc = { .ui = 0 };
switch (vk_format) {
case VK_FORMAT_B8G8R8A8_UNORM:
util_pack_color(clear_value->color.float32,
PIPE_FORMAT_R8G8B8A8_UNORM,
&uc);
break;
default:
assert(!"Unsupported format");
uc.ui[0] = 0;
break;
}
return uc.ui[0];
}
static VkResult
pvr_load_op_constants_create_and_upload(struct pvr_cmd_buffer *cmd_buffer,
const struct pvr_load_op *load_op,
@ -581,7 +560,7 @@ pvr_load_op_constants_create_and_upload(struct pvr_cmd_buffer *cmd_buffer,
&pass->attachments[color_init->index];
const VkClearValue *clear_value =
&render_pass_info->clear_values[color_init->index];
uint32_t hw_clear_value;
uint32_t hw_clear_value[PVR_CLEAR_COLOR_ARRAY_SIZE];
struct pvr_bo *clear_bo;
VkResult result;
@ -594,10 +573,15 @@ pvr_load_op_constants_create_and_upload(struct pvr_cmd_buffer *cmd_buffer,
assert(color_init->op == VK_ATTACHMENT_LOAD_OP_CLEAR);
/* FIXME: do this at the point we store the clear values? */
hw_clear_value = pvr_get_hw_clear_color(attachment->vk_format, clear_value);
pvr_get_hw_clear_color(attachment->vk_format,
clear_value->color,
hw_clear_value);
if (vk_format_get_blocksize(attachment->vk_format) > 4)
pvr_finishme("Handle clear color greater than 32 bits.");
result = pvr_cmd_buffer_upload_general(cmd_buffer,
&hw_clear_value,
&hw_clear_value[0],
sizeof(hw_clear_value),
&clear_bo);
if (result != VK_SUCCESS)

View file

@ -30,6 +30,9 @@
#include "hwdef/rogue_hw_utils.h"
#include "pvr_formats.h"
#include "pvr_private.h"
#include "util/bitpack_helpers.h"
#include "util/format/format_utils.h"
#include "util/half_float.h"
#include "util/log.h"
#include "util/macros.h"
#include "util/u_math.h"
@ -281,6 +284,148 @@ uint32_t pvr_get_pbe_accum_format_size_in_bytes(VkFormat vk_format)
}
}
/**
* \brief Packs VK_FORMAT_A2B10G10R10_UINT_PACK32 or A2R10G10B10.
*
* \param[in] values RGBA ordered values to pack.
* \param[in] swap_rb If true pack A2B10G10R10 else pack A2R10G10B10.
*/
static inline uint32_t pvr_pack_a2x10y10z10_uint(
const uint32_t values[static const PVR_CLEAR_COLOR_ARRAY_SIZE],
bool swap_rb)
{
const uint32_t blue = swap_rb ? values[0] : values[2];
const uint32_t red = swap_rb ? values[2] : values[0];
uint32_t packed_val;
/* The user is allowed to specify a value which is over the range
* representable for a component so we need to AND before packing.
*/
packed_val = util_bitpack_uint(values[3] & BITSET_MASK(2), 30, 31);
packed_val |= util_bitpack_uint(red & BITSET_MASK(10), 20, 29);
packed_val |= util_bitpack_uint(values[1] & BITSET_MASK(10), 10, 19);
packed_val |= util_bitpack_uint(blue & BITSET_MASK(10), 0, 9);
return packed_val;
}
#define APPLY_FUNC_4V(DST, FUNC, ARG) \
ASSIGN_4V(DST, FUNC(ARG[0]), FUNC(ARG[1]), FUNC(ARG[2]), FUNC(ARG[3]))
#define f32_to_unorm8(val) _mesa_float_to_unorm(val, 8)
#define f32_to_unorm16(val) _mesa_float_to_unorm(val, 16)
#define f32_to_snorm8(val) _mesa_float_to_snorm(val, 8)
#define f32_to_snorm16(val) _mesa_float_to_snorm(val, 16)
#define f32_to_f16(val) _mesa_float_to_half(val)
/**
* \brief Packs clear color input values into the appropriate accum format.
*
* The input value array must have zeroed out elements for components not
* present in the format. E.g. R8G8B8 has no A component so [3] must be 0.
*
* Note: the output is not swizzled so it's packed in RGBA order no matter the
* component order specified by the vk_format.
*
* \param[in] vk_format Vulkan format of the input color value.
* \param[in] value Unpacked RGBA input color values.
* \param[out] packed_out Accum format packed values.
*/
void pvr_get_hw_clear_color(
VkFormat vk_format,
VkClearColorValue value,
uint32_t packed_out[static const PVR_CLEAR_COLOR_ARRAY_SIZE])
{
union {
uint32_t u32[PVR_CLEAR_COLOR_ARRAY_SIZE];
int32_t i32[PVR_CLEAR_COLOR_ARRAY_SIZE];
uint16_t u16[PVR_CLEAR_COLOR_ARRAY_SIZE * 2];
int16_t i16[PVR_CLEAR_COLOR_ARRAY_SIZE * 2];
uint8_t u8[PVR_CLEAR_COLOR_ARRAY_SIZE * 4];
int8_t i8[PVR_CLEAR_COLOR_ARRAY_SIZE * 4];
} packed_val = { 0 };
const enum pvr_pbe_accum_format pbe_accum_format =
pvr_get_pbe_accum_format(vk_format);
const uint32_t nr_components = vk_format_get_nr_components(vk_format);
/* Make sure that the caller has zeroed out unused components. Otherwise we
* might end up with garbage being packed with the actual values.
*/
for (uint32_t i = nr_components; i < 4; i++)
assert(value.uint32[i] == 0);
static_assert(ARRAY_SIZE(value.uint32) == PVR_CLEAR_COLOR_ARRAY_SIZE,
"Size mismatch. Unknown/unhandled extra values.");
/* TODO: Right now we pack all RGBA values. Would we get any benefit in
* packing just the components required by the format?
*/
switch (pbe_accum_format) {
case PVR_PBE_ACCUM_FORMAT_U8:
APPLY_FUNC_4V(packed_val.u8, f32_to_unorm8, value.float32);
break;
case PVR_PBE_ACCUM_FORMAT_S8:
APPLY_FUNC_4V(packed_val.i8, f32_to_snorm8, value.float32);
break;
case PVR_PBE_ACCUM_FORMAT_UINT8:
COPY_4V(packed_val.u8, value.uint32);
break;
case PVR_PBE_ACCUM_FORMAT_SINT8:
COPY_4V(packed_val.i8, value.int32);
break;
case PVR_PBE_ACCUM_FORMAT_U16:
APPLY_FUNC_4V(packed_val.u16, f32_to_unorm16, value.float32);
break;
case PVR_PBE_ACCUM_FORMAT_S16:
APPLY_FUNC_4V(packed_val.i16, f32_to_snorm16, value.float32);
break;
case PVR_PBE_ACCUM_FORMAT_F16:
APPLY_FUNC_4V(packed_val.u16, f32_to_f16, value.float32);
break;
case PVR_PBE_ACCUM_FORMAT_UINT16:
COPY_4V(packed_val.u16, value.uint32);
break;
case PVR_PBE_ACCUM_FORMAT_SINT16:
COPY_4V(packed_val.i16, value.int32);
break;
case PVR_PBE_ACCUM_FORMAT_F32:
COPY_4V(packed_val.u32, value.uint32);
break;
case PVR_PBE_ACCUM_FORMAT_UINT32:
/* The PBE can't pack 1010102 UINT. */
if (vk_format == VK_FORMAT_A2B10G10R10_UINT_PACK32) {
packed_val.u32[0] = pvr_pack_a2x10y10z10_uint(value.uint32, true);
break;
} else if (vk_format == VK_FORMAT_A2R10G10B10_UINT_PACK32) {
packed_val.u32[0] = pvr_pack_a2x10y10z10_uint(value.uint32, false);
break;
}
COPY_4V(packed_val.u32, value.uint32);
break;
case PVR_PBE_ACCUM_FORMAT_SINT32:
COPY_4V(packed_val.i32, value.int32);
break;
default:
unreachable("Packing not supported for the accum format.");
break;
}
COPY_4V(packed_out, packed_val.u32);
}
#undef APPLY_FUNC_4V
#undef f32_to_unorm8
#undef f32_to_unorm16
#undef f32_to_snorm8
#undef f32_to_snorm16
#undef f32_to_f16
static VkFormatFeatureFlags
pvr_get_image_format_features(const struct pvr_format *pvr_format,
VkImageTiling vk_tiling)

View file

@ -28,6 +28,14 @@
#include <stdint.h>
#include <vulkan/vulkan.h>
/* This is based on VkClearColorValue which is an array of RGBA, and on the
* output register usage for the biggest 32 bit 4 component formats which use up
* all 4 output registers.
* So this can be used for both unpacked RGBA value and to represent values
* packed according to the hardware (the accum format).
*/
#define PVR_CLEAR_COLOR_ARRAY_SIZE 4
enum pvr_pbe_accum_format {
PVR_PBE_ACCUM_FORMAT_INVALID = 0, /* Explicitly treat 0 as invalid. */
PVR_PBE_ACCUM_FORMAT_U8,
@ -56,4 +64,8 @@ uint32_t pvr_get_pbe_accum_format(VkFormat vk_format);
uint32_t pvr_get_pbe_accum_format_size_in_bytes(VkFormat vk_format);
bool pvr_format_is_pbe_downscalable(VkFormat vk_format);
void pvr_get_hw_clear_color(VkFormat vk_format,
VkClearColorValue value,
uint32_t packed_out[static const 4]);
#endif /* PVR_FORMATS_H */