diff options
| author | Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> | 2025-02-05 11:28:23 +0200 |
|---|---|---|
| committer | Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> | 2025-03-26 15:44:00 +0200 |
| commit | a9e7ecab862183399c5947931f2bad69ecec393d (patch) | |
| tree | 6c02b4e7a4cb19f9af1421afccd87eef1b084d3a /kms++/src/pixelformats.cpp | |
| parent | 8b1c053359ed7593e43222daccb8c0db8fcc441f (diff) | |
PixelFormats: New PixelFormatInfo code
New pixel format code, from Python pixutils library.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Diffstat (limited to 'kms++/src/pixelformats.cpp')
| -rw-r--r-- | kms++/src/pixelformats.cpp | 540 |
1 files changed, 318 insertions, 222 deletions
diff --git a/kms++/src/pixelformats.cpp b/kms++/src/pixelformats.cpp index 5f13ef4..8e3a120 100644 --- a/kms++/src/pixelformats.cpp +++ b/kms++/src/pixelformats.cpp @@ -1,4 +1,6 @@ #include <map> +#include <stdexcept> +#include <cassert> #include <kms++/pixelformats.h> @@ -6,228 +8,223 @@ using namespace std; namespace kms { -static const map<PixelFormat, PixelFormatInfo> format_info_array = { - /* YUV packed */ - { PixelFormat::UYVY, { - PixelColorType::YUV, - 1, - { { 16, 2, 1 } }, - } }, - { PixelFormat::YUYV, { - PixelColorType::YUV, - 1, - { { 16, 2, 1 } }, - } }, - { PixelFormat::YVYU, { - PixelColorType::YUV, - 1, - { { 16, 2, 1 } }, - } }, - { PixelFormat::VYUY, { - PixelColorType::YUV, - 1, - { { 16, 2, 1 } }, - } }, - { PixelFormat::Y210, { - PixelColorType::YUV, - 1, - { { 32, 2, 1 } }, - } }, - { PixelFormat::Y212, { - PixelColorType::YUV, - 1, - { { 32, 2, 1 } }, - } }, - { PixelFormat::Y216, { - PixelColorType::YUV, - 1, - { { 32, 2, 1 } }, - } }, - - /* YUV semi-planar */ - { PixelFormat::NV12, { - PixelColorType::YUV, - 2, - { { 8, 1, 1 }, { 8, 2, 2 } }, - } }, - { PixelFormat::NV21, { - PixelColorType::YUV, - 2, - { { 8, 1, 1 }, { 8, 2, 2 } }, - } }, - { PixelFormat::NV16, { - PixelColorType::YUV, - 2, - { { 8, 1, 1 }, { 8, 2, 1 } }, - } }, - { PixelFormat::NV61, { - PixelColorType::YUV, - 2, - { { 8, 1, 1 }, { 8, 2, 1 } }, - } }, - /* YUV planar */ - { PixelFormat::YUV420, { - PixelColorType::YUV, - 3, - { { 8, 1, 1 }, { 8, 2, 2 }, { 8, 2, 2 } }, - } }, - { PixelFormat::YVU420, { - PixelColorType::YUV, - 3, - { { 8, 1, 1 }, { 8, 2, 2 }, { 8, 2, 2 } }, - } }, - { PixelFormat::YUV422, { - PixelColorType::YUV, - 3, - { { 8, 1, 1 }, { 8, 2, 1 }, { 8, 2, 1 } }, - } }, - { PixelFormat::YVU422, { - PixelColorType::YUV, - 3, - { { 8, 1, 1 }, { 8, 2, 1 }, { 8, 2, 1 } }, - } }, - { PixelFormat::YUV444, { - PixelColorType::YUV, - 3, - { { 8, 1, 1 }, { 8, 1, 1 }, { 8, 1, 1 } }, - } }, - { PixelFormat::YVU444, { - PixelColorType::YUV, - 3, - { { 8, 1, 1 }, { 8, 1, 1 }, { 8, 1, 1 } }, - } }, - /* RGB8 */ - { PixelFormat::RGB332, { - PixelColorType::RGB, - 1, - { { 8, 1, 1 } }, - } }, - /* RGB16 */ - { PixelFormat::RGB565, { - PixelColorType::RGB, - 1, - { { 16, 1, 1 } }, - } }, - { PixelFormat::BGR565, { - PixelColorType::RGB, - 1, - { { 16, 1, 1 } }, - } }, - { PixelFormat::XRGB4444, { - PixelColorType::RGB, - 1, - { { 16, 1, 1 } }, - } }, - { PixelFormat::XRGB1555, { - PixelColorType::RGB, - 1, - { { 16, 1, 1 } }, - } }, - { PixelFormat::ARGB4444, { - PixelColorType::RGB, - 1, - { { 16, 1, 1 } }, - } }, - { PixelFormat::ARGB1555, { - PixelColorType::RGB, - 1, - { { 16, 1, 1 } }, - } }, - /* RGB24 */ - { PixelFormat::RGB888, { - PixelColorType::RGB, - 1, - { { 24, 1, 1 } }, - } }, - { PixelFormat::BGR888, { - PixelColorType::RGB, - 1, - { { 24, 1, 1 } }, - } }, - /* RGB32 */ - { PixelFormat::XRGB8888, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - { PixelFormat::XBGR8888, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - { PixelFormat::RGBX8888, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - { PixelFormat::BGRX8888, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - - { PixelFormat::ARGB8888, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - { PixelFormat::ABGR8888, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - { PixelFormat::RGBA8888, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - { PixelFormat::BGRA8888, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - - { PixelFormat::XRGB2101010, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - { PixelFormat::XBGR2101010, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - { PixelFormat::RGBX1010102, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - { PixelFormat::BGRX1010102, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - - { PixelFormat::ARGB2101010, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - { PixelFormat::ABGR2101010, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - { PixelFormat::RGBA1010102, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, - { PixelFormat::BGRA1010102, { - PixelColorType::RGB, - 1, - { { 32, 1, 1 } }, - } }, +static map<PixelFormat, PixelFormatInfo> format_info_array = { + { + PixelFormat::RGB565, { + PixelFormatInfo { + "RGB565", + "RG16", + "RGBP", + PixelColorType::RGB, + { 1, 1 }, + { { 2, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::XRGB1555, { + PixelFormatInfo { + "XRGB1555", + "XR15", + "", + PixelColorType::RGB, + { 1, 1 }, + { { 2, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::XRGB4444, { + PixelFormatInfo { + "XRGB4444", + "XR12", + "", + PixelColorType::RGB, + { 1, 1 }, + { { 2, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::ARGB1555, { + PixelFormatInfo { + "ARGB1555", + "AR15", + "", + PixelColorType::RGB, + { 1, 1 }, + { { 2, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::ARGB4444, { + PixelFormatInfo { + "ARGB4444", + "AR12", + "", + PixelColorType::RGB, + { 1, 1 }, + { { 2, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::RGB888, { + PixelFormatInfo { + "RGB888", + "RG24", + "BGR3", + PixelColorType::RGB, + { 1, 1 }, + { { 3, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::BGR888, { + PixelFormatInfo { + "BGR888", + "BG24", + "RGB3", + PixelColorType::RGB, + { 1, 1 }, + { { 3, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::XRGB8888, { + PixelFormatInfo { + "XRGB8888", + "XR24", + "XR24", + PixelColorType::RGB, + { 1, 1 }, + { { 4, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::XBGR8888, { + PixelFormatInfo { + "XBGR8888", + "XB24", + "XB24", + PixelColorType::RGB, + { 1, 1 }, + { { 4, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::RGBX8888, { + PixelFormatInfo { + "RGBX8888", + "RX24", + "RX24", + PixelColorType::RGB, + { 1, 1 }, + { { 4, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::XBGR2101010, { + PixelFormatInfo { + "XBGR2101010", + "XB30", + "RX30", + PixelColorType::RGB, + { 1, 1 }, + { { 4, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::ARGB8888, { + PixelFormatInfo { + "ARGB8888", + "AR24", + "AR24", + PixelColorType::RGB, + { 1, 1 }, + { { 4, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::ABGR8888, { + PixelFormatInfo { + "ABGR8888", + "AB24", + "AB24", + PixelColorType::RGB, + { 1, 1 }, + { { 4, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::RGBA8888, { + PixelFormatInfo { + "RGBA8888", + "RA24", + "RA24", + PixelColorType::RGB, + { 1, 1 }, + { { 4, 1, 1, 1 } }, + } + } + }, + { + PixelFormat::NV12, { + PixelFormatInfo { + "NV12", + "NV12", + "NM12", + PixelColorType::YUV, + { 2, 2 }, + { { 1, 1, 1, 1 }, { 2, 1, 2, 2 } }, + } + } + }, + { + PixelFormat::NV16, { + PixelFormatInfo { + "NV16", + "NV16", + "NM16", + PixelColorType::YUV, + { 2, 1 }, + { { 1, 1, 1, 1 }, { 2, 1, 2, 1 } }, + } + } + }, + { + PixelFormat::YUYV, { + PixelFormatInfo { + "YUYV", + "YUYV", + "YUYV", + PixelColorType::YUV, + { 2, 1 }, + { { 4, 2, 1, 1 } }, + } + } + }, + { + PixelFormat::UYVY, { + PixelFormatInfo { + "UYVY", + "UYVY", + "UYVY", + PixelColorType::YUV, + { 2, 1 }, + { { 4, 2, 1, 1 } }, + } + } + }, }; const struct PixelFormatInfo& get_pixel_format_info(PixelFormat format) @@ -238,4 +235,103 @@ const struct PixelFormatInfo& get_pixel_format_info(PixelFormat format) return format_info_array.at(format); } + +static constexpr uint32_t _div_round_up(uint32_t a, uint32_t b) +{ + return (a + b - 1) / b; +} + +static constexpr uint32_t _align_up(uint32_t a, uint32_t b) +{ + return _div_round_up(a, b) * b; +} + +std::tuple<uint32_t, uint32_t> PixelFormatInfo::align_pixels(uint32_t width, + uint32_t height) const +{ + return { _align_up(width, std::get<0>(pixel_align)), + _align_up(height, std::get<1>(pixel_align)) }; +} + +uint32_t PixelFormatInfo::stride(uint32_t width, uint32_t plane, uint32_t align) const +{ + if (plane >= num_planes) + throw std::runtime_error("Invalid plane number"); + + assert(width % std::get<0>(pixel_align) == 0); + + const auto& pi = planes[plane]; + + assert(width % pi.pixels_per_block == 0); + uint32_t stride = width / pi.pixels_per_block * pi.bytes_per_block; + + assert(stride % pi.hsub == 0); + stride = stride / pi.hsub; + + stride = _align_up(stride, align); + + return stride; +} + +uint32_t PixelFormatInfo::planesize(uint32_t stride, uint32_t height, + uint32_t plane) const +{ + assert(height % std::get<1>(pixel_align) == 0); + + const auto& pi = planes[plane]; + + assert(height % pi.vsub == 0); + + return stride * (height / pi.vsub); +} + +uint32_t PixelFormatInfo::framesize(uint32_t width, uint32_t height, + uint32_t align) const +{ + uint32_t size = 0; + + for (uint32_t i = 0; i < num_planes; ++i) { + uint32_t s = stride(width, i, align); + size += planesize(s, height, i); + } + + return size; +} + +std::tuple<uint32_t, uint32_t, uint32_t> PixelFormatInfo::dumb_size(uint32_t width, + uint32_t height, + uint32_t plane, + uint32_t align) const +{ + /* + Helper function mainly for DRM dumb framebuffer + Returns (width, height, bitspp) tuple which results in a suitable plane + size. + + DRM_IOCTL_MODE_CREATE_DUMB takes a 'bpp' (bits-per-pixel) argument, + which is then used with the width and height to allocate the buffer. + This doesn't work for pixel formats where the average bits-per-pixel + is not an integer (e.g. XV15) + + So, we instead use the bytes_per_block (in bits) as + the 'bpp' argument, and adjust the width accordingly. + */ + + assert(height % std::get<1>(pixel_align) == 0); + + const auto& pi = planes[plane]; + + assert(height % pi.vsub == 0); + + uint32_t stride = PixelFormatInfo::stride(width, plane, align); + + assert(stride % pi.bytes_per_block == 0); + + width = stride / pi.bytes_per_block; + height = height / pi.vsub; + uint32_t bitspp = pi.bytes_per_block * 8; + + return { width, height, bitspp }; +} + } // namespace kms |
