Skip to content

Commit 1b5aac0

Browse files
khyperiaXAMPPRocky
andauthored
Support GLSL450 and Simple memory models (#168)
* Support GLSL450 and Simple memory models * Update spirv-builder/src/lib.rs Co-authored-by: XAMPPRocky <[email protected]> * Only emit SPV_KHR_vulkan_memory_model when needed Co-authored-by: XAMPPRocky <[email protected]>
1 parent b784710 commit 1b5aac0

File tree

4 files changed

+70
-23
lines changed

4 files changed

+70
-23
lines changed

rustc_codegen_spirv/src/builder_spirv.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,26 @@ pub struct BuilderSpirv {
7171
}
7272

7373
impl BuilderSpirv {
74-
pub fn new(version: Option<(u8, u8)>, kernel_mode: bool) -> Self {
74+
pub fn new(
75+
version: Option<(u8, u8)>,
76+
memory_model: Option<MemoryModel>,
77+
kernel_mode: bool,
78+
) -> Self {
7579
let mut builder = Builder::new();
7680
// Default to spir-v 1.3
7781
let version = version.unwrap_or((1, 3));
7882
builder.set_version(version.0, version.1);
83+
let memory_model = memory_model.unwrap_or(MemoryModel::Vulkan);
7984
if kernel_mode {
8085
builder.capability(Capability::Kernel);
8186
} else {
82-
builder.extension("SPV_KHR_vulkan_memory_model");
8387
builder.capability(Capability::Shader);
84-
builder.capability(Capability::VulkanMemoryModel);
88+
if memory_model == MemoryModel::Vulkan {
89+
if version < (1, 5) {
90+
builder.extension("SPV_KHR_vulkan_memory_model");
91+
}
92+
builder.capability(Capability::VulkanMemoryModel);
93+
}
8594
builder.capability(Capability::VariablePointers);
8695
if version < (1, 3) {
8796
builder.extension("SPV_KHR_variable_pointers");
@@ -98,7 +107,7 @@ impl BuilderSpirv {
98107
builder.capability(Capability::Addresses);
99108
builder.memory_model(AddressingModel::Physical32, MemoryModel::OpenCL);
100109
} else {
101-
builder.memory_model(AddressingModel::Logical, MemoryModel::Vulkan);
110+
builder.memory_model(AddressingModel::Logical, memory_model);
102111
}
103112
Self {
104113
builder: RefCell::new(builder),

rustc_codegen_spirv/src/codegen_cx/mod.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::spirv_type::{SpirvType, SpirvTypePrinter, TypeCache};
1010
use crate::symbols::Symbols;
1111
use bimap::BiHashMap;
1212
use rspirv::dr::{Module, Operand};
13-
use rspirv::spirv::{Decoration, LinkageType, StorageClass, Word};
13+
use rspirv::spirv::{Decoration, LinkageType, MemoryModel, StorageClass, Word};
1414
use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind};
1515
use rustc_codegen_ssa::traits::{
1616
AsmMethods, BackendTypes, CoverageInfoMethods, DebugInfoMethods, MiscMethods,
@@ -63,8 +63,9 @@ pub struct CodegenCx<'tcx> {
6363
impl<'tcx> CodegenCx<'tcx> {
6464
pub fn new(tcx: TyCtxt<'tcx>, codegen_unit: &'tcx CodegenUnit<'tcx>) -> Self {
6565
let sym = Box::new(Symbols::new());
66-
let mut kernel_mode = false;
6766
let mut spirv_version = None;
67+
let mut memory_model = None;
68+
let mut kernel_mode = false;
6869
for &feature in &tcx.sess.target_features {
6970
if feature == sym.kernel {
7071
kernel_mode = true;
@@ -80,12 +81,20 @@ impl<'tcx> CodegenCx<'tcx> {
8081
spirv_version = Some((1, 4));
8182
} else if feature == sym.spirv15 {
8283
spirv_version = Some((1, 5));
84+
} else if feature == sym.simple {
85+
memory_model = Some(MemoryModel::Simple);
86+
} else if feature == sym.vulkan {
87+
memory_model = Some(MemoryModel::Vulkan);
88+
} else if feature == sym.glsl450 {
89+
memory_model = Some(MemoryModel::GLSL450);
90+
} else {
91+
tcx.sess.err(&format!("Unknown feature {}", feature));
8392
}
8493
}
8594
Self {
8695
tcx,
8796
codegen_unit,
88-
builder: BuilderSpirv::new(spirv_version, kernel_mode),
97+
builder: BuilderSpirv::new(spirv_version, memory_model, kernel_mode),
8998
instances: Default::default(),
9099
function_parameter_values: Default::default(),
91100
type_cache: Default::default(),

rustc_codegen_spirv/src/symbols.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ pub struct Symbols {
1313
pub spirv: Symbol,
1414
pub spirv_std: Symbol,
1515
pub kernel: Symbol,
16+
pub simple: Symbol,
17+
pub vulkan: Symbol,
18+
pub glsl450: Symbol,
1619
pub spirv10: Symbol,
1720
pub spirv11: Symbol,
1821
pub spirv12: Symbol,
@@ -217,6 +220,9 @@ impl Symbols {
217220
spirv: Symbol::intern("spirv"),
218221
spirv_std: Symbol::intern("spirv_std"),
219222
kernel: Symbol::intern("kernel"),
223+
simple: Symbol::intern("simple"),
224+
vulkan: Symbol::intern("vulkan"),
225+
glsl450: Symbol::intern("glsl450"),
220226
spirv10: Symbol::intern("spirv1.0"),
221227
spirv11: Symbol::intern("spirv1.1"),
222228
spirv12: Symbol::intern("spirv1.2"),

spirv-builder/src/lib.rs

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,25 @@ impl fmt::Display for SpirvBuilderError {
2727

2828
impl Error for SpirvBuilderError {}
2929

30+
pub enum MemoryModel {
31+
Simple,
32+
Vulkan,
33+
GLSL450,
34+
}
35+
3036
pub struct SpirvBuilder {
3137
path_to_crate: PathBuf,
3238
print_metadata: bool,
3339
spirv_version: Option<(u8, u8)>,
40+
memory_model: Option<MemoryModel>,
3441
}
3542
impl SpirvBuilder {
3643
pub fn new(path_to_crate: impl AsRef<Path>) -> Self {
3744
Self {
3845
path_to_crate: path_to_crate.as_ref().to_owned(),
3946
print_metadata: true,
4047
spirv_version: None,
48+
memory_model: None,
4149
}
4250
}
4351

@@ -47,20 +55,23 @@ impl SpirvBuilder {
4755
self
4856
}
4957

58+
/// Sets the SPIR-V binary version to use. Defaults to v1.3.
5059
pub fn spirv_version(mut self, major: u8, minor: u8) -> Self {
5160
self.spirv_version = Some((major, minor));
5261
self
5362
}
5463

64+
/// Sets the SPIR-V memory model. Defaults to Vulkan.
65+
pub fn memory_model(mut self, memory_model: MemoryModel) -> Self {
66+
self.memory_model = Some(memory_model);
67+
self
68+
}
69+
5570
/// Builds the module. Returns the path to the built spir-v file. If print_metadata is true,
5671
/// you usually don't have to inspect the path, as the environment variable will already be
5772
/// set.
5873
pub fn build(self) -> Result<PathBuf, SpirvBuilderError> {
59-
let spirv_module = invoke_rustc(
60-
self.path_to_crate.as_ref(),
61-
self.print_metadata,
62-
self.spirv_version,
63-
)?;
74+
let spirv_module = invoke_rustc(&self)?;
6475
let env_var = spirv_module.file_name().unwrap().to_str().unwrap();
6576
if self.print_metadata {
6677
println!("cargo:rustc-env={}={}", env_var, spirv_module.display());
@@ -101,11 +112,7 @@ fn find_rustc_codegen_spirv() -> PathBuf {
101112
panic!("Could not find {} in library path", filename);
102113
}
103114

104-
fn invoke_rustc(
105-
path_to_crate: &Path,
106-
print_metadata: bool,
107-
spirv_version: Option<(u8, u8)>,
108-
) -> Result<PathBuf, SpirvBuilderError> {
115+
fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
109116
// Okay, this is a little bonkers: in a normal world, we'd have the user clone
110117
// rustc_codegen_spirv and pass in the path to it, and then we'd invoke cargo to build it, grab
111118
// the resulting .so, and pass it into -Z codegen-backend. But that's really gross: the user
@@ -115,14 +122,30 @@ fn invoke_rustc(
115122
// rustc expects a full path, instead of a filename looked up via LD_LIBRARY_PATH, so we need
116123
// to copy cargo's understanding of library lookup and find the library and its full path.
117124
let rustc_codegen_spirv = find_rustc_codegen_spirv();
118-
let spirv_version_feture = match spirv_version {
119-
None => "".to_string(),
120-
Some((major, minor)) => format!(" -C target-feature=+spirv{}.{}", major, minor),
125+
let mut target_features = Vec::new();
126+
// these must match codegen_cx/mod.rs
127+
if let Some((major, minor)) = builder.spirv_version {
128+
target_features.push(format!("+spirv{}.{}", major, minor));
129+
}
130+
if let Some(memory_model) = &builder.memory_model {
131+
target_features.push(
132+
match memory_model {
133+
MemoryModel::Simple => "+simple",
134+
MemoryModel::Vulkan => "+vulkan",
135+
MemoryModel::GLSL450 => "+glsl450",
136+
}
137+
.to_string(),
138+
);
139+
}
140+
let feature_flag = if target_features.is_empty() {
141+
String::new()
142+
} else {
143+
format!(" -C target-feature={}", target_features.join(","))
121144
};
122145
let rustflags = format!(
123146
"-Z codegen-backend={}{}",
124147
rustc_codegen_spirv.display(),
125-
spirv_version_feture
148+
feature_flag,
126149
);
127150
let build = Command::new("cargo")
128151
.args(&[
@@ -135,14 +158,14 @@ fn invoke_rustc(
135158
"--release",
136159
])
137160
.stderr(Stdio::inherit())
138-
.current_dir(path_to_crate)
161+
.current_dir(&builder.path_to_crate)
139162
.env("RUSTFLAGS", rustflags)
140163
.output()
141164
.expect("failed to execute cargo build");
142165
if build.status.success() {
143166
let stdout = String::from_utf8(build.stdout).unwrap();
144167
let artifact = get_last_artifact(&stdout);
145-
if print_metadata {
168+
if builder.print_metadata {
146169
print_deps_of(&artifact);
147170
}
148171
Ok(artifact)

0 commit comments

Comments
 (0)