# Phase 0 — substrate for iter5 Opened **2026-05-19** after [iter4 close GREEN](phase8_iteration4_close.md). ## Locked research question — iter5 > **Render a non-fullscreen triangle into a 64×64 R8G8B8A8_UNORM attachment via a vertex buffer + UBO. Vertex buffer: 3 vertices, each (pos vec2 + color vec3) = 20 bytes (with 8-byte align padding → 32-byte stride). UBO: single mat4 transform (scaling 0.8 in x/y, identity otherwise). Triangle in scaled-NDC: v0(-0.5,-0.5) red, v1(0.5,-0.5) green, v2(0,0.5) blue. Fragment shader outputs interpolated color (mixed RGB at centroid).** > > **Verify:** > 1. **Centroid pixel** (32, 28) has all of R, G, B > 0x10 (interpolated, non-black). > 2. **Top-left pixel** (0, 0) is exactly 0x00000000 (clear, outside triangle). > 3. **Top-right pixel** (63, 0) is exactly 0x00000000 (clear, outside triangle). > 4. **Covered pixel count** (non-clear pixels) ∈ [800, 1600] (triangle area ≈ 1310 pixels). > > If GREEN: iter6 stress-tests with a multi-draw scene or a Zink-on-PanVk smoke. If RED: characterize vertex input / UBO descriptor / NIR varying interpolation. ## Why this shape iter4 closed the descriptor model for fragment-stage texture binding. iter5 adds **vertex-stage descriptor binding** + **vertex input** (the vertex-side counterpart). What's new: - Vertex buffer (`VK_BUFFER_USAGE_VERTEX_BUFFER_BIT`) + `vkCmdBindVertexBuffers` - `VkPipelineVertexInputStateCreateInfo` with non-empty bindings + attributes (pos location 0, color location 1) - UBO (`VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER`) bound to vertex stage - Vertex shader reads attribute layouts + UBO via descriptor - Interpolated varying (color) from vertex → fragment ## Hypothesis space 1. **Vertex input bindings on Bifrost.** Bifrost's attribute descriptor model has been a divergence point per `panvk_vX_cmd_draw.c`'s `PANVK_BIFROST_DESC` references. First time we exercise non-zero `VkPipelineVertexInputStateCreateInfo`. 2. **UBO descriptor binding for vertex stage.** Different from iter4's fragment-stage COMBINED_IMAGE_SAMPLER. 3. **Vertex-stage descriptor lowering in NIR** (Bifrost-specific code paths). 4. **Varying interpolation** (color) from vertex output → fragment input. 5. **UBO data fetch** — does the GPU actually read the matrix from the bound buffer correctly? 6. **Non-fullscreen rasterization** — partial coverage, edge pixels, anti-aliased-or-not boundaries on Bifrost's tile binner. ## In-scope (LOCKED 2026-05-19 for iter5) - 1 vertex buffer (3 verts), interleaved pos+color, 32-byte stride. - 1 UBO (64 bytes, mat4). - 1 descriptor set with 1 UBO binding bound to vertex stage. - Triangle in NDC, scaled by 0.8 via UBO matrix. - 4-point pixel-level verification + range-bound coverage count. ## Out-of-scope (LOCKED 2026-05-19 for iter5) - Index buffer / `vkCmdDrawIndexed`. - Multiple draws. - Push constants. - Texture sampling (iter4 already covered). - Depth / stencil. - Blending (clear=opaque-black, triangle has α=1). - MSAA. - Compressed formats. - Mipmaps. - Real workloads (vkcube/vkmark/Zink) — that's iter6+. ## Reference - Prior closes: [iter1](phase8_iteration1_close.md), [iter2](phase8_iteration2_close.md), [iter3](phase8_iteration3_close.md), [iter4](phase8_iteration4_close.md).