mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 14:24:18 +00:00
Use shaderc instead of glsl-to-spirv for shader compilation (#947)
* Use shaderc instead of glsl-to-spirv for shader compilation * added some setup notes
This commit is contained in:
parent
e3bfe4270c
commit
b507034df7
@ -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
|
||||
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
||||
[submodule "glsl-to-spirv/glslang"]
|
||||
path = glsl-to-spirv/glslang
|
||||
url = https://github.com/KhronosGroup/glslang
|
@ -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 ] &&
|
||||
|
@ -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
|
||||
|
@ -1,7 +1,6 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"examples",
|
||||
"glsl-to-spirv",
|
||||
"vk-sys",
|
||||
"vulkano",
|
||||
"vulkano-shaders",
|
||||
|
18
README.md
18
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.
|
||||
|
@ -1,16 +0,0 @@
|
||||
[package]
|
||||
name = "glsl-to-spirv"
|
||||
version = "0.1.7"
|
||||
authors = ["Pierre Krieger <pierre.krieger1708@gmail.com>", "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"
|
@ -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");
|
||||
}
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
Subproject commit 4fbb8cb45e144ff63383b48fb1d3244522602438
|
@ -1 +0,0 @@
|
||||
This crate is deprecated please use [shaderc-rs](https://github.com/google/shaderc-rs) instead.
|
@ -1,76 +0,0 @@
|
||||
// Copyright (c) 2016 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
||||
// 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<SpirvOutput, String> {
|
||||
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<SpirvOutput, String>
|
||||
where I: IntoIterator<Item = (&'a str, ShaderType)>
|
||||
{
|
||||
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,
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
// Copyright (c) 2016 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
||||
// 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();
|
||||
}
|
@ -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" }
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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<Item = (&'a str, ShaderType)>
|
||||
where I: IntoIterator<Item = (&'a str, ShaderKind)>
|
||||
{
|
||||
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<R>(name: &str, mut spirv: R) -> Result<String, Error>
|
||||
where R: Read
|
||||
{
|
||||
let mut data = Vec::new();
|
||||
spirv.read_to_end(&mut data)?;
|
||||
pub fn compile(code: &str, ty: ShaderKind) -> Result<CompilationArtifact, String> {
|
||||
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<String, Error> {
|
||||
let doc = parse::parse_spirv(spirv)?;
|
||||
|
||||
let mut output = String::new();
|
||||
output.push_str(
|
||||
@ -118,8 +122,8 @@ pub fn reflect<R>(name: &str, mut spirv: R) -> Result<String, Error>
|
||||
|
||||
{
|
||||
// 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::<Vec<String>>()
|
||||
.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
|
||||
|
@ -9,43 +9,8 @@
|
||||
|
||||
use enums::*;
|
||||
|
||||
/// Parses a SPIR-V document.
|
||||
pub fn parse_spirv(data: &[u8]) -> Result<Spirv, ParseError> {
|
||||
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::<Vec<_>>()
|
||||
|
||||
} 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::<Vec<_>>()
|
||||
|
||||
} 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<Spirv, ParseError> {
|
||||
/// Parses a SPIR-V document from a list of words.
|
||||
pub fn parse_spirv(i: &[u32]) -> Result<Spirv, ParseError> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user