From e40f8abe2c190a3874580733d356bc94a30f07d5 Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 11 Mar 2026 02:56:43 +0300 Subject: [PATCH 1/3] docs: update WindowProvider to logical points (DIP) after RETINA refactor Size() now returns logical points, not physical pixels. Updated interface docs, NullWindowProvider, CHANGELOG, README examples. --- CHANGELOG.md | 12 +++++++++++- README.md | 22 +++++++++++++++------- window.go | 35 ++++++++++++++++++----------------- 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9f8fb8..cf761c6 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). +## [Unreleased] + +### Changed + +- **WindowProvider.Size()** now documented as returning logical points (DIP) instead of physical pixels + - Aligns with gogpu RETINA refactor: `App.Size()` returns logical coordinates + - Physical pixel dimensions = `Size() * ScaleFactor()` + - `NullWindowProvider` fields W/H updated to logical points + - README examples updated for HiDPI-aware rendering pattern + ## [0.9.0] - 2026-02-10 ### Added @@ -22,7 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - **WindowProvider interface** for window geometry and DPI integration - - `Size() (width, height int)` — window client area in physical pixels + - `Size() (width, height int)` — window client area in logical points (DIP) - `ScaleFactor() float64` — DPI scale factor (1.0 = standard, 2.0 = Retina/HiDPI) - `RequestRedraw()` — request a new frame in on-demand rendering mode - `NullWindowProvider` — configurable defaults for testing and headless operation diff --git a/README.md b/README.md index 96a842d..50c03aa 100644 --- a/README.md +++ b/README.md @@ -86,18 +86,26 @@ func (app *App) HalDevice() any { return app.halDevice } func (app *App) HalQueue() any { return app.halQueue } ``` -### WindowProvider (for UI frameworks) +### WindowProvider (for UI frameworks and rendering libraries) -The `WindowProvider` interface enables UI frameworks to query window dimensions and DPI: +The `WindowProvider` interface enables UI frameworks and rendering libraries to query +window dimensions (logical points) and DPI scale factor: ```go // In gogpu/ui - uses WindowProvider for layout func (ui *UI) Layout(wp gpucontext.WindowProvider) { - w, h := wp.Size() - scale := wp.ScaleFactor() - dpW := float64(w) / scale - dpH := float64(h) / scale - ui.root.Layout(dpW, dpH) + w, h := wp.Size() // logical points (DIP) + scale := wp.ScaleFactor() // 2.0 on Retina + ui.root.Layout(w, h, scale) +} + +// In gg/ggcanvas - auto-detects HiDPI from provider +func New(provider gpucontext.DeviceProvider, w, h int) (*Canvas, error) { + scale := 1.0 + if wp, ok := provider.(gpucontext.WindowProvider); ok { + scale = wp.ScaleFactor() + } + // allocate pixmap at physical resolution: w*scale x h*scale } ``` diff --git a/window.go b/window.go index cdc15c7..9c0fc67 100644 --- a/window.go +++ b/window.go @@ -5,33 +5,34 @@ package gpucontext // WindowProvider provides window geometry and DPI information. // -// This interface enables UI frameworks (like gogpu/ui) to query window -// dimensions and scale factor for layout calculations in density-independent -// pixels (Dp), and to request redraws for on-demand rendering. +// This interface enables UI frameworks (like gogpu/ui) and rendering +// libraries (like gg/ggcanvas) to query window dimensions and scale factor +// for HiDPI-aware layout and rendering. +// +// Size() returns logical points (DIP — density-independent pixels). +// To get physical pixel dimensions, multiply by ScaleFactor(): +// +// physW := int(float64(w) * scale) // // Implementations: // - gogpu.App implements WindowProvider via platform window +// - gogpu.gpuContextAdapter implements WindowProvider (returned by GPUContextProvider) // - NullWindowProvider provides configurable defaults for testing // -// Example usage in a UI framework: +// Example usage: // // func (ui *UI) Layout(wp gpucontext.WindowProvider) { -// w, h := wp.Size() -// scale := wp.ScaleFactor() -// dpW := float64(w) / scale -// dpH := float64(h) / scale -// ui.root.Layout(dpW, dpH) +// w, h := wp.Size() // logical points +// scale := wp.ScaleFactor() // 2.0 on Retina +// ui.root.Layout(w, h, scale) // } -// -// Note: This interface is designed for gogpu <-> ui integration. -// The rendering library (gg) does NOT use this interface. type WindowProvider interface { - // Size returns the current window client area dimensions in physical pixels. + // Size returns the current window client area dimensions in logical points (DIP). + // On HiDPI displays, multiply by ScaleFactor() to get physical pixel dimensions. Size() (width, height int) // ScaleFactor returns the DPI scale factor. // 1.0 = standard (96 DPI on Windows, 72 on macOS), 2.0 = Retina/HiDPI. - // Used to convert between physical pixels and density-independent pixels (Dp). ScaleFactor() float64 // RequestRedraw requests the host to render a new frame. @@ -48,13 +49,13 @@ type WindowProvider interface { // Example: // // wp := gpucontext.NullWindowProvider{W: 800, H: 600, SF: 2.0} -// w, h := wp.Size() // 800, 600 +// w, h := wp.Size() // 800, 600 (logical points) // scale := wp.ScaleFactor() // 2.0 type NullWindowProvider struct { - // W is the window width in physical pixels. + // W is the window width in logical points (DIP). W int - // H is the window height in physical pixels. + // H is the window height in logical points (DIP). H int // SF is the DPI scale factor. When zero, ScaleFactor returns 1.0. From 1ba2cc3cab48f9d7e7d0667ac1ca7ca48ddce38f Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 15 Mar 2026 02:09:10 +0300 Subject: [PATCH 2/3] refactor: remove HalProvider, typed Device/Queue interfaces (zero any) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING: HalProvider interface deleted. HalDevice()/HalQueue() with any returns removed entirely. Device, Queue, Adapter, Surface, Instance converted to minimal type-token interfaces. Enables Go implicit interface satisfaction — *wgpu.Device implements gpucontext.Device without gpucontext importing wgpu. Pattern: accept interfaces, return structs (Go standard library pattern). Consumers type-assert to *wgpu.Device when they need full API access. Zero any in the device provider chain. --- CHANGELOG.md | 11 +++++ README.md | 29 ++++++------ hal_provider.go | 27 ----------- webgpu_types.go | 117 ++++++++++++++++++++---------------------------- 4 files changed, 73 insertions(+), 111 deletions(-) delete mode 100644 hal_provider.go diff --git a/CHANGELOG.md b/CHANGELOG.md index cf761c6..4066a1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Removed + +- **HalProvider interface DELETED** — `HalDevice() any` and `HalQueue() any` removed entirely. + Replaced by typed pattern: `provider.Device()` returns `gpucontext.Device`, consumers + type-assert to `*wgpu.Device` for full API access. Zero `any` in the device provider chain. + Go "accept interfaces, return structs" pattern. + ### Changed +- **Device, Queue, Adapter, Surface, Instance** interfaces in webgpu_types.go converted to + minimal type-token interfaces. Enables implicit Go interface satisfaction — `*wgpu.Device` + implements `gpucontext.Device` without gpucontext importing wgpu. + - **WindowProvider.Size()** now documented as returning logical points (DIP) instead of physical pixels - Aligns with gogpu RETINA refactor: `App.Size()` returns logical coordinates - Physical pixel dimensions = `Size() * ScaleFactor()` diff --git a/README.md b/README.md index 50c03aa..05df2bc 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,7 @@ go get github.com/gogpu/gpucontext ## Features -- **DeviceProvider** — Interface for injecting GPU device and queue -- **HalProvider** — Optional direct access to HAL device/queue for GPU accelerators +- **DeviceProvider** — Interface for injecting GPU device and queue (typed, zero `any`) - **WindowProvider** — Window geometry, DPI scale factor, and redraw requests - **PlatformProvider** — Clipboard, cursor, dark mode, and accessibility preferences - **CursorShape** — 12 standard cursor shapes (arrow, pointer, text, resize, etc.) @@ -66,26 +65,26 @@ func NewGPUCanvas(provider gpucontext.DeviceProvider) *Canvas { } ``` -### HalProvider (for GPU accelerators) +### Device Sharing (typed, zero `any`) -`HalProvider` is an optional interface on `DeviceProvider` that exposes low-level HAL types. -This enables GPU accelerators (like gg's SDF pipeline) to share the host device without creating their own: +GPU accelerators (like gg's SDF pipeline) share the host device via typed interfaces: ```go -// In gogpu/gg - GPU accelerator checks for HAL access +// Consumer gets typed device from provider func (a *SDFAccelerator) SetDeviceProvider(dp gpucontext.DeviceProvider) { - if hp, ok := dp.(gpucontext.HalProvider); ok { - device := hp.HalDevice().(hal.Device) - queue := hp.HalQueue().(hal.Queue) - a.initWithSharedDevice(device, queue) + dev := dp.Device() // gpucontext.Device (minimal interface) + wgpuDev, ok := dev.(*wgpu.Device) // type assert for full wgpu API + if ok { + a.initWithSharedDevice(wgpuDev) } } - -// In gogpu/gogpu - implements HalProvider -func (app *App) HalDevice() any { return app.halDevice } -func (app *App) HalQueue() any { return app.halQueue } ``` +The pattern follows Go's "accept interfaces, return structs": +- `gpucontext.Device` — minimal interface (type token) +- `*wgpu.Device` — concrete type, satisfies `gpucontext.Device` implicitly +- Consumer type-asserts when it needs the full API + ### WindowProvider (for UI frameworks and rendering libraries) The `WindowProvider` interface enables UI frameworks and rendering libraries to query @@ -290,7 +289,7 @@ names := backends.Available() // ["vulkan", "software"] ▼ gpucontext (imports gputypes) - DeviceProvider, HalProvider, + DeviceProvider, WindowProvider, PlatformProvider, EventSource, Texture, Registry │ diff --git a/hal_provider.go b/hal_provider.go deleted file mode 100644 index 9650925..0000000 --- a/hal_provider.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2026 The gogpu Authors -// SPDX-License-Identifier: MIT - -package gpucontext - -// HalProvider is an optional interface for DeviceProviders that can expose -// low-level HAL types directly. This enables GPU accelerators to share -// devices without creating their own. -// -// The returned any values are hal.Device and hal.Queue from wgpu/hal. -// Consumers type-assert to the concrete hal types they need. -// -// Example usage: -// -// if hp, ok := provider.(gpucontext.HalProvider); ok { -// device := hp.HalDevice().(hal.Device) -// queue := hp.HalQueue().(hal.Queue) -// } -type HalProvider interface { - // HalDevice returns the underlying HAL device for direct GPU access. - // Returns nil if HAL access is not available. - HalDevice() any - - // HalQueue returns the underlying HAL queue for direct GPU access. - // Returns nil if HAL access is not available. - HalQueue() any -} diff --git a/webgpu_types.go b/webgpu_types.go index cdbcf9c..89b33dc 100644 --- a/webgpu_types.go +++ b/webgpu_types.go @@ -3,85 +3,64 @@ package gpucontext -// WebGPU Interface Definitions for Cross-Package Sharing +// WebGPU Type Token Interfaces for Cross-Package Sharing // -// This file defines interfaces that are implemented by wgpu/hal -// and used by consumers like gg, gogpu, and born-ml. +// This file defines type token interfaces for GPU objects (Device, Queue, etc.) +// that enable type-safe dependency injection between packages without coupling +// them to a specific GPU implementation. // -// Types (TextureFormat, BufferUsage, etc.) are in gputypes package. -// Interfaces (Device, Queue, etc.) are defined here as behavioral contracts. +// Concrete types (e.g., *wgpu.Device) satisfy these empty interfaces implicitly. +// Consumers type-assert to the concrete type when they need the full API. // -// Users should import both packages: +// Types (TextureFormat, BufferUsage, etc.) are in the gputypes package. +// +// Usage: // // import ( // "github.com/gogpu/gpucontext" // "github.com/gogpu/gputypes" // ) -// Device represents a logical GPU device. -// Implemented by wgpu/hal.Device. -type Device interface { - // Poll processes pending operations. - Poll(wait bool) - - // Destroy releases the device resources. - Destroy() -} - -// Queue represents a GPU command queue. -// Implemented by wgpu/hal.Queue. -type Queue interface { - // Submit submits command buffers for execution. - // Submit(commandBuffers []CommandBuffer) - - // WriteBuffer writes data to a buffer. - // WriteBuffer(buffer Buffer, offset uint64, data []byte) - - // WriteTexture writes data to a texture. - // WriteTexture(destination gputypes.ImageCopyTexture, data []byte, layout gputypes.TextureDataLayout, size gputypes.Extent3D) -} - -// Adapter represents a physical GPU. -// Implemented by wgpu/hal.Adapter. -type Adapter interface { - // RequestDevice requests a logical device from this adapter. - // RequestDevice(descriptor gputypes.DeviceDescriptor) (Device, Queue, error) - - // GetInfo returns information about this adapter. - // GetInfo() gputypes.AdapterInfo - - // Features returns the features supported by this adapter. - // Features() gputypes.Features - - // Limits returns the limits of this adapter. - // Limits() gputypes.Limits -} - -// Surface represents a rendering surface (window). -// Implemented by wgpu/hal.Surface. -type Surface interface { - // Configure configures the surface for rendering. - // Configure(device Device, config gputypes.SurfaceConfiguration) - - // GetCurrentTexture gets the current texture for rendering. - // GetCurrentTexture() (SurfaceTexture, error) - - // Present presents the current frame. - // Present() -} - -// Instance is the entry point for GPU operations. -// Implemented by wgpu/hal.Instance. -type Instance interface { - // CreateSurface creates a surface for a window. - // CreateSurface(descriptor SurfaceDescriptor) (Surface, error) - - // RequestAdapter requests a GPU adapter. - // RequestAdapter(options gputypes.RequestAdapterOptions) (Adapter, error) +// Device is a type token for a logical GPU device. +// +// Concrete implementations (e.g., *wgpu.Device) satisfy this interface +// implicitly. Consumers that need the full device API should type-assert +// to the concrete type: +// +// dev := provider.Device() +// wgpuDev, ok := dev.(*wgpu.Device) +// if ok { +// halDevice := wgpuDev.HalDevice() +// } +// +// The interface is intentionally minimal to avoid coupling gpucontext +// to any specific GPU implementation. +type Device interface{} - // EnumerateAdapters returns all available adapters. - // EnumerateAdapters() []Adapter -} +// Queue is a type token for a GPU command queue. +// +// Concrete implementations (e.g., *wgpu.Queue) satisfy this interface +// implicitly. Consumers that need the full queue API should type-assert +// to the concrete type: +// +// q := provider.Queue() +// wgpuQueue, ok := q.(*wgpu.Queue) +type Queue interface{} + +// Adapter is a type token for a physical GPU adapter. +// Consumers that need the full adapter API should type-assert +// to the concrete type (e.g., *wgpu.Adapter). +type Adapter interface{} + +// Surface is a type token for a rendering surface (window). +// Consumers that need the full surface API should type-assert +// to the concrete type (e.g., *wgpu.Surface). +type Surface interface{} + +// Instance is a type token for the GPU instance entry point. +// Consumers that need the full instance API should type-assert +// to the concrete type (e.g., *wgpu.Instance). +type Instance interface{} // OpenDevice bundles a device and queue together. // This is a convenience type for initialization. From ab6caa9b756da8168998a9b89cfeaad656df5d39 Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 15 Mar 2026 14:01:20 +0300 Subject: [PATCH 3/3] docs: update CHANGELOG for v0.10.0 release --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4066a1f..568cc77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.10.0] - 2026-03-15 + ### Removed - **HalProvider interface DELETED** — `HalDevice() any` and `HalQueue() any` removed entirely.