mirror of
https://github.com/EmbarkStudios/rust-gpu.git
synced 2024-11-25 08:14:12 +00:00
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:
parent
b784710193
commit
1b5aac084c
@ -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),
|
||||
|
@ -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(),
|
||||
|
@ -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"),
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user