mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-22 06:45:23 +00:00
Allow specifying the target Vulkan and SPIR-V versions in vulkano-shaders (#1584)
This commit is contained in:
parent
794d005351
commit
8bedccf9bd
@ -3,8 +3,10 @@
|
||||
Please add new changes at the bottom, preceded by a hyphen -.
|
||||
Breaking changes should be listed first, before other changes, and should be preceded by - **Breaking**.
|
||||
-->
|
||||
|
||||
- **Breaking** Vulkano-shaders now checks if the device supports the shader's SPIR-V version, when loading the shader.
|
||||
- Added `DeviceExtensions::khr_spirv_1_4`, which allows SPIR-V 1.4 shaders in Vulkan versions below 1.2.
|
||||
- **Breaking** (but unlikely) Vulkano-shaders now compiles to SPIR-V 1.0 by default. If your shader needs features only available in a higher version, you can specify the target version on the `shader!` macro with the new `vulkan_version: "major.minor"` and `spirv_version: "major.minor"` arguments.
|
||||
- Added `DeviceExtensions::khr_spirv_1_4`, which allows SPIR-V 1.4 shaders in Vulkan 1.1.
|
||||
- Added `FunctionPointers::api_version` to query the highest supported instance version.
|
||||
- Added `Instance::api_version` and `Device::api_version` to return the actual supported Vulkan version. These may differ between instance and device, and be lower than what `FunctionPointers::api_version` and `PhysicalDevice::api_version` return (currently never higher than 1.1, but this may change in the future).
|
||||
- Fixed the issue when creating a buffer with exportable fd on Linux(see to #1545).
|
||||
|
@ -7,31 +7,27 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use crate::entry_point;
|
||||
use crate::enums::Capability;
|
||||
use crate::enums::StorageClass;
|
||||
use crate::parse;
|
||||
use crate::parse::Instruction;
|
||||
pub use crate::parse::ParseError;
|
||||
use crate::read_file_to_string;
|
||||
use crate::spec_consts;
|
||||
use crate::structs;
|
||||
use crate::TypesMeta;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
pub use shaderc::{CompilationArtifact, IncludeType, ResolvedInclude, ShaderKind};
|
||||
use shaderc::{CompileOptions, Compiler, EnvVersion, SpirvVersion, TargetEnv};
|
||||
use std::iter::Iterator;
|
||||
use std::path::Path;
|
||||
use std::{
|
||||
cell::{RefCell, RefMut},
|
||||
io::Error as IoError,
|
||||
};
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use shaderc::{CompileOptions, Compiler, TargetEnv};
|
||||
use syn::Ident;
|
||||
|
||||
pub use crate::parse::ParseError;
|
||||
pub use shaderc::{CompilationArtifact, IncludeType, ResolvedInclude, ShaderKind};
|
||||
|
||||
use crate::enums::Capability;
|
||||
use crate::enums::StorageClass;
|
||||
use crate::parse::Instruction;
|
||||
|
||||
use crate::entry_point;
|
||||
use crate::parse;
|
||||
use crate::read_file_to_string;
|
||||
use crate::spec_consts;
|
||||
use crate::structs;
|
||||
use crate::TypesMeta;
|
||||
|
||||
pub(super) fn path_to_str(path: &Path) -> &str {
|
||||
path.to_str().expect(
|
||||
"Could not stringify the file to be included. Make sure the path consists of \
|
||||
@ -157,12 +153,22 @@ pub fn compile(
|
||||
ty: ShaderKind,
|
||||
include_directories: &[impl AsRef<Path>],
|
||||
macro_defines: &[(impl AsRef<str>, impl AsRef<str>)],
|
||||
vulkan_version: Option<EnvVersion>,
|
||||
spirv_version: Option<SpirvVersion>,
|
||||
) -> Result<(CompilationArtifact, Vec<String>), String> {
|
||||
let includes_tracker = RefCell::new(Vec::new());
|
||||
let mut compiler = Compiler::new().ok_or("failed to create GLSL compiler")?;
|
||||
let mut compile_options = CompileOptions::new().ok_or("failed to initialize compile option")?;
|
||||
const ENV_VULKAN_VERSION: u32 = (1 << 22) | (1 << 12);
|
||||
compile_options.set_target_env(TargetEnv::Vulkan, ENV_VULKAN_VERSION);
|
||||
|
||||
compile_options.set_target_env(
|
||||
TargetEnv::Vulkan,
|
||||
vulkan_version.unwrap_or(EnvVersion::Vulkan1_0) as u32,
|
||||
);
|
||||
|
||||
if let Some(spirv_version) = spirv_version {
|
||||
compile_options.set_target_spirv(spirv_version);
|
||||
}
|
||||
|
||||
let root_source_path = if let &Some(ref path) = &path {
|
||||
path
|
||||
} else {
|
||||
@ -619,6 +625,8 @@ mod tests {
|
||||
ShaderKind::Vertex,
|
||||
&includes,
|
||||
&defines,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let doc = parse::parse_spirv(comp.as_binary()).unwrap();
|
||||
@ -645,6 +653,8 @@ mod tests {
|
||||
ShaderKind::Vertex,
|
||||
&includes,
|
||||
&defines,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let doc = parse::parse_spirv(comp.as_binary()).unwrap();
|
||||
@ -675,6 +685,8 @@ mod tests {
|
||||
ShaderKind::Vertex,
|
||||
&includes,
|
||||
&defines,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let doc = parse::parse_spirv(comp.as_binary()).unwrap();
|
||||
@ -698,6 +710,8 @@ mod tests {
|
||||
ShaderKind::Vertex,
|
||||
&empty_includes,
|
||||
&defines,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.expect("Cannot resolve include files");
|
||||
|
||||
@ -716,6 +730,8 @@ mod tests {
|
||||
root_path.join("tests").join("include_dir_b"),
|
||||
],
|
||||
&defines,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.expect("Cannot resolve include files");
|
||||
assert_eq!(
|
||||
@ -741,6 +757,8 @@ mod tests {
|
||||
ShaderKind::Vertex,
|
||||
&[root_path.join("tests").join("include_dir_a")],
|
||||
&defines,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.expect("Cannot resolve include files");
|
||||
assert_eq!(
|
||||
@ -776,6 +794,8 @@ mod tests {
|
||||
ShaderKind::Vertex,
|
||||
&empty_includes,
|
||||
&defines,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.expect("Cannot resolve include files");
|
||||
assert_eq!(
|
||||
@ -800,6 +820,8 @@ mod tests {
|
||||
root_path.join("tests").join("include_dir_c"),
|
||||
],
|
||||
&defines,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.expect("Cannot resolve include files");
|
||||
assert_eq!(
|
||||
@ -834,6 +856,8 @@ mod tests {
|
||||
ShaderKind::Vertex,
|
||||
&empty_includes,
|
||||
&no_defines,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
assert!(compile_no_defines.is_err());
|
||||
|
||||
@ -844,6 +868,8 @@ mod tests {
|
||||
ShaderKind::Vertex,
|
||||
&empty_includes,
|
||||
&defines,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
compile_defines.expect("Setting shader macros did not work");
|
||||
}
|
||||
|
@ -723,6 +723,8 @@ mod tests {
|
||||
ShaderKind::Vertex,
|
||||
&includes,
|
||||
&defines,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let doc = parse::parse_spirv(comp.as_binary()).unwrap();
|
||||
|
@ -151,6 +151,16 @@
|
||||
//! Adds the given macro definitions to the pre-processor. This is equivalent to passing `-DNAME=VALUE`
|
||||
//! on the command line.
|
||||
//!
|
||||
//! ## `vulkan_version: "major.minor"` and `spirv_version: "major.minor"`
|
||||
//!
|
||||
//! Sets the Vulkan and SPIR-V versions to compile into, respectively. These map directly to the
|
||||
//! [`set_target_env`](shaderc::CompileOptions::set_target_env) and
|
||||
//! [`set_target_spirv`](shaderc::CompileOptions::set_target_spirv) compile options.
|
||||
//! If neither option is specified, then SPIR-V 1.0 code targeting Vulkan 1.0 will be generated.
|
||||
//!
|
||||
//! The generated code must be supported by the device at runtime. If not, then an error will be
|
||||
//! returned when calling `Shader::load`.
|
||||
//!
|
||||
//! ## `types_meta: { use a::b; #[derive(Clone, Default, PartialEq ...)] impl Eq }`
|
||||
//!
|
||||
//! Extends implementations of Rust structs that represent Shader structs.
|
||||
@ -211,12 +221,14 @@ extern crate quote;
|
||||
extern crate syn;
|
||||
extern crate proc_macro;
|
||||
|
||||
use crate::codegen::ShaderKind;
|
||||
use shaderc::{EnvVersion, SpirvVersion};
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Result as IoResult};
|
||||
use std::path::Path;
|
||||
use std::slice::from_raw_parts;
|
||||
use std::{env, iter::empty};
|
||||
|
||||
use syn::parse::{Parse, ParseStream, Result};
|
||||
use syn::{
|
||||
Ident, ItemUse, LitBool, LitStr, Meta, MetaList, NestedMeta, Path as SynPath, TypeImplTrait,
|
||||
@ -231,9 +243,6 @@ mod spec_consts;
|
||||
mod spirv_search;
|
||||
mod structs;
|
||||
|
||||
use crate::codegen::ShaderKind;
|
||||
use std::slice::from_raw_parts;
|
||||
|
||||
enum SourceKind {
|
||||
Src(String),
|
||||
Path(String),
|
||||
@ -287,63 +296,34 @@ impl TypesMeta {
|
||||
}
|
||||
|
||||
struct MacroInput {
|
||||
shader_kind: ShaderKind,
|
||||
source_kind: SourceKind,
|
||||
dump: bool,
|
||||
exact_entrypoint_interface: bool,
|
||||
include_directories: Vec<String>,
|
||||
macro_defines: Vec<(String, String)>,
|
||||
shader_kind: ShaderKind,
|
||||
source_kind: SourceKind,
|
||||
spirv_version: Option<SpirvVersion>,
|
||||
types_meta: TypesMeta,
|
||||
exact_entrypoint_interface: bool,
|
||||
dump: bool,
|
||||
vulkan_version: Option<EnvVersion>,
|
||||
}
|
||||
|
||||
impl Parse for MacroInput {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let mut dump = None;
|
||||
let mut shader_kind = None;
|
||||
let mut source_kind = None;
|
||||
let mut exact_entrypoint_interface = None;
|
||||
let mut include_directories = Vec::new();
|
||||
let mut macro_defines = Vec::new();
|
||||
let mut shader_kind = None;
|
||||
let mut source_kind = None;
|
||||
let mut spirv_version = None;
|
||||
let mut types_meta = None;
|
||||
let mut exact_entrypoint_interface = None;
|
||||
let mut vulkan_version = None;
|
||||
|
||||
while !input.is_empty() {
|
||||
let name: Ident = input.parse()?;
|
||||
input.parse::<Token![:]>()?;
|
||||
|
||||
match name.to_string().as_ref() {
|
||||
"ty" => {
|
||||
if shader_kind.is_some() {
|
||||
panic!("Only one `ty` can be defined")
|
||||
}
|
||||
|
||||
let ty: LitStr = input.parse()?;
|
||||
let ty = match ty.value().as_ref() {
|
||||
"vertex" => ShaderKind::Vertex,
|
||||
"fragment" => ShaderKind::Fragment,
|
||||
"geometry" => ShaderKind::Geometry,
|
||||
"tess_ctrl" => ShaderKind::TessControl,
|
||||
"tess_eval" => ShaderKind::TessEvaluation,
|
||||
"compute" => ShaderKind::Compute,
|
||||
_ => panic!("Unexpected shader type, valid values: vertex, fragment, geometry, tess_ctrl, tess_eval, compute")
|
||||
};
|
||||
shader_kind = Some(ty);
|
||||
}
|
||||
"src" => {
|
||||
if source_kind.is_some() {
|
||||
panic!("Only one of `src`, `path`, or `bytes` can be defined")
|
||||
}
|
||||
|
||||
let src: LitStr = input.parse()?;
|
||||
source_kind = Some(SourceKind::Src(src.value()));
|
||||
}
|
||||
"path" => {
|
||||
if source_kind.is_some() {
|
||||
panic!("Only one of `src`, `path`, or `bytes` can be defined")
|
||||
}
|
||||
|
||||
let path: LitStr = input.parse()?;
|
||||
source_kind = Some(SourceKind::Path(path.value()));
|
||||
}
|
||||
"bytes" => {
|
||||
if source_kind.is_some() {
|
||||
panic!("Only one of `src`, `path`, or `bytes` can be defined")
|
||||
@ -370,6 +350,20 @@ impl Parse for MacroInput {
|
||||
}
|
||||
}
|
||||
}
|
||||
"dump" => {
|
||||
if dump.is_some() {
|
||||
panic!("Only one `dump` can be defined")
|
||||
}
|
||||
let dump_lit: LitBool = input.parse()?;
|
||||
dump = Some(dump_lit.value);
|
||||
}
|
||||
"exact_entrypoint_interface" => {
|
||||
if exact_entrypoint_interface.is_some() {
|
||||
panic!("Only one `dump` can be defined")
|
||||
}
|
||||
let lit: LitBool = input.parse()?;
|
||||
exact_entrypoint_interface = Some(lit.value);
|
||||
}
|
||||
"include" => {
|
||||
let in_brackets;
|
||||
bracketed!(in_brackets in input);
|
||||
@ -384,6 +378,51 @@ impl Parse for MacroInput {
|
||||
}
|
||||
}
|
||||
}
|
||||
"path" => {
|
||||
if source_kind.is_some() {
|
||||
panic!("Only one of `src`, `path`, or `bytes` can be defined")
|
||||
}
|
||||
|
||||
let path: LitStr = input.parse()?;
|
||||
source_kind = Some(SourceKind::Path(path.value()));
|
||||
}
|
||||
"spirv_version" => {
|
||||
let version: LitStr = input.parse()?;
|
||||
spirv_version = Some(match version.value().as_ref() {
|
||||
"1.0" => SpirvVersion::V1_0,
|
||||
"1.1" => SpirvVersion::V1_1,
|
||||
"1.2" => SpirvVersion::V1_2,
|
||||
"1.3" => SpirvVersion::V1_3,
|
||||
"1.4" => SpirvVersion::V1_4,
|
||||
"1.5" => SpirvVersion::V1_5,
|
||||
_ => panic!("Unknown SPIR-V version: {}", version.value()),
|
||||
});
|
||||
}
|
||||
"src" => {
|
||||
if source_kind.is_some() {
|
||||
panic!("Only one of `src`, `path`, or `bytes` can be defined")
|
||||
}
|
||||
|
||||
let src: LitStr = input.parse()?;
|
||||
source_kind = Some(SourceKind::Src(src.value()));
|
||||
}
|
||||
"ty" => {
|
||||
if shader_kind.is_some() {
|
||||
panic!("Only one `ty` can be defined")
|
||||
}
|
||||
|
||||
let ty: LitStr = input.parse()?;
|
||||
let ty = match ty.value().as_ref() {
|
||||
"vertex" => ShaderKind::Vertex,
|
||||
"fragment" => ShaderKind::Fragment,
|
||||
"geometry" => ShaderKind::Geometry,
|
||||
"tess_ctrl" => ShaderKind::TessControl,
|
||||
"tess_eval" => ShaderKind::TessEvaluation,
|
||||
"compute" => ShaderKind::Compute,
|
||||
_ => panic!("Unexpected shader type, valid values: vertex, fragment, geometry, tess_ctrl, tess_eval, compute")
|
||||
};
|
||||
shader_kind = Some(ty);
|
||||
}
|
||||
"types_meta" => {
|
||||
let in_braces;
|
||||
braced!(in_braces in input);
|
||||
@ -522,19 +561,14 @@ impl Parse for MacroInput {
|
||||
|
||||
types_meta = Some(meta);
|
||||
}
|
||||
"exact_entrypoint_interface" => {
|
||||
if exact_entrypoint_interface.is_some() {
|
||||
panic!("Only one `dump` can be defined")
|
||||
}
|
||||
let lit: LitBool = input.parse()?;
|
||||
exact_entrypoint_interface = Some(lit.value);
|
||||
}
|
||||
"dump" => {
|
||||
if dump.is_some() {
|
||||
panic!("Only one `dump` can be defined")
|
||||
}
|
||||
let dump_lit: LitBool = input.parse()?;
|
||||
dump = Some(dump_lit.value);
|
||||
"vulkan_version" => {
|
||||
let version: LitStr = input.parse()?;
|
||||
vulkan_version = Some(match version.value().as_ref() {
|
||||
"1.0" => EnvVersion::Vulkan1_0,
|
||||
"1.1" => EnvVersion::Vulkan1_1,
|
||||
"1.2" => EnvVersion::Vulkan1_2,
|
||||
_ => panic!("Unknown Vulkan version: {}", version.value()),
|
||||
});
|
||||
}
|
||||
name => panic!("Unknown field name: {}", name),
|
||||
}
|
||||
@ -557,13 +591,15 @@ impl Parse for MacroInput {
|
||||
let dump = dump.unwrap_or(false);
|
||||
|
||||
Ok(Self {
|
||||
dump,
|
||||
exact_entrypoint_interface: exact_entrypoint_interface.unwrap_or(false),
|
||||
include_directories,
|
||||
macro_defines,
|
||||
shader_kind,
|
||||
source_kind,
|
||||
include_directories,
|
||||
dump,
|
||||
macro_defines,
|
||||
spirv_version,
|
||||
types_meta: types_meta.unwrap_or_else(|| TypesMeta::default()),
|
||||
exact_entrypoint_interface: exact_entrypoint_interface.unwrap_or(false),
|
||||
vulkan_version,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -641,6 +677,8 @@ pub fn shader(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
input.shader_kind,
|
||||
&include_paths,
|
||||
&input.macro_defines,
|
||||
input.vulkan_version,
|
||||
input.spirv_version,
|
||||
) {
|
||||
Ok(ok) => ok,
|
||||
Err(e) => panic!("{}", e.replace("(s): ", "(s):\n")),
|
||||
|
Loading…
Reference in New Issue
Block a user