use std::borrow::Borrow;
use std::hash::{Hash, Hasher};
use std::marker;
use std::ops::Deref;
use std::sync::Arc;
use fnv::FnvHasher;
use crate::buffer::{Buffer, BufferView};
use crate::image::texture_2d::{
FloatSampledTexture2D, IntegerSampledTexture2D, ShadowSampledTexture2D,
UnsignedIntegerSampledTexture2D,
};
use crate::image::texture_2d_array::{
FloatSampledTexture2DArray, IntegerSampledTexture2DArray, ShadowSampledTexture2DArray,
UnsignedIntegerSampledTexture2DArray,
};
use crate::image::texture_3d::{
FloatSampledTexture3D, IntegerSampledTexture3D, UnsignedIntegerSampledTexture3D,
};
use crate::image::texture_cube::{
FloatSampledTextureCube, IntegerSampledTextureCube, ShadowSampledTextureCube,
UnsignedIntegerSampledTextureCube,
};
use crate::pipeline::interface_block::{InterfaceBlock, MemoryUnit};
use crate::pipeline::resources::resource_bindings_encoding::{
BindGroupEncoding, BindGroupEncodingContext, ResourceBindingDescriptor,
};
use crate::pipeline::resources::resource_slot::IncompatibleInterface;
use crate::pipeline::resources::{
BindGroupDescriptor, BindGroupEncoder, ResourceBindingsEncoding,
ResourceBindingsEncodingContext, StaticResourceBindingsEncoder,
};
pub struct BindGroup<T> {
pub(crate) internal: BindGroupInternal,
_marker: marker::PhantomData<T>,
}
pub(crate) enum BindGroupInternal {
Empty,
NotEmpty {
object_id: u64,
context_id: u64,
encoding: Arc<Vec<ResourceBindingDescriptor>>,
},
}
impl<T> BindGroup<T>
where
T: EncodeBindableResourceGroup,
{
pub(crate) fn new(object_id: u64, context_id: u64, resources: T) -> Self {
let mut encoding_context = BindGroupEncodingContext::new(context_id);
let encoding = resources.encode_bindable_resource_group(&mut encoding_context);
BindGroup {
internal: BindGroupInternal::NotEmpty {
object_id,
context_id,
encoding: Arc::new(encoding.bindings),
},
_marker: marker::PhantomData,
}
}
}
impl BindGroup<()> {
pub const fn empty() -> Self {
BindGroup {
internal: BindGroupInternal::Empty,
_marker: marker::PhantomData,
}
}
}
impl<T> PartialEq for BindGroup<T> {
fn eq(&self, other: &Self) -> bool {
match &self.internal {
BindGroupInternal::Empty => {
if let BindGroupInternal::Empty = &other.internal {
true
} else {
false
}
}
BindGroupInternal::NotEmpty { object_id, .. } => {
if let BindGroupInternal::NotEmpty {
object_id: other_object_id,
..
} = &other.internal
{
object_id == other_object_id
} else {
false
}
}
}
}
}
impl<T> Hash for BindGroup<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
match &self.internal {
BindGroupInternal::Empty => 0.hash(state),
BindGroupInternal::NotEmpty { object_id, .. } => object_id.hash(state),
}
}
}
#[derive(Clone, Debug)]
pub struct ResourceBindingsLayoutDescriptor {
layout: Vec<LayoutElement>,
bind_groups: usize,
}
impl ResourceBindingsLayoutDescriptor {
pub fn bind_groups(&self) -> BindGroupLayouts {
BindGroupLayouts { layout: self }
}
pub(crate) fn key(&self) -> u64 {
let mut hasher = FnvHasher::default();
for element in self.layout.iter() {
match element {
LayoutElement::Slot(descriptor) => descriptor.hash(&mut hasher),
LayoutElement::NextBindGroup(element) => element.bind_group_index.hash(&mut hasher),
}
}
hasher.finish()
}
}
#[derive(Clone, Debug)]
enum LayoutElement {
Slot(ResourceSlotDescriptor),
NextBindGroup(BindGroupElement),
}
#[derive(Clone, Debug)]
struct BindGroupElement {
bind_group_index: u32,
len: usize,
}
#[derive(Clone, Copy)]
pub struct BindGroupLayouts<'a> {
layout: &'a ResourceBindingsLayoutDescriptor,
}
impl<'a> BindGroupLayouts<'a> {
pub fn len(&self) -> usize {
self.layout.bind_groups
}
pub fn iter(&self) -> BindGroupLayoutsIter {
BindGroupLayoutsIter {
layout: &self.layout.layout,
cursor: 0,
len: self.layout.bind_groups,
}
}
}
impl<'a> IntoIterator for BindGroupLayouts<'a> {
type Item = BindGroupLayout<'a>;
type IntoIter = BindGroupLayoutsIter<'a>;
fn into_iter(self) -> Self::IntoIter {
BindGroupLayoutsIter {
layout: &self.layout.layout,
cursor: 0,
len: self.layout.bind_groups,
}
}
}
pub struct BindGroupLayoutsIter<'a> {
layout: &'a [LayoutElement],
cursor: usize,
len: usize,
}
impl<'a> Iterator for BindGroupLayoutsIter<'a> {
type Item = BindGroupLayout<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.layout.get(self.cursor).map(|element| {
if let LayoutElement::NextBindGroup(element) = element {
let start = self.cursor as usize + 1;
let end = start + element.len;
self.cursor = end;
self.len -= 1;
BindGroupLayout {
slots: &self.layout[start..end],
bind_group_index: element.bind_group_index,
}
} else {
unreachable!()
}
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<'a> ExactSizeIterator for BindGroupLayoutsIter<'a> {
fn len(&self) -> usize {
self.len
}
}
pub struct BindGroupLayout<'a> {
slots: &'a [LayoutElement],
bind_group_index: u32,
}
impl<'a> BindGroupLayout<'a> {
pub fn bind_group_index(&self) -> u32 {
self.bind_group_index
}
pub fn slots(&self) -> BindGroupLayoutSlots {
BindGroupLayoutSlots { slots: self.slots }
}
}
pub struct BindGroupLayoutSlots<'a> {
slots: &'a [LayoutElement],
}
impl<'a> BindGroupLayoutSlots<'a> {
pub fn len(&self) -> usize {
self.slots.len()
}
pub fn iter(&self) -> BindGroupLayoutSlotsIter {
BindGroupLayoutSlotsIter {
iter: self.slots.iter(),
}
}
}
impl<'a> IntoIterator for BindGroupLayoutSlots<'a> {
type Item = &'a ResourceSlotDescriptor;
type IntoIter = BindGroupLayoutSlotsIter<'a>;
fn into_iter(self) -> Self::IntoIter {
BindGroupLayoutSlotsIter {
iter: self.slots.into_iter(),
}
}
}
pub struct BindGroupLayoutSlotsIter<'a> {
iter: std::slice::Iter<'a, LayoutElement>,
}
impl<'a> Iterator for BindGroupLayoutSlotsIter<'a> {
type Item = &'a ResourceSlotDescriptor;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|element| {
if let LayoutElement::Slot(slot) = element {
slot
} else {
unreachable!()
}
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a> ExactSizeIterator for BindGroupLayoutSlotsIter<'a> {
fn len(&self) -> usize {
self.iter.len()
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct LayoutAllocationHint {
pub bind_groups: usize,
pub total_resource_slots: usize,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ResourceBindingsLayoutBuilderError {
InvalidBindGroupSequence(InvalidBindGroupSequence),
InvalidResourceSlotSequence(InvalidResourceSlotSequence),
}
impl From<InvalidBindGroupSequence> for ResourceBindingsLayoutBuilderError {
fn from(err: InvalidBindGroupSequence) -> Self {
ResourceBindingsLayoutBuilderError::InvalidBindGroupSequence(err)
}
}
impl From<InvalidResourceSlotSequence> for ResourceBindingsLayoutBuilderError {
fn from(err: InvalidResourceSlotSequence) -> Self {
ResourceBindingsLayoutBuilderError::InvalidResourceSlotSequence(err)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct InvalidBindGroupSequence {
pub current_index: u32,
pub previous_index: u32,
}
pub struct ResourceBindingsLayoutBuilder {
layout: Vec<LayoutElement>,
last_bind_group_index: Option<u32>,
bind_groups: usize,
}
impl ResourceBindingsLayoutBuilder {
pub fn new(allocation_hint: Option<LayoutAllocationHint>) -> Self {
let layout = if let Some(hint) = allocation_hint {
Vec::with_capacity(hint.bind_groups + hint.total_resource_slots)
} else {
Vec::new()
};
ResourceBindingsLayoutBuilder {
layout,
last_bind_group_index: None,
bind_groups: 0,
}
}
pub fn add_bind_group(
mut self,
bind_group_index: u32,
) -> Result<BindGroupLayoutBuilder, InvalidBindGroupSequence> {
if let Some(last_bind_group_index) = self.last_bind_group_index {
if bind_group_index <= last_bind_group_index {
return Err(InvalidBindGroupSequence {
current_index: bind_group_index,
previous_index: last_bind_group_index,
});
}
}
let start = self.layout.len();
self.layout
.push(LayoutElement::NextBindGroup(BindGroupElement {
bind_group_index,
len: 0,
}));
self.bind_groups += 1;
Ok(BindGroupLayoutBuilder {
builder: self,
bind_group_index,
start,
last_slot_index: None,
})
}
pub fn finish(self) -> ResourceBindingsLayoutDescriptor {
ResourceBindingsLayoutDescriptor {
layout: self.layout,
bind_groups: self.bind_groups,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct InvalidResourceSlotSequence {
pub bind_group_index: u32,
pub current_index: u32,
pub previous_index: u32,
}
pub struct BindGroupLayoutBuilder {
builder: ResourceBindingsLayoutBuilder,
bind_group_index: u32,
start: usize,
last_slot_index: Option<u32>,
}
impl BindGroupLayoutBuilder {
pub fn add_resource_slot(
mut self,
descriptor: ResourceSlotDescriptor,
) -> Result<Self, InvalidResourceSlotSequence> {
if let Some(last_slot_index) = self.last_slot_index {
if descriptor.slot_index <= last_slot_index {
return Err(InvalidResourceSlotSequence {
bind_group_index: self.bind_group_index,
current_index: descriptor.slot_index,
previous_index: last_slot_index,
});
}
}
self.builder.layout.push(LayoutElement::Slot(descriptor));
Ok(self)
}
pub fn finish(mut self) -> ResourceBindingsLayoutBuilder {
let len = self.builder.layout.len() - self.start;
self.builder.layout[self.start] = LayoutElement::NextBindGroup(BindGroupElement {
bind_group_index: self.bind_group_index,
len,
});
self.builder
}
}
#[derive(Clone, Debug)]
pub struct TypedResourceBindingsLayoutDescriptor {
bind_groups: &'static [TypedBindGroupLayoutDescriptor],
}
impl TypedResourceBindingsLayoutDescriptor {
pub const unsafe fn new(bind_groups: &'static [TypedBindGroupLayoutDescriptor]) -> Self {
TypedResourceBindingsLayoutDescriptor { bind_groups }
}
pub const fn empty() -> Self {
TypedResourceBindingsLayoutDescriptor { bind_groups: &[] }
}
pub fn bind_groups(&self) -> &[TypedBindGroupLayoutDescriptor] {
&self.bind_groups
}
pub(crate) fn key(&self) -> u64 {
let mut hasher = FnvHasher::default();
for bind_group in self.bind_groups.iter() {
bind_group.bind_group_index.hash(&mut hasher);
for slot in bind_group.resource_slots.iter() {
let minimal: ResourceSlotDescriptor = slot.clone().into();
minimal.hash(&mut hasher)
}
}
hasher.finish()
}
}
#[derive(Clone, Debug)]
pub struct TypedBindGroupLayoutDescriptor {
bind_group_index: u32,
resource_slots: &'static [TypedResourceSlotDescriptor],
}
impl TypedBindGroupLayoutDescriptor {
pub const unsafe fn new(
bind_group_index: u32,
resource_slots: &'static [TypedResourceSlotDescriptor],
) -> Self {
TypedBindGroupLayoutDescriptor {
bind_group_index,
resource_slots,
}
}
pub fn bind_group_index(&self) -> u32 {
self.bind_group_index
}
pub fn slots(&self) -> &[TypedResourceSlotDescriptor] {
&self.resource_slots
}
}
pub trait TypedResourceBindingsLayout {
const LAYOUT: TypedResourceBindingsLayoutDescriptor;
}
macro_rules! implement_typed_resource_bindings_layout {
($($T:ident: $i:tt),*) => {
#[allow(unused_parens)]
impl<$($T),*> TypedResourceBindingsLayout for ($($T),*)
where
$($T: TypedBindGroupLayout),*
{
const LAYOUT: TypedResourceBindingsLayoutDescriptor = unsafe {
TypedResourceBindingsLayoutDescriptor::new(&[
$(TypedBindGroupLayoutDescriptor::new($i, $T::LAYOUT)),*
])
};
}
}
}
implement_typed_resource_bindings_layout!(T0: 0);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2, T3: 3);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10, T11: 11);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10, T11: 11, T12: 12);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10, T11: 11, T12: 12, T13: 13);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10, T11: 11, T12: 12, T13: 13, T14: 14);
implement_typed_resource_bindings_layout!(T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10, T11: 11, T12: 12, T13: 13, T14: 14, T15: 15);
pub trait TypedBindGroupLayout {
const LAYOUT: &'static [TypedResourceSlotDescriptor];
}
pub trait EncodeBindableResourceGroup {
type Encoding;
fn encode_bindable_resource_group(
self,
encoding_context: &mut BindGroupEncodingContext,
) -> BindGroupEncoding<Self::Encoding>;
}
pub unsafe trait TypedBindableResourceGroup: EncodeBindableResourceGroup {
type Layout: TypedBindGroupLayout;
}
pub trait ResourceBindings {
type BindGroups: Borrow<[BindGroupDescriptor]> + 'static;
fn encode(
self,
encoding_context: &mut ResourceBindingsEncodingContext,
) -> ResourceBindingsEncoding<Self::BindGroups>;
}
impl ResourceBindings for () {
type BindGroups = [BindGroupDescriptor; 0];
fn encode(
self,
encoding_context: &mut ResourceBindingsEncodingContext,
) -> ResourceBindingsEncoding<Self::BindGroups> {
ResourceBindingsEncoding::empty(encoding_context)
}
}
macro_rules! implement_resource_bindings {
($n:tt, $($T:ident: $i:tt),*) => {
#[allow(unused_parens)]
impl<$($T),*> ResourceBindings for ($(&'_ BindGroup<$T>),*) {
type BindGroups = [BindGroupDescriptor; $n];
fn encode(self, encoding_context: &mut ResourceBindingsEncodingContext) -> ResourceBindingsEncoding<Self::BindGroups> {
let encoder = StaticResourceBindingsEncoder::new(encoding_context);
#[allow(unused_parens, non_snake_case)]
let ($($T),*) = self;
$(let encoder = encoder.add_bind_group($i, $T);)*
encoder.finish()
}
}
}
}
implement_resource_bindings!(1, T0: 0);
implement_resource_bindings!(2, T0: 0, T1: 1);
implement_resource_bindings!(3, T0: 0, T1: 1, T2: 2);
implement_resource_bindings!(4, T0: 0, T1: 1, T2: 2, T3: 3);
implement_resource_bindings!(5, T0: 0, T1: 1, T2: 2, T3: 3, T4: 4);
implement_resource_bindings!(6, T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5);
implement_resource_bindings!(7, T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6);
implement_resource_bindings!(8, T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7);
implement_resource_bindings!(9, T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8);
implement_resource_bindings!(10, T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9);
implement_resource_bindings!(11, T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10);
implement_resource_bindings!(12, T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10, T11: 11);
implement_resource_bindings!(13, T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10, T11: 11, T12: 12);
implement_resource_bindings!(14, T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10, T11: 11, T12: 12, T13: 13);
implement_resource_bindings!(15, T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10, T11: 11, T12: 12, T13: 13, T14: 14);
implement_resource_bindings!(16, T0: 0, T1: 1, T2: 2, T3: 3, T4: 4, T5: 5, T6: 6, T7: 7, T8: 8, T9: 9, T10: 10, T11: 11, T12: 12, T13: 13, T14: 14, T15: 15);
pub unsafe trait TypedResourceBindings: ResourceBindings {
type Layout: TypedResourceBindingsLayout;
}
unsafe impl TypedResourceBindings for () {
type Layout = ();
}
macro_rules! impl_typed_resource_bindings {
($($T:ident),*) => {
#[allow(unused_parens)]
unsafe impl<$($T),*> TypedResourceBindings for ($(&'_ BindGroup<$T>),*)
where
$($T: TypedBindableResourceGroup),*
{
#[allow(unused_parens)]
type Layout = ($($T::Layout),*);
}
}
}
impl_typed_resource_bindings!(T0);
impl_typed_resource_bindings!(T0, T1);
impl_typed_resource_bindings!(T0, T1, T2);
impl_typed_resource_bindings!(T0, T1, T2, T3);
impl_typed_resource_bindings!(T0, T1, T2, T3, T4);
impl_typed_resource_bindings!(T0, T1, T2, T3, T4, T5);
impl_typed_resource_bindings!(T0, T1, T2, T3, T4, T5, T6);
impl_typed_resource_bindings!(T0, T1, T2, T3, T4, T5, T6, T7);
impl_typed_resource_bindings!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
impl_typed_resource_bindings!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
impl_typed_resource_bindings!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
impl_typed_resource_bindings!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
impl_typed_resource_bindings!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
impl_typed_resource_bindings!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
impl_typed_resource_bindings!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
impl_typed_resource_bindings!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
#[derive(Clone, Debug)]
pub enum ResourceSlotIdentifier {
Static(&'static str),
Dynamic(String),
}
impl From<&'static str> for ResourceSlotIdentifier {
fn from(value: &'static str) -> Self {
ResourceSlotIdentifier::Static(value)
}
}
impl From<String> for ResourceSlotIdentifier {
fn from(value: String) -> Self {
ResourceSlotIdentifier::Dynamic(value)
}
}
impl PartialEq for ResourceSlotIdentifier {
fn eq(&self, other: &Self) -> bool {
self.deref() == other.deref()
}
}
impl Hash for ResourceSlotIdentifier {
fn hash<H: Hasher>(&self, state: &mut H) {
let as_str: &str = self.deref();
as_str.hash(state);
}
}
impl Deref for ResourceSlotIdentifier {
type Target = str;
fn deref(&self) -> &Self::Target {
match self {
ResourceSlotIdentifier::Static(s) => s,
ResourceSlotIdentifier::Dynamic(s) => s,
}
}
}
#[derive(Clone, Hash, PartialEq, Debug)]
pub struct ResourceSlotDescriptor {
pub slot_identifier: ResourceSlotIdentifier,
pub slot_index: u32,
pub slot_kind: ResourceSlotKind,
}
impl From<TypedResourceSlotDescriptor> for ResourceSlotDescriptor {
fn from(descriptor: TypedResourceSlotDescriptor) -> Self {
let TypedResourceSlotDescriptor {
slot_identifier,
slot_index,
slot_type,
} = descriptor;
ResourceSlotDescriptor {
slot_identifier,
slot_index,
slot_kind: slot_type.into(),
}
}
}
#[derive(Clone, Copy, Hash, PartialEq, Debug)]
pub enum ResourceSlotKind {
UniformBuffer,
SampledTexture,
}
impl ResourceSlotKind {
pub fn is_uniform_buffer(&self) -> bool {
if let ResourceSlotKind::UniformBuffer = self {
true
} else {
false
}
}
pub fn is_sampled_texture(&self) -> bool {
if let ResourceSlotKind::UniformBuffer = self {
true
} else {
false
}
}
}
impl From<ResourceSlotType> for ResourceSlotKind {
fn from(slot_type: ResourceSlotType) -> Self {
match slot_type {
ResourceSlotType::UniformBuffer(_) => ResourceSlotKind::UniformBuffer,
ResourceSlotType::SampledTexture(_) => ResourceSlotKind::SampledTexture,
}
}
}
#[derive(Clone, PartialEq, Debug)]
pub struct TypedResourceSlotDescriptor {
pub slot_identifier: ResourceSlotIdentifier,
pub slot_index: u32,
pub slot_type: ResourceSlotType,
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ResourceSlotType {
UniformBuffer(&'static [MemoryUnit]),
SampledTexture(SampledTextureType),
}
#[derive(Clone, Copy, Hash, PartialEq, Debug)]
pub enum SampledTextureType {
FloatSampler2D,
IntegerSampler2D,
UnsignedIntegerSampler2D,
FloatSampler2DArray,
IntegerSampler2DArray,
UnsignedIntegerSampler2DArray,
FloatSampler3D,
IntegerSampler3D,
UnsignedIntegerSampler3D,
FloatSamplerCube,
IntegerSamplerCube,
UnsignedIntegerSamplerCube,
Sampler2DShadow,
Sampler2DArrayShadow,
SamplerCubeShadow,
}
pub unsafe trait Resources {
type Encoding;
const LAYOUT: &'static [TypedResourceSlotDescriptor];
fn encode_bind_group(
self,
encoding_context: &mut BindGroupEncodingContext,
) -> BindGroupEncoding<Self::Encoding>;
}
impl<T> TypedBindGroupLayout for T
where
T: Resources,
{
const LAYOUT: &'static [TypedResourceSlotDescriptor] = T::LAYOUT;
}
impl<T> EncodeBindableResourceGroup for T
where
T: Resources,
{
type Encoding = T::Encoding;
fn encode_bindable_resource_group(
self,
encoding_context: &mut BindGroupEncodingContext,
) -> BindGroupEncoding<Self::Encoding> {
<T as Resources>::encode_bind_group(self, encoding_context)
}
}
unsafe impl<T> TypedBindableResourceGroup for T
where
T: Resources,
{
type Layout = T;
}
impl TypedBindGroupLayout for () {
const LAYOUT: &'static [TypedResourceSlotDescriptor] = &[];
}
impl EncodeBindableResourceGroup for () {
type Encoding = ();
fn encode_bindable_resource_group(
self,
encoding_context: &mut BindGroupEncodingContext,
) -> BindGroupEncoding<()> {
BindGroupEncoding::empty(encoding_context)
}
}
unsafe impl TypedBindableResourceGroup for () {
type Layout = ();
}
#[derive(Debug)]
pub enum IncompatibleResources {
MissingBindGroup(u32),
MissingResource(ResourceSlotIdentifier),
ResourceTypeMismatch(ResourceSlotIdentifier),
IncompatibleInterface(ResourceSlotIdentifier, IncompatibleInterface),
SlotBindingMismatch { expected: usize, actual: usize },
}
pub unsafe trait Resource {
type Encoding;
const TYPE: ResourceSlotType;
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)>;
}
unsafe impl<'a, T> Resource for &'a Buffer<T>
where
T: InterfaceBlock,
{
type Encoding = BufferView<'a, T>;
const TYPE: ResourceSlotType = ResourceSlotType::UniformBuffer(T::MEMORY_UNITS);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_buffer_view(slot_index, self.into())
}
}
unsafe impl<'a, T> Resource for BufferView<'a, T>
where
T: InterfaceBlock,
{
type Encoding = Self;
const TYPE: ResourceSlotType = ResourceSlotType::UniformBuffer(T::MEMORY_UNITS);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_buffer_view(slot_index, self)
}
}
unsafe impl<'a> Resource for FloatSampledTexture2D<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::FloatSampler2D);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_float_sampled_texture_2d(slot_index, self)
}
}
unsafe impl<'a> Resource for FloatSampledTexture2DArray<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::FloatSampler2DArray);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_float_sampled_texture_2d_array(slot_index, self)
}
}
unsafe impl<'a> Resource for FloatSampledTexture3D<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::FloatSampler3D);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_float_sampled_texture_3d(slot_index, self)
}
}
unsafe impl<'a> Resource for FloatSampledTextureCube<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::FloatSamplerCube);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_float_sampled_texture_cube(slot_index, self)
}
}
unsafe impl<'a> Resource for IntegerSampledTexture2D<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::IntegerSampler2D);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_integer_sampled_texture_2d(slot_index, self)
}
}
unsafe impl<'a> Resource for IntegerSampledTexture2DArray<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::IntegerSampler2DArray);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_integer_sampled_texture_2d_array(slot_index, self)
}
}
unsafe impl<'a> Resource for IntegerSampledTexture3D<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::IntegerSampler3D);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_integer_sampled_texture_3d(slot_index, self)
}
}
unsafe impl<'a> Resource for IntegerSampledTextureCube<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::IntegerSamplerCube);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_integer_sampled_texture_cube(slot_index, self)
}
}
unsafe impl<'a> Resource for UnsignedIntegerSampledTexture2D<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::UnsignedIntegerSampler2D);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_unsigned_integer_sampled_texture_2d(slot_index, self)
}
}
unsafe impl<'a> Resource for UnsignedIntegerSampledTexture2DArray<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::UnsignedIntegerSampler2DArray);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_unsigned_integer_sampled_texture_2d_array(slot_index, self)
}
}
unsafe impl<'a> Resource for UnsignedIntegerSampledTexture3D<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::UnsignedIntegerSampler3D);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_unsigned_integer_sampled_texture_3d(slot_index, self)
}
}
unsafe impl<'a> Resource for UnsignedIntegerSampledTextureCube<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::UnsignedIntegerSamplerCube);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_unsigned_integer_sampled_texture_cube(slot_index, self)
}
}
unsafe impl<'a> Resource for ShadowSampledTexture2D<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::Sampler2DShadow);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_shadow_sampled_texture_2d(slot_index, self)
}
}
unsafe impl<'a> Resource for ShadowSampledTexture2DArray<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::Sampler2DArrayShadow);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_shadow_sampled_texture_2d_array(slot_index, self)
}
}
unsafe impl<'a> Resource for ShadowSampledTextureCube<'a> {
type Encoding = Self;
const TYPE: ResourceSlotType =
ResourceSlotType::SampledTexture(SampledTextureType::SamplerCubeShadow);
fn encode<E>(
self,
slot_index: u32,
encoder: BindGroupEncoder<E>,
) -> BindGroupEncoder<(Self::Encoding, E)> {
encoder.add_shadow_sampled_texture_cube(slot_index, self)
}
}