diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ca319f48..cf1ef33f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,7 +13,6 @@ stages: job1: stage: test script: - - cargo test -v --manifest-path glsl-to-spirv/Cargo.toml - cargo test -v --manifest-path vulkano-shaders/Cargo.toml - cargo test --no-run -v --manifest-path vulkano/Cargo.toml diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index cdbe339a..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "glsl-to-spirv/glslang"] - path = glsl-to-spirv/glslang - url = https://github.com/KhronosGroup/glslang diff --git a/.travis.yml b/.travis.yml index 9a45120f..a3bd8e39 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ addons: - cmake-data script: - - cargo test --all -j 1 + - travis_wait cargo test --all -j 1 - cd examples - cargo build - cd .. # this is very important or else the below `cargo publish` will fail @@ -40,10 +40,6 @@ after_success: [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && cargo publish --token ${CRATESIO_TOKEN} --manifest-path vulkano-win/Cargo.toml - - | - [ $TRAVIS_BRANCH = master ] && - [ $TRAVIS_PULL_REQUEST = false ] && - cargo publish --token ${CRATESIO_TOKEN} --manifest-path glsl-to-spirv/Cargo.toml - | [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && diff --git a/CHANGELOG.md b/CHANGELOG.md index 69663c6d..a4912707 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - Fix instance_count when using draw_index with instance buffers - Added a `reinterpret` function to `BufferSlice` +- Use [google/shaderc](https://github.com/google/shaderc-rs) for shader compilation + # Version 0.10.0 (2018-08-10) - Use dynamically loaded `libvulkan` like on other platforms instead of linking to MoltenVK on macOS diff --git a/Cargo.toml b/Cargo.toml index 8f596597..f3b40d95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,6 @@ [workspace] members = [ "examples", - "glsl-to-spirv", "vk-sys", "vulkano", "vulkano-shaders", diff --git a/README.md b/README.md index cbf32cc0..00fb6a69 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,17 @@ To get started you are encouraged to use the following resources: examples in the repo and also a list of projects that use vulkano. * [docs.rs](https://docs.rs/vulkano) - Full Vulkano API documentation -## macOS and iOS Setup +## Setup + +Vulkano uses [shaderc-rs](https://github.com/google/shaderc-rs) for shader compilation. In order to +build the shaderc-rs crate the following tools must be installed and available on `PATH`: +- [CMake](https://cmake.org/) +- [Python](https://www.python.org/) (works with both Python 2.x and 3.x) + +These requirements can be either installed with your favourite package manager or with installers +from the projects' websites. + +### macOS and iOS Specific Setup Vulkan is not natively supported by macOS and iOS. However, there exists [MoltenVK](https://github.com/KhronosGroup/MoltenVK) a Vulkan implementation on top of Apple's Metal API. This allows vulkano to build and run on macOS @@ -107,14 +117,10 @@ This repository contains six libraries: easily integrate your GLSL shaders within the rest of your source code. - `vulkano-win` provides a safe link between vulkano and the `winit` library which can create a window to render to. -- `glsl-to-spirv` can compile GLSL to SPIR-V by wrapping around `glslang`. `glsl-to-spirv` is an - implementation detail that you don't need to use manually if you use vulkano. - `vk-sys` contains raw bindings for Vulkan. You can use it even if you don't care about vulkano. Once procedural macros are stabilized in Rust, the `vulkano-shaders` and `vulkano-shader-derive` -crates will be merged with the `vulkano` crate. The `glsl-to-spirv` crate is an implementation -detail of vulkano and is not supposed to be used directly if you use vulkano. You are, however, -free to use it if you want to write an alternative to vulkano. +crates will be merged with the `vulkano` crate. In order to run tests, run `cargo test --all` at the root of the repository. Make sure your Vulkan driver is up to date before doing so. diff --git a/glsl-to-spirv/Cargo.toml b/glsl-to-spirv/Cargo.toml deleted file mode 100644 index 237d7ff2..00000000 --- a/glsl-to-spirv/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "glsl-to-spirv" -version = "0.1.7" -authors = ["Pierre Krieger ", "The vulkano contributors"] -repository = "https://github.com/vulkano-rs/vulkano" -description = "Deprecated. Use shaderc-rs instead." -license = "MIT/Apache-2.0" -build = "build/build.rs" -categories = ["rendering::graphics-api"] - -[dependencies] -tempfile = "3" - -[build-dependencies] -cmake = "0.1.27" -sha2 = "0.7" diff --git a/glsl-to-spirv/build/build.rs b/glsl-to-spirv/build/build.rs deleted file mode 100644 index 17a4853d..00000000 --- a/glsl-to-spirv/build/build.rs +++ /dev/null @@ -1,44 +0,0 @@ -extern crate cmake; -extern crate sha2; - -use std::env; -use std::fs; -use std::path::Path; -use std::process::Command; - -use sha2::{Sha256, Digest}; - -fn main() { - println!("cargo:rerun-if-changed=build/glslangValidator.exe"); - - let target = env::var("TARGET").unwrap(); - let out_file = Path::new(&env::var("OUT_DIR").unwrap()).join("glslang_validator"); - - let path = if target.contains("windows") { - const SHA256SUM: &'static str = - "90b377479fb137f4ac69460d5f5cdc54cd23bace5eb6e6812516fdfa693b25cf"; - let path = Path::new("build/glslangValidator.exe").to_owned(); - let content = fs::read(&path).expect("failed to open executable"); - let mut hasher = Sha256::default(); - hasher.input(&content); - let result = hasher.result(); - let sha256sum = format!("{:x}", result); - assert_eq!(sha256sum, SHA256SUM, "glslangValidator.exe checksum failed"); - path - - } else { - // Try to initialize submodules. Don't care if it fails, since this code also runs for - // the crates.io package. - let _ = Command::new("git") - .arg("submodule") - .arg("update") - .arg("--init") - .status(); - cmake::build("glslang"); - Path::new(&env::var("OUT_DIR").unwrap()) - .join("bin") - .join("glslangValidator") - }; - - fs::copy(&path, &out_file).expect("failed to copy executable"); -} diff --git a/glsl-to-spirv/build/glslangValidator.exe b/glsl-to-spirv/build/glslangValidator.exe deleted file mode 100644 index e552247d..00000000 Binary files a/glsl-to-spirv/build/glslangValidator.exe and /dev/null differ diff --git a/glsl-to-spirv/glslang b/glsl-to-spirv/glslang deleted file mode 160000 index 4fbb8cb4..00000000 --- a/glsl-to-spirv/glslang +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4fbb8cb45e144ff63383b48fb1d3244522602438 diff --git a/glsl-to-spirv/readme.md b/glsl-to-spirv/readme.md deleted file mode 100644 index bffb0d92..00000000 --- a/glsl-to-spirv/readme.md +++ /dev/null @@ -1 +0,0 @@ -This crate is deprecated please use [shaderc-rs](https://github.com/google/shaderc-rs) instead. diff --git a/glsl-to-spirv/src/lib.rs b/glsl-to-spirv/src/lib.rs deleted file mode 100644 index 93acd325..00000000 --- a/glsl-to-spirv/src/lib.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2016 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// or the MIT -// license , -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - -extern crate tempfile; - -use std::fs::File; -use std::io::Write; -use std::process::Command; - -pub type SpirvOutput = File; - -pub fn compile(code: &str, ty: ShaderType) -> Result { - compile_inner(Some((code, ty))) -} - -// Eventually the API will look like this, with an iterator for multiple shader stages. -// However for the moment GLSLang doesn't like that, so we only pass one shader at a time. -fn compile_inner<'a, I>(shaders: I) -> Result - where I: IntoIterator -{ - let temp_dir = tempfile::tempdir().unwrap(); - let output_file = temp_dir.path().join("compilation_output.spv"); - - let mut command = Command::new(concat!(env!("OUT_DIR"), "/glslang_validator")); - command.arg("-V"); - command.arg("-l"); - command.arg("-o").arg(&output_file); - - for (num, (source, ty)) in shaders.into_iter().enumerate() { - let extension = match ty { - ShaderType::Vertex => ".vert", - ShaderType::Fragment => ".frag", - ShaderType::Geometry => ".geom", - ShaderType::TessellationControl => ".tesc", - ShaderType::TessellationEvaluation => ".tese", - ShaderType::Compute => ".comp", - }; - - let file_path = temp_dir.path().join(format!("{}{}", num, extension)); - File::create(&file_path) - .unwrap() - .write_all(source.as_bytes()) - .unwrap(); - command.arg(file_path); - } - - let output = command - .output() - .expect("Failed to execute glslangValidator"); - - if output.status.success() { - let spirv_output = File::open(output_file).expect("failed to open SPIR-V output file"); - return Ok(spirv_output); - } - - let error1 = String::from_utf8_lossy(&output.stdout); - let error2 = String::from_utf8_lossy(&output.stderr); - return Err(error1.into_owned() + &error2); -} - -/// Type of shader. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ShaderType { - Vertex, - Fragment, - Geometry, - TessellationControl, - TessellationEvaluation, - Compute, -} diff --git a/glsl-to-spirv/tests/test.rs b/glsl-to-spirv/tests/test.rs deleted file mode 100644 index 26b6d2a6..00000000 --- a/glsl-to-spirv/tests/test.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2016 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// or the MIT -// license , -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - -extern crate glsl_to_spirv; - -#[test] -fn test1() { - let shader = r#" -#version 330 - -layout(location = 0) out vec4 f_color; - -void main() { - f_color = vec4(1.0); -} -"#; - - glsl_to_spirv::compile(shader, glsl_to_spirv::ShaderType::Fragment).unwrap(); -} diff --git a/vulkano-shader-derive/Cargo.toml b/vulkano-shader-derive/Cargo.toml index 37ac9e8b..7d4c1f83 100644 --- a/vulkano-shader-derive/Cargo.toml +++ b/vulkano-shader-derive/Cargo.toml @@ -13,7 +13,6 @@ name = "vulkano_shader_derive" proc-macro = true [dependencies] -glsl-to-spirv = { version = "0.1.6", path = "../glsl-to-spirv" } syn = "0.14" vulkano-shaders = { version = "0.10", path = "../vulkano-shaders" } diff --git a/vulkano-shader-derive/src/lib.rs b/vulkano-shader-derive/src/lib.rs index 6b115965..8403f158 100644 --- a/vulkano-shader-derive/src/lib.rs +++ b/vulkano-shader-derive/src/lib.rs @@ -155,7 +155,6 @@ //! [SpecializationConstants]: https://docs.rs/vulkano/*/vulkano/pipeline/shader/trait.SpecializationConstants.html //! [pipeline]: https://docs.rs/vulkano/*/vulkano/pipeline/index.html -extern crate glsl_to_spirv; extern crate proc_macro; extern crate syn; extern crate vulkano_shaders; @@ -235,19 +234,18 @@ pub fn derive(input: TokenStream) -> TokenStream { }).next().expect("Can't find `ty` attribute ; put #[ty = \"vertex\"] for example."); let ty = match &ty_str[..] { - "vertex" => glsl_to_spirv::ShaderType::Vertex, - "fragment" => glsl_to_spirv::ShaderType::Fragment, - "geometry" => glsl_to_spirv::ShaderType::Geometry, - "tess_ctrl" => glsl_to_spirv::ShaderType::TessellationControl, - "tess_eval" => glsl_to_spirv::ShaderType::TessellationEvaluation, - "compute" => glsl_to_spirv::ShaderType::Compute, + "vertex" => vulkano_shaders::ShaderKind::Vertex, + "fragment" => vulkano_shaders::ShaderKind::Fragment, + "geometry" => vulkano_shaders::ShaderKind::Geometry, + "tess_ctrl" => vulkano_shaders::ShaderKind::TessControl, + "tess_eval" => vulkano_shaders::ShaderKind::TessEvaluation, + "compute" => vulkano_shaders::ShaderKind::Compute, _ => panic!("Unexpected shader type ; valid values: vertex, fragment, geometry, tess_ctrl, tess_eval, compute") }; - - let spirv_data = match glsl_to_spirv::compile(&source_code, ty) { - Ok(compiled) => compiled, - Err(message) => panic!("{}\nfailed to compile shader", message), - }; - - vulkano_shaders::reflect("Shader", spirv_data).unwrap().parse().unwrap() + let content = vulkano_shaders::compile(&source_code, ty).unwrap(); + + vulkano_shaders::reflect("Shader", content.as_binary()) + .unwrap() + .parse() + .unwrap() } diff --git a/vulkano-shaders/Cargo.toml b/vulkano-shaders/Cargo.toml index 58f55e1c..d059b37c 100644 --- a/vulkano-shaders/Cargo.toml +++ b/vulkano-shaders/Cargo.toml @@ -9,4 +9,4 @@ documentation = "http://tomaka.github.io/vulkano/vulkano/index.html" categories = ["rendering::graphics-api"] [dependencies] -glsl-to-spirv = { version = "0.1.6", path = "../glsl-to-spirv" } +shaderc = "0.3" diff --git a/vulkano-shaders/examples/example.rs b/vulkano-shaders/examples/example.rs index 5a33295a..fedcff2f 100644 --- a/vulkano-shaders/examples/example.rs +++ b/vulkano-shaders/examples/example.rs @@ -7,7 +7,6 @@ // notice may not be copied, modified, or distributed except // according to those terms. -extern crate glsl_to_spirv; extern crate vulkano_shaders; fn main() { @@ -40,7 +39,7 @@ void main() { "#; - let content = glsl_to_spirv::compile(shader, glsl_to_spirv::ShaderType::Fragment).unwrap(); - let output = vulkano_shaders::reflect("Shader", content).unwrap(); + let content = vulkano_shaders::compile(shader, vulkano_shaders::ShaderKind::Fragment).unwrap(); + let output = vulkano_shaders::reflect("Shader", content.as_binary()).unwrap(); println!("{}", output); } diff --git a/vulkano-shaders/src/lib.rs b/vulkano-shaders/src/lib.rs index 7488694c..e3123715 100644 --- a/vulkano-shaders/src/lib.rs +++ b/vulkano-shaders/src/lib.rs @@ -7,7 +7,7 @@ // notice may not be copied, modified, or distributed except // according to those terms. -extern crate glsl_to_spirv; +extern crate shaderc; use std::env; use std::fs; @@ -17,7 +17,9 @@ use std::io::Read; use std::io::Write; use std::path::Path; -pub use glsl_to_spirv::ShaderType; +use shaderc::{Compiler, CompileOptions}; + +pub use shaderc::{CompilationArtifact, ShaderKind}; pub use parse::ParseError; mod descriptor_sets; @@ -28,7 +30,7 @@ mod spec_consts; mod structs; pub fn build_glsl_shaders<'a, I>(shaders: I) - where I: IntoIterator + where I: IntoIterator { let destination = env::var("OUT_DIR").unwrap(); let destination = Path::new(&destination); @@ -55,23 +57,25 @@ pub fn build_glsl_shaders<'a, I>(shaders: I) let mut file_output = File::create(&destination.join("shaders").join(shader)) .expect("failed to open shader output"); - let content = match glsl_to_spirv::compile(&shader_content, ty) { - Ok(compiled) => compiled, - Err(message) => panic!("{}\nfailed to compile shader", message), - }; - let output = reflect("Shader", content).unwrap(); + let content = compile(&shader_content, ty).unwrap(); + let output = reflect("Shader", content.as_binary()).unwrap(); write!(file_output, "{}", output).unwrap(); } } -pub fn reflect(name: &str, mut spirv: R) -> Result - where R: Read -{ - let mut data = Vec::new(); - spirv.read_to_end(&mut data)?; +pub fn compile(code: &str, ty: ShaderKind) -> Result { + let mut compiler = Compiler::new().ok_or("failed to create GLSL compiler")?; + let compile_options = CompileOptions::new().ok_or("failed to initialize compile option")?; - // now parsing the document - let doc = parse::parse_spirv(&data)?; + let content = compiler + .compile_into_spirv(&code, ty, "shader.glsl", "main", Some(&compile_options)) + .map_err(|e| e.to_string())?; + + Ok(content) +} + +pub fn reflect(name: &str, spirv: &[u32]) -> Result { + let doc = parse::parse_spirv(spirv)?; let mut output = String::new(); output.push_str( @@ -118,8 +122,8 @@ pub fn reflect(name: &str, mut spirv: R) -> Result { // contains the data that was passed as input to this function - let spirv_data = data.iter() - .map(|&byte| byte.to_string()) + let spirv_words = spirv.iter() + .map(|&word| word.to_string()) .collect::>() .join(", "); @@ -162,10 +166,10 @@ impl {name} {{ output.push_str(&format!( r#" unsafe {{ - let data = [{spirv_data}]; - + let words = [{spirv_words}]; + Ok({name} {{ - shader: try!(::vulkano::pipeline::shader::ShaderModule::new(device, &data)) + shader: try!(::vulkano::pipeline::shader::ShaderModule::from_words(device, &words)) }}) }} }} @@ -178,7 +182,7 @@ impl {name} {{ }} "#, name = name, - spirv_data = spirv_data + spirv_words = spirv_words )); // writing one method for each entry point of this module diff --git a/vulkano-shaders/src/parse.rs b/vulkano-shaders/src/parse.rs index 92701666..6b9a2ae6 100644 --- a/vulkano-shaders/src/parse.rs +++ b/vulkano-shaders/src/parse.rs @@ -9,43 +9,8 @@ use enums::*; -/// Parses a SPIR-V document. -pub fn parse_spirv(data: &[u8]) -> Result { - if data.len() < 20 { - return Err(ParseError::MissingHeader); - } - - // we need to determine whether we are in big endian order or little endian order depending - // on the magic number at the start of the file - let data = if data[0] == 0x07 && data[1] == 0x23 && data[2] == 0x02 && data[3] == 0x03 { - // big endian - data.chunks(4) - .map(|c| { - ((c[0] as u32) << 24) | ((c[1] as u32) << 16) | ((c[2] as u32) << 8) | - c[3] as u32 - }) - .collect::>() - - } else if data[3] == 0x07 && data[2] == 0x23 && data[1] == 0x02 && data[0] == 0x03 { - // little endian - data.chunks(4) - .map(|c| { - ((c[3] as u32) << 24) | ((c[2] as u32) << 16) | ((c[1] as u32) << 8) | - c[0] as u32 - }) - .collect::>() - - } else { - return Err(ParseError::MissingHeader); - }; - - parse_u32s(&data) -} - -/// Parses a SPIR-V document from a list of u32s. -/// -/// Endianness has already been handled. -fn parse_u32s(i: &[u32]) -> Result { +/// Parses a SPIR-V document from a list of words. +pub fn parse_spirv(i: &[u32]) -> Result { if i.len() < 5 { return Err(ParseError::MissingHeader); } @@ -399,6 +364,12 @@ mod test { #[test] fn test() { let data = include_bytes!("../tests/frag.spv"); - parse::parse_spirv(data).unwrap(); + let insts: Vec<_> = data.chunks(4) + .map(|c| { + ((c[3] as u32) << 24) | ((c[2] as u32) << 16) | ((c[1] as u32) << 8) | c[0] as u32 + }) + .collect(); + + parse::parse_spirv(&insts).unwrap(); } }