Skip to content

Revision 2026 Partycoding#69

Open
ikskuh wants to merge 37 commits intomasterfrom
work/revision_2026
Open

Revision 2026 Partycoding#69
ikskuh wants to merge 37 commits intomasterfrom
work/revision_2026

Conversation

@ikskuh
Copy link
Copy Markdown
Contributor

@ikskuh ikskuh commented Apr 3, 2026

Summary by CodeRabbit

  • New Features

    • Slideshow app and new demo "revision2026"; demo mode can auto-launch the demo.
  • Improvements

    • New tiled rasterizer and async/background rendering with runtime rasterizer switching (Alt+F8) and perf-counter toggle.
    • VBlank-aware flushing, tighter framebuffer alignment, and improved window occlusion for cleaner rendering.
  • Tools

    • New profiling and render-analysis utilities.
  • Documentation

    • Added demoscene credits slide.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 3, 2026

Walkthrough

This PR adds a tiled rasterizer library and integrates selectable rasterizer backends (sync/async, tiled/linear) into kernel graphics, updates framebuffer alignment and rectangle APIs, adds VBlank event plumbing and demo-mode GPIO/syscall, introduces demo and slideshow apps, and adds profiling/tools and build wiring.

Changes

Cohort / File(s) Summary
Tiled rasterizer library
src/userland/libs/agp-tiled-rast/build.zig, src/userland/libs/agp-tiled-rast/build.zig.zon, src/userland/libs/agp-tiled-rast/src/tiled-raster.zig, src/userland/libs/agp-tiled-rast/test/gif.zig
New agp-tiled-rast package: tile-based renderer (64×64 tiles), command stream validation, tile-state tracking, partial-replay rendering, resolver API for fonts/framebuffers, unit tests and GIF encoder utility.
AGP & software rasterizer refactor
src/userland/libs/agp/src/agp.zig, src/userland/libs/agp-swrast/src/agp-swrast.zig, src/userland/libs/libAshetOS/module/src/libashet/graphics.zig
AGP: added BufferDecoder, OptimizingEncoder, area-of-effect helpers; swrast: replaced cursor-based API with Image/RenderTarget/Rasterizer that writes directly to memory; changed decoder/encoder APIs and added tests.
Kernel graphics & async pipeline
src/kernel/components/graphics.zig, src/kernel/components/syscalls.zig
Added RasterizerBackend enum, selected_rasterizer/use_perfctrl, render_queue + worker for async backends, render_one_task wrapper, backend dispatch (tiled vs linear), overlay enumeration, and changed invalidate_framebuffer to return errors and perform type-based invalidation.
Framebuffer alignment & GUI
src/kernel/components/gui.zig, src/userland/apps/desktop/classic/src/DamageTracking.zig, src/userland/apps/desktop/classic/src/classic-desktop.zig
Window/Widget pixel buffers switched to 64-byte alignment and stride-based allocation; widget resize logic updated; damage tracking now uses overlappedRegion; desktop icon rendering gated by occlusion checks.
Rectangle & ABI changes
src/abi/src/ashet.abi, src/abi/src/ports/zig.abi.zpatch, src/userland/apps/desktop/classic/src/WindowManager.zig
ABI: added get_demo_mode syscall and Rectangle.everything; Rectangle API changes (overlap→overlappedRegion, enclosingRegion added, empty semantics changed, clamping helpers). WindowIterator made public.
VBlank support & driver
src/kernel/components/video.zig, src/kernel/drivers/video/HSTX_DVI_2.zig
VideoDevice gained optional get_one_vblank_event hook; HSTX_DVI_2 driver sets atomic vsync flag and exposes get_one_vblank_event; tick/flush logic updated to poll and notify vblank awaiters.
Thread stack & scheduler
src/kernel/components/scheduler.zig, src/kernel/components/multi_tasking.zig
Threads support external_stack via ThreadSpawnOptions; Thread.Flags gains has_external_stack to avoid freeing external stacks; kernel thread marked accordingly; spawn log level changed to info.
Platform/board changes
src/abi/src/platforms.zig, src/kernel/port/machine/arm/ashet-hc/ashet-hc.zig, src/kernel/port/machine/arm/ashet-hc/hw_alloc.zig, src/kernel/port/machine/arm/ashet-hc/psram.zig
ARM ABI set to eabihf; demo_mode GPIO pin added and initialized; SysTick handler made exception-frame-aware with exported last_pc and increment handler; get_demo_mode() added; PSRAM constants reformatted.
New demo & slideshow apps
src/userland/apps/demos/revision2026/*, src/userland/apps/slideshow/*, src/userland/apps/init/init.zig
Added revision2026 demo and slideshow app with builds/manifests; init now conditionally spawns revision2026 when get_demo_mode() is enabled.
Build & wiring
src/kernel/build.zig, src/kernel/build.zig.zon, src/os/build.zig, src/os/build.zig.zon, build.zig, justfile
Integrated agp-tiled-rast into kernel imports, added slideshow/revision2026 to OS app packaging/manifests, appended .ashex to run-path app names, and added just recipes for slideshow and trace.
Drivers & input tweak
src/kernel/drivers/input/PropIO_PS2_Device.zig
Increased per-slot PS/2 inbound_data ring buffer capacity from 16 → 30 bytes to better accommodate mouse reports.
Tools & scripts
scripts/profiler.py, scripts/analyze-render-stats.py, src/tools/abi-mapper/src/syntax.zig, assets/slides/CREDITS.md, .gitignore
Added OpenOCD-based profiler, render-stats analyzer, tokenizer support for negative numbers, slide credits file, and .gitignore entries for .tmp/, .codex, .serena/.
Misc userland updates
src/userland/apps/dungeon/src/dungeon.zig, src/userland/apps/hello-gui/build.zig, src/userland/libs/libAshetOS/build.zig
Dungeon: raycaster refactor with perspective background sampling and raycache; hello-gui build adds icon conversion; SDK adds convert_image helper using mkicon.
Large refactor & tests
various
Many API renames and dense logic changes across rendering, decoding and rasterizer modules; new tests added in rasterizer packages—review(render/decoder/overlay) recommended.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Graphics as Graphics
    participant Queue as Render Queue
    participant Worker as Render Worker
    participant Raster as Rasterizer
    participant FB as Framebuffer

    App->>Graphics: render_async(call, inputs)
    Graphics->>Graphics: check selected_rasterizer.is_async()
    alt async backend
        Graphics->>Queue: enqueue(task)
        Graphics-->>App: return
        Worker->>Queue: dequeue(task)
        Worker->>Graphics: reconstruct Render from Arc
        Worker->>Raster: render_one_task(inputs, target)
        Raster->>FB: write pixels / overlays
        Raster-->>Worker: complete
        Worker->>Graphics: finalize async call
    else sync backend
        Graphics->>Raster: render_one_task(inputs, target)
        Raster->>FB: write pixels / overlays
        Raster-->>Graphics: complete
        Graphics-->>App: return (synchronous)
    end
Loading
sequenceDiagram
    participant Video as Video Tick
    participant VideoDev as VideoDevice
    participant Driver as HSTX_DVI_2
    participant Awaiter as VBlank Awaiter

    Video->>VideoDev: tick()
    VideoDev->>Driver: get_one_vblank_event()
    Driver->>Driver: atomically swap vsync_has_happened
    alt vsync true
        Driver-->>VideoDev: true
        VideoDev->>VideoDev: force_flush(output*)
        VideoDev->>Awaiter: notify vblank awaiters
    else false
        Driver-->>VideoDev: false
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 Tiles hop, pixels dance and spin,

Queues hum softly, workers grin,
VBlank pulses, drivers cheer,
Slides and demos appear near,
A rabbit paints the screen with vim.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Revision 2026 Partycoding' directly relates to the primary changes in this PR, which adds a new demo application (revision2026) that implements real-time graphics rendering with textures and animations for a partycoding competition.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch work/revision_2026

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Felix "xq" Queißner added 28 commits April 3, 2026 19:50
…hen the command would be clipped anyways. This improves rasterizer performance in the backend in general. Also fixes some of the remaining bugs in the tiled rasterizer, which now only misses text rendering.
@ikskuh ikskuh marked this pull request as ready for review April 10, 2026 22:05
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 18

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/abi/src/ports/zig.abi.zpatch (1)

281-293: ⚠️ Potential issue | 🔴 Critical

Fix enclosingRegion()'s top bound.

_top must use @min, not @max. As written, the returned rectangle can exclude whichever input starts higher on the screen, so the “enclosing” region is not actually a union.

🧭 Suggested fix
     pub fn enclosingRegion(a: Rectangle, b: Rectangle) Rectangle {
         const _left = `@min`(a.left(), b.left());
         const _right = `@max`(a.right(), b.right()) +| 1;
-        const _top = `@max`(a.top(), b.top());
+        const _top = `@min`(a.top(), b.top());
         const _bottom = `@max`(a.bottom(), b.bottom()) +| 1;
 
         return .{
             .x = _left,
             .y = _top,
-            .width = `@intCast`(_right -| _left),
-            .height = `@intCast`(_bottom -| _top),
+            .width = clamp_u16(`@as`(i32, _right) - `@as`(i32, _left)),
+            .height = clamp_u16(`@as`(i32, _bottom) - `@as`(i32, _top)),
         };
     }
src/userland/apps/desktop/classic/src/DamageTracking.zig (1)

39-58: ⚠️ Potential issue | 🟠 Major

Drop empty intersections after clipping.

overlappedRegion() now returns a zero-sized rectangle when region falls outside tracked_area. Without if (target.empty()) return, this path can enqueue empty invalidations and also send an empty rectangle into containsRectangle().

✂️ Suggested fix
     const target = dt.tracked_area.overlappedRegion(region);
+    if (target.empty())
+        return;
 
     // check if we already have this region invalidated
     for (dt.invalidation_areas.items) |rect| {
🟡 Minor comments (6)
src/userland/apps/dungeon/src/dungeon.zig-497-497 (1)

497-497: ⚠️ Potential issue | 🟡 Minor

Drop the debug tint from ceiling texture sampling.

Line 497 applies .shift(16 * texture_id) only on the ceiling perspective-texture path, so the sampled bitmap will not render with its original colors. This looks like a leftover debug effect.

src/userland/apps/dungeon/src/dungeon.zig-313-319 (1)

313-319: ⚠️ Potential issue | 🟡 Minor

Use the full texture dimensions for repeating floor/ceiling sampling.

Line 317-318 multiplies fract() by texture.width - 1 / texture.height - 1, but fract() is always < 1.0. That makes the last texel row and column unreachable for perspective backgrounds, so the tiled pattern is compressed by one texel.

🎯 Proposed fix
         return .{
             .texture = texture,
-            .u_scale = `@as`(f32, `@floatFromInt`(texture.width - 1)),
-            .v_scale = `@as`(f32, `@floatFromInt`(texture.height - 1)),
+            .u_scale = `@as`(f32, `@floatFromInt`(texture.width)),
+            .v_scale = `@as`(f32, `@floatFromInt`(texture.height)),
         };
assets/slides/CREDITS.md-3-3 (1)

3-3: ⚠️ Potential issue | 🟡 Minor

Polish intro wording for readability.

Line 3 reads awkwardly (“were from”). Suggest “are from” or “come from”.

Suggested wording tweak
-These slides were from different demoscene contributions over the last years:
+These slides are from different demoscene contributions over the last years:
justfile-283-301 (1)

283-301: ⚠️ Potential issue | 🟡 Minor

Create output directories before writing generated files.

Line 284+ and Line 295+ assume rootfs/dev/data/slideshow and .tmp already exist. On a clean tree, both recipes can fail immediately.

💡 Proposed fix
 slideshow:
+    mkdir -p rootfs/dev/data/slideshow
     ./zig-out/bin/mkicon -g 600x350 -o rootfs/dev/data/slideshow/debris.abm             assets/slides/debris.png
     ./zig-out/bin/mkicon -g 600x350 -o rootfs/dev/data/slideshow/heritages.abm          assets/slides/heritages.png
     ./zig-out/bin/mkicon -g 600x350 -o rootfs/dev/data/slideshow/hoody.abm              assets/slides/hoody.png
@@
 trace:
+    mkdir -p .tmp
     python scripts/profiler.py \
         > .tmp/trace.log
src/userland/libs/agp-tiled-rast/src/tiled-raster.zig-226-227 (1)

226-227: ⚠️ Potential issue | 🟡 Minor

Allow the documented 2048px limit.

max_image_size is 2048, but Line 226 rejects width/height equal to 2048 because of >=. That makes the effective limit 2047.

Proposed fix
-        if (target.width >= max_image_size or target.height >= max_image_size)
+        if (target.width > max_image_size or target.height > max_image_size)
             return error.ImageTooLarge;
src/userland/apps/demos/revision2026/revision2026.zig-26-35 (1)

26-35: ⚠️ Potential issue | 🟡 Minor

Use strict bounds before indexing the bitmap.

ux == bmp.width or uy == bmp.height is already out of bounds for bmp.pixels[index]. With padded strides that reads padding; with tight strides it can fault. Use < here.

Proposed fix
-    std.debug.assert(ux <= bmp.width);
-    std.debug.assert(uy <= bmp.height);
+    std.debug.assert(ux < bmp.width);
+    std.debug.assert(uy < bmp.height);
🧹 Nitpick comments (2)
src/kernel/port/machine/arm/ashet-hc/psram.zig (1)

29-29: Remove redundant legacy-value inline comment.

// 109000000; is now noise and may drift from the actual constant over time. Prefer keeping only the canonical value.

src/abi/src/ashet.abi (1)

13-17: Expose get_demo_mode as an enum, not a raw u8.

This is now part of the public ABI, so leaving it as an untyped byte makes the contract easy to drift across kernel and userland. A dedicated enum keeps the values self-documenting and prevents magic-number callers.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7a70355a-556a-413f-9c89-28528d9f23da

📥 Commits

Reviewing files that changed from the base of the PR and between 8721bd1 and 92ad3d9.

⛔ Files ignored due to path filters (12)
  • assets/images/wallpaper-info.png is excluded by !**/*.png
  • assets/slides/debris.png is excluded by !**/*.png
  • assets/slides/heritages.png is excluded by !**/*.png
  • assets/slides/hoody.png is excluded by !**/*.png
  • assets/slides/modern-furnishing.png is excluded by !**/*.png
  • assets/slides/opium.png is excluded by !**/*.png
  • assets/slides/r-cade.png is excluded by !**/*.png
  • assets/slides/velocity.png is excluded by !**/*.png
  • src/userland/apps/demos/revision2026/data/Brick01.png is excluded by !**/*.png
  • src/userland/apps/demos/revision2026/data/Doors10.png is excluded by !**/*.png
  • src/userland/apps/demos/revision2026/data/Stone01.png is excluded by !**/*.png
  • src/userland/apps/demos/revision2026/data/Tiles05.png is excluded by !**/*.png
📒 Files selected for processing (50)
  • .gitignore
  • assets/images/wallpaper.xcf
  • assets/slides/CREDITS.md
  • build.zig
  • justfile
  • scripts/profiler.py
  • src/abi/src/ashet.abi
  • src/abi/src/platforms.zig
  • src/abi/src/ports/zig.abi.zpatch
  • src/kernel/build.zig
  • src/kernel/build.zig.zon
  • src/kernel/components/graphics.zig
  • src/kernel/components/gui.zig
  • src/kernel/components/multi_tasking.zig
  • src/kernel/components/scheduler.zig
  • src/kernel/components/syscalls.zig
  • src/kernel/components/video.zig
  • src/kernel/drivers/input/PropIO_PS2_Device.zig
  • src/kernel/drivers/video/HSTX_DVI_2.zig
  • src/kernel/main.zig
  • src/kernel/port/machine/arm/ashet-hc/ashet-hc.zig
  • src/kernel/port/machine/arm/ashet-hc/hw_alloc.zig
  • src/kernel/port/machine/arm/ashet-hc/psram.zig
  • src/os/build.zig
  • src/os/build.zig.zon
  • src/tools/abi-mapper/src/syntax.zig
  • src/userland/apps/demos/revision2026/build.zig
  • src/userland/apps/demos/revision2026/build.zig.zon
  • src/userland/apps/demos/revision2026/revision2026.zig
  • src/userland/apps/desktop/classic/src/DamageTracking.zig
  • src/userland/apps/desktop/classic/src/WindowManager.zig
  • src/userland/apps/desktop/classic/src/classic-desktop.zig
  • src/userland/apps/dungeon/src/dungeon.zig
  • src/userland/apps/hello-gui/build.zig
  • src/userland/apps/init/init.zig
  • src/userland/apps/slideshow/build.zig
  • src/userland/apps/slideshow/build.zig.zon
  • src/userland/apps/slideshow/src/slideshow.zig
  • src/userland/libs/agp-swrast/src/agp-swrast.zig
  • src/userland/libs/agp-tiled-rast/build.zig
  • src/userland/libs/agp-tiled-rast/build.zig.zon
  • src/userland/libs/agp-tiled-rast/src/tiled-raster.zig
  • src/userland/libs/agp-tiled-rast/test/exerciser.zig
  • src/userland/libs/agp-tiled-rast/test/gif.zig
  • src/userland/libs/agp-tiled-rast/test/mono-6.font
  • src/userland/libs/agp-tiled-rast/test/mono-8.font
  • src/userland/libs/agp-tiled-rast/test/sans.font
  • src/userland/libs/agp/src/agp.zig
  • src/userland/libs/libAshetOS/build.zig
  • src/userland/libs/libAshetOS/module/src/libashet/graphics.zig

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (3)
src/userland/libs/agp-swrast/src/agp-swrast.zig (1)

425-430: ⚠️ Potential issue | 🔴 Critical

Clip negative source coordinates before the u16 cast.

source_pos.x / source_pos.y can still be negative here. In that case @intCast(...) traps before any source-space clipping happens, so a partial blit with a negative source origin can take down the linear rasterizer path.

src/kernel/components/graphics.zig (2)

74-82: ⚠️ Potential issue | 🔴 Critical

Don't reuse the global decoder arena across concurrent renders.

This still makes render_one_task() run on both the caller thread and the worker thread, but render_sync() keeps resetting the single global render_temp_buffer. Two renders in flight can stomp each other's decoder arena and corrupt command decoding.

Also applies to: 588-640


621-634: ⚠️ Potential issue | 🔴 Critical

Return a render error here instead of panicking the kernel.

This is still processing user-controlled AGP input. Converting rasterizer decode/resolve failures into @panic() lets a bad draw request crash the whole kernel instead of surfacing error.BadCode.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 28d0a1c5-8fc0-4abc-869b-e615d684a1a6

📥 Commits

Reviewing files that changed from the base of the PR and between 92ad3d9 and 5ea3031.

📒 Files selected for processing (6)
  • scripts/analyze-render-stats.py
  • src/abi/src/ports/zig.abi.zpatch
  • src/kernel/components/graphics.zig
  • src/kernel/main.zig
  • src/userland/libs/agp-swrast/src/agp-swrast.zig
  • src/userland/libs/agp-tiled-rast/src/tiled-raster.zig
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/kernel/main.zig
  • src/abi/src/ports/zig.abi.zpatch
  • src/userland/libs/agp-tiled-rast/src/tiled-raster.zig

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/abi/src/ashet.abi (1)

3188-3193: ⚠️ Potential issue | 🟠 Major

Rectangle.everything still excludes negative-space rectangles.

Line 3189 and Line 3190 keep origin at (0,0), so this sentinel is not “everything” for signed coordinates.

Suggested fix
 const everything: Rectangle = .{
-    .x = 0, //? TODO: Fix parsing and numeric handling so we can use -32768
-    .y = 0, //? TODO: Fix parsing and numeric handling so we can use -32768
+    .x = -32767 - 1,
+    .y = -32767 - 1,
     .width = 65535,
     .height = 65535
 };

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c1ba3b91-945a-4ec2-a034-faaa2165c304

📥 Commits

Reviewing files that changed from the base of the PR and between 5ea3031 and e99929e.

📒 Files selected for processing (2)
  • src/abi/src/ashet.abi
  • src/kernel/components/graphics.zig
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/kernel/components/graphics.zig

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant