Vixen
dd8b0a81
csharp
public readonly record struct UiShape

Everything the box shader needs about one box, in the layout it reads.

No guide page documents this yet — the page shows what the code says about itself.

Remarks

⚠ Per box, not per vertex, and that is the whole reason this type exists. Four corners with an elliptical radius each is eight floats, a three-stop gradient is another fifteen, and a box is four vertices — so carrying them on the vertex would take it from forty-eight bytes to well past a hundred, and every glyph and every path triangle in the frame would pay for fields no shader reads on them. One record per box costs a hundred and sixty bytes against the sixty-four the four vertices already spend on Shape, and the vertex layout does not move at all: a box's Shape.X becomes the index of its record.

⚠ Ten Vector4s, written out rather than left to a struct layout to work out. This is copied into a storage buffer with MemoryMarshal and read back by a shader whose own alignment rules are not C#'s — a float beside a Vector2 lays out differently under std430 than under sequential, and the failure is a box drawn with another box's radii, which looks like a bug in the geometry.

⚠ Several files have to agree about this layout, and half of them are invisible to a search for this type's name. The ones that name it: this record, Platform/Vixen.Ui.Desktop/Shaders/Ui.rvn, the committed UiBox.frag.spv and UiBox.reflect.json beside it, and SoftwareUiRasterizer. The ones that do not: UiRenderer, which needs only the size and once spelled it 80 in three places; and one hand-maintained GLSL copy of the box shader, under Vixen.Graphics.Golden.Tests, which calls the struct Shape. There were three GLSL copies until the sample and the vixen-app template stopped carrying their own frame loops, and two Raven ones until Vixen.Editor.Host's duplicate of Ui.rvn was deleted — so what is left is one source, named and checked rather than transcribed.

⚠ Which test covers which half is worth knowing before changing this. UiShapeLayoutTests pins the record's shape against the committed reflection beside Platform/Vixen.Ui.Desktop/Shaders/Ui.rvn and has nothing to say about how a host sizes a buffer around it; ./build.sh CheckShaders pins the Raven source against its modules and does not see GLSL. The stride and the GLSL copy are caught only by Vixen.Graphics.Golden.Tests, on a real device — which is exactly what caught them when this record grew. UiRenderer now derives its stride from Marshal.SizeOf, so that one cannot drift again; the GLSL still can.

⚠ Every lane this record has ever grown was appended, and the two repurposed ones were both zero. Growing from eighty bytes to a hundred and twelve, then to a hundred and forty-four and then to a hundred and sixty, left every existing offset exactly where the shader already read it: Axis.w was declared padding and is now the interpolation space, whose zero is Linear — which is what the shader did before there was a choice — and Size.w was a zero-or-one gradient flag and is now the shape, whose one is Linear, which is what a flag set to one meant. That is not a coincidence to admire; it is a hazard to name. A stale shader reading this record still draws two-stop linear gradients correctly and silently ignores everything below offset eighty, so drift here does not announce itself as garbage on screen. The test is the only thing that finds it.

Fields and properties (10)

  • public Vector4 Size

    Half width, half height, border thickness, and which family of gradient.

  • public Vector4 RadiiX

    The four horizontal radii, clockwise from the top left.

  • public Vector4 RadiiY

    The four vertical radii, in the same order.

  • public Vector4 Axis

    The gradient's direction, then a shadow's blur radius, then the interpolation space.

  • public Vector4 End

    The colour at the last stop.

  • public Vector4 Mid

    The colour at the middle stop, read only when Stops's last lane is set.

  • public Vector4 Stops

    Where the three stops sit, then whether the middle one exists.

  • public Vector4 Paint

    The ramp's own centre, then how far it reaches. A zero reach means the box.

  • public Vector4 Area

    The first tile's centre, then half its size with background-repeat in the sign. All zero means the tile is the box.

  • public Vector4 Inset

    An inset shadow's offset and spread, then whether it is one at all. All zero is every box and every outer shadow.

Methods (2)

Used by (7)

  • SoftwareUiRasterizerVixen.Ui.Testing
  • UiGamutTestsVixen.Ui.Tests
  • UiGeometryVixen.Ui
  • UiGeometryBuilderVixen.Ui
  • UiGeometryTestsVixen.Ui.Tests
  • UiRendererVixen.Ui.Renderer
  • UiShapeLayoutTestsVixen.Ui.Tests