Skip to content

Commit e2d6880

Browse files
authored
Support for the OVR_multiview2 WebGL extension (gfx-rs#1933)
* Make some (currently hacky) changes to enable multiview in webgl * Fix ViewIndex built in for this extension * Run cargo fmt, fix tests * Allow specifying if we're targetting webgl in the glsl version * Document multiview2 extension * fn embedded -> const fn embedded * Fix tests * Fix benches * Add snapshot tests * Revamp so that the glsl options have some multiview options. Also add tests * Make clippy happier * Go back to having is_webgl be part of Version * Use wgsl as input for tests * Rename Version::new_embedded to Version::new_gles, fix glsl validation * Run cargo fmt * Fix brand new clippy warnings
1 parent b746e0a commit e2d6880

19 files changed

+180
-27
lines changed

benches/criterion.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ fn backends(c: &mut Criterion) {
239239
b.iter(|| {
240240
let mut string = String::new();
241241
let options = naga::back::glsl::Options {
242-
version: naga::back::glsl::Version::Embedded(320),
242+
version: naga::back::glsl::Version::new_gles(320),
243243
writer_flags: naga::back::glsl::WriterFlags::empty(),
244244
binding_map: Default::default(),
245245
};
@@ -248,6 +248,7 @@ fn backends(c: &mut Criterion) {
248248
let pipeline_options = naga::back::glsl::PipelineOptions {
249249
shader_stage: ep.stage,
250250
entry_point: ep.name.clone(),
251+
multiview: None,
251252
};
252253
match naga::back::glsl::Writer::new(
253254
&mut string,

cli/src/main.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ impl FromStr for GlslProfileArg {
133133
Ok(Self(if s.starts_with("core") {
134134
Version::Desktop(s[4..].parse().unwrap_or(330))
135135
} else if s.starts_with("es") {
136-
Version::Embedded(s[2..].parse().unwrap_or(310))
136+
Version::new_gles(s[2..].parse().unwrap_or(310))
137137
} else {
138138
return Err(format!("Unknown profile: {}", s));
139139
}))
@@ -454,6 +454,7 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
454454
"comp" => naga::ShaderStage::Compute,
455455
_ => unreachable!(),
456456
},
457+
multiview: None,
457458
};
458459

459460
let mut buffer = String::new();

src/back/glsl/features.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ impl FeaturesManager {
8282
// Used when both core and es support the feature
8383
($feature:ident, $core:literal, $es:literal) => {
8484
if self.0.contains(Features::$feature)
85-
&& (version < Version::Desktop($core) || version < Version::Embedded($es))
85+
&& (version < Version::Desktop($core) || version < Version::new_gles($es))
8686
{
8787
missing |= Features::$feature;
8888
}
@@ -106,7 +106,10 @@ impl FeaturesManager {
106106
check_feature!(CULL_DISTANCE, 450, 300);
107107
check_feature!(SAMPLE_VARIABLES, 400, 300);
108108
check_feature!(DYNAMIC_ARRAY_SIZE, 430, 310);
109-
check_feature!(MULTI_VIEW, 140, 310);
109+
match version {
110+
Version::Embedded { is_webgl: true, .. } => check_feature!(MULTI_VIEW, 140, 300),
111+
_ => check_feature!(MULTI_VIEW, 140, 310),
112+
};
110113
// Only available on glsl core, this means that opengl es can't query the number
111114
// of samples nor levels in a image and neither do bound checks on the sample nor
112115
// the level argument of texelFecth
@@ -212,11 +215,16 @@ impl FeaturesManager {
212215
}
213216

214217
if self.0.contains(Features::MULTI_VIEW) {
215-
// https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_multiview.txt
216-
writeln!(out, "#extension GL_EXT_multiview : require")?;
218+
if let Version::Embedded { is_webgl: true, .. } = version {
219+
// https://www.khronos.org/registry/OpenGL/extensions/OVR/OVR_multiview2.txt
220+
writeln!(out, "#extension GL_OVR_multiview2 : require")?;
221+
} else {
222+
// https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_multiview.txt
223+
writeln!(out, "#extension GL_EXT_multiview : require")?;
224+
}
217225
}
218226

219-
if self.0.contains(Features::FMA) && version >= Version::Embedded(310) {
227+
if self.0.contains(Features::FMA) && version >= Version::new_gles(310) {
220228
// https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_gpu_shader5.txt
221229
writeln!(out, "#extension GL_EXT_gpu_shader5 : require")?;
222230
}
@@ -269,6 +277,10 @@ impl<'a, W> Writer<'a, W> {
269277
self.features.request(Features::COMPUTE_SHADER)
270278
}
271279

280+
if self.multiview.is_some() {
281+
self.features.request(Features::MULTI_VIEW);
282+
}
283+
272284
for (ty_handle, ty) in self.module.types.iter() {
273285
match ty.inner {
274286
TypeInner::Scalar { kind, width } => self.scalar_required_features(kind, width),

src/back/glsl/mod.rs

+62-14
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,31 @@ pub enum Version {
119119
/// `core` GLSL.
120120
Desktop(u16),
121121
/// `es` GLSL.
122-
Embedded(u16),
122+
Embedded { version: u16, is_webgl: bool },
123123
}
124124

125125
impl Version {
126+
/// Create a new gles version
127+
pub const fn new_gles(version: u16) -> Self {
128+
Self::Embedded {
129+
version,
130+
is_webgl: false,
131+
}
132+
}
133+
126134
/// Returns true if self is `Version::Embedded` (i.e. is a es version)
127135
const fn is_es(&self) -> bool {
128136
match *self {
129137
Version::Desktop(_) => false,
130-
Version::Embedded(_) => true,
138+
Version::Embedded { .. } => true,
139+
}
140+
}
141+
142+
/// Returns true if targetting WebGL
143+
const fn is_webgl(&self) -> bool {
144+
match *self {
145+
Version::Desktop(_) => false,
146+
Version::Embedded { is_webgl, .. } => is_webgl,
131147
}
132148
}
133149

@@ -140,7 +156,7 @@ impl Version {
140156
fn is_supported(&self) -> bool {
141157
match *self {
142158
Version::Desktop(v) => SUPPORTED_CORE_VERSIONS.contains(&v),
143-
Version::Embedded(v) => SUPPORTED_ES_VERSIONS.contains(&v),
159+
Version::Embedded { version: v, .. } => SUPPORTED_ES_VERSIONS.contains(&v),
144160
}
145161
}
146162

@@ -151,27 +167,29 @@ impl Version {
151167
/// Note: `location=` for vertex inputs and fragment outputs is supported
152168
/// unconditionally for GLES 300.
153169
fn supports_explicit_locations(&self) -> bool {
154-
*self >= Version::Embedded(310) || *self >= Version::Desktop(410)
170+
*self >= Version::Desktop(410) || *self >= Version::new_gles(310)
155171
}
156172

157173
fn supports_early_depth_test(&self) -> bool {
158-
*self >= Version::Desktop(130) || *self >= Version::Embedded(310)
174+
*self >= Version::Desktop(130) || *self >= Version::new_gles(310)
159175
}
160176

161177
fn supports_std430_layout(&self) -> bool {
162-
*self >= Version::Desktop(430) || *self >= Version::Embedded(310)
178+
*self >= Version::Desktop(430) || *self >= Version::new_gles(310)
163179
}
164180

165181
fn supports_fma_function(&self) -> bool {
166-
*self >= Version::Desktop(400) || *self >= Version::Embedded(310)
182+
*self >= Version::Desktop(400) || *self >= Version::new_gles(310)
167183
}
168184
}
169185

170186
impl PartialOrd for Version {
171187
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
172188
match (*self, *other) {
173189
(Version::Desktop(x), Version::Desktop(y)) => Some(x.cmp(&y)),
174-
(Version::Embedded(x), Version::Embedded(y)) => Some(x.cmp(&y)),
190+
(Version::Embedded { version: x, .. }, Version::Embedded { version: y, .. }) => {
191+
Some(x.cmp(&y))
192+
}
175193
_ => None,
176194
}
177195
}
@@ -181,7 +199,7 @@ impl fmt::Display for Version {
181199
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182200
match *self {
183201
Version::Desktop(v) => write!(f, "{} core", v),
184-
Version::Embedded(v) => write!(f, "{} es", v),
202+
Version::Embedded { version: v, .. } => write!(f, "{} es", v),
185203
}
186204
}
187205
}
@@ -215,7 +233,7 @@ pub struct Options {
215233
impl Default for Options {
216234
fn default() -> Self {
217235
Options {
218-
version: Version::Embedded(310),
236+
version: Version::new_gles(310),
219237
writer_flags: WriterFlags::ADJUST_COORDINATE_SPACE,
220238
binding_map: BindingMap::default(),
221239
}
@@ -233,6 +251,8 @@ pub struct PipelineOptions {
233251
///
234252
/// If no entry point that matches is found while creating a [`Writer`], a error will be thrown.
235253
pub entry_point: String,
254+
/// How many views to render to, if doing multiview rendering.
255+
pub multiview: Option<std::num::NonZeroU32>,
236256
}
237257

238258
/// Reflection info for texture mappings and uniforms.
@@ -285,6 +305,7 @@ struct VaryingName<'a> {
285305
binding: &'a crate::Binding,
286306
stage: ShaderStage,
287307
output: bool,
308+
targetting_webgl: bool,
288309
}
289310
impl fmt::Display for VaryingName<'_> {
290311
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -302,7 +323,11 @@ impl fmt::Display for VaryingName<'_> {
302323
write!(f, "_{}_location{}", prefix, location,)
303324
}
304325
crate::Binding::BuiltIn(built_in) => {
305-
write!(f, "{}", glsl_built_in(built_in, self.output))
326+
write!(
327+
f,
328+
"{}",
329+
glsl_built_in(built_in, self.output, self.targetting_webgl)
330+
)
306331
}
307332
}
308333
}
@@ -400,6 +425,8 @@ pub struct Writer<'a, W> {
400425
named_expressions: crate::NamedExpressions,
401426
/// Set of expressions that need to be baked to avoid unnecessary repetition in output
402427
need_bake_expressions: back::NeedBakeExpressions,
428+
/// How many views to render to, if doing multiview rendering.
429+
multiview: Option<std::num::NonZeroU32>,
403430
}
404431

405432
impl<'a, W: Write> Writer<'a, W> {
@@ -451,7 +478,7 @@ impl<'a, W: Write> Writer<'a, W> {
451478
reflection_names_globals: crate::FastHashMap::default(),
452479
entry_point: &module.entry_points[ep_idx],
453480
entry_point_idx: ep_idx as u16,
454-
481+
multiview: pipeline_options.multiview,
455482
block_id: IdGenerator::default(),
456483
named_expressions: Default::default(),
457484
need_bake_expressions: Default::default(),
@@ -540,6 +567,13 @@ impl<'a, W: Write> Writer<'a, W> {
540567
}
541568
}
542569

570+
if self.entry_point.stage == ShaderStage::Vertex && self.options.version.is_webgl() {
571+
if let Some(multiview) = self.multiview.as_ref() {
572+
writeln!(self.out, "layout(num_views = {}) in;", multiview)?;
573+
writeln!(self.out)?;
574+
}
575+
}
576+
543577
let ep_info = self.info.get_entry_point(self.entry_point_idx as usize);
544578

545579
// Write struct types.
@@ -1180,7 +1214,11 @@ impl<'a, W: Write> Writer<'a, W> {
11801214
} => (location, interpolation, sampling),
11811215
crate::Binding::BuiltIn(built_in) => {
11821216
if let crate::BuiltIn::Position { invariant: true } = built_in {
1183-
writeln!(self.out, "invariant {};", glsl_built_in(built_in, output))?;
1217+
writeln!(
1218+
self.out,
1219+
"invariant {};",
1220+
glsl_built_in(built_in, output, self.options.version.is_webgl())
1221+
)?;
11841222
}
11851223
return Ok(());
11861224
}
@@ -1238,6 +1276,7 @@ impl<'a, W: Write> Writer<'a, W> {
12381276
},
12391277
stage: self.entry_point.stage,
12401278
output,
1279+
targetting_webgl: self.options.version.is_webgl(),
12411280
};
12421281
writeln!(self.out, " {};", vname)?;
12431282

@@ -1378,6 +1417,7 @@ impl<'a, W: Write> Writer<'a, W> {
13781417
binding: member.binding.as_ref().unwrap(),
13791418
stage,
13801419
output: false,
1420+
targetting_webgl: self.options.version.is_webgl(),
13811421
};
13821422
if index != 0 {
13831423
write!(self.out, ", ")?;
@@ -1391,6 +1431,7 @@ impl<'a, W: Write> Writer<'a, W> {
13911431
binding: arg.binding.as_ref().unwrap(),
13921432
stage,
13931433
output: false,
1434+
targetting_webgl: self.options.version.is_webgl(),
13941435
};
13951436
writeln!(self.out, "{};", varying_name)?;
13961437
}
@@ -1897,6 +1938,7 @@ impl<'a, W: Write> Writer<'a, W> {
18971938
binding: member.binding.as_ref().unwrap(),
18981939
stage: ep.stage,
18991940
output: true,
1941+
targetting_webgl: self.options.version.is_webgl(),
19001942
};
19011943
write!(self.out, "{} = ", varying_name)?;
19021944

@@ -1921,6 +1963,7 @@ impl<'a, W: Write> Writer<'a, W> {
19211963
binding: result.binding.as_ref().unwrap(),
19221964
stage: ep.stage,
19231965
output: true,
1966+
targetting_webgl: self.options.version.is_webgl(),
19241967
};
19251968
write!(self.out, "{} = ", name)?;
19261969
self.write_expr(value, ctx)?;
@@ -3629,7 +3672,11 @@ const fn glsl_scalar(
36293672
}
36303673

36313674
/// Helper function that returns the glsl variable name for a builtin
3632-
const fn glsl_built_in(built_in: crate::BuiltIn, output: bool) -> &'static str {
3675+
const fn glsl_built_in(
3676+
built_in: crate::BuiltIn,
3677+
output: bool,
3678+
targetting_webgl: bool,
3679+
) -> &'static str {
36333680
use crate::BuiltIn as Bi;
36343681

36353682
match built_in {
@@ -3640,6 +3687,7 @@ const fn glsl_built_in(built_in: crate::BuiltIn, output: bool) -> &'static str {
36403687
"gl_FragCoord"
36413688
}
36423689
}
3690+
Bi::ViewIndex if targetting_webgl => "int(gl_ViewID_OVR)",
36433691
Bi::ViewIndex => "gl_ViewIndex",
36443692
// vertex
36453693
Bi::BaseInstance => "uint(gl_BaseInstance)",

src/back/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ struct FunctionCtx<'a> {
5959
named_expressions: &'a crate::NamedExpressions,
6060
}
6161

62-
impl<'a> FunctionCtx<'_> {
62+
impl FunctionCtx<'_> {
6363
/// Helper method that generates a [`NameKey`](crate::proc::NameKey) for a local in the current function
6464
const fn name_key(&self, local: crate::Handle<crate::LocalVariable>) -> crate::proc::NameKey {
6565
match self.ty {

src/valid/analyzer.rs

-1
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,6 @@ impl FunctionInfo {
484484
return Err(ExpressionError::MissingCapabilities(needed_caps));
485485
}
486486

487-
let _ = ();
488487
Uniformity {
489488
non_uniform_result: self
490489
.add_assignable_ref(base, &mut assignable_global)

tests/in/functions-webgl.param.ron

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
(
22
glsl: (
3-
version: Embedded(300),
3+
version: Embedded(
4+
version: 300,
5+
is_webgl: false
6+
),
47
writer_flags: (bits: 0),
58
binding_map: {},
69
),

tests/in/multiview.param.ron

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(
2+
glsl_multiview: Some(2),
3+
)

tests/in/multiview.wgsl

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@vertex
2+
fn main(@builtin(view_index) view_index: i32) {}

tests/in/multiview_webgl.param.ron

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
(
2+
glsl: (
3+
version: Embedded (
4+
version: 300,
5+
is_webgl: true
6+
),
7+
writer_flags: (bits: 0),
8+
binding_map: {},
9+
),
10+
glsl_multiview: Some(2),
11+
)

tests/in/multiview_webgl.wgsl

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@vertex
2+
fn main(@builtin(view_index) view_index: i32) {}

tests/in/push-constants.param.ron

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
(
22
god_mode: true,
33
glsl: (
4-
version: Embedded(320),
4+
version: Embedded(
5+
version: 320,
6+
is_webgl: false
7+
),
58
writer_flags: (bits: 0),
69
binding_map: {},
710
),

tests/in/quad.param.ron

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
adjust_coordinate_space: true,
66
),
77
glsl: (
8-
version: Embedded(300),
8+
version: Embedded(
9+
version: 300,
10+
is_webgl: false
11+
),
912
writer_flags: (bits: 0),
1013
binding_map: {},
1114
),

0 commit comments

Comments
 (0)