From c2163603379326d311a8f25d2329e2336953b8ec Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Wed, 15 Apr 2026 15:10:57 -0400 Subject: [PATCH] kernel/interface: 30-bit RGB pixel format support On Apple ARM platforms, iBoot sets up a 30-bit framebuffer Change-Id: I6c03937303a3363fde511c8b8b7f8fd66a6a6965 Reviewed-on: https://review.haiku-os.org/c/haiku/+/11128 Tested-by: Commit checker robot Reviewed-by: waddlesplash --- headers/os/interface/GraphicsDefs.h | 3 ++ .../boot/platform/generic/video_blitter.h | 29 +++++++++++++++++++ .../graphics/framebuffer/framebuffer.cpp | 2 ++ src/build/libbe/interface/Bitmap.cpp | 1 + src/build/libbe/interface/GraphicsDefs.cpp | 2 ++ src/kits/interface/Bitmap.cpp | 1 + src/kits/interface/GraphicsDefs.cpp | 1 + src/preferences/screen/ScreenMode.cpp | 3 +- src/preferences/screen/ScreenWindow.cpp | 13 ++++----- src/servers/app/drawing/HWInterface.cpp | 21 ++++++++++++++ src/system/boot/platform/efi/video.cpp | 28 ++++++++++-------- .../kernel/debug/frame_buffer_console.cpp | 17 +++++++++-- .../kits/interface/bbitmap/BBitmapTester.cpp | 1 + 13 files changed, 99 insertions(+), 23 deletions(-) diff --git a/headers/os/interface/GraphicsDefs.h b/headers/os/interface/GraphicsDefs.h index cd0f6571aa..b9209b30a6 100644 --- a/headers/os/interface/GraphicsDefs.h +++ b/headers/os/interface/GraphicsDefs.h @@ -175,6 +175,7 @@ typedef enum { B_RGB48 = 0x0011, // RGB RGB 16:16:16 B_RGB32 = 0x0008, // BGR- -RGB 8:8:8:8 B_RGBA32 = 0x2008, // BGRA ARGB 8:8:8:8 + B_RGB30 = 0x0009, // BGR- -RGB 2:10:10:10 B_RGB24 = 0x0003, // BGR RGB 8:8:8 B_RGB16 = 0x0005, // BGR RGB 5:6:5 B_RGB15 = 0x0010, // BGR- -RGB 1:5:5:5 @@ -188,6 +189,7 @@ typedef enum { B_RGB48_BIG = 0x1011, // RGB RGB 16:16:16 B_RGB32_BIG = 0x1008, // -RGB BGR- 8:8:8:8 B_RGBA32_BIG = 0x3008, // ARGB BGRA 8:8:8:8 + B_RGB30_BIG = 0x1009, // -RGB BGR- 10:10:10:2 B_RGB24_BIG = 0x1003, // RGB BGR 8:8:8 B_RGB16_BIG = 0x1005, // RGB BGR 5:6:5 B_RGB15_BIG = 0x1010, // -RGB BGR- 5:5:5:1 @@ -198,6 +200,7 @@ typedef enum { B_RGB48_LITTLE = B_RGB48, B_RGB32_LITTLE = B_RGB32, B_RGBA32_LITTLE = B_RGBA32, + B_RGB30_LITTLE = B_RGB30, B_RGB24_LITTLE = B_RGB24, B_RGB16_LITTLE = B_RGB16, B_RGB15_LITTLE = B_RGB15, diff --git a/headers/private/kernel/boot/platform/generic/video_blitter.h b/headers/private/kernel/boot/platform/generic/video_blitter.h index d9c061b966..0bca6bf101 100644 --- a/headers/private/kernel/boot/platform/generic/video_blitter.h +++ b/headers/private/kernel/boot/platform/generic/video_blitter.h @@ -128,6 +128,32 @@ blit24(const BlitParameters& params) } +static void +blit30(const BlitParameters& params) +{ + const uint8* data = params.from; + data += (params.fromWidth * params.fromTop + params.fromLeft) * 3; + uint32* start = (uint32*)(params.to + + params.toBytesPerRow * params.toTop + + 4 * params.toLeft); + + for (int32 y = params.fromTop; y < params.fromBottom; y++) { + const uint8* src = data; + uint32* dst = start; + for (int32 x = params.fromLeft; x < params.fromRight; x++) { + dst[0] = (((src[2] * 1023) / 255) << 20) + | (((src[1] * 1023) / 255) << 10) + | ((src[0] * 1023) / 255); + dst++; + src += 3; + } + + data += params.fromWidth * 3; + start = (uint32*)((addr_t)start + params.toBytesPerRow); + } +} + + static void blit32(const BlitParameters& params) { @@ -168,6 +194,9 @@ blit(const BlitParameters& params, int32 depth) case 24: blit24(params); return; + case 30: + blit30(params); + return; case 32: blit32(params); return; diff --git a/src/add-ons/kernel/drivers/graphics/framebuffer/framebuffer.cpp b/src/add-ons/kernel/drivers/graphics/framebuffer/framebuffer.cpp index ed16a9568b..abdd71138d 100644 --- a/src/add-ons/kernel/drivers/graphics/framebuffer/framebuffer.cpp +++ b/src/add-ons/kernel/drivers/graphics/framebuffer/framebuffer.cpp @@ -39,6 +39,8 @@ get_color_space_for_depth(uint32 depth) return B_RGB16; case 24: return B_RGB24; + case 30: + return B_RGB30; case 32: return B_RGB32; } diff --git a/src/build/libbe/interface/Bitmap.cpp b/src/build/libbe/interface/Bitmap.cpp index 99855c2239..6b50313938 100644 --- a/src/build/libbe/interface/Bitmap.cpp +++ b/src/build/libbe/interface/Bitmap.cpp @@ -71,6 +71,7 @@ get_raw_bytes_per_row(color_space colorSpace, int32 width) case B_CMY32: case B_CMYA32: case B_CMYK32: bpr = 4 * width; break; + case B_RGB30: case B_RGB30_BIG: case B_RGB24: case B_RGB24_BIG: case B_UVL24: case B_LAB24: case B_HSI24: case B_HSV24: case B_HLS24: case B_CMY24: diff --git a/src/build/libbe/interface/GraphicsDefs.cpp b/src/build/libbe/interface/GraphicsDefs.cpp index 33bdb73f4a..a5817fb9a8 100644 --- a/src/build/libbe/interface/GraphicsDefs.cpp +++ b/src/build/libbe/interface/GraphicsDefs.cpp @@ -73,6 +73,7 @@ get_pixel_size_for(color_space space, size_t *pixelChunk, size_t *rowAlignment, case B_HSV32: case B_HSVA32: case B_HLS32: case B_HLSA32: case B_CMY32: case B_CMYA32: case B_CMYK32: + case B_RGB30: case B_RGB30_BIG: bytesPerPixel = 4; pixPerChunk = 1; break; @@ -162,6 +163,7 @@ bitmaps_support_space(color_space space, uint32 *supportFlags) case B_RGB48: case B_RGB48_BIG: case B_RGB32: case B_RGBA32: case B_RGB24: case B_RGB32_BIG: case B_RGBA32_BIG: case B_RGB24_BIG: + case B_RGB30: case B_RGB30_BIG: case B_RGB16: case B_RGB15: case B_RGBA15: case B_RGB16_BIG: case B_RGB15_BIG: case B_RGBA15_BIG: case B_CMAP8: case B_GRAY8: case B_GRAY1: diff --git a/src/kits/interface/Bitmap.cpp b/src/kits/interface/Bitmap.cpp index 38ddfaaf87..a4c092ddf3 100644 --- a/src/kits/interface/Bitmap.cpp +++ b/src/kits/interface/Bitmap.cpp @@ -95,6 +95,7 @@ get_raw_bytes_per_row(color_space colorSpace, int32 width) break; case B_RGB32: case B_RGBA32: case B_RGB32_BIG: case B_RGBA32_BIG: + case B_RGB30: case B_RGB30_BIG: case B_UVL32: case B_UVLA32: case B_LAB32: case B_LABA32: case B_HSI32: case B_HSIA32: diff --git a/src/kits/interface/GraphicsDefs.cpp b/src/kits/interface/GraphicsDefs.cpp index d14b25bcdd..82c832b262 100644 --- a/src/kits/interface/GraphicsDefs.cpp +++ b/src/kits/interface/GraphicsDefs.cpp @@ -232,6 +232,7 @@ bitmaps_support_space(color_space space, uint32 *supportFlags) // supported, but cannot draw case B_RGBA64: case B_RGBA64_BIG: case B_RGB48: case B_RGB48_BIG: + case B_RGB30: case B_RGB30_BIG: case B_YCbCr422: case B_YCbCr411: case B_YCbCr444: case B_YCbCr420: case B_YUV422: case B_YUV411: case B_YUV444: case B_YUV420: case B_UVL24: case B_UVL32: case B_UVLA32: diff --git a/src/preferences/screen/ScreenMode.cpp b/src/preferences/screen/ScreenMode.cpp index 8564758a76..48ae360aab 100644 --- a/src/preferences/screen/ScreenMode.cpp +++ b/src/preferences/screen/ScreenMode.cpp @@ -130,7 +130,8 @@ int32 screen_mode::BitsPerPixel() const { switch (space) { - case B_RGB32: return 32; + case B_RGB30: return 30; + case B_RGB32: return 24; case B_RGB24: return 24; case B_RGB16: return 16; case B_RGB15: return 15; diff --git a/src/preferences/screen/ScreenWindow.cpp b/src/preferences/screen/ScreenWindow.cpp index 76cde13557..ee8f1346e3 100644 --- a/src/preferences/screen/ScreenWindow.cpp +++ b/src/preferences/screen/ScreenWindow.cpp @@ -76,14 +76,14 @@ const char* kBackgroundsSignature = "application/x-vnd.Haiku-Backgrounds"; // list of officially supported colour spaces static const struct { color_space space; - int32 bits_per_pixel; const char* label; } kColorSpaces[] = { - { B_CMAP8, 8, B_TRANSLATE("8 bits/pixel, 256 colors") }, - { B_RGB15, 15, B_TRANSLATE("15 bits/pixel, 32768 colors") }, - { B_RGB16, 16, B_TRANSLATE("16 bits/pixel, 65536 colors") }, - { B_RGB24, 24, B_TRANSLATE("24 bits/pixel, 16 Million colors") }, - { B_RGB32, 32, B_TRANSLATE("32 bits/pixel, 16 Million colors") } + { B_CMAP8, B_TRANSLATE("8 bits/pixel, 256 colors") }, + { B_RGB15, B_TRANSLATE("15 bits/pixel, 32768 colors") }, + { B_RGB16, B_TRANSLATE("16 bits/pixel, 65536 colors") }, + { B_RGB24, B_TRANSLATE("24 bits/pixel, 16 million colors") }, + { B_RGB32, B_TRANSLATE("24 bits/pixel, 16 million colors") }, + { B_RGB30, B_TRANSLATE("30 bits/pixel, 1 billion colors") } }; static const int32 kColorSpaceCount = B_COUNT_OF(kColorSpaces); @@ -396,7 +396,6 @@ ScreenWindow::ScreenWindow(ScreenSettings* settings) continue; BMessage* message = new BMessage(POP_COLORS_MSG); - message->AddInt32("bits_per_pixel", kColorSpaces[i].bits_per_pixel); message->AddInt32("space", kColorSpaces[i].space); BMenuItem* item = new BMenuItem(kColorSpaces[i].label, message); diff --git a/src/servers/app/drawing/HWInterface.cpp b/src/servers/app/drawing/HWInterface.cpp index f335662322..d16ecd68b8 100644 --- a/src/servers/app/drawing/HWInterface.cpp +++ b/src/servers/app/drawing/HWInterface.cpp @@ -650,6 +650,27 @@ HWInterface::_CopyToFront(uint8* src, uint32 srcBPR, int32 x, int32 y, break; } + case B_RGB30: + { + dst += y * dstBPR + x * 4; + for (; y <= bottom; y++) { + uint32* srcHandle = (uint32*)dst; + uint32* dstHandle = (uint32*)src; + for (int32 left = x; left <= right; left++, srcHandle++, dstHandle++) { + uint32 r = (*dstHandle) & 0xff; + uint32 g = (*dstHandle >> 8) & 0xff; + uint32 b = (*dstHandle >> 16) & 0xff; + *srcHandle = ((r * 1023) / 255) + | (((g * 1023) / 255) << 10) + | (((b * 1023) / 255) << 20); + } + + src += srcBPR; + dst += dstBPR; + } + break; + } + case B_RGB24: { // offset to left top pixel in dest buffer diff --git a/src/system/boot/platform/efi/video.cpp b/src/system/boot/platform/efi/video.cpp index 969e77f693..88faaf0e8b 100644 --- a/src/system/boot/platform/efi/video.cpp +++ b/src/system/boot/platform/efi/video.cpp @@ -177,9 +177,10 @@ platform_init_video(void) TRACE(("looking for best graphics mode...\n")); + size_t depth = 0, bytes_per_row = 0; + efi_graphics_output_mode_information *info = NULL; for (size_t mode = 0; mode < sGraphicsOutput->Mode->MaxMode; ++mode) { - efi_graphics_output_mode_information *info; - size_t size, depth; + size_t size; sGraphicsOutput->QueryMode(sGraphicsOutput, mode, &size, &info); size_t area = info->HorizontalResolution * info->VerticalResolution; TRACE((" mode: %lu\n", mode)); @@ -191,6 +192,12 @@ platform_init_video(void) } else if (info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) { // seen this in the wild, but acts like RGB, go figure... depth = 32; + } else if (info->PixelFormat == PixelBitMask + && info->PixelInformation.RedMask == 0x3FF00000 + && info->PixelInformation.GreenMask == 0x000FFC00 + && info->PixelInformation.BlueMask == 0x000003FF + && info->PixelInformation.ReservedMask == 0xC0000000) { + depth = 30; } else if (info->PixelFormat == PixelBitMask && info->PixelInformation.RedMask == 0xFF0000 && info->PixelInformation.GreenMask == 0x00FF00 @@ -210,13 +217,15 @@ platform_init_video(void) } TRACE((" depth: %lu\n", depth)); + bytes_per_row = info->PixelsPerScanLine * ((depth + 7) / 8); + video_mode *videoMode = (video_mode*)malloc(sizeof(struct video_mode)); if (videoMode != NULL) { videoMode->mode = mode; videoMode->width = info->HorizontalResolution; videoMode->height = info->VerticalResolution; videoMode->bits_per_pixel = depth; - videoMode->bytes_per_row = info->PixelsPerScanLine * depth / 8; + videoMode->bytes_per_row = bytes_per_row; add_video_mode(videoMode); } @@ -237,6 +246,10 @@ platform_init_video(void) } gKernelArgs.frame_buffer.enabled = true; + gKernelArgs.frame_buffer.depth = depth; + gKernelArgs.frame_buffer.width = info->HorizontalResolution; + gKernelArgs.frame_buffer.height = info->VerticalResolution; + gKernelArgs.frame_buffer.bytes_per_row = bytes_per_row; sModeChosen = false; sSettingsLoaded = false; @@ -268,15 +281,6 @@ platform_switch_to_logo(void) sGraphicsOutput->Mode->FrameBufferBase; gKernelArgs.frame_buffer.physical_buffer.size = sGraphicsOutput->Mode->FrameBufferSize; - gKernelArgs.frame_buffer.width = - sGraphicsOutput->Mode->Info->HorizontalResolution; - gKernelArgs.frame_buffer.height = - sGraphicsOutput->Mode->Info->VerticalResolution; - gKernelArgs.frame_buffer.depth = - sGraphicsOutput->Mode->Info->PixelFormat == PixelBitMask ? 24 : 32; - gKernelArgs.frame_buffer.bytes_per_row = - sGraphicsOutput->Mode->Info->PixelsPerScanLine - * gKernelArgs.frame_buffer.depth / 8; video_display_splash(gKernelArgs.frame_buffer.physical_buffer.start); } diff --git a/src/system/kernel/debug/frame_buffer_console.cpp b/src/system/kernel/debug/frame_buffer_console.cpp index 015d8c6c91..250fa70fb3 100644 --- a/src/system/kernel/debug/frame_buffer_console.cpp +++ b/src/system/kernel/debug/frame_buffer_console.cpp @@ -78,8 +78,7 @@ static uint16 sPalette16[] = { // bbbbbggggggrrrrr (5-6-5) 0xffff, 0x3333, 0x4cc0, 0x04d3, 0xc800, 0x722f, 0xdd40, 0x0000, }; -static uint32 sPalette32[] = { - // is also used by 24 bit modes +static uint32 sPalette24[] = { 0xffffff, // white 0x336698, // blue 0x4e9a00, // green @@ -89,6 +88,16 @@ static uint32 sPalette32[] = { 0xdaa800, // yellow 0x000000, // black }; +static uint32 sPalette30[] = { + 0x3fcff3fc, // white + 0x0cc66260, // blue + 0x1389a000, // green + 0x01898268, // cyan + 0x33000000, // red + 0x1cc441ec, // magenta + 0x368a8000, // yellow + 0x00000000, // black +}; static struct console_info sConsole; @@ -122,8 +131,10 @@ get_palette_entry(uint8 index) return (uint8*)&sPalette15[index]; case 16: return (uint8*)&sPalette16[index]; + case 30: + return (uint8*)&sPalette30[index]; default: - return (uint8*)&sPalette32[index]; + return (uint8*)&sPalette24[index]; } } diff --git a/src/tests/kits/interface/bbitmap/BBitmapTester.cpp b/src/tests/kits/interface/bbitmap/BBitmapTester.cpp index 0215bb0d38..7a0a48a60d 100644 --- a/src/tests/kits/interface/bbitmap/BBitmapTester.cpp +++ b/src/tests/kits/interface/bbitmap/BBitmapTester.cpp @@ -49,6 +49,7 @@ get_bytes_per_row(color_space colorSpace, int32 width) case B_HSV32: case B_HSVA32: case B_HLS32: case B_HLSA32: case B_CMY32: case B_CMYA32: case B_CMYK32: + case B_RGB30: case B_RGB30_BIG: bpr = 4 * width; break; case B_RGB24: case B_RGB24_BIG: