P0.2: draw a colored quad on the iOS Simulator, driven by sx
Prove the render path end-to-end: bring up UIKit + Metal (already scaffolded), clear to a solid blue, and draw one centered orange quad via the GPU protocol's clear+quad path — an MSL pass-through pipeline plus a 6-vertex (2-triangle) NDC buffer, created lazily once the MTLDevice exists. Geometry is NDC [-0.5, 0.5]² so the quad is the central 50%x50% of the drawable regardless of device resolution, keeping the screenshot golden unambiguous. Background (0.10, 0.20, 0.55), quad (1.0, 0.6, 0.0). goldens/p0_quad.png is the first screenshot golden, captured from the booted iOS 26.0 simulator after install + launch.
This commit is contained in:
74
main.sx
74
main.sx
@@ -22,6 +22,60 @@ g_viewport_h : f32 = 600.0;
|
||||
g_uikit_plat : *UIKitPlatform = null;
|
||||
g_metal_gpu : *MetalGPU = null;
|
||||
|
||||
// ── Render-path proof (P0.2) ─────────────────────────────────────────────
|
||||
// Clear to a solid blue, then draw one centered orange quad covering the
|
||||
// central 50%×50% of the drawable. Geometry is in NDC ([-0.5, 0.5]²) so the
|
||||
// quad stays screen-size independent across simulator devices, which keeps
|
||||
// the screenshot golden unambiguous. This is the GPU protocol's
|
||||
// clear+quad path: an MSL pipeline state plus a 6-vertex (2-triangle)
|
||||
// buffer, created lazily once the MTLDevice exists.
|
||||
g_quad_shader : ShaderHandle = 0;
|
||||
g_quad_vbuf : BufferHandle = 0;
|
||||
|
||||
BG_CLEAR :: ClearColor.{ r = 0.10, g = 0.20, b = 0.55, a = 1.0 };
|
||||
|
||||
// Vertex layout matches QUAD_MSL's `Vertex`: packed_float2 pos +
|
||||
// packed_float4 color = 24 bytes. `packed_*` avoids the 16-byte alignment
|
||||
// padding a plain `float4` would force. 6 vertices = 2 triangles.
|
||||
QUAD_VERTS : [36]f32 = .[
|
||||
-0.5, 0.5, 1.0, 0.6, 0.0, 1.0,
|
||||
0.5, 0.5, 1.0, 0.6, 0.0, 1.0,
|
||||
-0.5, -0.5, 1.0, 0.6, 0.0, 1.0,
|
||||
0.5, 0.5, 1.0, 0.6, 0.0, 1.0,
|
||||
0.5, -0.5, 1.0, 0.6, 0.0, 1.0,
|
||||
-0.5, -0.5, 1.0, 0.6, 0.0, 1.0,
|
||||
];
|
||||
|
||||
// Pass-through shader: the vertex stage emits NDC positions directly (no
|
||||
// projection), the fragment stage returns the interpolated vertex color.
|
||||
// Entry-point names vmain / fmain are what MetalGPU.create_shader looks up.
|
||||
QUAD_MSL :: #string MSL
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct Vertex {
|
||||
packed_float2 pos;
|
||||
packed_float4 color;
|
||||
};
|
||||
|
||||
struct RasterizerData {
|
||||
float4 position [[position]];
|
||||
float4 color;
|
||||
};
|
||||
|
||||
vertex RasterizerData vmain(uint vid [[vertex_id]],
|
||||
constant Vertex* vertices [[buffer(0)]]) {
|
||||
RasterizerData out;
|
||||
out.position = float4(vertices[vid].pos, 0.0, 1.0);
|
||||
out.color = float4(vertices[vid].color);
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment float4 fmain(RasterizerData in [[stage_in]]) {
|
||||
return in.color;
|
||||
}
|
||||
MSL;
|
||||
|
||||
frame :: () {
|
||||
fc := g_plat.begin_frame();
|
||||
g_viewport_w = fc.viewport_w;
|
||||
@@ -49,12 +103,26 @@ frame :: () {
|
||||
} else if g_metal_gpu.pixel_w != g_uikit_plat.pixel_w or g_metal_gpu.pixel_h != g_uikit_plat.pixel_h {
|
||||
g_metal_gpu.resize(g_uikit_plat.pixel_w, g_uikit_plat.pixel_h);
|
||||
}
|
||||
clear : ClearColor = .{ r = 0.12, g = 0.12, b = 0.15, a = 1.0 };
|
||||
if !g_metal_gpu.begin_frame(clear) { return; }
|
||||
// Compile the quad pipeline + upload its vertices once. The MTLDevice
|
||||
// was created eagerly in main(), so both only need a valid device.
|
||||
if g_quad_shader == 0 {
|
||||
g_quad_shader = g_metal_gpu.create_shader(QUAD_MSL, "");
|
||||
if g_quad_shader == 0 { return; }
|
||||
}
|
||||
if g_quad_vbuf == 0 {
|
||||
g_quad_vbuf = g_metal_gpu.create_buffer(size_of([36]f32));
|
||||
if g_quad_vbuf == 0 { return; }
|
||||
g_metal_gpu.update_buffer(g_quad_vbuf, xx @QUAD_VERTS, size_of([36]f32));
|
||||
}
|
||||
|
||||
if !g_metal_gpu.begin_frame(BG_CLEAR) { return; }
|
||||
g_metal_gpu.set_shader(g_quad_shader);
|
||||
g_metal_gpu.set_vertex_buffer(g_quad_vbuf);
|
||||
g_metal_gpu.draw_triangles(0, 6);
|
||||
g_metal_gpu.end_frame(fc.target_present_time);
|
||||
} else {
|
||||
glViewport(0, 0, fc.pixel_w, fc.pixel_h);
|
||||
glClearColor(0.12, 0.12, 0.15, 1.0);
|
||||
glClearColor(0.10, 0.20, 0.55, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
g_plat.end_frame();
|
||||
|
||||
Reference in New Issue
Block a user