Skip to main content

forge-ui-rendering

Render the forge-gpu immediate-mode UI system on the GPU with a single draw call, font atlas texture, alpha blending, and dynamic buffer streaming. Based on Lesson 28.

Ir para a instalação

Informações da origem

Repositório
Nebulavenus/forge-gpu
Última atividade na origem
1 de março de 2026 às 21:31
Idioma detectado do SKILL.md
inglês
Estrelas
38
Forks
7

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
forge-ui-rendering
description
Render the forge-gpu immediate-mode UI system on the GPU with a single draw call, font atlas texture, alpha blending, and dynamic buffer streaming. Based on Lesson 28.
Render the CPU-side immediate-mode UI (forge_ui_ctx.h, forge_ui_window.h) using the SDL GPU API. Based on GPU Lesson 28. ## When to use - You have a ForgeUiContext producing vertex/index arrays and need to draw them - You need to render text glyphs from a font atlas with alpha blending - You need a single-draw-call 2D UI pipeline with dynamic buffer streaming - You want to integrate the UI track output into a GPU application ## Key API calls - `SDL_CreateGPUTexture` with `SDL_GPU_TEXTUREFORMAT_R8_UNORM` — single-channel atlas - `SDL_CreateGPUSampler` — linear filter, clamp-to-edge for atlas - `SDL_CreateGPUGraphicsPipeline` — alpha blend, no depth, cull none - `SDL_CreateGPUTransferBuffer` / `SDL_MapGPUTransferBuffer` — per-frame upload - `SDL_UploadToGPUBuffer` — copy vertex + index data via copy pass - `SDL_PushGPUVertexUniformData` — orthographic projection matrix - `SDL_DrawGPUIndexedPrimitives` — single batched draw call - `forge_ui_ctx_begin` / `forge_ui_ctx_end` — UI declaration phase - `forge_ui_wctx_begin` / `forge_ui_wctx_end` — window z-order sorting ## Correct order 1. **Init (once)** a. Load font with `forge_ui_ttf_load`, build atlas with `forge_ui_atlas_build` b. Upload atlas pixels to R8_UNORM GPU texture via transfer buffer + copy pass c. Create sampler (linear, clamp-to-edge) d. Create vertex and fragment shaders from compiled HLSL bytecode e. Create pipeline: alpha blend enabled, no depth, cull none, 4x FLOAT2 vertex attrs f. Pre-allocate vertex and index GPU buffers (power-of-two sizes) g. Init ForgeUiContext and ForgeUiWindowContext 2. **Each frame** a. Query window size and mouse state b. `forge_ui_ctx_begin` — start UI declaration c. Declare windows and widgets (labels, buttons, checkboxes, sliders, text input) d. `forge_ui_wctx_end` / `forge_ui_ctx_end` — finalize vertex/index arrays e. Resize GPU buffers if needed (power-of-two growth) f. Create single transfer buffer, map, copy vertex+index data, unmap g. Copy pass: upload vertex data at offset 0, index data after h. Release transfer buffer i. Acquire swapchain, begin render pass (clear) j. Bind pipeline, vertex buffer, index buffer, atlas texture+sampler k. Push orthographic projection uniform l. `SDL_DrawGPUIndexedPrimitives` — one call for all UI m. End render pass, submit command buffer ## Key concepts 1. **ForgeUiVertex is 32 bytes** — 8 floats: pos(2), uv(2), color(4). Pipeline reads as 4x FLOAT2. 2. **White-pixel technique** — solid rects use UVs pointing to a white region in the atlas where coverage = 1.0, so the fragment shader works for both text and solid geometry. 3. **R8_UNORM atlas** — single-channel texture saves 4x memory vs RGBA8. Fragment shader reads `.r` as coverage. 4. **Orthographic projection** — maps [0..W, 0..H] pixels to [-1..+1] clip space with Y flipped for top-left origin. Rebuilt every frame for automatic resize handling. 5. **No depth buffer** — 2D UI uses painter's algorithm via z_order sorting in the window context. 6. **No backface culling** — UI quads may have either winding order. 7. **Single draw call** — all widgets batched into one vertex/index stream by the UI context. ## Theme colors The forge-gpu project uses a dark blue-gray palette defined in `scripts/forge_diagrams/_common.py`. All UI colors follow this theme. The key property: dark surfaces carry a strong blue tint (B/R ratio ~1.8) that tapers toward neutral at brighter levels (~1.07 for text). ### Reference palette (sRGB) | Role | Hex | RGBA float | Used for | |------|-----|------------|----------| | Background | `#1a1a2e` | (0.10, 0.10, 0.18, 1.0) | Clear color | | Surface | `#252545` | (0.14, 0.14, 0.27, 1.0) | Panel/window BG | | Grid | `#2a2a4a` | (0.16, 0.16, 0.29, 1.0) | Title bar BG | | Accent cyan | `#4fc3f7` | (0.31, 0.76, 0.97, 1.0) | Active/focused states, cursors, borders | | Accent orange | `#ff7043` | (1.00, 0.44, 0.26, 1.0) | Secondary highlights | | Accent green | `#66bb6a` | (0.40, 0.73, 0.42, 1.0) | Tertiary highlights | | Accent purple | `#ab47bc` | (0.67, 0.28, 0.74, 1.0) | Special elements | | Warn yellow | `#ffd54f` | (1.00, 0.84, 0.31, 1.0) | Warnings, annotations | | Text | `#e0e0f0` | (0.88, 0.88, 0.94, 1.0) | Primary text, labels | | Dim text | `#8888aa` | (0.53, 0.53, 0.67, 1.0) | Secondary/info text | ### Deriving new colors When adding new UI elements, derive colors from the theme by maintaining the blue tint ratio for the brightness level: - **Dark** (0.10–0.20 R/G): set B ≈ R × 1.7–1.8 - **Medium** (0.20–0.40 R/G): set B ≈ R × 1.5–1.6 - **Bright** (0.40–0.60 R/G): set B ≈ R × 1.3–1.4 - **Near-white** (0.80+ R/G): set B ≈ R × 1.05–1.15 The default widget colors in `forge_ui_ctx.h` and `forge_ui_window.h` already follow this theme. The clear color and label colors are set per lesson (see `main.c` `CLEAR_R/G/B` and `TITLE_LABEL_R/G/B` defines). ## Common mistakes 1. **Using RGBA8 for the atlas** — wastes 4x GPU memory and requires CPU-side pixel expansion. Use R8_UNORM. 2. **Forgetting to flip Y in the projection** — without `-2.0f / height`, the UI renders upside down. 3. **Not checking SDL_SubmitGPUCommandBuffer return** — must check on every path, including error paths after swapchain acquisition. 4. **Leaking the transfer buffer** — release it after the copy pass ends, not after submit. 5. **Not handling the minimized window case** — when swapchain texture is NULL, submit the command buffer and return. 6. **Fixed-size buffers** — if the UI grows beyond initial capacity, you must resize. Use power-of-two growth. 7. **Depth testing with alpha blending** — depth test would discard semi-transparent fragments. Disable it for 2D UI. ## Template ```c #define SDL_MAIN_USE_CALLBACKS 1 #include "ui/forge_ui.h" #include "ui/forge_ui_ctx.h" #include "ui/forge_ui_window.h" #include "math/forge_math.h" #include <SDL3/SDL.h> #include <SDL3/SDL_main.h> /* Include compiled shader headers */ #include "shaders/compiled/ui_vert_spirv.h" #include "shaders/compiled/ui_vert_dxil.h" #include "shaders/compiled/ui_frag_spirv.h" #include "shaders/compiled/ui_frag_dxil.h" typedef struct UiUniforms { mat4 projection; /* orthographic pixel-to-NDC mapping */ } UiUniforms; typedef struct app_state { SDL_Window *window; SDL_GPUDevice *device; SDL_GPUGraphicsPipeline *pipeline; SDL_GPUTexture *atlas_texture; /* R8_UNORM font atlas */ SDL_GPUSampler *atlas_sampler; /* linear, clamp-to-edge */ SDL_GPUBuffer *vertex_buffer; SDL_GPUBuffer *index_buffer; Uint32 vertex_buffer_size; Uint32 index_buffer_size; ForgeUiFont font; ForgeUiFontAtlas atlas; ForgeUiContext ui_ctx; ForgeUiWindowContext ui_wctx; /* ... widget state ... */ } app_state; /* Orthographic projection: top-left origin, y-down */ static mat4 ui_ortho_projection(float width, float height) { mat4 m = mat4_identity(); m.m[0] = 2.0f / width; m.m[5] = -2.0f / height; m.m[12] = -1.0f; m.m[13] = 1.0f; return m; } ```
Ver no GitHub