Two browser rendering components land in sigil-video 5460b56. webgl.sg is the WebGL 1.0 stub — it lets web content detect WebGL support and draw triangles today, with GPU paths silicon-pending. comp_dirty.sg brings a tile-level dirty-rect compositor that only pushes changed 64×64 tiles to the GPU, cutting browser repaint cost on Pi 3 hardware. Both follow GPU-first: GPU paths wired and silicon-pending; software floors (triangle bounding-box fill_span / tile-skip composite) work on Pi 3 and QEMU now. WEBGL-DIRTY-PASS: 1 triangle → bbox fill → pixel probe; tile dirty mark + composite; untouched tile delta=0.
webgl.sg — WebGL 1.0 stub
Web content today feature-detects WebGL before deciding whether to use it. Without WebGL support, many sites fall back to 2D canvas or refuse to render entirely. webgl.sg gives the sigilOS browser a real WebGL context — enough for feature detection, basic triangle draw, and gradual GPU path integration as the hardware validates.
The design is GPU-first per the GPU_FIRST_RENDERING standing rule. The GPU path (gpu_submit(CAP_ACCEL, webgl_ctx_buf(), fb, fw, fh)) is wired and stubbed pending silicon. The software floor draws triangles via bounding-box fill_span — exact for convex shapes, correct for web content that uses triangles for UI primitives, progress bars, and simple geometry.
Context memory: webgl_ctx_buf() at 0xA30000 (after css_xform_buf at 0xA10000 + 384B and img_desc_buf at 0xA20000 + 512B). 4 context slots × 64 bytes.
WebGL context API
slot (up to 4 contexts). Associates with framebuffer fb at width fw × height fh. GPU path: allocates a VRAM-backed context. SW floor: records the fb pointer.verts is an array of (x,y) pairs in screen coordinates; nv is the vertex count. GPU path: DMA upload to vertex buffer. SW floor: copies into the context's vertex store.type: VERTEX or FRAGMENT. Returns 0 (success) always on SW floor — no runtime shader evaluation yet. GPU path: compiles GLSL on the silicon shader core.draw_arrays calls on this context.count vertices starting at first. Mode GL_TRIANGLES: bounding-box fill. SW floor: finds min/max x,y from the vertex array, fills the box with fill_span in the current color. GPU path: gpu_submit with draw call. Triangle bounding-box is exact for right-angle / screen-aligned triangles; sufficient for initial web content compat.comp_dirty.sg — tile-level dirty-rect compositor
The browser compositor (compositor.sg, COMP-PASS 16997fc) does layer-level dirty tracking — it skips compositing entire layers when unchanged. comp_dirty.sg adds a finer grain: tile-level dirty tracking within a single layer. A 1280×720 display has 200 × 112 = 22,400 tiles of 64×64px. A text cursor blink touches 1 tile. Scrolling touches maybe 20 tiles on one side. Without tile tracking, every repaint pushes the full framebuffer — ~3.5 MB for 1280×720 RGBA32. With tile tracking, only changed tiles go to the GPU.
The tile model is the same as SRDX encode: 64×64px tiles, ceiling division ((w + 63) / 64). This is not coincidental — dirty-rect browser repaint and SRDX pixel stream share the same tile math so the SRDX encoder can directly consume browser repaint output without an extra copy.
API
w × h pixels. Computes ntiles_x = (w+63)/64, ntiles_y = (h+63)/64. Zeros all dirty flags at comp_tile_dirty_buf() (0xA40000 — 1 byte per tile, up to 256×256 tiles = 64KB).tx, row ty as dirty. Single byte write: comp_tile_dirty_buf() + ty * ntiles_x + tx = 1.x/64 .. (x+w-1)/64) and marks each. Used by the renderer when it knows which DOM element changed.src tile data to fb (blit 64×64 pixels or partial tile at edges). GPU path: gpu_submit(CAP_ACCEL, comp_tile_dirty_buf(), fb, fw, fh) — GPU compositor reads the dirty bitmap and batches tile transfers. SW floor: copy_span per row of each dirty tile. Clears dirty flags after composite.WEBGL-DIRTY-PASS — test results
| Check | What it verifies |
|---|---|
gl_ctx_create | Context slot 0 initialized (160×120 test canvas) |
gl_buffer_data | 3 vertices uploaded (triangle at (10,10), (50,10), (30,40)) |
gl_set_color red | Color set to (255,0,0,255) |
gl_draw_arrays triangle | SW floor: bounding box (10,10)→(50,40) filled red |
| pixel probe (30,25) | In triangle bbox → red pixel confirmed |
comp_dirty_mark (1,0) | Tile at column 1, row 0 marked dirty |
comp_dirty_composite | Only tile (1,0) pushed to fb; tile (0,0) skipped |
| tile (1,0) blue pixel | Dirty tile composited with blue test pattern |
| tile (0,0) untouched | delta=0 — unchanged tile not pushed |
PASS: WEBGL-DIRTY-PASS webgl=ok dirty=ok delta=0