Skip to main content

iridia_interface/
binding.rs

1//! What a program's own code shows of how it uses what it is bound: how a constant buffer's lines hold a matrix, what a
2//! discard compares a constant with, and what an output's lanes are tested or blended by. These are observations the
3//! analyses of `iridia` make (`iridia::matrix`, `iridia::output_uses`), held as plain data so that a consumer without
4//! naga can keep them; what an observation makes a value stand for is the consumer's to decide.
5
6use serde::Serialize;
7
8use crate::{Label, ResourceId};
9
10/// What a discard compares against a constant word (an alpha reference), proved from the program's data flow
11/// (`iridia::output_uses::discard_compares`).
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
13#[serde(rename_all = "snake_case")]
14pub enum AlphaComparison {
15    /// The output alpha itself (including unchanged branch arms).
16    Output,
17    /// A scalar that reaches output alpha through arithmetic. Cutting the output is an approximation.
18    Transformed,
19    /// A pre-transform alpha plus `(dither.a - 0.5) * scale`. `scale_word` is a word offset in the reference's own
20    /// buffer. A hard cutoff on output alpha approximates the program's stochastic, pre-transform test.
21    Dithered {
22        /// Word offset of the dither scale in the reference's own buffer.
23        scale_word: u32,
24    },
25    /// The discard compares a value made of texture samples and constants that reaches no target's alpha (a G-buffer
26    /// program writes none: `t1.w * t0.w + scale * (noise - 0.5) < reference`). The test is the program's own
27    /// expression, read exactly from its graph (`iridia::output_uses::alpha_tests`); a cutoff on any output alpha is not
28    /// it, and a consumer that cuts evaluates that expression, or does not cut.
29    Unwritten,
30}
31/// How a matrix constant's 16-byte lines hold the matrix the program applies to column vectors (a view-projection's
32/// clip position is `M * p`). The layout's packing (`row_major`, `column_major`) does not decide it, since a program may
33/// multiply on either side (`mul(M, v)`, `mul(v, M)`): `iridia::matrix::lines_at` reads it from what the program does.
34#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
35#[serde(rename_all = "snake_case")]
36pub enum MatrixLines {
37    /// Each line is one of the matrix's rows.
38    Rows,
39    /// Each line is one of its columns.
40    Columns,
41    /// The program does not show which, and why ([`Unshown`]). A consumer that writes a matrix unequal to its
42    /// transpose (a camera's) cannot bind it; one that writes the identity can.
43    Unshown(Unshown),
44}
45/// Why a program does not show a matrix's lines ([`MatrixLines::Unshown`]): the kind a consumer branches on, its text
46/// ([`std::fmt::Display`]) the reason.
47#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
48#[serde(rename_all = "snake_case")]
49pub enum Unshown {
50    /// Its results are made of none of the matrix's words.
51    NotRead,
52    /// It reads them but sums no product of them with other values: it does not apply the matrix.
53    NotApplied,
54    /// It applies the matrix both ways: `along` sums of one line's words, `across` of one lane's.
55    BothWays {
56        /// How many sums of the words of one line there are.
57        along: usize,
58        /// How many sums of the words of one lane across lines there are.
59        across: usize,
60    },
61    /// The program could not be examined for it, and `why`: its value graph could not be built, or the matrix's buffer
62    /// could not be found in it.
63    Unexamined {
64        /// Why the program could not be examined.
65        why: String,
66    },
67}
68impl std::fmt::Display for Unshown {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        match self {
71            Unshown::NotRead => f.write_str("the program's results are made of none of the matrix's words"),
72            Unshown::NotApplied => f.write_str(
73                "the program sums no product of the matrix's words with other values: it does not show how it \
74                 applies the matrix",
75            ),
76            Unshown::BothWays { along, across } => write!(
77                f,
78                "the program applies the matrix both ways: {along} sums of one line's words and {across} of one lane's"
79            ),
80            Unshown::Unexamined { why } => f.write_str(why),
81        }
82    }
83}
84/// What the source states of how it binds a constant buffer of the program, beyond what its constants are.
85///
86/// A program declares a constant buffer at the size it indexes it, and a source can bind more: D3D12 bounds a constant
87/// buffer read by the size of the view the draw binds (the CBV's `SizeInBytes`), not by the shader's declaration, so a
88/// skinning palette a program declares as two matrices is bound as the hundreds the draw uploads, and a joint index past
89/// the declaration reads the palette, not zero. A lifter takes the rows of a buffer's uniform array from the bound size
90/// when it has one (`iridia::BoundSizes`).
91#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
92pub struct ConstantBufferBinding {
93    /// A constant buffer resource of the shader.
94    pub resource: ResourceId,
95    /// The bytes the source binds the buffer with, more than the program declares and a whole number of 16-byte rows;
96    /// `None` is the declared size. Where the engine binds different sizes for different draws, the largest it binds:
97    /// a consumer that fills fewer rows leaves the rest zero.
98    pub bound_size: Option<u32>,
99}
100/// What a pixel program's code and its target's stated blend show of the lanes of one output that is a render target
101/// (`iridia::output_uses::output_uses`): observations, not roles. Each is a lane mask, bit k lane k.
102#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
103pub struct OutputUse {
104    /// The output.
105    pub label: Label,
106    /// The render target it is written to: its system value `SV_Target<n>`, or its label's index where it has none.
107    pub target: u32,
108    /// Lane 3 where the target's stated blend weighs the colour by the source alpha (the colour equation's source or
109    /// destination factor is `SrcAlpha` or `OneMinusSrcAlpha`), else none.
110    pub blend_weight: u8,
111    /// The lanes whose written value is among what a discard's conditions are made of. A literal is no evidence (equal
112    /// literals are one node of the value graph); none where the program's value graph was not given.
113    pub discard_tested: u8,
114}