From 567db3b9ba42caee87370848663f36225c61898f Mon Sep 17 00:00:00 2001 From: Andy Date: Sat, 9 May 2026 16:08:58 +0300 Subject: [PATCH] feat: SubpixelLayout on PlatformProvider for LCD/ClearType detection (ADR-024, v0.18.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add SubpixelLayout type (None/RGB/BGR/VRGB/VBGR) and SubpixelLayout() method to PlatformProvider interface. Enables auto-detection of display subpixel arrangement for ClearType-quality font rendering in gg. Follows Qt6 QPlatformScreen pattern — subpixel is a display/OS property, not GPU. Researched Qt6, GTK4/Wayland, FreeType, DRM/KMS. NullPlatformProvider returns SubpixelNone (grayscale AA fallback). --- CHANGELOG.md | 10 ++++++++++ ROADMAP.md | 4 +++- platform.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ platform_test.go | 11 +++++----- 4 files changed, 71 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8afe119..86a2123 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.18.0] - 2026-05-09 + +### Added + +- **SubpixelLayout on PlatformProvider** (ADR-024) — `SubpixelLayout()` method returns display subpixel arrangement (`SubpixelNone`, `SubpixelRGB`, `SubpixelBGR`, `SubpixelVRGB`, `SubpixelVBGR`). Enables LCD/ClearType font rendering in gg. Follows Qt6 `QPlatformScreen::SubpixelAntialiasingType` pattern — subpixel is a display/OS property, not GPU. `NullPlatformProvider` returns `SubpixelNone` (grayscale AA). Researched Qt6, GTK4/Wayland, FreeType, DRM/KMS — all treat subpixel as platform property. + +### Fixed + +- **Lint:** extracted `stringNone` reuse for SubpixelLayout.String(). + ## [0.17.0] - 2026-05-06 ### Added diff --git a/ROADMAP.md b/ROADMAP.md index df61597..e6e957b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,8 +4,10 @@ `gpucontext` is the shared foundation for the [gogpu](https://github.com/gogpu) ecosystem, providing interfaces and utilities for GPU resource sharing without circular dependencies. -## Current: v0.16.0 +## Current: v0.18.0 +- SubpixelLayout on PlatformProvider (ADR-024, LCD/ClearType auto-detection) +- AdapterInfo on DeviceProvider (ADR-020, render mode auto-selection) - WindowChrome.SetFullscreen / IsFullscreen (ADR-018, runtime fullscreen toggle) - CursorMode (Locked/Confined/Normal) for mouse grab / pointer lock - PointerEvent.DeltaX/DeltaY for relative mouse movement diff --git a/platform.go b/platform.go index 152fb96..509c548 100644 --- a/platform.go +++ b/platform.go @@ -50,6 +50,55 @@ type PlatformProvider interface { // FontScale returns the user's font size preference multiplier. // 1.0 = default system font size. Used to scale Sp (scale-independent pixels). FontScale() float32 + + // SubpixelLayout returns the display's subpixel arrangement for LCD text rendering. + // Used by 2D graphics libraries (gg) to enable ClearType-quality font rendering. + // Returns SubpixelNone when subpixel info is unavailable or on HiDPI displays + // where subpixels are too small to be visible. + SubpixelLayout() SubpixelLayout +} + +// SubpixelLayout describes the physical arrangement of RGB subpixels on a display. +// Used for LCD/ClearType font rendering to achieve sharper text by exploiting +// the subpixel structure. Qt6 (QPlatformScreen), Wayland (wl_output.geometry), +// and DRM/KMS (drmModeConnector) all expose this as a display property. +type SubpixelLayout int + +const ( + // SubpixelNone means no subpixel information is available or applicable. + // Text rendering falls back to grayscale anti-aliasing. + // Used on HiDPI displays where subpixels are too small to exploit. + SubpixelNone SubpixelLayout = iota + + // SubpixelRGB is horizontal RGB ordering (most common: Windows LCD, most external monitors). + SubpixelRGB + + // SubpixelBGR is horizontal BGR ordering (some Samsung and older displays). + SubpixelBGR + + // SubpixelVRGB is vertical RGB ordering (rare, some rotated displays). + SubpixelVRGB + + // SubpixelVBGR is vertical BGR ordering (rare). + SubpixelVBGR +) + +// String returns the subpixel layout name for debugging. +func (s SubpixelLayout) String() string { + switch s { + case SubpixelNone: + return stringNone + case SubpixelRGB: + return "RGB" + case SubpixelBGR: + return "BGR" + case SubpixelVRGB: + return "VRGB" + case SubpixelVBGR: + return "VBGR" + default: + return "Unknown" + } } // CursorShape represents the mouse cursor shape. @@ -205,5 +254,8 @@ func (NullPlatformProvider) HighContrast() bool { return false } // FontScale returns 1.0. func (NullPlatformProvider) FontScale() float32 { return 1.0 } +// SubpixelLayout returns SubpixelNone (grayscale AA). +func (NullPlatformProvider) SubpixelLayout() SubpixelLayout { return SubpixelNone } + // Ensure NullPlatformProvider implements PlatformProvider. var _ PlatformProvider = NullPlatformProvider{} diff --git a/platform_test.go b/platform_test.go index 5701509..75f7272 100644 --- a/platform_test.go +++ b/platform_test.go @@ -141,11 +141,12 @@ func (m *mockPlatformProvider) ClipboardWrite(text string) error { m.clipboard = text return nil } -func (m *mockPlatformProvider) SetCursor(cursor CursorShape) { m.cursor = cursor } -func (m *mockPlatformProvider) DarkMode() bool { return m.darkMode } -func (m *mockPlatformProvider) ReduceMotion() bool { return m.reduceMotion } -func (m *mockPlatformProvider) HighContrast() bool { return m.highContrast } -func (m *mockPlatformProvider) FontScale() float32 { return m.fontScale } +func (m *mockPlatformProvider) SetCursor(cursor CursorShape) { m.cursor = cursor } +func (m *mockPlatformProvider) DarkMode() bool { return m.darkMode } +func (m *mockPlatformProvider) ReduceMotion() bool { return m.reduceMotion } +func (m *mockPlatformProvider) HighContrast() bool { return m.highContrast } +func (m *mockPlatformProvider) FontScale() float32 { return m.fontScale } +func (m *mockPlatformProvider) SubpixelLayout() SubpixelLayout { return SubpixelRGB } // Ensure mockPlatformProvider implements PlatformProvider. var _ PlatformProvider = &mockPlatformProvider{}