Skip to content

Commit c2d5fa4

Browse files
committed
[naga] Test validation of function/entry point name collision.
Unlike WGSL, Naga IR permits functions to have conflicting names, and entry points must only have distinct names if they are for the same shader stage. Document and test this.
1 parent faac3bb commit c2d5fa4

2 files changed

Lines changed: 155 additions & 1 deletion

File tree

naga/src/ir/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2411,6 +2411,12 @@ pub struct FunctionResult {
24112411
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
24122412
pub struct Function {
24132413
/// Name of the function, if any.
2414+
///
2415+
/// Unlike WGSL, Naga IR allows a module to have multiple functions with the
2416+
/// same name. Since functions are generally identified by handle, the name
2417+
/// is mostly needed for diagnostics and as a hint to [`Namer`].
2418+
///
2419+
/// [`Namer`]: crate::proc::Namer
24142420
pub name: Option<String>,
24152421
/// Information about function argument.
24162422
pub arguments: Vec<FunctionArgument>,
@@ -2502,7 +2508,9 @@ pub struct Function {
25022508
pub struct EntryPoint {
25032509
/// Name of this entry point, visible externally.
25042510
///
2505-
/// Entry point names for a given `stage` must be distinct within a module.
2511+
/// Unlike WGSL, Naga IR allows a module to have multiple entry points with
2512+
/// the same name, as long as they are for different shader stages. That is,
2513+
/// `(name, stage)` pairs must be distinct within a module.
25062514
pub name: String,
25072515
/// Shader stage.
25082516
pub stage: ShaderStage,

naga/tests/naga/validation.rs

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,3 +1753,149 @@ fn memory_decorations_require_storage_address_space() {
17531753
}
17541754
));
17551755
}
1756+
1757+
/// Naga validation should permit multiple entry points to have the same name,
1758+
/// as long as they are for distinct stages.
1759+
///
1760+
/// WGSL does not permit conflicting names; this is a case where Naga IR is
1761+
/// looser than WGSL.
1762+
#[test]
1763+
fn entry_points_distinguished_by_stage() {
1764+
let mut test_spans = TestSpanGenerator::default();
1765+
let mut module = Module::default();
1766+
1767+
let ty_vec4f = module.types.insert(
1768+
ir::Type {
1769+
name: Some("vec4f".to_string()),
1770+
inner: ir::TypeInner::Vector {
1771+
size: ir::VectorSize::Quad,
1772+
scalar: ir::Scalar::F32,
1773+
},
1774+
},
1775+
test_spans.next(),
1776+
);
1777+
1778+
let vertex_function = ir::Function {
1779+
name: Some("non_unique_name".into()),
1780+
result: Some(ir::FunctionResult {
1781+
ty: ty_vec4f,
1782+
binding: Some(ir::Binding::BuiltIn(ir::BuiltIn::Position {
1783+
invariant: false,
1784+
})),
1785+
}),
1786+
..ir::Function::default()
1787+
};
1788+
module.entry_points.push(ir::EntryPoint {
1789+
name: "non_unique_name".into(),
1790+
stage: ir::ShaderStage::Vertex,
1791+
early_depth_test: None,
1792+
workgroup_size: [0, 0, 0],
1793+
workgroup_size_overrides: None,
1794+
function: vertex_function,
1795+
mesh_info: None,
1796+
task_payload: None,
1797+
incoming_ray_payload: None,
1798+
});
1799+
1800+
module.entry_points.push(ir::EntryPoint {
1801+
name: "non_unique_name".into(),
1802+
stage: ir::ShaderStage::Compute,
1803+
early_depth_test: None,
1804+
workgroup_size: [1, 1, 1],
1805+
workgroup_size_overrides: None,
1806+
function: ir::Function::default(),
1807+
mesh_info: None,
1808+
task_payload: None,
1809+
incoming_ray_payload: None,
1810+
});
1811+
1812+
valid::Validator::new(
1813+
valid::ValidationFlags::default(),
1814+
valid::Capabilities::default(),
1815+
)
1816+
.validate(&module)
1817+
.expect("module should be valid");
1818+
}
1819+
1820+
/// Naga validation should not allow a `Module` to have multiple entry points
1821+
/// with the same name and the same stage.
1822+
#[test]
1823+
fn entry_points_share_name() {
1824+
let mut module = Module::default();
1825+
1826+
module.entry_points.push(ir::EntryPoint {
1827+
name: "non_unique_name".into(),
1828+
stage: ir::ShaderStage::Compute,
1829+
early_depth_test: None,
1830+
workgroup_size: [1, 1, 1],
1831+
workgroup_size_overrides: None,
1832+
function: ir::Function::default(),
1833+
mesh_info: None,
1834+
task_payload: None,
1835+
incoming_ray_payload: None,
1836+
});
1837+
1838+
module.entry_points.push(ir::EntryPoint {
1839+
name: "non_unique_name".into(),
1840+
stage: ir::ShaderStage::Compute,
1841+
early_depth_test: None,
1842+
workgroup_size: [1, 1, 1],
1843+
workgroup_size_overrides: None,
1844+
function: ir::Function::default(),
1845+
mesh_info: None,
1846+
task_payload: None,
1847+
incoming_ray_payload: None,
1848+
});
1849+
1850+
let err = valid::Validator::new(
1851+
valid::ValidationFlags::default(),
1852+
valid::Capabilities::default(),
1853+
)
1854+
.validate(&module)
1855+
.expect_err("module should be invalid");
1856+
1857+
assert!(matches!(
1858+
err.into_inner(),
1859+
valid::ValidationError::EntryPoint {
1860+
source: valid::EntryPointError::Conflict,
1861+
..
1862+
}
1863+
));
1864+
}
1865+
1866+
/// Naga validation should permit a `Module` to have multiple non-entry-point
1867+
/// functions with the same name.
1868+
///
1869+
/// WGSL does not allow this, but Naga IR does: it always refers to functions by
1870+
/// handle, so the names aren't actually needed to interpret the module's
1871+
/// contents.
1872+
#[test]
1873+
fn functions_share_name() {
1874+
let mut test_spans = TestSpanGenerator::default();
1875+
let mut module = Module::default();
1876+
1877+
module.functions.append(
1878+
ir::Function {
1879+
name: Some("non_unique_name".into()),
1880+
result: None,
1881+
..ir::Function::default()
1882+
},
1883+
test_spans.next(),
1884+
);
1885+
1886+
module.functions.append(
1887+
ir::Function {
1888+
name: Some("non_unique_name".into()),
1889+
result: None,
1890+
..ir::Function::default()
1891+
},
1892+
test_spans.next(),
1893+
);
1894+
1895+
valid::Validator::new(
1896+
valid::ValidationFlags::default(),
1897+
valid::Capabilities::default(),
1898+
)
1899+
.validate(&module)
1900+
.expect("module should be valid");
1901+
}

0 commit comments

Comments
 (0)