Skip to content

Commit 0f65bdd

Browse files
committed
WIP
1 parent dd056a3 commit 0f65bdd

File tree

1 file changed

+172
-60
lines changed
  • crates/spirv-builder/src

1 file changed

+172
-60
lines changed

crates/spirv-builder/src/lib.rs

+172-60
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ impl fmt::Display for SpirvBuilderError {
154154

155155
impl Error for SpirvBuilderError {}
156156

157-
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
157+
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
158158
pub enum MetadataPrintout {
159159
/// Print no cargo metadata.
160160
None,
@@ -163,12 +163,14 @@ pub enum MetadataPrintout {
163163
/// Print all cargo metadata.
164164
///
165165
/// Includes dependency information and spirv environment variable.
166+
#[default]
166167
Full,
167168
}
168169

169-
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
170+
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
170171
pub enum SpirvMetadata {
171172
/// Strip all names and other debug information from SPIR-V output.
173+
#[default]
172174
None,
173175
/// Only include `OpName`s for public interface variables (uniforms and the like), to allow
174176
/// shader reflection.
@@ -178,13 +180,14 @@ pub enum SpirvMetadata {
178180
}
179181

180182
/// Strategy used to handle Rust `panic!`s in shaders compiled to SPIR-V.
181-
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
183+
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
182184
pub enum ShaderPanicStrategy {
183185
/// Return from shader entry-point with no side-effects **(default)**.
184186
///
185187
/// While similar to the standard SPIR-V `OpTerminateInvocation`, this is
186188
/// *not* limited to fragment shaders, and instead supports all shaders
187189
/// (as it's handled via control-flow rewriting, instead of SPIR-V features).
190+
#[default]
188191
SilentExit,
189192

190193
/// Like `SilentExit`, but also using `debugPrintf` to report the panic in
@@ -258,76 +261,185 @@ pub enum ShaderPanicStrategy {
258261
UNSOUND_DO_NOT_USE_UndefinedBehaviorViaUnreachable,
259262
}
260263

264+
/// Options for specifying the behavior of the validator
265+
/// Copied from `spirv-tools/src/val.rs` struct `ValidatorOptions`, with some fields disabled.
266+
#[derive(Default, Clone)]
267+
pub struct ValidatorOptions {
268+
/// Record whether or not the validator should relax the rules on types for
269+
/// stores to structs. When relaxed, it will allow a type mismatch as long as
270+
/// the types are structs with the same layout. Two structs have the same layout
271+
/// if
272+
///
273+
/// 1) the members of the structs are either the same type or are structs with
274+
/// same layout, and
275+
///
276+
/// 2) the decorations that affect the memory layout are identical for both
277+
/// types. Other decorations are not relevant.
278+
pub relax_struct_store: bool,
279+
/// Records whether or not the validator should relax the rules on pointer usage
280+
/// in logical addressing mode.
281+
///
282+
/// When relaxed, it will allow the following usage cases of pointers:
283+
/// 1) `OpVariable` allocating an object whose type is a pointer type
284+
/// 2) `OpReturnValue` returning a pointer value
285+
pub relax_logical_pointer: bool,
286+
// /// Records whether or not the validator should relax the rules because it is
287+
// /// expected that the optimizations will make the code legal.
288+
// ///
289+
// /// When relaxed, it will allow the following:
290+
// /// 1) It will allow relaxed logical pointers. Setting this option will also
291+
// /// set that option.
292+
// /// 2) Pointers that are pass as parameters to function calls do not have to
293+
// /// match the storage class of the formal parameter.
294+
// /// 3) Pointers that are actaul parameters on function calls do not have to point
295+
// /// to the same type pointed as the formal parameter. The types just need to
296+
// /// logically match.
297+
// pub before_legalization: bool,
298+
/// Records whether the validator should use "relaxed" block layout rules.
299+
/// Relaxed layout rules are described by Vulkan extension
300+
/// `VK_KHR_relaxed_block_layout`, and they affect uniform blocks, storage blocks,
301+
/// and push constants.
302+
///
303+
/// This is enabled by default when targeting Vulkan 1.1 or later.
304+
/// Relaxed layout is more permissive than the default rules in Vulkan 1.0.
305+
pub relax_block_layout: Option<bool>,
306+
/// Records whether the validator should use standard block layout rules for
307+
/// uniform blocks.
308+
pub uniform_buffer_standard_layout: bool,
309+
/// Records whether the validator should use "scalar" block layout rules.
310+
/// Scalar layout rules are more permissive than relaxed block layout.
311+
///
312+
/// See Vulkan extnesion `VK_EXT_scalar_block_layout`. The scalar alignment is
313+
/// defined as follows:
314+
/// - scalar alignment of a scalar is the scalar size
315+
/// - scalar alignment of a vector is the scalar alignment of its component
316+
/// - scalar alignment of a matrix is the scalar alignment of its component
317+
/// - scalar alignment of an array is the scalar alignment of its element
318+
/// - scalar alignment of a struct is the max scalar alignment among its
319+
/// members
320+
///
321+
/// For a struct in Uniform, `StorageClass`, or `PushConstant`:
322+
/// - a member Offset must be a multiple of the member's scalar alignment
323+
/// - `ArrayStride` or `MatrixStride` must be a multiple of the array or matrix
324+
/// scalar alignment
325+
pub scalar_block_layout: bool,
326+
/// Records whether or not the validator should skip validating standard
327+
/// uniform/storage block layout.
328+
pub skip_block_layout: bool,
329+
// /// Applies a maximum to one or more Universal limits
330+
// pub max_limits: Vec<(ValidatorLimits, u32)>,
331+
}
332+
333+
/// Options for specifying the behavior of the optimizer
334+
/// Copied from `spirv-tools/src/opt.rs` struct `Options`, with some fields disabled.
335+
#[derive(Default, Clone)]
336+
pub struct OptimizerOptions {
337+
// /// Records the validator options that should be passed to the validator,
338+
// /// the validator will run with the options before optimizer.
339+
// pub validator_options: Option<crate::val::ValidatorOptions>,
340+
// /// Records the maximum possible value for the id bound.
341+
// pub max_id_bound: Option<u32>,
342+
/// Records whether all bindings within the module should be preserved.
343+
pub preserve_bindings: bool,
344+
// /// Records whether all specialization constants within the module
345+
// /// should be preserved.
346+
// pub preserve_spec_constants: bool,
347+
}
348+
261349
/// Cargo features specification for building the shader crate.
262350
#[derive(Default)]
263-
struct ShaderCrateFeatures {
264-
default_features: Option<bool>,
265-
features: Vec<String>,
351+
pub struct ShaderCrateFeatures {
352+
/// Set --default-features for the target shader crate.
353+
pub default_features: Option<bool>,
354+
/// Set --features for the target shader crate.
355+
pub features: Vec<String>,
266356
}
267357

358+
#[non_exhaustive]
268359
pub struct SpirvBuilder {
269-
path_to_crate: PathBuf,
270-
print_metadata: MetadataPrintout,
271-
release: bool,
272-
target: String,
273-
shader_crate_features: ShaderCrateFeatures,
274-
deny_warnings: bool,
275-
multimodule: bool,
276-
spirv_metadata: SpirvMetadata,
277-
capabilities: Vec<Capability>,
278-
extensions: Vec<String>,
279-
extra_args: Vec<String>,
360+
pub path_to_crate: Option<PathBuf>,
361+
/// Whether to print build.rs cargo metadata (e.g. cargo:rustc-env=var=val). Defaults to [`MetadataPrintout::Full`].
362+
pub print_metadata: MetadataPrintout,
363+
/// Build in release. Defaults to true.
364+
pub release: bool,
365+
/// The target triple, eg. `spirv-unknown-vulkan1.2`
366+
pub target: Option<String>,
367+
/// Cargo features specification for building the shader crate.
368+
pub shader_crate_features: ShaderCrateFeatures,
369+
/// Deny any warnings, as they may never be printed when building within a build script. Defaults to false.
370+
pub deny_warnings: bool,
371+
/// Splits the resulting SPIR-V file into one module per entry point. This is useful in cases
372+
/// where ecosystem tooling has bugs around multiple entry points per module - having all entry
373+
/// points bundled into a single file is the preferred system.
374+
pub multimodule: bool,
375+
/// Sets the level of metadata (primarily `OpName` and `OpLine`) included in the SPIR-V binary.
376+
/// Including metadata significantly increases binary size.
377+
pub spirv_metadata: SpirvMetadata,
378+
/// Adds a capability to the SPIR-V module. Checking if a capability is enabled in code can be
379+
/// done via `#[cfg(target_feature = "TheCapability")]`.
380+
pub capabilities: Vec<Capability>,
381+
/// Adds an extension to the SPIR-V module. Checking if an extension is enabled in code can be
382+
/// done via `#[cfg(target_feature = "ext:the_extension")]`.
383+
pub extensions: Vec<String>,
384+
/// Set additional "codegen arg". Note: the `RUSTGPU_CODEGEN_ARGS` environment variable
385+
/// takes precedence over any set arguments using this function.
386+
pub extra_args: Vec<String>,
280387
// Optional location of a known `rustc_codegen_spirv` dylib
281-
rustc_codegen_spirv_location: Option<std::path::PathBuf>,
282-
// Optional location of a known "target-spec" file
283-
path_to_target_spec: Option<PathBuf>,
284-
target_dir_path: Option<String>,
388+
pub rustc_codegen_spirv_location: Option<std::path::PathBuf>,
389+
390+
/// The path of the "target specification" file.
391+
///
392+
/// For more info on "target specification" see
393+
/// [this RFC](https://rust-lang.github.io/rfcs/0131-target-specification.html).
394+
pub path_to_target_spec: Option<PathBuf>,
395+
/// Set the target dir path within `./target` to use for building shaders. Defaults to `spirv-builder`, resulting
396+
/// in the path `./target/spirv-builder`.
397+
pub target_dir_path: Option<String>,
285398

286399
// `rustc_codegen_spirv::linker` codegen args
400+
/// Change the shader `panic!` handling strategy (see [`ShaderPanicStrategy`]).
287401
pub shader_panic_strategy: ShaderPanicStrategy,
288402

289-
// spirv-val flags
290-
pub relax_struct_store: bool,
291-
pub relax_logical_pointer: bool,
292-
pub relax_block_layout: bool,
293-
pub uniform_buffer_standard_layout: bool,
294-
pub scalar_block_layout: bool,
295-
pub skip_block_layout: bool,
403+
/// spirv-val flags
404+
pub validator: ValidatorOptions,
296405

297-
// spirv-opt flags
298-
pub preserve_bindings: bool,
406+
/// spirv-opt flags
407+
pub optimizer: OptimizerOptions,
299408
}
300409

301-
impl SpirvBuilder {
302-
pub fn new(path_to_crate: impl AsRef<Path>, target: impl Into<String>) -> Self {
410+
impl Default for SpirvBuilder {
411+
fn default() -> Self {
303412
Self {
304-
path_to_crate: path_to_crate.as_ref().to_owned(),
305-
print_metadata: MetadataPrintout::Full,
413+
path_to_crate: None,
414+
print_metadata: MetadataPrintout::default(),
306415
release: true,
307-
target: target.into(),
416+
target: None,
308417
deny_warnings: false,
309418
multimodule: false,
310-
spirv_metadata: SpirvMetadata::None,
419+
spirv_metadata: SpirvMetadata::default(),
311420
capabilities: Vec::new(),
312421
extensions: Vec::new(),
313422
extra_args: Vec::new(),
314423
rustc_codegen_spirv_location: None,
315424
path_to_target_spec: None,
316425
target_dir_path: None,
317426

318-
shader_panic_strategy: ShaderPanicStrategy::SilentExit,
319-
320-
relax_struct_store: false,
321-
relax_logical_pointer: false,
322-
relax_block_layout: false,
323-
uniform_buffer_standard_layout: false,
324-
scalar_block_layout: false,
325-
skip_block_layout: false,
326-
327-
preserve_bindings: false,
427+
shader_panic_strategy: ShaderPanicStrategy::default(),
428+
validator: ValidatorOptions::default(),
429+
optimizer: OptimizerOptions::default(),
328430
shader_crate_features: ShaderCrateFeatures::default(),
329431
}
330432
}
433+
}
434+
435+
impl SpirvBuilder {
436+
pub fn new(path_to_crate: impl AsRef<Path>, target: impl Into<String>) -> Self {
437+
Self {
438+
path_to_crate: Some(path_to_crate.as_ref().to_owned()),
439+
target: Some(target.into()),
440+
..SpirvBuilder::default()
441+
}
442+
}
331443

332444
/// Sets the path of the "target specification" file.
333445
///
@@ -402,31 +514,31 @@ impl SpirvBuilder {
402514
/// Allow store from one struct type to a different type with compatible layout and members.
403515
#[must_use]
404516
pub fn relax_struct_store(mut self, v: bool) -> Self {
405-
self.relax_struct_store = v;
517+
self.validator.relax_struct_store = v;
406518
self
407519
}
408520

409521
/// Allow allocating an object of a pointer type and returning a pointer value from a function
410522
/// in logical addressing mode
411523
#[must_use]
412524
pub fn relax_logical_pointer(mut self, v: bool) -> Self {
413-
self.relax_logical_pointer = v;
525+
self.validator.relax_logical_pointer = v;
414526
self
415527
}
416528

417529
/// Enable `VK_KHR_relaxed_block_layout` when checking standard uniform, storage buffer, and
418530
/// push constant layouts. This is the default when targeting Vulkan 1.1 or later.
419531
#[must_use]
420532
pub fn relax_block_layout(mut self, v: bool) -> Self {
421-
self.relax_block_layout = v;
533+
self.validator.relax_block_layout = Some(v);
422534
self
423535
}
424536

425537
/// Enable `VK_KHR_uniform_buffer_standard_layout` when checking standard uniform buffer
426538
/// layouts.
427539
#[must_use]
428540
pub fn uniform_buffer_standard_layout(mut self, v: bool) -> Self {
429-
self.uniform_buffer_standard_layout = v;
541+
self.validator.uniform_buffer_standard_layout = v;
430542
self
431543
}
432544

@@ -435,22 +547,22 @@ impl SpirvBuilder {
435547
/// in effect this will override the --relax-block-layout option.
436548
#[must_use]
437549
pub fn scalar_block_layout(mut self, v: bool) -> Self {
438-
self.scalar_block_layout = v;
550+
self.validator.scalar_block_layout = v;
439551
self
440552
}
441553

442554
/// Skip checking standard uniform/storage buffer layout. Overrides any --relax-block-layout or
443555
/// --scalar-block-layout option.
444556
#[must_use]
445557
pub fn skip_block_layout(mut self, v: bool) -> Self {
446-
self.skip_block_layout = v;
558+
self.validator.skip_block_layout = v;
447559
self
448560
}
449561

450562
/// Preserve unused descriptor bindings. Useful for reflection.
451563
#[must_use]
452564
pub fn preserve_bindings(mut self, v: bool) -> Self {
453-
self.preserve_bindings = v;
565+
self.optimizer.preserve_bindings = v;
454566
self
455567
}
456568

@@ -696,25 +808,25 @@ fn invoke_rustc(builder: &SpirvBuilder) -> Result<PathBuf, SpirvBuilderError> {
696808
}
697809
SpirvMetadata::Full => llvm_args.push("--spirv-metadata=full".to_string()),
698810
}
699-
if builder.relax_struct_store {
811+
if builder.validator.relax_struct_store {
700812
llvm_args.push("--relax-struct-store".to_string());
701813
}
702-
if builder.relax_logical_pointer {
814+
if builder.validator.relax_logical_pointer {
703815
llvm_args.push("--relax-logical-pointer".to_string());
704816
}
705-
if builder.relax_block_layout {
817+
if builder.validator.relax_block_layout {
706818
llvm_args.push("--relax-block-layout".to_string());
707819
}
708-
if builder.uniform_buffer_standard_layout {
820+
if builder.validator.uniform_buffer_standard_layout {
709821
llvm_args.push("--uniform-buffer-standard-layout".to_string());
710822
}
711-
if builder.scalar_block_layout {
823+
if builder.validator.scalar_block_layout {
712824
llvm_args.push("--scalar-block-layout".to_string());
713825
}
714-
if builder.skip_block_layout {
826+
if builder.validator.skip_block_layout {
715827
llvm_args.push("--skip-block-layout".to_string());
716828
}
717-
if builder.preserve_bindings {
829+
if builder.optimizer.preserve_bindings {
718830
llvm_args.push("--preserve-bindings".to_string());
719831
}
720832
let mut target_features = vec![];

0 commit comments

Comments
 (0)