Skip to content

Commit

Permalink
Add arch functions for the GLSL.std.450 S/U Min/Max functions (Emba…
Browse files Browse the repository at this point in the history
…rkStudios#763)

* Add (un)signed_(min|max) glsl functinos

* Add gpu_only to call glsl op
  • Loading branch information
expenses authored Oct 12, 2021
1 parent 14e2152 commit f8a1130
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 1 deletion.
47 changes: 46 additions & 1 deletion crates/spirv-std/src/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
//! This module is intended as a low level abstraction over SPIR-V instructions.
//! These functions will typically map to a single instruction, and will perform
//! no additional safety checks beyond type-checking.
use crate::{scalar::Scalar, vector::Vector};
use crate::{
integer::{Integer, SignedInteger, UnsignedInteger},
scalar::Scalar,
vector::Vector,
};

mod barrier;
mod demote_to_helper_invocation_ext;
Expand Down Expand Up @@ -200,3 +204,44 @@ pub unsafe fn read_clock_uvec2_khr<V: Vector<u32, 2>, const SCOPE: u32>() -> V {

result
}

#[spirv_std_macros::gpu_only]
unsafe fn call_glsl_op_with_ints<T: Integer, const OP: u32>(a: T, b: T) -> T {
let mut result = T::default();
asm!(
"%glsl = OpExtInstImport \"GLSL.std.450\"",
"%a = OpLoad _ {a}",
"%b = OpLoad _ {b}",
"%result = OpExtInst typeof*{result} %glsl {op} %a %b",
"OpStore {result} %result",
a = in(reg) &a,
b = in(reg) &b,
result = in(reg) &mut result,
op = const OP
);
result
}

/// Compute the minimum of two unsigned integers via a GLSL extended instruction.
#[spirv_std_macros::gpu_only]
pub fn unsigned_min<T: UnsignedInteger>(a: T, b: T) -> T {
unsafe { call_glsl_op_with_ints::<_, 38>(a, b) }
}

/// Compute the maximum of two unsigned integers via a GLSL extended instruction.
#[spirv_std_macros::gpu_only]
pub fn unsigned_max<T: UnsignedInteger>(a: T, b: T) -> T {
unsafe { call_glsl_op_with_ints::<_, 41>(a, b) }
}

/// Compute the minimum of two signed integers via a GLSL extended instruction.
#[spirv_std_macros::gpu_only]
pub fn signed_min<T: SignedInteger>(a: T, b: T) -> T {
unsafe { call_glsl_op_with_ints::<_, 39>(a, b) }
}

/// Compute the maximum of two signed integers via a GLSL extended instruction.
#[spirv_std_macros::gpu_only]
pub fn signed_max<T: SignedInteger>(a: T, b: T) -> T {
unsafe { call_glsl_op_with_ints::<_, 42>(a, b) }
}
26 changes: 26 additions & 0 deletions tests/ui/arch/integer_min_and_max.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// build-pass

use spirv_std::arch::{signed_max, signed_min, unsigned_max, unsigned_min};

#[spirv(fragment)]
pub fn main() {
assert!(unsigned_min(39_u8, 13) == 13);
assert!(unsigned_min(39_u16, 13) == 13);
assert!(unsigned_min(39_u32, 13) == 13);
assert!(unsigned_min(39_u64, 13) == 13);

assert!(unsigned_max(39_u8, 13) == 39);
assert!(unsigned_max(39_u16, 13) == 39);
assert!(unsigned_max(39_u32, 13) == 39);
assert!(unsigned_max(39_u64, 13) == 39);

assert!(signed_min(-112_i8, -45) == -112);
assert!(signed_min(-112_i16, -45) == -112);
assert!(signed_min(-112_i32, -45) == -112);
assert!(signed_min(-112_i64, -45) == -112);

assert!(signed_max(-112_i8, -45) == -45);
assert!(signed_max(-112_i16, -45) == -45);
assert!(signed_max(-112_i32, -45) == -45);
assert!(signed_max(-112_i64, -45) == -45);
}

0 comments on commit f8a1130

Please sign in to comment.