Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added read_subpass for SubpassData images, and necessary attrs for it. #643

Merged
merged 6 commits into from
Jun 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion crates/rustc_codegen_spirv/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub enum SpirvAttribute {
Binding(u32),
Flat,
Invariant,
InputAttachmentIndex(u32),

// `fn`/closure attributes:
UnrollLoops,
Expand Down Expand Up @@ -130,6 +131,7 @@ pub struct AggregatedSpirvAttributes {
pub binding: Option<Spanned<u32>>,
pub flat: Option<Spanned<()>>,
pub invariant: Option<Spanned<()>>,
pub input_attachment_index: Option<Spanned<u32>>,

// `fn`/closure attributes:
pub unroll_loops: Option<Spanned<()>>,
Expand Down Expand Up @@ -215,6 +217,12 @@ impl AggregatedSpirvAttributes {
Binding(value) => try_insert(&mut self.binding, value, span, "#[spirv(binding)]"),
Flat => try_insert(&mut self.flat, (), span, "#[spirv(flat)]"),
Invariant => try_insert(&mut self.invariant, (), span, "#[spirv(invariant)]"),
InputAttachmentIndex(value) => try_insert(
&mut self.input_attachment_index,
value,
span,
"#[spirv(attachment_index)]",
),
UnrollLoops => try_insert(&mut self.unroll_loops, (), span, "#[spirv(unroll_loops)]"),
InternalBufferLoad => try_insert(
&mut self.internal_buffer_load,
Expand Down Expand Up @@ -308,7 +316,8 @@ impl CheckSpirvAttrVisitor<'_> {
| SpirvAttribute::DescriptorSet(_)
| SpirvAttribute::Binding(_)
| SpirvAttribute::Flat
| SpirvAttribute::Invariant => match target {
| SpirvAttribute::Invariant
| SpirvAttribute::InputAttachmentIndex(_) => match target {
Target::Param => {
let parent_hir_id = self.tcx.hir().get_parent_node(hir_id);
let parent_is_entry_point =
Expand Down
44 changes: 43 additions & 1 deletion crates/rustc_codegen_spirv/src/codegen_cx/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use crate::builder_spirv::{SpirvValue, SpirvValueExt};
use crate::codegen_cx::BindlessDescriptorSets;
use crate::spirv_type::SpirvType;
use rspirv::dr::Operand;
use rspirv::spirv::{Capability, Decoration, ExecutionModel, FunctionControl, StorageClass, Word};
use rspirv::spirv::{
Capability, Decoration, Dim, ExecutionModel, FunctionControl, StorageClass, Word,
};
use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
Expand Down Expand Up @@ -663,6 +665,46 @@ impl<'tcx> CodegenCx<'tcx> {
}
}

let is_subpass_input = match self.lookup_type(value_spirv_type) {
SpirvType::Image {
dim: Dim::DimSubpassData,
..
} => true,
SpirvType::RuntimeArray { element: elt, .. }
| SpirvType::Array { element: elt, .. } => matches!(
self.lookup_type(elt),
SpirvType::Image {
dim: Dim::DimSubpassData,
..
}
),
_ => false,
};
if let Some(attachment_index) = attrs.input_attachment_index {
if is_subpass_input && self.builder.has_capability(Capability::InputAttachment) {
self.emit_global().decorate(
var,
Decoration::InputAttachmentIndex,
std::iter::once(Operand::LiteralInt32(attachment_index.value)),
)
} else if is_subpass_input {
self.tcx
.sess
.span_err(hir_param.ty_span, "Missing capability InputAttachment")
} else {
self.tcx.sess.span_err(
attachment_index.span,
"#[spirv(input_attachment_index)] is only valid on Image types with dim = SubpassData"
);
}
decoration_supersedes_location = true;
} else if is_subpass_input {
self.tcx.sess.span_err(
hir_param.ty_span,
"Image types with dim = SubpassData require #[spirv(input_attachment_index)] decoration",
)
}

// Assign locations from left to right, incrementing each storage class
// individually.
// TODO: Is this right for UniformConstant? Do they share locations with
Expand Down
4 changes: 4 additions & 0 deletions crates/rustc_codegen_spirv/src/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub struct Symbols {
pub entry_point_name: Symbol,
descriptor_set: Symbol,
binding: Symbol,
input_attachment_index: Symbol,
image_type: Symbol,
dim: Symbol,
depth: Symbol,
Expand Down Expand Up @@ -380,6 +381,7 @@ impl Symbols {
num_traits: Symbol::intern("num_traits"),
descriptor_set: Symbol::intern("descriptor_set"),
binding: Symbol::intern("binding"),
input_attachment_index: Symbol::intern("input_attachment_index"),
image_type: Symbol::intern("image_type"),
dim: Symbol::intern("dim"),
depth: Symbol::intern("depth"),
Expand Down Expand Up @@ -452,6 +454,8 @@ pub(crate) fn parse_attrs_for_checking<'a>(
SpirvAttribute::DescriptorSet(parse_attr_int_value(arg)?)
} else if arg.has_name(sym.binding) {
SpirvAttribute::Binding(parse_attr_int_value(arg)?)
} else if arg.has_name(sym.input_attachment_index) {
SpirvAttribute::InputAttachmentIndex(parse_attr_int_value(arg)?)
} else {
let name = match arg.ident() {
Some(i) => i,
Expand Down
51 changes: 50 additions & 1 deletion crates/spirv-std/src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#[rustfmt::skip]
mod params;

pub use self::params::{ImageCoordinate, SampleType};
pub use self::params::{ImageCoordinate, ImageCoordinateSubpassData, SampleType};
pub use crate::macros::Image;
pub use spirv_types::image_params::{
AccessQualifier, Arrayed, Dimensionality, ImageDepth, ImageFormat, Multisampled, Sampled,
Expand Down Expand Up @@ -659,6 +659,55 @@ impl<
}
}

impl<
SampledType: SampleType<FORMAT>,
const DEPTH: ImageDepth,
const ARRAYED: Arrayed,
const MULTISAMPLED: Multisampled,
const FORMAT: ImageFormat,
const ACCESS_QUALIFIER: Option<AccessQualifier>,
>
Image<
SampledType,
{ Dimensionality::SubpassData },
DEPTH,
ARRAYED,
MULTISAMPLED,
{ Sampled::No },
FORMAT,
ACCESS_QUALIFIER,
>
{
/// Read a texel from subpass input attachment.
/// Note: Vulkan only allows the read if the first two components of the coordinate are zero.
#[crate::macros::gpu_only]
#[doc(alias = "OpImageRead")]
pub fn read_subpass<I, V, const N: usize>(
&self,
coordinate: impl ImageCoordinateSubpassData<I, ARRAYED>,
) -> V
where
I: Integer,
V: Vector<SampledType, N>,
{
let mut result = V::default();

unsafe {
asm! {
"%image = OpLoad _ {this}",
"%coordinate = OpLoad _ {coordinate}",
"%result = OpImageRead typeof*{result} %image %coordinate",
"OpStore {result} %result",
this = in(reg) self,
coordinate = in(reg) &coordinate,
result = in(reg) &mut result,
}
}

result
}
}

impl<
SampledType: SampleType<FORMAT>,
const DIM: Dimensionality,
Expand Down
7 changes: 6 additions & 1 deletion crates/spirv-std/src/image/params.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{Arrayed, Dimensionality, ImageFormat};
use crate::{scalar::Scalar, vector::Vector};
use crate::{scalar::Scalar, vector::Vector, integer::Integer};

/// Marker trait for arguments that accept single scalar values or vectors
/// of scalars.
Expand Down Expand Up @@ -72,3 +72,8 @@ impl<V: Vector<S, 3>, S: Scalar> ImageCoordinate<S, { Dimensionality::TwoD }, {
impl<V: Vector<S, 3>, S: Scalar> ImageCoordinate<S, { Dimensionality::Rect }, { Arrayed::True }> for V {}
impl<V: Vector<S, 4>, S: Scalar> ImageCoordinate<S, { Dimensionality::Cube }, { Arrayed::True }> for V {}
impl<V: Vector<S, 4>, S: Scalar> ImageCoordinate<S, { Dimensionality::ThreeD }, { Arrayed::True }> for V {}

/// Marker trait for arguments that are valid for a [`crate::image::Dimensionality::SubpassData`] image query.
pub trait ImageCoordinateSubpassData<T, const ARRAYED: Arrayed> {}
impl<V: Vector<I, 2>, I: Integer> ImageCoordinateSubpassData<I, { Arrayed::False }> for V {}
impl<V: Vector<I, 3>, I: Integer> ImageCoordinateSubpassData<I, { Arrayed::True }> for V {}
14 changes: 7 additions & 7 deletions tests/ui/image/query/query_levels_err.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
error: OpImageQueryLevels's image has a dimension of DimRect
--> $SPIRV_STD_SRC/image.rs:684:13
--> $SPIRV_STD_SRC/image.rs:733:13
|
684 | / asm! {
685 | | "%image = OpLoad _ {this}",
686 | | "{result} = OpImageQueryLevels typeof{result} %image",
687 | | this = in(reg) self,
688 | | result = out(reg) result,
689 | | }
733 | / asm! {
734 | | "%image = OpLoad _ {this}",
735 | | "{result} = OpImageQueryLevels typeof{result} %image",
736 | | this = in(reg) self,
737 | | result = out(reg) result,
738 | | }
| |_____________^
|
= note: Allowed dimensions are 1D, 2D, 3D, and Cube
Expand Down
14 changes: 7 additions & 7 deletions tests/ui/image/query/query_lod_err.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error: OpImageQueryLod's image has a dimension of DimRect
--> $SPIRV_STD_SRC/image.rs:717:13
--> $SPIRV_STD_SRC/image.rs:766:13
|
717 | / asm! {
718 | | "%typeSampledImage = OpTypeSampledImage typeof*{this}",
719 | | "%image = OpLoad _ {this}",
720 | | "%sampler = OpLoad _ {sampler}",
766 | / asm! {
767 | | "%typeSampledImage = OpTypeSampledImage typeof*{this}",
768 | | "%image = OpLoad _ {this}",
769 | | "%sampler = OpLoad _ {sampler}",
... |
728 | | coord = in(reg) &coord
729 | | }
777 | | coord = in(reg) &coord
778 | | }
| |_____________^
|
= note: Allowed dimensions are 1D, 2D, 3D, and Cube
Expand Down
16 changes: 8 additions & 8 deletions tests/ui/image/query/query_size_err.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error: OpImageQuerySize is invalid for this image type
--> $SPIRV_STD_SRC/image.rs:746:13
--> $SPIRV_STD_SRC/image.rs:795:13
|
746 | / asm! {
747 | | "%image = OpLoad _ {this}",
748 | | "%result = OpImageQuerySize typeof*{result} %image",
749 | | "OpStore {result} %result",
750 | | this = in(reg) self,
751 | | result = in(reg) &mut result,
752 | | }
795 | / asm! {
796 | | "%image = OpLoad _ {this}",
797 | | "%result = OpImageQuerySize typeof*{result} %image",
798 | | "OpStore {result} %result",
799 | | this = in(reg) self,
800 | | result = in(reg) &mut result,
801 | | }
| |_____________^
|
= note: allowed dimensions are 1D, 2D, 3D, Buffer, Rect, or Cube. if dimension is 1D, 2D, 3D, or Cube, it must have either multisampled be true, *or* sampled of Unknown or No
Expand Down
14 changes: 7 additions & 7 deletions tests/ui/image/query/query_size_lod_err.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error: OpImageQuerySizeLod is invalid for this image type
--> $SPIRV_STD_SRC/image.rs:792:13
--> $SPIRV_STD_SRC/image.rs:841:13
|
792 | / asm! {
793 | | "%image = OpLoad _ {this}",
794 | | "%result = OpImageQuerySizeLod typeof*{result} %image {lod}",
795 | | "OpStore {result} %result",
841 | / asm! {
842 | | "%image = OpLoad _ {this}",
843 | | "%result = OpImageQuerySizeLod typeof*{result} %image {lod}",
844 | | "OpStore {result} %result",
... |
798 | | result = in(reg) &mut result,
799 | | }
847 | | result = in(reg) &mut result,
848 | | }
| |_____________^
|
= note: The image's dimension must be 1D, 2D, 3D, or Cube. Multisampled must be false.
Expand Down
13 changes: 13 additions & 0 deletions tests/ui/image/read_subpass.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// build-pass
// compile-flags: -C target-feature=+InputAttachment

use spirv_std::{arch, Image};

#[spirv(fragment)]
pub fn main(
#[spirv(descriptor_set = 0, binding = 0, input_attachment_index = 0)] image: &Image!(subpass, type=f32, sampled=false),
output: &mut glam::Vec4,
) {
let coords = image.read_subpass(glam::IVec2::new(0, 0));
*output = coords;
}