Skip to content

Video Driver Architecture

opencode-agent[bot] edited this page May 9, 2026 · 1 revision

Video Driver Architecture

JNode's video driver subsystem provides a framebuffer abstraction layer that enables hardware-accelerated and software-rendered 2D graphics through the Surface and FrameBufferAPI interfaces.

Overview

The video driver architecture sits at the lowest level of JNode's GUI stack, providing direct access to the graphics hardware through a layered design. At the top level, applications interact with Java AWT graphics that ultimately delegate to Surface objects. Each Surface wraps either a physical video device (framebuffer) or an in-memory image buffer.

Location: gui/src/driver/org/jnode/driver/video/

Key Components

Class/File Package Purpose
Surface org.jnode.driver.video Interface defining a paintable 2D surface
AbstractSurface org.jnode.driver.video.util Generic Surface implementation with shape rendering
FrameBufferAPI org.jnode.driver.video Interface for framebuffer device discovery and configuration
AbstractFrameBufferDriver org.jnode.driver.video Base driver class implementing FrameBufferAPI
VESADriver / VESACore org.jnode.driver.video.vesa VBE-compliant framebuffer driver
NVidiaAcceleration org.jnode.driver.video.nvidia Hardware acceleration for NVidia GPUs
RadeonAcceleration org.jnode.driver.video.ati.radeon Hardware acceleration for ATI/AMD GPUs
BitmapGraphics org.jnode.awt.util Low-level pixel manipulation on video RAM

The Surface Interface

Surface (gui/src/driver/org/jnode/driver/video/Surface.java) is the central abstraction for a paintable region. It defines methods for:

  • Shape operations: draw(Shape, ...) and fill(Shape, ...) with AffineTransform, clipping, and color
  • Region copying: copyArea(x, y, w, h, dx, dy) for blitting
  • Image rendering: drawCompatibleRaster(...) and drawAlphaRaster(...) for bitmap blitting
  • Pixel access: getRGBPixel / setRGBPixel / getRGBPixels for direct pixel manipulation
  • Screen update: update(x, y, w, h) flushes changes to the display

Rendering modes are defined as constants:

  • PAINT_MODE (0x00): Opaque overwrite
  • XOR_MODE (0x01): XOR blend with existing pixels

AbstractSurface

AbstractSurface (org.jnode.driver.video.util/AbstractSurface.java) provides the generic rendering engine:

  • Bresenham line drawing in drawLine(x1, y1, x2, y2, color, mode)
  • PathIterator traversal for arbitrary shape rendering
  • Bezier and quadratic curves via the Curves utility
  • Rectangle optimization for axis-aligned rectangles (via fillRect)
  • drawPixel and convertColor are abstract — subclasses implement device-specific pixel writing and color conversion

The fill algorithm decomposes arbitrary shapes by iterating pixel coordinates and using shape.contains(x, y), which is efficient for convex shapes but can be slow for complex paths.

// Simplified fill logic
Rectangle bounds = shape.getBounds();
for (int row = 0; row < bounds.height; row++) {
    for (int col = 0; col < bounds.width; col++) {
        int x = bounds.x + col;
        int y = bounds.y + row;
        if (shape.contains(x, y) && (clip == null || clip.contains(x, y))) {
            drawPixel(x, y, color, mode);
        }
    }
}

FrameBufferAPI and Driver Model

FrameBufferAPI defines how framebuffer devices expose their capabilities:

public interface FrameBufferAPI extends DeviceAPI {
    FrameBufferConfiguration[] getConfigurations();
    FrameBufferConfiguration getCurrentConfiguration();
    Surface open(FrameBufferConfiguration config) throws ...;
    boolean isOpen();
    void requestOwnership(FrameBufferAPIOwner owner);
    void releaseOwnership(FrameBufferAPIOwner owner);
    Surface getCurrentSurface() throws NotOpenException;
}

AbstractFrameBufferDriver extends Driver and implements FrameBufferAPI:

  • Registers itself as FrameBufferAPI in startDevice()
  • Renames the device to fb-<deviceId> via DeviceManager
  • Manages a stack of FrameBufferAPIOwner instances for exclusive access
  • requestOwnership pushes the new owner and notifies the previous owner via ownershipLost()
  • releaseOwnership pops the stack and notifies the new top via ownershipGained()

VESA Driver

VESADriver extends AbstractFrameBufferDriver:

  • Reads VBE info blocks (VbeInfoBlock, ModeInfoBlock) from BIOS memory mapped at boot
  • Creates a VESACore that extends AbstractSurface and implements HardwareCursorAPI
  • VESACore claims video RAM via ResourceManager.claimMemoryResource()
  • Supports 8/16/24/32 bpp modes with different BitmapGraphics implementations per depth
  • The actual pixel operations delegate to BitmapGraphics which performs byte/short/int writes to video RAM
public final void drawPixel(int x, int y, int color, int mode) {
    bitmapGraphics.drawPixels(x, y, 1, color, mode);
}

Hardware Acceleration

Hardware acceleration is plugged in via device-specific *Acceleration classes:

NVidiaAcceleration

NVidiaAcceleration (gui/src/driver/org/jnode/driver/video/nvidia/NVidiaAcceleration.java) drives NVidia GPU acceleration:

  • Uses MMIO (Memory-Mapped I/O) via NVidiaVgaIO to access GPU registers
  • Programs the PFIFO command queue (256 32-bit words) for 2D operations
  • Key operations:
    • setupRectangle(color) / fillRectangle(x, y, w, h) — rectangle fills
    • setupInvertRectangle() / invertRectangle(x, y, w, h) — XOR inversion
    • accInit(...) — initializes the graphics engine, context tables, tile/pitch registers
  • Supports NV04, NV10, NV20, NV30 architectures

RadeonAcceleration

RadeonAcceleration (gui/src/driver/org/jnode/driver/video/ati/radeon/RadeonAcceleration.java) provides ATI/AMD GPU acceleration:

  • Uses register MMIO via RadeonVgaIO
  • Programs the CP (Command Processor) FIFO
  • Key operations:
    • screenToScreenCopy(srcX, srcY, w, h, dstX, dstY) — fast blit using DP_MIX with ROP3_SRCCOPY

Pattern: Acceleration classes are separate from the Surface

Unlike VESA (where VESACore IS the Surface), hardware-accelerated drivers like NVidia and Radeon separate acceleration logic:

  • NVidiaCore / RadeonCore extends AbstractSurface for rendering
  • NVidiaAcceleration / RadeonAcceleration provides the low-level GPU programming
  • The acceleration object is typically held as a field in the Core class and called from within overridden methods

Hardware Cursor

HardwareCursorAPI extends the framebuffer with cursor support:

public interface HardwareCursorAPI extends DeviceAPI {
    void setCursorPosition(int x, int y);
    void setCursorVisible(boolean visible);
    void setCursorImage(HardwareCursor cursor);
}
  • SoftwareCursor wraps BitmapGraphics with software cursor rendering (sprite over surface)
  • Hardware cursor support is provided by NVidiaHardwareCursor, RadeonHardwareCursor which program the GPU's cursor sprite registers

Gotchas

  1. VESA driver requires GRUB to set the video mode — if GRUB hasn't switched to a VBE mode, VESADriver.startDevice() throws "grub haven't switched to graphic mode".

  2. AbstractSurface pixel iteration is slow for complex shapes — the fill(Shape, ...) method checks every pixel in the bounding box. Complex shapes with many interior points can be expensive.

  3. Ownership stack is LIFOrequestOwnership pushes on a stack; multiple owners can chain, with the new owner displacing the old one.

  4. BitmapGraphics depth switchesVESACore creates different BitmapGraphics subclasses per bit depth (8/16/24/32). The convertColor method must handle each depth's pixel format.

  5. NVidia acceleration needs architecture detectionNVidiaAcceleration checks architecture >= NV10A or >= NV20A to use different register sets, requiring careful handling of legacy NV04 vs modern GPUs.

  6. FrameBufferConfiguration equalityVESADriver.open() compares configs by reference (config.equals(configs[i])); a new VESAConfiguration instance won't match the stored one.

Related Pages

Clone this wiki locally