How to Start #1

Open
opened 2025-12-21 15:26:01 -06:00 by marsultor · 0 comments
Owner

Phase 0 — Define the “golden path”

Before writing real code, lock this in mentally:

I want one fullscreen layer-shell surface per output, with a working EGL context and a frame-callback-driven render loop.

Nothing else matters until this is rock-solid.


Phase 1 — Minimal fullscreen layer-shell client (NO GL)

Goal

Show a solid-color fullscreen surface on all outputs and keep it visible forever.

What you implement

  • wl_display connect

  • Registry bind:

    • wl_compositor
    • wl_output
    • zwlr_layer_shell_v1
  • Output tracking

  • One wl_surface + zwlr_layer_surface_v1 per output

Hard requirements

  • Layer: overlay
  • Anchors: all sides
  • Exclusive zone: -1
  • Keyboard interactivity: exclusive

If this fails, your lock is not secure.

Success criteria

  • Covers all monitors
  • Cannot be obscured
  • Survives window creation/destruction
  • Survives workspace changes

👉 Stop here until this works perfectly.


Phase 2 — Frame callbacks (still NO GL)

Goal

Prove you can drive animation without busy-looping.

What you add

  • wl_surface_frame
  • A timer or monotonic clock
  • Redraw on frame callback

For now:

  • Alternate background color
  • Or move a rectangle in software (wl_shm)

Success criteria

  • CPU usage near zero when idle
  • Smooth updates
  • No tearing or flicker

If you can’t get frame callbacks right, GL will stutter later.


Phase 3 — EGL + OpenGL (still NO particles)

Goal

Clear the screen using OpenGL on every frame.

What you add

  • wayland-egl
  • EGLDisplay, EGLContext, EGLSurface
  • OpenGL ES context (3.1+)

Render loop:

frame callback →
  eglMakeCurrent →
  glClear →
  eglSwapBuffers →
  request next frame

Success criteria

  • No black frames
  • No crashes on resize
  • Works on all outputs
  • Context survives VT switch

At this point, you officially “own” the GPU as a client.


Phase 4 — One compute shader, zero text

Goal

Prove compute shaders work in your environment.

What you add

  • One SSBO

  • One compute shader that:

    • writes a moving point
  • Render that point

Success criteria

  • GPU updates positions
  • CPU only supplies dt
  • No CPU-side vertex updates

This validates your “everything on GPU” rule.


Phase 5 — Text mask upload (CPU → GPU, ONCE)

Goal

Upload a bitmap and sample it in a shader.

What you add

  • FreeType + HarfBuzz
  • Rasterize one word (“LOCKED”)
  • Upload as R8 texture
  • Visualize mask as particles or points

Success criteria

  • Bitmap never changes per frame
  • No CPU readback
  • No per-frame uploads

Phase 6 — GPU particle spawn pass

Goal

Spawn particles from the text mask on the GPU.

What you add

  • Compute shader:

    • Reads text texture
    • Allocates particles
  • Fixed max particle count

Success criteria

  • Particle count matches glyph density
  • No CPU involvement
  • Deterministic layout

Phase 7 — Vector field + failure animation

Goal

Wrong password triggers chaos.

What you add

  • Vector field function
  • State uniform (locked / failed)
  • Forces applied only when failed

Success criteria

  • Visual response is immediate
  • Reset does not require regeneration

Phase 8 — Input + PAM

Goal

Make it real.

What you add

  • wl_keyboard
  • xkbcommon
  • PAM worker thread
  • Unlock signal to Hyprland

Render loop never blocks.


Phase 9 — Hardening

You handle:

  • Output hotplug
  • Suspend/resume
  • VT switch
  • Compositor restart
  • GL context loss

This is what separates demos from lockscreens.

# Phase 0 — Define the “golden path” Before writing real code, lock this in mentally: > **I want one fullscreen layer-shell surface per output, with a working EGL context and a frame-callback-driven render loop.** Nothing else matters until this is rock-solid. --- # Phase 1 — Minimal fullscreen layer-shell client (NO GL) ### Goal Show a solid-color fullscreen surface on **all outputs** and keep it visible forever. ### What you implement * `wl_display` connect * Registry bind: * `wl_compositor` * `wl_output` * `zwlr_layer_shell_v1` * Output tracking * One `wl_surface` + `zwlr_layer_surface_v1` **per output** ### Hard requirements * Layer: `overlay` * Anchors: all sides * Exclusive zone: `-1` * Keyboard interactivity: `exclusive` If this fails, your lock is not secure. ### Success criteria * Covers all monitors * Cannot be obscured * Survives window creation/destruction * Survives workspace changes 👉 **Stop here until this works perfectly.** --- # Phase 2 — Frame callbacks (still NO GL) ### Goal Prove you can drive animation **without busy-looping**. ### What you add * `wl_surface_frame` * A timer or monotonic clock * Redraw on frame callback For now: * Alternate background color * Or move a rectangle in software (wl_shm) ### Success criteria * CPU usage near zero when idle * Smooth updates * No tearing or flicker If you can’t get frame callbacks right, **GL will stutter later**. --- # Phase 3 — EGL + OpenGL (still NO particles) ### Goal Clear the screen using OpenGL on every frame. ### What you add * `wayland-egl` * `EGLDisplay`, `EGLContext`, `EGLSurface` * OpenGL ES context (3.1+) Render loop: ```text frame callback → eglMakeCurrent → glClear → eglSwapBuffers → request next frame ``` ### Success criteria * No black frames * No crashes on resize * Works on all outputs * Context survives VT switch At this point, you officially “own” the GPU **as a client**. --- # Phase 4 — One compute shader, zero text ### Goal Prove compute shaders work in your environment. ### What you add * One SSBO * One compute shader that: * writes a moving point * Render that point ### Success criteria * GPU updates positions * CPU only supplies `dt` * No CPU-side vertex updates This validates your “everything on GPU” rule. --- # Phase 5 — Text mask upload (CPU → GPU, ONCE) ### Goal Upload a bitmap and sample it in a shader. ### What you add * FreeType + HarfBuzz * Rasterize one word (“LOCKED”) * Upload as `R8` texture * Visualize mask as particles or points ### Success criteria * Bitmap never changes per frame * No CPU readback * No per-frame uploads --- # Phase 6 — GPU particle spawn pass ### Goal Spawn particles from the text mask **on the GPU**. ### What you add * Compute shader: * Reads text texture * Allocates particles * Fixed max particle count ### Success criteria * Particle count matches glyph density * No CPU involvement * Deterministic layout --- # Phase 7 — Vector field + failure animation ### Goal Wrong password triggers chaos. ### What you add * Vector field function * State uniform (`locked / failed`) * Forces applied only when failed ### Success criteria * Visual response is immediate * Reset does not require regeneration --- # Phase 8 — Input + PAM ### Goal Make it real. ### What you add * `wl_keyboard` * `xkbcommon` * PAM worker thread * Unlock signal to Hyprland Render loop **never blocks**. --- # Phase 9 — Hardening You handle: * Output hotplug * Suspend/resume * VT switch * Compositor restart * GL context loss This is what separates demos from lockscreens.
marsultor added the
Kind/Feature
Reviewed
Confirmed
1
Priority
Critical
1
labels 2025-12-21 15:26:01 -06:00
Sign in to join this conversation.
No description provided.