From 3495831d729b25292c33bf6fb9af7f167627a637 Mon Sep 17 00:00:00 2001 From: Ella Stanforth Date: Tue, 6 Jan 2026 11:46:08 +0000 Subject: [PATCH] pvr: setup csc tables Reviewed-by: Simon Perretta Part-of: --- src/imagination/common/meson.build | 1 + src/imagination/common/pvr_ycbcr.c | 101 ++++++++++++++++++ src/imagination/common/pvr_ycbcr.h | 23 ++++ src/imagination/vulkan/pvr_arch_image.c | 23 ++++ src/imagination/vulkan/pvr_arch_tex_state.c | 1 + src/imagination/vulkan/pvr_tex_state.h | 5 + .../vulkan/winsys/pvr_winsys_helper.c | 5 + 7 files changed, 159 insertions(+) create mode 100644 src/imagination/common/pvr_ycbcr.c create mode 100644 src/imagination/common/pvr_ycbcr.h diff --git a/src/imagination/common/meson.build b/src/imagination/common/meson.build index 652e916f89f..2bc88a83ae0 100644 --- a/src/imagination/common/meson.build +++ b/src/imagination/common/meson.build @@ -11,6 +11,7 @@ libpowervr_common = static_library( 'pvr_dump.c', 'pvr_dump_info.c', 'pvr_util.c', + 'pvr_ycbcr.c', sha1_h, ], include_directories : [ diff --git a/src/imagination/common/pvr_ycbcr.c b/src/imagination/common/pvr_ycbcr.c new file mode 100644 index 00000000000..64e0c6e0a46 --- /dev/null +++ b/src/imagination/common/pvr_ycbcr.c @@ -0,0 +1,101 @@ +/* + * Copyright © 2026 Imagination Technologies Ltd. + * SPDX-License-Identifier: MIT + */ +#include "pvr_ycbcr.h" + +#include "util/macros.h" + +/* number of slots occupied */ +#define PVR_YCBCR_SLOTS 9 + +struct pvr_ycbcr_csc_table_entry { + uint16_t value[32]; +} PACKED; + +struct pvr_ycbcr_csc_table { + struct pvr_ycbcr_csc_table_entry slots[PVR_YCBCR_SLOTS]; +} PACKED; + +/* clang-format off */ +static const uint16_t RGB_IDENTITY[] = { + 0x0000, 0x1ffc, 0x0000, + 0x0000, 0x0000, 0x1ffc, + 0x1ffc, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, +}; + +static const uint16_t YCBCR_IDENTITY_FULL[] = { + 0x0000, 0x1ffc, 0x0000, + 0x0000, 0x0000, 0x1ffc, + 0x1ffc, 0x0000, 0x0000, + 0xfff0, 0x0000, 0xfff0, +}; + +static const uint16_t YCBCR_IDENTITY[] = { + 0x0000, 0x253e, 0x0000, + 0x0000, 0x0000, 0x2469, + 0x2469, 0x0000, 0x0000, + 0xfdb9, 0xfdac, 0xfdb9, +}; + +static const uint16_t YCBCR_709_FULL[] = { + 0x1ffc, 0x1ffc, 0x1ffc, + 0x0000, 0xfa02, 0x3b5a, + 0x325e, 0xf107, 0x0000, + 0xe6d1, 0x0a7b, 0xe253, +}; + +static const uint16_t YCBCR_709[] = { + 0x253e, 0x253e, 0x253e, + 0x0000, 0xf92e, 0x4390, + 0x3957, 0xeef5, 0x0000, + 0xe101, 0x099b, 0xdbe4, +}; + +static const uint16_t YCBCR_601_FULL[] = { + 0x1ffc, 0x1ffc, 0x1ffc, + 0x0000, 0xf4fe, 0x38ad, + 0x2cd8, 0xe929, 0x0000, + 0xe994, 0x10ed, 0xe3a9, +}; + +static const uint16_t YCBCR_601[] = { + 0x253e, 0x253e, 0x253e, + 0x0000, 0xf378, 0x4085, + 0x330c, 0xe5ff, 0x0000, + 0xe426, 0x10f0, 0xdd6a, +}; + +static const uint16_t YCBCR_2020_FULL[] = { + 0x1ffc, 0x1ffc, 0x1ffc, + 0x0000, 0xfabd, 0x3c2d, + 0x2f2a, 0xedba, 0x0000, + 0xe86b, 0x0bc5, 0xe1ea, +}; + +static const uint16_t YCBCR_2020[] = { + 0x253e, 0x253e, 0x253e, + 0x0000, 0xfa02, 0x4481, + 0x35b1, 0xeb32, 0x0000, + 0xe2d4, 0x0b12, 0xdb6c, +}; +/* clang-format on */ + +#define fill_slot(table, entry) \ + memcpy(&table->slots[PVR_YCBCR_SLOT_##entry].value, entry, sizeof(entry)) + +void pvr_setup_static_yuv_csc_table(uint8_t *map, uint64_t offset) +{ + struct pvr_ycbcr_csc_table *table = + (struct pvr_ycbcr_csc_table *)(&map[offset]); + fill_slot(table, RGB_IDENTITY); + fill_slot(table, YCBCR_IDENTITY_FULL); + fill_slot(table, YCBCR_IDENTITY); + fill_slot(table, YCBCR_709_FULL); + fill_slot(table, YCBCR_709); + fill_slot(table, YCBCR_601_FULL); + fill_slot(table, YCBCR_601); + fill_slot(table, YCBCR_2020_FULL); + fill_slot(table, YCBCR_2020); +} diff --git a/src/imagination/common/pvr_ycbcr.h b/src/imagination/common/pvr_ycbcr.h new file mode 100644 index 00000000000..2876dbd81bf --- /dev/null +++ b/src/imagination/common/pvr_ycbcr.h @@ -0,0 +1,23 @@ +/* + * Copyright © 2026 Imagination Technologies Ltd. + * SPDX-License-Identifier: MIT + */ +#ifndef PVR_YCBCR_H +#define PVR_YCBCR_H + +#include + +void pvr_setup_static_yuv_csc_table(uint8_t *const heap_ptr, + uint64_t yuv_table_offset_in_bytes); + +#define PVR_YCBCR_SLOT_RGB_IDENTITY 0 +#define PVR_YCBCR_SLOT_YCBCR_IDENTITY_FULL 1 +#define PVR_YCBCR_SLOT_YCBCR_IDENTITY 2 +#define PVR_YCBCR_SLOT_YCBCR_709_FULL 3 +#define PVR_YCBCR_SLOT_YCBCR_709 4 +#define PVR_YCBCR_SLOT_YCBCR_601_FULL 5 +#define PVR_YCBCR_SLOT_YCBCR_601 6 +#define PVR_YCBCR_SLOT_YCBCR_2020_FULL 7 +#define PVR_YCBCR_SLOT_YCBCR_2020 8 + +#endif /* PVR_YCBCR_H */ diff --git a/src/imagination/vulkan/pvr_arch_image.c b/src/imagination/vulkan/pvr_arch_image.c index f2140c8c6f5..2ff49ef9865 100644 --- a/src/imagination/vulkan/pvr_arch_image.c +++ b/src/imagination/vulkan/pvr_arch_image.c @@ -19,6 +19,7 @@ #include "pvr_macros.h" #include "pvr_physical_device.h" #include "pvr_tex_state.h" +#include "pvr_ycbcr.h" static void pvr_adjust_non_compressed_view(const struct pvr_image *image, const struct pvr_image_plane *plane, @@ -44,6 +45,26 @@ static void pvr_adjust_non_compressed_view(const struct pvr_image *image, info->base_level = 0; } +static unsigned int pvr_ycbcr_csc_index(struct vk_ycbcr_conversion *conversion) +{ +#define MAPPING(vk, slot_full, slot_narrow) \ + [VK_SAMPLER_YCBCR_MODEL_CONVERSION_##vk] = { \ + PVR_YCBCR_SLOT_##slot_full, \ + PVR_YCBCR_SLOT_##slot_narrow \ + } + + static unsigned int mapping[][2] = { + MAPPING(RGB_IDENTITY, RGB_IDENTITY, RGB_IDENTITY), + MAPPING(YCBCR_IDENTITY, YCBCR_IDENTITY_FULL, YCBCR_IDENTITY), + MAPPING(YCBCR_709, YCBCR_709_FULL, YCBCR_709), + MAPPING(YCBCR_601, YCBCR_601_FULL, YCBCR_601), + MAPPING(YCBCR_2020, YCBCR_2020_FULL, YCBCR_2020), + }; + return mapping[conversion->state.ycbcr_model][conversion->state.ycbcr_range]; + +#undef MAPPING +} + VkResult PVR_PER_ARCH(CreateImageView)(VkDevice _device, const VkImageViewCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, @@ -127,6 +148,8 @@ VkResult PVR_PER_ARCH(CreateImageView)(VkDevice _device, input_swizzle[3] = PIPE_SWIZZLE_0; } + info.csc_coeff_index = pvr_ycbcr_csc_index(conversion); + pvr_csb_pack (&iview->sampler_words[0], TEXSTATE_SAMPLER_WORD0, cfg) { cfg.texaddr_plane2_lo = PVR_DEV_ADDR_OFFSET(image->dev_addr, image->planes[1].offset); diff --git a/src/imagination/vulkan/pvr_arch_tex_state.c b/src/imagination/vulkan/pvr_arch_tex_state.c index ffe80efd962..cb1667f5be2 100644 --- a/src/imagination/vulkan/pvr_arch_tex_state.c +++ b/src/imagination/vulkan/pvr_arch_tex_state.c @@ -278,6 +278,7 @@ VkResult pvr_arch_pack_tex_state(struct pvr_device *device, word1.chroma_interpolation_u = 0; word1.stride = info->extent.width - 1; word1.texaddr = PVR_DEV_ADDR_OFFSET(info->addr, info->offset); + word1.csc_coeff_index = info->csc_coeff_index; } } else if (mem_layout == PVR_MEMLAYOUT_LINEAR) { pvr_csb_pack (&state->words[1], TEXSTATE_STRIDE_IMAGE_WORD1, word1) { diff --git a/src/imagination/vulkan/pvr_tex_state.h b/src/imagination/vulkan/pvr_tex_state.h index 852a2a038d7..5344dfa6e9e 100644 --- a/src/imagination/vulkan/pvr_tex_state.h +++ b/src/imagination/vulkan/pvr_tex_state.h @@ -107,6 +107,11 @@ struct pvr_texture_state_info { uint32_t layer_size; uint32_t buffer_elems; uint32_t z_slice; + + /** + * YCbCr CSC matrix + */ + uint8_t csc_coeff_index; }; #ifdef PVR_PER_ARCH diff --git a/src/imagination/vulkan/winsys/pvr_winsys_helper.c b/src/imagination/vulkan/winsys/pvr_winsys_helper.c index 2dcddfc17ad..5dcd4027f99 100644 --- a/src/imagination/vulkan/winsys/pvr_winsys_helper.c +++ b/src/imagination/vulkan/winsys/pvr_winsys_helper.c @@ -34,6 +34,7 @@ #include "pvr_types.h" #include "pvr_winsys.h" #include "pvr_winsys_helper.h" +#include "pvr_ycbcr.h" #include "util/u_atomic.h" #include "vk_log.h" @@ -343,6 +344,10 @@ pvr_winsys_helper_fill_static_memory(struct pvr_winsys *const ws, pvr_setup_static_pixel_event_program(pds_vma->bo->map, pds_vma->heap->static_data_offsets.eot); + pvr_setup_static_yuv_csc_table( + general_vma->bo->map, + general_vma->heap->static_data_offsets.yuv_csc); + ws->ops->buffer_unmap(usc_vma->bo, false); ws->ops->buffer_unmap(pds_vma->bo, false); ws->ops->buffer_unmap(general_vma->bo, false);