From 5dbffa75501869bbdd935d0d091511424ddc4652 Mon Sep 17 00:00:00 2001 From: Nick Hollinghurst Date: Thu, 31 Jul 2025 14:09:15 +0100 Subject: [PATCH 1/4] v4l2_device, pisp_utils: Add support for "RGBX8888" By analogy with our existing "RGB888", define "RGBX8888" to be RGBX in byte address order, i.e. V4L2-style rather than DRM-style. This implies that the ORDER_SWAPPED flag should not be set. These strings are private to libpisp and mostly used only by convert. Signed-off-by: Nick Hollinghurst --- src/helpers/v4l2_device.cpp | 1 + src/libpisp/common/pisp_utils.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/helpers/v4l2_device.cpp b/src/helpers/v4l2_device.cpp index 2b4c875..d3f5489 100644 --- a/src/helpers/v4l2_device.cpp +++ b/src/helpers/v4l2_device.cpp @@ -31,6 +31,7 @@ static FormatInfo get_v4l2_format(const std::string &format) { std::map formats { { "RGB888", { V4L2_PIX_FMT_RGB24, 1 } }, + { "RGBX8888", { V4L2_PIX_FMT_RGBX32, 1 } }, { "YUV420P", { V4L2_PIX_FMT_YUV420, 1 } }, { "YUV422P", { V4L2_PIX_FMT_YUV422P, 1 } }, { "YUV444P", { V4L2_PIX_FMT_YUV444M, 3 } }, diff --git a/src/libpisp/common/pisp_utils.cpp b/src/libpisp/common/pisp_utils.cpp index 3c57c21..e078478 100644 --- a/src/libpisp/common/pisp_utils.cpp +++ b/src/libpisp/common/pisp_utils.cpp @@ -240,7 +240,7 @@ static const std::map &formats_table() { "NV61", PISP_IMAGE_FORMAT_THREE_CHANNEL + PISP_IMAGE_FORMAT_BPS_8 + PISP_IMAGE_FORMAT_SAMPLING_422 + PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR + PISP_IMAGE_FORMAT_ORDER_SWAPPED }, { "RGB888", PISP_IMAGE_FORMAT_THREE_CHANNEL }, - { "RGBX8888", PISP_IMAGE_FORMAT_THREE_CHANNEL + PISP_IMAGE_FORMAT_BPP_32 + PISP_IMAGE_FORMAT_ORDER_SWAPPED }, + { "RGBX8888", PISP_IMAGE_FORMAT_THREE_CHANNEL + PISP_IMAGE_FORMAT_BPP_32 }, { "RGB161616", PISP_IMAGE_FORMAT_THREE_CHANNEL + PISP_IMAGE_FORMAT_BPS_16 }, { "BAYER", PISP_IMAGE_FORMAT_BPS_16 + PISP_IMAGE_FORMAT_UNCOMPRESSED }, { "PISP_COMP1", PISP_IMAGE_FORMAT_COMPRESSION_MODE_1 }, From 9f28861b0ba74c3aac301eb596e06ffe9f24a874 Mon Sep 17 00:00:00 2001 From: Nick Hollinghurst Date: Fri, 1 Aug 2025 10:08:38 +0100 Subject: [PATCH 2/4] examples: convert: Add support for RGBX input and output We also check if the hardware platform supports this. Signed-off-by: Nick Hollinghurst --- src/examples/convert.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/examples/convert.cpp b/src/examples/convert.cpp index 14f2729..a4cf3cb 100644 --- a/src/examples/convert.cpp +++ b/src/examples/convert.cpp @@ -65,6 +65,18 @@ void write_rgb888(std::ofstream &out, std::array &mem, unsigned in write_plane(out, (uint8_t *)mem[0], width * 3, height, file_stride, buffer_stride); } +void read_32(std::array &mem, std::ifstream &in, unsigned int width, unsigned int height, + unsigned int file_stride, unsigned int buffer_stride) +{ + read_plane((uint8_t *)mem[0], in, width * 4, height, file_stride, buffer_stride); +} + +void write_32(std::ofstream &out, std::array &mem, unsigned int width, unsigned int height, + unsigned int file_stride, unsigned int buffer_stride) +{ + write_plane(out, (uint8_t *)mem[0], width * 4, height, file_stride, buffer_stride); +} + void read_yuv(std::array &mem, std::ifstream &in, unsigned int width, unsigned int height, unsigned int file_stride, unsigned int buffer_stride, unsigned int ss_x, unsigned int ss_y) { @@ -152,6 +164,7 @@ struct FormatFuncs const std::map Formats = { { "RGB888", { read_rgb888, write_rgb888 } }, + { "RGBX8888", { read_32, write_32 } }, { "YUV420P", { read_yuv420, write_yuv420 } }, { "YUV422P", { read_yuv422p, write_yuv422p } }, { "YUV444P", { read_yuv444p, write_yuv444p } }, @@ -280,6 +293,11 @@ int main(int argc, char *argv[]) global.bayer_enables = 0; global.rgb_enables = PISP_BE_RGB_ENABLE_INPUT + PISP_BE_RGB_ENABLE_OUTPUT0; + if ((in_file.format == "RGBX8888" || out_file.format == "RGBX8888") && !variant->BackendRGB32Supported(0)) + { + std::cerr << "Backend hardware does not support RGBX formats" << std::endl; + exit(-1); + } pisp_image_format_config i = {}; i.width = in_file.width; i.height = in_file.height; @@ -299,20 +317,20 @@ int main(int argc, char *argv[]) if (!out_file.stride) out_file.stride = o.image.stride; - if (in_file.format != "RGB888") + if (in_file.format >= "U") { pisp_be_ccm_config csc; be.InitialiseYcbcrInverse(csc, "jpeg"); be.SetCcm(csc); - global.rgb_enables += PISP_BE_RGB_ENABLE_CCM; + global.rgb_enables |= PISP_BE_RGB_ENABLE_CCM; } - if (out_file.format != "RGB888") + if (out_file.format >= "U") { pisp_be_ccm_config csc; be.InitialiseYcbcr(csc, "jpeg"); be.SetCsc(0, csc); - global.rgb_enables += PISP_BE_RGB_ENABLE_CSC0; + global.rgb_enables |= PISP_BE_RGB_ENABLE_CSC0; } be.SetGlobal(global); From 69eba05245f5bb4884e5e1e5a6deb6c8040158af Mon Sep 17 00:00:00 2001 From: Nick Hollinghurst Date: Thu, 31 Jul 2025 14:01:39 +0100 Subject: [PATCH 3/4] backend: Don't assert on odd-width output for interleaved 422 (UYVY) This is largely a hack to support scaling by a factor of exactly 2; but nothing bad seems to happen when it is allowed (given we have a 2-pix-per-cycle ISP it's no more objectionable than odd-width 444). Signed-off-by: Nick Hollinghurst --- src/libpisp/backend/backend_prepare.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libpisp/backend/backend_prepare.cpp b/src/libpisp/backend/backend_prepare.cpp index fcb4191..e8a001c 100644 --- a/src/libpisp/backend/backend_prepare.cpp +++ b/src/libpisp/backend/backend_prepare.cpp @@ -294,7 +294,7 @@ void finalise_output(pisp_be_output_format_config &config) throw std::runtime_error("finalise_output: 420 image height should be even"); if ((PISP_IMAGE_FORMAT_SAMPLING_420(config.image.format) || PISP_IMAGE_FORMAT_SAMPLING_422(config.image.format)) && - (config.image.width & 1)) + !PISP_IMAGE_FORMAT_INTERLEAVED(config.image.format) && (config.image.width & 1)) throw std::runtime_error("finalise_output: 420/422 image width should be even"); if (PISP_IMAGE_FORMAT_WALLPAPER(config.image.format)) From 8aa77a0b564fa33aa2abf6991f5ce077b7861aeb Mon Sep 17 00:00:00 2001 From: Nick Hollinghurst Date: Fri, 1 Aug 2025 10:28:44 +0100 Subject: [PATCH 4/4] examples: convert: Add support for RGBX output from 2712C1 By doubling the width, changing the output format to "UYVY" and applying a matrix to swap the first two colour components, we can output RGBX. The gotcha is that when downscaling, this can result in an oversharp/aliasy image. No support for RGBX input (though that would theoretically be possible at unity scale, using a customized Resample kernel). Signed-off-by: Nick Hollinghurst --- src/examples/convert.cpp | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/examples/convert.cpp b/src/examples/convert.cpp index a4cf3cb..b732e0d 100644 --- a/src/examples/convert.cpp +++ b/src/examples/convert.cpp @@ -293,9 +293,9 @@ int main(int argc, char *argv[]) global.bayer_enables = 0; global.rgb_enables = PISP_BE_RGB_ENABLE_INPUT + PISP_BE_RGB_ENABLE_OUTPUT0; - if ((in_file.format == "RGBX8888" || out_file.format == "RGBX8888") && !variant->BackendRGB32Supported(0)) + if (in_file.format == "RGBX8888" && !variant->BackendRGB32Supported(0)) { - std::cerr << "Backend hardware does not support RGBX formats" << std::endl; + std::cerr << "Backend hardware does not support RGBX input" << std::endl; exit(-1); } pisp_image_format_config i = {}; @@ -307,9 +307,32 @@ int main(int argc, char *argv[]) be.SetInputFormat(i); pisp_be_output_format_config o = {}; - o.image.width = out_file.width; - o.image.height = out_file.height; - o.image.format = libpisp::get_pisp_image_format(out_file.format); + if (out_file.format == "RGBX8888" && !variant->BackendRGB32Supported(0)) + { + // Hack to generate RGBX even when BE_MINOR_VERSION < 1 using Resample + if (out_file.width < i.width) + std::cerr << "Backend hardware has limited RGBX support; resize artifacts may be present" << std::endl; + + o.image.width = out_file.width * 2 - 1; + o.image.height = out_file.height; + o.image.format = libpisp::get_pisp_image_format("UYVY"); + + pisp_be_ccm_config csc = {}; // Define a matrix to swap components [0] and [1] + csc.coeffs[1] = 1024; + csc.coeffs[3] = 1024; + csc.coeffs[8] = 1024; + csc.offsets[0] = 131072; // round to nearest after Resample, for 8-bit output + csc.offsets[1] = 131072; + csc.offsets[2] = 131072; + be.SetCsc(0, csc); + global.rgb_enables |= PISP_BE_RGB_ENABLE_CSC0; + } + else + { + o.image.width = out_file.width; + o.image.height = out_file.height; + o.image.format = libpisp::get_pisp_image_format(out_file.format); + } assert(o.image.format); libpisp::compute_optimal_stride(o.image, true); be.SetOutputFormat(0, o);