Skip to content
This repository was archived by the owner on Jan 29, 2025. It is now read-only.

Commit

Permalink
[glsl-out] binding location mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Jun 27, 2021
1 parent 19de60f commit 57b3256
Show file tree
Hide file tree
Showing 12 changed files with 182 additions and 95 deletions.
30 changes: 21 additions & 9 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::{env, error::Error, path::Path};
struct Parameters {
validation_flags: naga::valid::ValidationFlags,
index_bounds_check_policy: naga::back::IndexBoundsCheckPolicy,
entry_point: Option<String>,
spv_adjust_coordinate_space: bool,
spv_flow_dump_prefix: Option<String>,
spv: naga::back::spv::Options,
Expand Down Expand Up @@ -89,7 +90,7 @@ fn main() {
};
}
"flow-dir" => params.spv_flow_dump_prefix = args.next(),
"entry-point" => params.glsl.entry_point = args.next().unwrap(),
"entry-point" => params.entry_point = Some(args.next().unwrap()),
"profile" => {
use naga::back::glsl::Version;
let string = args.next().unwrap();
Expand Down Expand Up @@ -282,17 +283,28 @@ fn main() {
stage @ "vert" | stage @ "frag" | stage @ "comp" => {
use naga::back::glsl;

params.glsl.shader_stage = match stage {
"vert" => naga::ShaderStage::Vertex,
"frag" => naga::ShaderStage::Fragment,
"comp" => naga::ShaderStage::Compute,
_ => unreachable!(),
let pipeline_options = glsl::PipelineOptions {
entry_point: match params.entry_point {
Some(ref name) => name.clone(),
None => "main".to_string(),
},
shader_stage: match stage {
"vert" => naga::ShaderStage::Vertex,
"frag" => naga::ShaderStage::Fragment,
"comp" => naga::ShaderStage::Compute,
_ => unreachable!(),
},
};

let mut buffer = String::new();
let mut writer =
glsl::Writer::new(&mut buffer, &module, info.as_ref().unwrap(), &params.glsl)
.unwrap_pretty();
let mut writer = glsl::Writer::new(
&mut buffer,
&module,
info.as_ref().unwrap(),
&params.glsl,
&pipeline_options,
)
.unwrap_pretty();
writer.write().unwrap();
fs::write(output_path, buffer).unwrap();
}
Expand Down
2 changes: 1 addition & 1 deletion src/back/glsl/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ impl<'a, W> Writer<'a, W> {
self.varying_required_features(result.binding.as_ref(), result.ty);
}

if let ShaderStage::Compute = self.options.shader_stage {
if let ShaderStage::Compute = self.entry_point.stage {
self.features.request(Features::COMPUTE_SHADER)
}

Expand Down
89 changes: 69 additions & 20 deletions src/back/glsl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,12 @@ pub const SUPPORTED_CORE_VERSIONS: &[u16] = &[330, 400, 410, 420, 430, 440, 450]
/// List of supported es glsl versions
pub const SUPPORTED_ES_VERSIONS: &[u16] = &[300, 310, 320];

pub type BindingMap = std::collections::BTreeMap<crate::ResourceBinding, u8>;

/// glsl version
#[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
pub enum Version {
/// `core` glsl
Desktop(u16),
Expand Down Expand Up @@ -124,28 +128,38 @@ impl fmt::Display for Version {

/// Structure that contains the configuration used in the [`Writer`](Writer)
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
pub struct Options {
/// The glsl version to be used
pub version: Version,
/// The stage of the entry point
pub shader_stage: ShaderStage,
/// The name of the entry point
///
/// If no entry point that matches is found a error will be thrown while creating a new instance
/// of [`Writer`](struct.Writer.html)
pub entry_point: String,
/// Map of resources association to binding locations.
pub binding_map: BindingMap,
}

impl Default for Options {
fn default() -> Self {
Options {
version: Version::Embedded(320),
shader_stage: ShaderStage::Compute,
entry_point: "main".to_string(),
version: Version::Embedded(310),
binding_map: BindingMap::default(),
}
}
}

// A subset of options that are meant to be changed per pipeline.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
pub struct PipelineOptions {
/// The stage of the entry point
pub shader_stage: ShaderStage,
/// The name of the entry point
///
/// If no entry point that matches is found a error will be thrown while creating a new instance
/// of [`Writer`](struct.Writer.html)
pub entry_point: String,
}

/// Structure that contains a reflection info
pub struct ReflectionInfo {
pub texture_mapping: crate::FastHashMap<String, TextureMapping>,
Expand Down Expand Up @@ -297,6 +311,7 @@ impl<'a, W: Write> Writer<'a, W> {
module: &'a crate::Module,
info: &'a valid::ModuleInfo,
options: &'a Options,
pipeline_options: &'a PipelineOptions,
) -> Result<Self, Error> {
// Check if the requested version is supported
if !options.version.is_supported() {
Expand All @@ -308,7 +323,9 @@ impl<'a, W: Write> Writer<'a, W> {
let ep_idx = module
.entry_points
.iter()
.position(|ep| options.shader_stage == ep.stage && options.entry_point == ep.name)
.position(|ep| {
pipeline_options.shader_stage == ep.stage && pipeline_options.entry_point == ep.name
})
.ok_or(Error::EntryPointNotFound)?;

// Generate a map with names required to write the module
Expand Down Expand Up @@ -370,7 +387,7 @@ impl<'a, W: Write> Writer<'a, W> {
writeln!(self.out)?;
}

if self.options.shader_stage == ShaderStage::Compute {
if self.entry_point.stage == ShaderStage::Compute {
let workgroup_size = self.entry_point.workgroup_size;
writeln!(
self.out,
Expand Down Expand Up @@ -439,13 +456,36 @@ impl<'a, W: Write> Writer<'a, W> {
arrayed,
class,
} => {
// Write the storage format if needed
if let TypeInner::Image {
class: crate::ImageClass::Storage(format),
..
} = self.module.types[global.ty].inner
{
write!(self.out, "layout({}) ", glsl_storage_format(format))?;
// Gather the storage format if needed
let layout_storage_format = match self.module.types[global.ty].inner {
TypeInner::Image {
class: crate::ImageClass::Storage(format),
..
} => Some(glsl_storage_format(format)),
_ => None,
};
// Gether the location if needed
let layout_binding = if self.options.version.supports_explicit_locations() {
let br = global.binding.as_ref().unwrap();
self.options.binding_map.get(br).cloned()
} else {
None
};

// Write all the layout qualifiers
if layout_binding.is_some() || layout_storage_format.is_some() {
write!(self.out, "layout(")?;
if let Some(binding) = layout_binding {
write!(self.out, "binding = {}", binding)?;
}
if let Some(format) = layout_storage_format {
let separator = match layout_binding {
Some(_) => ",",
None => "",
};
write!(self.out, "{}{}", separator, format)?;
}
write!(self.out, ") ")?;
}

if let Some(storage_access) = glsl_storage_access(global.storage_access) {
Expand Down Expand Up @@ -702,6 +742,15 @@ impl<'a, W: Write> Writer<'a, W> {
handle: Handle<crate::GlobalVariable>,
global: &crate::GlobalVariable,
) -> BackendResult {
if self.options.version.supports_explicit_locations() {
if let Some(ref br) = global.binding {
match self.options.binding_map.get(br) {
Some(binding) => write!(self.out, "layout(binding = {}) ", binding)?,
None => log::debug!("unassigned binding for {:?}", global.name),
}
}
}

if let Some(storage_access) = glsl_storage_access(global.storage_access) {
write!(self.out, "{} ", storage_access)?;
}
Expand Down Expand Up @@ -782,7 +831,7 @@ impl<'a, W: Write> Writer<'a, W> {
//
// We ignore all interpolation and auxiliary modifiers that aren't used in fragment
// shaders' input globals or vertex shaders' output globals.
let emit_interpolation_and_auxiliary = match self.options.shader_stage {
let emit_interpolation_and_auxiliary = match self.entry_point.stage {
ShaderStage::Vertex => output,
ShaderStage::Fragment => !output,
_ => false,
Expand Down
70 changes: 33 additions & 37 deletions src/back/msl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ holding the result.
!*/

use crate::{arena::Handle, valid::ModuleInfo};
use std::fmt::{Error as FmtError, Write};
use std::{
fmt::{Error as FmtError, Write},
ops,
};

mod keywords;
pub mod sampler;
Expand Down Expand Up @@ -57,21 +60,16 @@ pub struct BindTarget {
pub mutable: bool,
}

#[derive(Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
pub struct BindSource {
pub stage: crate::ShaderStage,
pub group: u32,
pub binding: u32,
}

pub type BindingMap = std::collections::BTreeMap<BindSource, BindTarget>;
// Using `BTreeMap` instead of `HashMap` so that we can hash itself.
pub type BindingMap = std::collections::BTreeMap<crate::ResourceBinding, BindTarget>;

#[derive(Clone, Debug, Default, Hash, Eq, Ord, PartialEq, PartialOrd)]
#[derive(Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
pub struct PerStageResources {
#[cfg_attr(feature = "deserialize", serde(default))]
pub resources: BindingMap,

#[cfg_attr(feature = "deserialize", serde(default))]
pub push_constant_buffer: Option<Slot>,

Expand All @@ -82,7 +80,7 @@ pub struct PerStageResources {
pub sizes_buffer: Option<Slot>,
}

#[derive(Clone, Debug, Default, Hash, Eq, Ord, PartialEq, PartialOrd)]
#[derive(Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
pub struct PerStageMap {
Expand All @@ -94,6 +92,17 @@ pub struct PerStageMap {
pub cs: PerStageResources,
}

impl ops::Index<crate::ShaderStage> for PerStageMap {
type Output = PerStageResources;
fn index(&self, stage: crate::ShaderStage) -> &PerStageResources {
match stage {
crate::ShaderStage::Vertex => &self.vs,
crate::ShaderStage::Fragment => &self.fs,
crate::ShaderStage::Compute => &self.cs,
}
}
}

enum ResolvedBinding {
BuiltIn(crate::BuiltIn),
Attribute(u32),
Expand Down Expand Up @@ -146,11 +155,11 @@ pub enum Error {
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
pub enum EntryPointError {
#[error("mapping of {0:?} is missing")]
MissingBinding(BindSource),
#[error("mapping for push constants at stage {0:?} is missing")]
MissingPushConstants(crate::ShaderStage),
#[error("mapping for sizes buffer for stage {0:?} is missing")]
MissingSizesBuffer(crate::ShaderStage),
MissingBinding(crate::ResourceBinding),
#[error("mapping for push constants is missing")]
MissingPushConstants,
#[error("mapping for sizes buffer is missing")]
MissingSizesBuffer,
}

#[derive(Clone, Copy, Debug)]
Expand All @@ -167,9 +176,7 @@ enum LocationMode {
pub struct Options {
/// (Major, Minor) target version of the Metal Shading Language.
pub lang_version: (u8, u8),
/// Binding model mapping to Metal.
pub binding_map: BindingMap,
/// Map of per-stage resources (e.g. push constants) to slots
/// Map of per-stage resources to slots.
pub per_stage_map: PerStageMap,
/// Samplers to be inlined into the code.
pub inline_samplers: Vec<sampler::InlineSampler>,
Expand All @@ -183,7 +190,6 @@ impl Default for Options {
fn default() -> Self {
Options {
lang_version: (1, 0),
binding_map: BindingMap::default(),
per_stage_map: PerStageMap::default(),
inline_samplers: Vec::new(),
spirv_cross_compatibility: false,
Expand Down Expand Up @@ -257,19 +263,14 @@ impl Options {
stage: crate::ShaderStage,
res_binding: &crate::ResourceBinding,
) -> Result<ResolvedBinding, EntryPointError> {
let source = BindSource {
stage,
group: res_binding.group,
binding: res_binding.binding,
};
match self.binding_map.get(&source) {
match self.per_stage_map[stage].resources.get(&res_binding) {
Some(target) => Ok(ResolvedBinding::Resource(target.clone())),
None if self.fake_missing_bindings => Ok(ResolvedBinding::User {
prefix: "fake",
index: 0,
interpolation: None,
}),
None => Err(EntryPointError::MissingBinding(source)),
None => Err(EntryPointError::MissingBinding(res_binding.clone())),
}
}

Expand All @@ -294,20 +295,15 @@ impl Options {
index: 0,
interpolation: None,
}),
None => Err(EntryPointError::MissingPushConstants(stage)),
None => Err(EntryPointError::MissingPushConstants),
}
}

fn resolve_sizes_buffer(
&self,
stage: crate::ShaderStage,
) -> Result<ResolvedBinding, EntryPointError> {
let slot = match stage {
crate::ShaderStage::Vertex => self.per_stage_map.vs.sizes_buffer,
crate::ShaderStage::Fragment => self.per_stage_map.fs.sizes_buffer,
crate::ShaderStage::Compute => self.per_stage_map.cs.sizes_buffer,
};

let slot = self.per_stage_map[stage].sizes_buffer;
match slot {
Some(slot) => Ok(ResolvedBinding::Resource(BindTarget {
buffer: Some(slot),
Expand All @@ -320,7 +316,7 @@ impl Options {
index: 0,
interpolation: None,
}),
None => Err(EntryPointError::MissingSizesBuffer(stage)),
None => Err(EntryPointError::MissingSizesBuffer),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ pub enum Binding {
}

/// Pipeline binding information for global resources.
#[derive(Clone, Debug, Hash, PartialEq)]
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
pub struct ResourceBinding {
Expand Down
Loading

0 comments on commit 57b3256

Please sign in to comment.