[iterate-4A] intro-video: complete RectangleList quad (fix diagonal seam)
A Xenos RectangleList gives 3 corners of a rectangle; the GPU synthesizes the 4th (v3 = v0 + v2 - v1) and tessellates the quad as two triangles (v0,v1,v2) + (v0,v2,v3). Our expansion emitted only the front triangle, so the movie's fullscreen YUV rect filled half the screen and left a diagonal seam down the frame (absent in canary). expand_rectangles now emits the full 6-index quad. Since v3 has no backing vertex in the guest window, the translated VS synthesizes its attributes: the RectangleList arm maps 6 host verts through [0,1,2, 0,2,3], flags the 4th corner, and emit_vfetch computes that corner's attributes (position and every interpolator) as v0 + v2 - v1 by reading the three real source vertices. Non-rect draws are unaffected (the synth flag is false). Verified: the movie background now fills the whole frame uniformly, no diagonal, matching canary. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -143,18 +143,17 @@ fn expand_quads(indices: Option<&[u32]>, vertex_count: u32) -> ProcessedPrimitiv
|
||||
/// `primitive_processor.cc:389-456`): a 4-vertex triangle strip per rect with
|
||||
/// the 4th corner synthesized *in the VS* from the host-vertex index.
|
||||
///
|
||||
/// Our replay pipeline has no host-VS corner synthesis (and the procedural
|
||||
/// `vs_main` does not consume `rewritten_indices` yet), so we mirror the
|
||||
/// `expand_quads`/`expand_fan` CPU idiom and emit the 3 real vertices of each
|
||||
/// rect as one triangle list `(v0,v1,v2)` — the visible lower half of the
|
||||
/// rect. This un-rejects the draw and gives a faithful `host_vertex_count`.
|
||||
///
|
||||
/// TODO: once `vs_main` does real vertex fetch + interpolation, upgrade to the
|
||||
/// full quad — 6 indices `[v0,v1,v2, v2,v1,v3]` with a synthesized `v3` corner
|
||||
/// — mirroring canary's `kRectangleListAsTriangleStrip`.
|
||||
/// We draw the full quad as a 6-vertex triangle list `[v0,v1,v2, v0,v2,v3]`
|
||||
/// per rect (canary's tessellation). The synthesized `v3` (index `base+3`) has no backing vertex in
|
||||
/// the guest window, so the translated `vs_main` computes its attributes as
|
||||
/// `v0 + v2 - v1` when the host-vertex index maps to that corner (see the
|
||||
/// RectangleList handling + `emit_vfetch` corner synthesis in `translator.rs`).
|
||||
/// Emitting only the front triangle `(v0,v1,v2)` — as we used to — fills just
|
||||
/// half the rect and leaves a diagonal seam (the movie's fullscreen YUV rect
|
||||
/// showed exactly that).
|
||||
fn expand_rectangles(indices: Option<&[u32]>, vertex_count: u32) -> ProcessedPrimitive {
|
||||
let rect_count = vertex_count / 3;
|
||||
let mut out = Vec::with_capacity(3 * rect_count as usize);
|
||||
let mut out = Vec::with_capacity(6 * rect_count as usize);
|
||||
let get = |i: u32| -> u32 {
|
||||
match indices {
|
||||
Some(buf) => buf[i as usize],
|
||||
@@ -163,9 +162,11 @@ fn expand_rectangles(indices: Option<&[u32]>, vertex_count: u32) -> ProcessedPri
|
||||
};
|
||||
for r in 0..rect_count {
|
||||
let base = r * 3;
|
||||
out.push(get(base));
|
||||
out.push(get(base + 1));
|
||||
out.push(get(base + 2));
|
||||
let (v0, v1, v2) = (get(base), get(base + 1), get(base + 2));
|
||||
// Front triangle (v0,v1,v2), then the completing triangle (v0,v2,v3)
|
||||
// with the synthesized 4th corner (index `base + 3`; the VS
|
||||
// extrapolates its attributes as v0+v2-v1).
|
||||
out.extend_from_slice(&[v0, v1, v2, v0, v2, base + 3]);
|
||||
}
|
||||
let host_vertex_count = out.len() as u32;
|
||||
metrics::counter!("gpu.primitive.expanded", "shape" => "rectangle_list").increment(1);
|
||||
@@ -239,12 +240,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn rectangle_list_expansion() {
|
||||
// 2 rects (6 verts) → one triangle (v0,v1,v2) per rect, not rejected.
|
||||
// 2 rects (6 verts) → full quad per rect: [v0,v1,v2, v2,v1,v3] where
|
||||
// v3 is the synthesized 4th corner (index base+3, extrapolated in the
|
||||
// VS). rect0 → base 0, rect1 → base 3.
|
||||
let p = process(PrimitiveType::RectangleList, 6, None);
|
||||
let idx = p.rewritten_indices.unwrap();
|
||||
assert_eq!(idx, vec![0, 1, 2, 3, 4, 5]);
|
||||
assert_eq!(idx, vec![0, 1, 2, 0, 2, 3, 3, 4, 5, 3, 5, 6]);
|
||||
assert_eq!(p.topology, HostTopology::TriangleList);
|
||||
assert_eq!(p.host_vertex_count, 6);
|
||||
assert_eq!(p.host_vertex_count, 12);
|
||||
assert!(!p.rejected);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user