surface/registry.go
Functions
func Available
func (r *Registry) Available() []string {
r.mu.RLock()
defer r.mu.RUnlock()
return r.sortedNames(true)
}
func Available
Available returns names of all available backends sorted by priority.
func Available() []string {
return globalRegistry.Available()
}
func Error
func (e *BackendUnavailableError) Error() string {
return "surface: backend unavailable: " + e.Name
}
func Error
func (e *BackendNotFoundError) Error() string {
return "surface: backend not found: " + e.Name
}
func Get
Get returns information about a specific backend.
func (r *Registry) Get(name string) (*RegistryEntry, bool) {
r.mu.RLock()
defer r.mu.RUnlock()
entry, ok := r.entries[name]
if !ok {
return nil, false
}
// Return a copy to prevent modification
entryCopy := *entry
return &entryCopy, true
}
func Get
Get returns information about a specific backend.
func Get(name string) (*RegistryEntry, bool) {
return globalRegistry.Get(name)
}
func List
List returns all registered backend names sorted by priority.
func (r *Registry) List() []string {
r.mu.RLock()
defer r.mu.RUnlock()
return r.sortedNames(false)
}
func List
List returns all registered backend names sorted by priority (highest first).
func List() []string {
return globalRegistry.List()
}
func NewRegistry
NewRegistry creates a new empty registry.
Most code should use the global registry via Register and NewSurface.
func NewRegistry() *Registry {
return &Registry{
entries: make(map[string]*RegistryEntry),
}
}
func NewSurface
NewSurface creates a surface using the best available backend.
Returns an error if no backends are available.
func NewSurface(width, height int) (Surface, error) {
return globalRegistry.NewSurface(Options{Width: width, Height: height})
}
func NewSurface
NewSurface creates a surface using the best available backend.
func (r *Registry) NewSurface(opts Options) (Surface, error) {
r.mu.RLock()
available := r.sortedNames(true)
r.mu.RUnlock()
if len(available) == 0 {
return nil, ErrNoBackendAvailable
}
// Try each available backend in priority order
var lastErr error
for _, name := range available {
s, err := r.NewSurfaceByName(name, opts)
if err == nil {
return s, nil
}
lastErr = err
}
if lastErr != nil {
return nil, lastErr
}
return nil, ErrNoBackendAvailable
}
func NewSurfaceByName
NewSurfaceByName creates a surface using a specific named backend.
func NewSurfaceByName(name string, width, height int) (Surface, error) {
return globalRegistry.NewSurfaceByName(name, Options{Width: width, Height: height})
}
func NewSurfaceByName
NewSurfaceByName creates a surface using a specific backend.
func (r *Registry) NewSurfaceByName(name string, opts Options) (Surface, error) {
r.mu.RLock()
entry, ok := r.entries[name]
r.mu.RUnlock()
if !ok {
return nil, &BackendNotFoundError{Name: name}
}
if !entry.Available() {
return nil, &BackendUnavailableError{Name: name}
}
return entry.Factory(opts)
}
func NewSurfaceByNameWithOptions
NewSurfaceByNameWithOptions creates a surface using a specific backend.
func NewSurfaceByNameWithOptions(name string, opts Options) (Surface, error) {
return globalRegistry.NewSurfaceByName(name, opts)
}
func NewSurfaceWithOptions
NewSurfaceWithOptions creates a surface using the best available backend.
func NewSurfaceWithOptions(opts Options) (Surface, error) {
return globalRegistry.NewSurface(opts)
}
func Register
Register adds a backend to this registry.
func (r *Registry) Register(name string, priority int, factory SurfaceFactory, available func() bool) {
r.mu.Lock()
defer r.mu.Unlock()
if r.entries == nil {
r.entries = make(map[string]*RegistryEntry)
}
if available == nil {
available = func() bool { return true }
}
r.entries[name] = &RegistryEntry{
Name: name,
Priority: priority,
Factory: factory,
Available: available,
}
}
func Register
Register adds a backend to the global registry.
Parameters:
- name: unique identifier (e.g., "vulkan", "metal", "software")
- priority: selection priority (higher = preferred)
- factory: function to create surface instances
- available: function to check if backend is available
If available is nil, the backend is assumed always available.
Registering a name that already exists replaces the previous entry.
func Register(name string, priority int, factory SurfaceFactory, available func() bool) {
globalRegistry.Register(name, priority, factory, available)
}
func Unregister
Unregister removes a backend from this registry.
func (r *Registry) Unregister(name string) {
r.mu.Lock()
defer r.mu.Unlock()
delete(r.entries, name)
}
func Unregister
Unregister removes a backend from the global registry.
func Unregister(name string) {
globalRegistry.Unregister(name)
}
Structs
type RegistryEntry struct
RegistryEntry represents a registered surface backend.
type RegistryEntry struct {
// Name is the unique identifier for this backend.
Name string
// Priority determines selection order (higher = preferred).
// Standard priorities:
// - 100: GPU backends (Vulkan, Metal, D3D12)
// - 50: Hardware-accelerated software (WARP)
// - 10: Pure software backends
Priority int
// Factory creates surface instances.
Factory SurfaceFactory
// Available reports if the backend is available on this system.
// This is called during registration and cached.
Available func() bool
}
type Registry struct
Registry manages registered surface backends.
The registry enables third-party backends to register themselves
without requiring changes to the core library (RFC #46).
Example registration:
func init() {
surface.Register("vulkan", 100, vulkanFactory, vulkanAvailable)
}
Example usage:
s, err := surface.NewSurfaceByName("vulkan", 800, 600)
// or auto-select best available:
s, err := surface.NewSurface(800, 600)
type Registry struct {
mu sync.RWMutex
entries map[string]*RegistryEntry
}
type BackendNotFoundError struct
BackendNotFoundError indicates a named backend is not registered.
type BackendNotFoundError struct {
Name string
}
Available returns names of all available backends sorted by priority.