Support GLSL450 and Simple memory models (#168)

* Support GLSL450 and Simple memory models

* Update spirv-builder/src/lib.rs

Co-authored-by: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com>

* Only emit SPV_KHR_vulkan_memory_model when needed

Co-authored-by: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com>
This commit is contained in:
Ashley Hauck 2020-10-28 14:49:44 +01:00 committed by GitHub
parent b784710193
commit 1b5aac084c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 23 deletions

View File

@ -71,17 +71,26 @@ pub struct BuilderSpirv {
}
impl BuilderSpirv {
pub fn new(version: Option<(u8, u8)>, kernel_mode: bool) -> Self {
pub fn new(
version: Option<(u8, u8)>,
memory_model: Option<MemoryModel>,
kernel_mode: bool,
) -> Self {
let mut builder = Builder::new();
// Default to spir-v 1.3
let version = version.unwrap_or((1, 3));
builder.set_version(version.0, version.1);
let memory_model = memory_model.unwrap_or(MemoryModel::Vulkan);
if kernel_mode {
builder.capability(Capability::Kernel);
} else {
builder.extension("SPV_KHR_vulkan_memory_model");
builder.capability(Capability::Shader);
builder.capability(Capability::VulkanMemoryModel);
if memory_model == MemoryModel::Vulkan {
if version < (1, 5) {
builder.extension("SPV_KHR_vulkan_memory_model");
}
builder.capability(Capability::VulkanMemoryModel);
}
builder.capability(Capability::VariablePointers);
if version < (1, 3) {
builder.extension("SPV_KHR_variable_pointers");
@ -98,7 +107,7 @@ impl BuilderSpirv {
builder.capability(Capability::Addresses);
builder.memory_model(AddressingModel::Physical32, MemoryModel::OpenCL);
} else {
builder.memory_model(AddressingModel::Logical, MemoryModel::Vulkan);
builder.memory_model(AddressingModel::Logical, memory_model);
}
Self {
builder: RefCell::new(builder),

View File

@ -10,7 +10,7 @@ use crate::spirv_type::{SpirvType, SpirvTypePrinter, TypeCache};
use crate::symbols::Symbols;
use bimap::BiHashMap;
use rspirv::dr::{Module, Operand};
use rspirv::spirv::{Decoration, LinkageType, StorageClass, Word};
use rspirv::spirv::{Decoration, LinkageType, MemoryModel, StorageClass, Word};
use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind};
use rustc_codegen_ssa::traits::{
AsmMethods, BackendTypes, CoverageInfoMethods, DebugInfoMethods, MiscMethods,
@ -63,8 +63,9 @@ pub struct CodegenCx<'tcx> {
impl<'tcx> CodegenCx<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, codegen_unit: &'tcx CodegenUnit<'tcx>) -> Self {
let sym = Box::new(Symbols::new());
let mut kernel_mode = false;
let mut spirv_version = None;
let mut memory_model = None;
let mut kernel_mode = false;
for &feature in &tcx.sess.target_features {
if feature == sym.kernel {
kernel_mode = true;
@ -80,12 +81,20 @@ impl<'tcx> CodegenCx<'tcx> {
spirv_version = Some((1, 4));
} else if feature == sym.spirv15 {
spirv_version = Some((1, 5));
} else if feature == sym.simple {
memory_model = Some(MemoryModel::Simple);
} else if feature == sym.vulkan {
memory_model = Some(MemoryModel::Vulkan);
} else if feature == sym.glsl450 {
memory_model = Some(MemoryModel::GLSL450);
} else {
tcx.sess.err(&format!("Unknown feature {}", feature));
}
}
Self {
tcx,
codegen_unit,
builder: BuilderSpirv::new(spirv_version, kernel_mode),
builder: BuilderSpirv::new(spirv_version, memory_model, kernel_mode),
instances: Default::default(),
function_parameter_values: Default::default(),
type_cache: Default::default(),

View File

@ -13,6 +13,9 @@ pub struct Symbols {
pub spirv: Symbol,
pub spirv_std: Symbol,
pub kernel: Symbol,
pub simple: Symbol,
pub vulkan: Symbol,
pub glsl450: Symbol,
pub spirv10: Symbol,
pub spirv11: Symbol,
pub spirv12: Symbol,
@ -217,6 +220,9 @@ impl Symbols {
spirv: Symbol::intern("spirv"),
spirv_std: Symbol::intern("spirv_std"),
kernel: Symbol::intern("kernel"),
simple: Symbol::intern("simple"),
vulkan: Symbol::intern("vulkan"),
glsl450: Symbol::intern("glsl450"),
spirv10: Symbol::intern("spirv1.0"),
spirv11: Symbol::intern("spirv1.1"),
spirv12: Symbol::intern("spirv1.2"),

View File

@ -27,10 +27,17 @@ impl fmt::Display for SpirvBuilderError {
impl Error for SpirvBuilderError {}
pub enum MemoryModel {
Simple,
Vulkan,
GLSL450,
}
pub struct SpirvBuilder {
path_to_crate: PathBuf,
print_metadata: bool,
spirv_version: Option<(u8, u8)>,
memory_model: Option<MemoryModel>,
}
impl SpirvBuilder {
pub fn new(path_to_crate: impl AsRef<Path>) -> Self {
@ -38,6 +45,7 @@ impl SpirvBuilder {
path_to_crate: path_to_crate.as_ref().to_owned(),
print_metadata: true,
spirv_version: None,
memory_model: None,
}
}
@ -47,20 +55,23 @@ impl SpirvBuilder {
self
}
/// Sets the SPIR-V binary version to use. Defaults to v1.3.
pub fn spirv_version(mut self, major: u8, minor: u8) -> Self {
self.spirv_version = Some((major, minor));
self
}
/// Sets the SPIR-V memory model. Defaults to Vulkan.
pub fn memory_model(mut self, memory_model: MemoryModel) -> Self {
self.memory_model = Some(memory_model);
self
}
/// Builds the module. Returns the path to the built spir-v file. If print_metadata is true,
/// you usually don't have to inspect the path, as the environment variable will already be
/// set.
pub fn build(self) -> Result<PathBuf, SpirvBuilderError> {
let spirv_module = invoke_rustc(
self.path_to_crate.as_ref(),
self.print_metadata,
self.spirv_version,
)?;
let spirv_module = invoke_rustc(&self)?;
let env_var = spirv_module.file_name().unwrap().to_str().unwrap();
if self.print_metadata {
println!("cargo:rustc-env={}={}", env_var, spirv_module.display());
@ -101,11 +112,7 @@ fn find_rustc_codegen_spirv() -> PathBuf {
panic!("Could not find {} in library path", filename);
}
fn invoke_rustc(
path_to_crate: &Path,
print_metadata: bool,
spirv_version: Option<(u8, u8)>,
) -> Result<PathBuf, SpirvBuilderError> {
fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
// Okay, this is a little bonkers: in a normal world, we'd have the user clone
// rustc_codegen_spirv and pass in the path to it, and then we'd invoke cargo to build it, grab
// the resulting .so, and pass it into -Z codegen-backend. But that's really gross: the user
@ -115,14 +122,30 @@ fn invoke_rustc(
// rustc expects a full path, instead of a filename looked up via LD_LIBRARY_PATH, so we need
// to copy cargo's understanding of library lookup and find the library and its full path.
let rustc_codegen_spirv = find_rustc_codegen_spirv();
let spirv_version_feture = match spirv_version {
None => "".to_string(),
Some((major, minor)) => format!(" -C target-feature=+spirv{}.{}", major, minor),
let mut target_features = Vec::new();
// these must match codegen_cx/mod.rs
if let Some((major, minor)) = builder.spirv_version {
target_features.push(format!("+spirv{}.{}", major, minor));
}
if let Some(memory_model) = &builder.memory_model {
target_features.push(
match memory_model {
MemoryModel::Simple => "+simple",
MemoryModel::Vulkan => "+vulkan",
MemoryModel::GLSL450 => "+glsl450",
}
.to_string(),
);
}
let feature_flag = if target_features.is_empty() {
String::new()
} else {
format!(" -C target-feature={}", target_features.join(","))
};
let rustflags = format!(
"-Z codegen-backend={}{}",
rustc_codegen_spirv.display(),
spirv_version_feture
feature_flag,
);
let build = Command::new("cargo")
.args(&[
@ -135,14 +158,14 @@ fn invoke_rustc(
"--release",
])
.stderr(Stdio::inherit())
.current_dir(path_to_crate)
.current_dir(&builder.path_to_crate)
.env("RUSTFLAGS", rustflags)
.output()
.expect("failed to execute cargo build");
if build.status.success() {
let stdout = String::from_utf8(build.stdout).unwrap();
let artifact = get_last_artifact(&stdout);
if print_metadata {
if builder.print_metadata {
print_deps_of(&artifact);
}
Ok(artifact)