Skip to content

Commit

Permalink
Support for the OVR_multiview2 WebGL extension (#1933)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
expenses authored Jun 30, 2022
1 parent b746e0a commit e2d6880
Show file tree
Hide file tree
Showing 19 changed files with 180 additions and 27 deletions.
3 changes: 2 additions & 1 deletion benches/criterion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ fn backends(c: &mut Criterion) {
b.iter(|| {
let mut string = String::new();
let options = naga::back::glsl::Options {
version: naga::back::glsl::Version::Embedded(320),
version: naga::back::glsl::Version::new_gles(320),
writer_flags: naga::back::glsl::WriterFlags::empty(),
binding_map: Default::default(),
};
Expand All @@ -248,6 +248,7 @@ fn backends(c: &mut Criterion) {
let pipeline_options = naga::back::glsl::PipelineOptions {
shader_stage: ep.stage,
entry_point: ep.name.clone(),
multiview: None,
};
match naga::back::glsl::Writer::new(
&mut string,
Expand Down
3 changes: 2 additions & 1 deletion cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ impl FromStr for GlslProfileArg {
Ok(Self(if s.starts_with("core") {
Version::Desktop(s[4..].parse().unwrap_or(330))
} else if s.starts_with("es") {
Version::Embedded(s[2..].parse().unwrap_or(310))
Version::new_gles(s[2..].parse().unwrap_or(310))
} else {
return Err(format!("Unknown profile: {}", s));
}))
Expand Down Expand Up @@ -454,6 +454,7 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
"comp" => naga::ShaderStage::Compute,
_ => unreachable!(),
},
multiview: None,
};

let mut buffer = String::new();
Expand Down
22 changes: 17 additions & 5 deletions src/back/glsl/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl FeaturesManager {
// Used when both core and es support the feature
($feature:ident, $core:literal, $es:literal) => {
if self.0.contains(Features::$feature)
&& (version < Version::Desktop($core) || version < Version::Embedded($es))
&& (version < Version::Desktop($core) || version < Version::new_gles($es))
{
missing |= Features::$feature;
}
Expand All @@ -106,7 +106,10 @@ impl FeaturesManager {
check_feature!(CULL_DISTANCE, 450, 300);
check_feature!(SAMPLE_VARIABLES, 400, 300);
check_feature!(DYNAMIC_ARRAY_SIZE, 430, 310);
check_feature!(MULTI_VIEW, 140, 310);
match version {
Version::Embedded { is_webgl: true, .. } => check_feature!(MULTI_VIEW, 140, 300),
_ => check_feature!(MULTI_VIEW, 140, 310),
};
// Only available on glsl core, this means that opengl es can't query the number
// of samples nor levels in a image and neither do bound checks on the sample nor
// the level argument of texelFecth
Expand Down Expand Up @@ -212,11 +215,16 @@ impl FeaturesManager {
}

if self.0.contains(Features::MULTI_VIEW) {
// https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_multiview.txt
writeln!(out, "#extension GL_EXT_multiview : require")?;
if let Version::Embedded { is_webgl: true, .. } = version {
// https://www.khronos.org/registry/OpenGL/extensions/OVR/OVR_multiview2.txt
writeln!(out, "#extension GL_OVR_multiview2 : require")?;
} else {
// https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_multiview.txt
writeln!(out, "#extension GL_EXT_multiview : require")?;
}
}

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

if self.multiview.is_some() {
self.features.request(Features::MULTI_VIEW);
}

for (ty_handle, ty) in self.module.types.iter() {
match ty.inner {
TypeInner::Scalar { kind, width } => self.scalar_required_features(kind, width),
Expand Down
76 changes: 62 additions & 14 deletions src/back/glsl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,31 @@ pub enum Version {
/// `core` GLSL.
Desktop(u16),
/// `es` GLSL.
Embedded(u16),
Embedded { version: u16, is_webgl: bool },
}

impl Version {
/// Create a new gles version
pub const fn new_gles(version: u16) -> Self {
Self::Embedded {
version,
is_webgl: false,
}
}

/// Returns true if self is `Version::Embedded` (i.e. is a es version)
const fn is_es(&self) -> bool {
match *self {
Version::Desktop(_) => false,
Version::Embedded(_) => true,
Version::Embedded { .. } => true,
}
}

/// Returns true if targetting WebGL
const fn is_webgl(&self) -> bool {
match *self {
Version::Desktop(_) => false,
Version::Embedded { is_webgl, .. } => is_webgl,
}
}

Expand All @@ -140,7 +156,7 @@ impl Version {
fn is_supported(&self) -> bool {
match *self {
Version::Desktop(v) => SUPPORTED_CORE_VERSIONS.contains(&v),
Version::Embedded(v) => SUPPORTED_ES_VERSIONS.contains(&v),
Version::Embedded { version: v, .. } => SUPPORTED_ES_VERSIONS.contains(&v),
}
}

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

fn supports_early_depth_test(&self) -> bool {
*self >= Version::Desktop(130) || *self >= Version::Embedded(310)
*self >= Version::Desktop(130) || *self >= Version::new_gles(310)
}

fn supports_std430_layout(&self) -> bool {
*self >= Version::Desktop(430) || *self >= Version::Embedded(310)
*self >= Version::Desktop(430) || *self >= Version::new_gles(310)
}

fn supports_fma_function(&self) -> bool {
*self >= Version::Desktop(400) || *self >= Version::Embedded(310)
*self >= Version::Desktop(400) || *self >= Version::new_gles(310)
}
}

impl PartialOrd for Version {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (*self, *other) {
(Version::Desktop(x), Version::Desktop(y)) => Some(x.cmp(&y)),
(Version::Embedded(x), Version::Embedded(y)) => Some(x.cmp(&y)),
(Version::Embedded { version: x, .. }, Version::Embedded { version: y, .. }) => {
Some(x.cmp(&y))
}
_ => None,
}
}
Expand All @@ -181,7 +199,7 @@ impl fmt::Display for Version {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Version::Desktop(v) => write!(f, "{} core", v),
Version::Embedded(v) => write!(f, "{} es", v),
Version::Embedded { version: v, .. } => write!(f, "{} es", v),
}
}
}
Expand Down Expand Up @@ -215,7 +233,7 @@ pub struct Options {
impl Default for Options {
fn default() -> Self {
Options {
version: Version::Embedded(310),
version: Version::new_gles(310),
writer_flags: WriterFlags::ADJUST_COORDINATE_SPACE,
binding_map: BindingMap::default(),
}
Expand All @@ -233,6 +251,8 @@ pub struct PipelineOptions {
///
/// If no entry point that matches is found while creating a [`Writer`], a error will be thrown.
pub entry_point: String,
/// How many views to render to, if doing multiview rendering.
pub multiview: Option<std::num::NonZeroU32>,
}

/// Reflection info for texture mappings and uniforms.
Expand Down Expand Up @@ -285,6 +305,7 @@ struct VaryingName<'a> {
binding: &'a crate::Binding,
stage: ShaderStage,
output: bool,
targetting_webgl: bool,
}
impl fmt::Display for VaryingName<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Expand All @@ -302,7 +323,11 @@ impl fmt::Display for VaryingName<'_> {
write!(f, "_{}_location{}", prefix, location,)
}
crate::Binding::BuiltIn(built_in) => {
write!(f, "{}", glsl_built_in(built_in, self.output))
write!(
f,
"{}",
glsl_built_in(built_in, self.output, self.targetting_webgl)
)
}
}
}
Expand Down Expand Up @@ -400,6 +425,8 @@ pub struct Writer<'a, W> {
named_expressions: crate::NamedExpressions,
/// Set of expressions that need to be baked to avoid unnecessary repetition in output
need_bake_expressions: back::NeedBakeExpressions,
/// How many views to render to, if doing multiview rendering.
multiview: Option<std::num::NonZeroU32>,
}

impl<'a, W: Write> Writer<'a, W> {
Expand Down Expand Up @@ -451,7 +478,7 @@ impl<'a, W: Write> Writer<'a, W> {
reflection_names_globals: crate::FastHashMap::default(),
entry_point: &module.entry_points[ep_idx],
entry_point_idx: ep_idx as u16,

multiview: pipeline_options.multiview,
block_id: IdGenerator::default(),
named_expressions: Default::default(),
need_bake_expressions: Default::default(),
Expand Down Expand Up @@ -540,6 +567,13 @@ impl<'a, W: Write> Writer<'a, W> {
}
}

if self.entry_point.stage == ShaderStage::Vertex && self.options.version.is_webgl() {
if let Some(multiview) = self.multiview.as_ref() {
writeln!(self.out, "layout(num_views = {}) in;", multiview)?;
writeln!(self.out)?;
}
}

let ep_info = self.info.get_entry_point(self.entry_point_idx as usize);

// Write struct types.
Expand Down Expand Up @@ -1180,7 +1214,11 @@ impl<'a, W: Write> Writer<'a, W> {
} => (location, interpolation, sampling),
crate::Binding::BuiltIn(built_in) => {
if let crate::BuiltIn::Position { invariant: true } = built_in {
writeln!(self.out, "invariant {};", glsl_built_in(built_in, output))?;
writeln!(
self.out,
"invariant {};",
glsl_built_in(built_in, output, self.options.version.is_webgl())
)?;
}
return Ok(());
}
Expand Down Expand Up @@ -1238,6 +1276,7 @@ impl<'a, W: Write> Writer<'a, W> {
},
stage: self.entry_point.stage,
output,
targetting_webgl: self.options.version.is_webgl(),
};
writeln!(self.out, " {};", vname)?;

Expand Down Expand Up @@ -1378,6 +1417,7 @@ impl<'a, W: Write> Writer<'a, W> {
binding: member.binding.as_ref().unwrap(),
stage,
output: false,
targetting_webgl: self.options.version.is_webgl(),
};
if index != 0 {
write!(self.out, ", ")?;
Expand All @@ -1391,6 +1431,7 @@ impl<'a, W: Write> Writer<'a, W> {
binding: arg.binding.as_ref().unwrap(),
stage,
output: false,
targetting_webgl: self.options.version.is_webgl(),
};
writeln!(self.out, "{};", varying_name)?;
}
Expand Down Expand Up @@ -1897,6 +1938,7 @@ impl<'a, W: Write> Writer<'a, W> {
binding: member.binding.as_ref().unwrap(),
stage: ep.stage,
output: true,
targetting_webgl: self.options.version.is_webgl(),
};
write!(self.out, "{} = ", varying_name)?;

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

/// Helper function that returns the glsl variable name for a builtin
const fn glsl_built_in(built_in: crate::BuiltIn, output: bool) -> &'static str {
const fn glsl_built_in(
built_in: crate::BuiltIn,
output: bool,
targetting_webgl: bool,
) -> &'static str {
use crate::BuiltIn as Bi;

match built_in {
Expand All @@ -3640,6 +3687,7 @@ const fn glsl_built_in(built_in: crate::BuiltIn, output: bool) -> &'static str {
"gl_FragCoord"
}
}
Bi::ViewIndex if targetting_webgl => "int(gl_ViewID_OVR)",
Bi::ViewIndex => "gl_ViewIndex",
// vertex
Bi::BaseInstance => "uint(gl_BaseInstance)",
Expand Down
2 changes: 1 addition & 1 deletion src/back/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ struct FunctionCtx<'a> {
named_expressions: &'a crate::NamedExpressions,
}

impl<'a> FunctionCtx<'_> {
impl FunctionCtx<'_> {
/// Helper method that generates a [`NameKey`](crate::proc::NameKey) for a local in the current function
const fn name_key(&self, local: crate::Handle<crate::LocalVariable>) -> crate::proc::NameKey {
match self.ty {
Expand Down
1 change: 0 additions & 1 deletion src/valid/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,6 @@ impl FunctionInfo {
return Err(ExpressionError::MissingCapabilities(needed_caps));
}

let _ = ();
Uniformity {
non_uniform_result: self
.add_assignable_ref(base, &mut assignable_global)
Expand Down
5 changes: 4 additions & 1 deletion tests/in/functions-webgl.param.ron
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
(
glsl: (
version: Embedded(300),
version: Embedded(
version: 300,
is_webgl: false
),
writer_flags: (bits: 0),
binding_map: {},
),
Expand Down
3 changes: 3 additions & 0 deletions tests/in/multiview.param.ron
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(
glsl_multiview: Some(2),
)
2 changes: 2 additions & 0 deletions tests/in/multiview.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@vertex
fn main(@builtin(view_index) view_index: i32) {}
11 changes: 11 additions & 0 deletions tests/in/multiview_webgl.param.ron
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(
glsl: (
version: Embedded (
version: 300,
is_webgl: true
),
writer_flags: (bits: 0),
binding_map: {},
),
glsl_multiview: Some(2),
)
2 changes: 2 additions & 0 deletions tests/in/multiview_webgl.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@vertex
fn main(@builtin(view_index) view_index: i32) {}
5 changes: 4 additions & 1 deletion tests/in/push-constants.param.ron
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
(
god_mode: true,
glsl: (
version: Embedded(320),
version: Embedded(
version: 320,
is_webgl: false
),
writer_flags: (bits: 0),
binding_map: {},
),
Expand Down
5 changes: 4 additions & 1 deletion tests/in/quad.param.ron
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
adjust_coordinate_space: true,
),
glsl: (
version: Embedded(300),
version: Embedded(
version: 300,
is_webgl: false
),
writer_flags: (bits: 0),
binding_map: {},
),
Expand Down
Loading

0 comments on commit e2d6880

Please sign in to comment.