mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
make glsl and spirv support optional (#8491)
# Objective - Reduce compilation time ## Solution - Make `spirv` and `glsl` shader format support optional. They are not needed for Bevy shaders. - on my mac (where shaders are compiled to `msl`), this reduces the total build time by 2 to 5 seconds, improvement should be even better with less cores There is a big reduction in compile time for `naga`, and small improvements on `wgpu` and `bevy_render` This PR with optional shader formats enabled timings: <img width="1478" alt="current main" src="https://user-images.githubusercontent.com/8672791/234347032-cbd5c276-a9b0-49c3-b793-481677391c18.png"> This PR: <img width="1479" alt="this pr" src="https://user-images.githubusercontent.com/8672791/234347059-a67412a9-da8d-4356-91d8-7b0ae84ca100.png"> --- ## Migration Guide - If you want to use shaders in `spirv`, enable the `shader_format_spirv` feature - If you want to use shaders in `glsl`, enable the `shader_format_glsl` feature
This commit is contained in:
parent
dea91e94d6
commit
949487d92c
6 changed files with 56 additions and 7 deletions
|
@ -229,6 +229,12 @@ glam_assert = ["bevy_internal/glam_assert"]
|
|||
# Include a default font, containing only ASCII characters, at the cost of a 20kB binary size increase
|
||||
default_font = ["bevy_internal/default_font"]
|
||||
|
||||
# Enable support for shaders in GLSL
|
||||
shader_format_glsl = ["bevy_internal/shader_format_glsl"]
|
||||
|
||||
# Enable support for shaders in SPIR-V
|
||||
shader_format_spirv = ["bevy_internal/shader_format_spirv"]
|
||||
|
||||
[dependencies]
|
||||
bevy_dylib = { path = "crates/bevy_dylib", version = "0.11.0-dev", default-features = false, optional = true }
|
||||
bevy_internal = { path = "crates/bevy_internal", version = "0.11.0-dev", default-features = false }
|
||||
|
|
|
@ -57,6 +57,10 @@ symphonia-isomp4 = ["bevy_audio/symphonia-isomp4"]
|
|||
symphonia-vorbis = ["bevy_audio/symphonia-vorbis"]
|
||||
symphonia-wav = ["bevy_audio/symphonia-wav"]
|
||||
|
||||
# Shader formats
|
||||
shader_format_glsl = ["bevy_render/shader_format_glsl"]
|
||||
shader_format_spirv = ["bevy_render/shader_format_spirv"]
|
||||
|
||||
# Enable watching file system for asset hot reload
|
||||
filesystem_watcher = ["bevy_asset/filesystem_watcher"]
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ bmp = ["image/bmp"]
|
|||
webp = ["image/webp"]
|
||||
dds = ["ddsfile"]
|
||||
|
||||
shader_format_glsl = ["naga/glsl-in", "naga/wgsl-out"]
|
||||
shader_format_spirv = ["wgpu/spirv", "naga/spv-in", "naga/spv-out"]
|
||||
|
||||
# For ktx2 supercompression
|
||||
zlib = ["flate2"]
|
||||
zstd = ["ruzstd"]
|
||||
|
@ -52,10 +55,10 @@ bevy_tasks = { path = "../bevy_tasks", version = "0.11.0-dev" }
|
|||
image = { version = "0.24", default-features = false }
|
||||
|
||||
# misc
|
||||
wgpu = { version = "0.15.0", features = ["spirv"] }
|
||||
wgpu = { version = "0.15.0" }
|
||||
wgpu-hal = "0.15.1"
|
||||
codespan-reporting = "0.11.0"
|
||||
naga = { version = "0.11.0", features = ["glsl-in", "spv-in", "spv-out", "wgsl-in", "wgsl-out"] }
|
||||
naga = { version = "0.11.0", features = ["wgsl-in"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
bitflags = "1.2.1"
|
||||
smallvec = { version = "1.6", features = ["union", "const_generics"] }
|
||||
|
|
|
@ -752,6 +752,7 @@ fn log_shader_error(source: &ProcessedShader, error: &AsModuleDescriptorError) {
|
|||
let msg = error.emit_to_string(source);
|
||||
error!("failed to process shader:\n{}", msg);
|
||||
}
|
||||
#[cfg(feature = "shader_format_glsl")]
|
||||
ShaderReflectError::GlslParse(errors) => {
|
||||
let source = source
|
||||
.get_glsl_source()
|
||||
|
@ -776,6 +777,7 @@ fn log_shader_error(source: &ProcessedShader, error: &AsModuleDescriptorError) {
|
|||
|
||||
error!("failed to process shader: \n{}", msg);
|
||||
}
|
||||
#[cfg(feature = "shader_format_spirv")]
|
||||
ShaderReflectError::SpirVParse(error) => {
|
||||
error!("failed to process shader:\n{}", error);
|
||||
}
|
||||
|
@ -818,9 +820,11 @@ fn log_shader_error(source: &ProcessedShader, error: &AsModuleDescriptorError) {
|
|||
error!("failed to process shader: \n{}", msg);
|
||||
}
|
||||
},
|
||||
#[cfg(feature = "shader_format_glsl")]
|
||||
AsModuleDescriptorError::WgslConversion(error) => {
|
||||
error!("failed to convert shader to wgsl: \n{}", error);
|
||||
}
|
||||
#[cfg(feature = "shader_format_spirv")]
|
||||
AsModuleDescriptorError::SpirVConversion(error) => {
|
||||
error!("failed to convert shader to spirv: \n{}", error);
|
||||
}
|
||||
|
|
|
@ -3,12 +3,16 @@ use crate::define_atomic_id;
|
|||
use bevy_asset::{AssetLoader, AssetPath, Handle, LoadContext, LoadedAsset};
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_utils::{tracing::error, BoxedFuture, HashMap};
|
||||
use naga::{back::wgsl::WriterFlags, valid::Capabilities, valid::ModuleInfo, Module};
|
||||
#[cfg(feature = "shader_format_glsl")]
|
||||
use naga::back::wgsl::WriterFlags;
|
||||
use naga::{valid::Capabilities, valid::ModuleInfo, Module};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use std::{borrow::Cow, marker::Copy, ops::Deref, path::PathBuf, str::FromStr};
|
||||
use thiserror::Error;
|
||||
use wgpu::{util::make_spirv, Features, ShaderModuleDescriptor, ShaderSource};
|
||||
#[cfg(feature = "shader_format_spirv")]
|
||||
use wgpu::util::make_spirv;
|
||||
use wgpu::{Features, ShaderModuleDescriptor, ShaderSource};
|
||||
|
||||
define_atomic_id!(ShaderId);
|
||||
|
||||
|
@ -16,8 +20,10 @@ define_atomic_id!(ShaderId);
|
|||
pub enum ShaderReflectError {
|
||||
#[error(transparent)]
|
||||
WgslParse(#[from] naga::front::wgsl::ParseError),
|
||||
#[cfg(feature = "shader_format_glsl")]
|
||||
#[error("GLSL Parse Error: {0:?}")]
|
||||
GlslParse(Vec<naga::front::glsl::Error>),
|
||||
#[cfg(feature = "shader_format_spirv")]
|
||||
#[error(transparent)]
|
||||
SpirVParse(#[from] naga::front::spv::Error),
|
||||
#[error(transparent)]
|
||||
|
@ -120,12 +126,18 @@ impl ProcessedShader {
|
|||
let module = match &self {
|
||||
// TODO: process macros here
|
||||
ProcessedShader::Wgsl(source) => naga::front::wgsl::parse_str(source)?,
|
||||
#[cfg(feature = "shader_format_glsl")]
|
||||
ProcessedShader::Glsl(source, shader_stage) => {
|
||||
let mut parser = naga::front::glsl::Parser::default();
|
||||
parser
|
||||
.parse(&naga::front::glsl::Options::from(*shader_stage), source)
|
||||
.map_err(ShaderReflectError::GlslParse)?
|
||||
}
|
||||
#[cfg(not(feature = "shader_format_glsl"))]
|
||||
ProcessedShader::Glsl(_source, _shader_stage) => {
|
||||
unimplemented!("Enable feature \"shader_format_glsl\" to use GLSL shaders")
|
||||
}
|
||||
#[cfg(feature = "shader_format_spirv")]
|
||||
ProcessedShader::SpirV(source) => naga::front::spv::parse_u8_slice(
|
||||
source,
|
||||
&naga::front::spv::Options {
|
||||
|
@ -133,6 +145,10 @@ impl ProcessedShader {
|
|||
..naga::front::spv::Options::default()
|
||||
},
|
||||
)?,
|
||||
#[cfg(not(feature = "shader_format_spirv"))]
|
||||
ProcessedShader::SpirV(_source) => {
|
||||
unimplemented!("Enable feature \"shader_format_spirv\" to use SPIR-V shaders")
|
||||
}
|
||||
};
|
||||
const CAPABILITIES: &[(Features, Capabilities)] = &[
|
||||
(Features::PUSH_CONSTANTS, Capabilities::PUSH_CONSTANT),
|
||||
|
@ -172,7 +188,7 @@ impl ProcessedShader {
|
|||
|
||||
pub fn get_module_descriptor(
|
||||
&self,
|
||||
features: Features,
|
||||
_features: Features,
|
||||
) -> Result<ShaderModuleDescriptor, AsModuleDescriptorError> {
|
||||
Ok(ShaderModuleDescriptor {
|
||||
label: None,
|
||||
|
@ -182,18 +198,28 @@ impl ProcessedShader {
|
|||
// Parse and validate the shader early, so that (e.g. while hot reloading) we can
|
||||
// display nicely formatted error messages instead of relying on just displaying the error string
|
||||
// returned by wgpu upon creating the shader module.
|
||||
let _ = self.reflect(features)?;
|
||||
let _ = self.reflect(_features)?;
|
||||
|
||||
ShaderSource::Wgsl(source.clone())
|
||||
}
|
||||
#[cfg(feature = "shader_format_glsl")]
|
||||
ProcessedShader::Glsl(_source, _stage) => {
|
||||
let reflection = self.reflect(features)?;
|
||||
let reflection = self.reflect(_features)?;
|
||||
// TODO: it probably makes more sense to convert this to spirv, but as of writing
|
||||
// this comment, naga's spirv conversion is broken
|
||||
let wgsl = reflection.get_wgsl()?;
|
||||
ShaderSource::Wgsl(wgsl.into())
|
||||
}
|
||||
#[cfg(not(feature = "shader_format_glsl"))]
|
||||
ProcessedShader::Glsl(_source, _stage) => {
|
||||
unimplemented!("Enable feature \"shader_format_glsl\" to use GLSL shaders")
|
||||
}
|
||||
#[cfg(feature = "shader_format_spirv")]
|
||||
ProcessedShader::SpirV(source) => make_spirv(source),
|
||||
#[cfg(not(feature = "shader_format_spirv"))]
|
||||
ProcessedShader::SpirV(_source) => {
|
||||
unimplemented!()
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -203,8 +229,10 @@ impl ProcessedShader {
|
|||
pub enum AsModuleDescriptorError {
|
||||
#[error(transparent)]
|
||||
ShaderReflectError(#[from] ShaderReflectError),
|
||||
#[cfg(feature = "shader_format_glsl")]
|
||||
#[error(transparent)]
|
||||
WgslConversion(#[from] naga::back::wgsl::Error),
|
||||
#[cfg(feature = "shader_format_spirv")]
|
||||
#[error(transparent)]
|
||||
SpirVConversion(#[from] naga::back::spv::Error),
|
||||
}
|
||||
|
@ -215,6 +243,7 @@ pub struct ShaderReflection {
|
|||
}
|
||||
|
||||
impl ShaderReflection {
|
||||
#[cfg(feature = "shader_format_spirv")]
|
||||
pub fn get_spirv(&self) -> Result<Vec<u32>, naga::back::spv::Error> {
|
||||
naga::back::spv::write_vec(
|
||||
&self.module,
|
||||
|
@ -227,6 +256,7 @@ impl ShaderReflection {
|
|||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "shader_format_glsl")]
|
||||
pub fn get_wgsl(&self) -> Result<String, naga::back::wgsl::Error> {
|
||||
naga::back::wgsl::write_string(&self.module, &self.module_info, WriterFlags::EXPLICIT_TYPES)
|
||||
}
|
||||
|
|
|
@ -57,6 +57,8 @@ The default feature set enables most of the expected features of a game engine,
|
|||
|minimp3|MP3 audio format support (through minimp3)|
|
||||
|mp3|MP3 audio format support|
|
||||
|serialize|Enable serialization support through serde|
|
||||
|shader_format_glsl|Enable support for shaders in GLSL|
|
||||
|shader_format_spirv|Enable support for shaders in SPIR-V|
|
||||
|subpixel_glyph_atlas|Enable rendering of font glyphs using subpixel accuracy|
|
||||
|symphonia-aac|AAC audio format support (through symphonia)|
|
||||
|symphonia-all|AAC, FLAC, MP3, MP4, OGG/VORBIS, and WAV audio formats support (through symphonia)|
|
||||
|
|
Loading…
Reference in a new issue