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

* Added read_subpass for SubpassData images, and necessary attrs for it.

* Fix CI; test bless + rustfmt

* Rename attachment_index => input_attachment_index.

* Rustfmt

* Fix clippy warning.

* Review: check for cap rather than adding cap, fix error messages.
This commit is contained in:
Alex Es 2021-06-02 12:02:04 +03:00 committed by GitHub
parent 7fc445eb10
commit 985cbed9e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 155 additions and 33 deletions

View File

@ -96,6 +96,7 @@ pub enum SpirvAttribute {
Binding(u32),
Flat,
Invariant,
InputAttachmentIndex(u32),
// `fn`/closure attributes:
UnrollLoops,
@ -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<()>>,
@ -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,
@ -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 =

View File

@ -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;
@ -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

View File

@ -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,
@ -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"),
@ -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,

View File

@ -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,
@ -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,

View File

@ -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.
@ -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 {}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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;
}