Switch read-only storage textures to be exclusive and behind a feature

This commit is contained in:
Dzmitry Malyshau
2021-07-14 01:04:37 -04:00
parent f11639e8ea
commit 8cd17aafe3
16 changed files with 125 additions and 95 deletions

View File

@@ -149,8 +149,8 @@ pub enum CreateBindGroupError {
},
#[error("bound texture views can not have both depth and stencil aspects enabled")]
DepthStencilAspect,
#[error("the adapter does not support simultaneous read + write storage texture access for the format {0:?}")]
StorageReadWriteNotSupported(wgt::TextureFormat),
#[error("the adapter does not support read access for storages texture of format {0:?}")]
StorageReadNotSupported(wgt::TextureFormat),
#[error(transparent)]
ResourceUsageConflict(#[from] UsageConflict),
}

View File

@@ -51,7 +51,7 @@ pub fn map_buffer_usage(usage: wgt::BufferUsages) -> hal::BufferUses {
usage.contains(wgt::BufferUsages::UNIFORM),
);
u.set(
hal::BufferUses::STORAGE_LOAD | hal::BufferUses::STORAGE_STORE,
hal::BufferUses::STORAGE_READ | hal::BufferUses::STORAGE_WRITE,
usage.contains(wgt::BufferUsages::STORAGE),
);
u.set(
@@ -79,7 +79,7 @@ pub fn map_texture_usage(
usage.contains(wgt::TextureUsages::SAMPLED),
);
u.set(
hal::TextureUses::STORAGE_LOAD | hal::TextureUses::STORAGE_STORE,
hal::TextureUses::STORAGE_READ | hal::TextureUses::STORAGE_WRITE,
usage.contains(wgt::TextureUsages::STORAGE),
);
let is_color = aspect.contains(hal::FormatAspects::COLOR);

View File

@@ -737,8 +737,8 @@ impl<A: HalApi> Device<A> {
}
wgt::TextureViewDimension::D3 => {
hal::TextureUses::SAMPLED
| hal::TextureUses::STORAGE_LOAD
| hal::TextureUses::STORAGE_STORE
| hal::TextureUses::STORAGE_READ
| hal::TextureUses::STORAGE_WRITE
}
_ => hal::TextureUses::all(),
};
@@ -785,7 +785,7 @@ impl<A: HalApi> Device<A> {
samples: texture.desc.sample_count,
// once a storage - forever a storage
sampled_internal_use: if texture.desc.usage.contains(wgt::TextureUsages::STORAGE) {
hal::TextureUses::SAMPLED | hal::TextureUses::STORAGE_LOAD
hal::TextureUses::SAMPLED | hal::TextureUses::STORAGE_READ
} else {
hal::TextureUses::SAMPLED
},
@@ -900,7 +900,7 @@ impl<A: HalApi> Device<A> {
);
let info = naga::valid::Validator::new(naga::valid::ValidationFlags::all(), caps)
.validate(&module)?;
let interface = validation::Interface::new(&module, &info);
let interface = validation::Interface::new(&module, &info, self.features);
let hal_shader = hal::ShaderInput::Naga(hal::NagaShader { module, info });
let hal_desc = hal::ShaderModuleDescriptor {
@@ -1054,8 +1054,12 @@ impl<A: HalApi> Device<A> {
| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY,
),
match access {
wgt::StorageTextureAccess::ReadOnly => WritableStorage::No,
wgt::StorageTextureAccess::WriteOnly => WritableStorage::Yes,
wgt::StorageTextureAccess::ReadOnly => {
required_features |=
wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES;
WritableStorage::No
}
wgt::StorageTextureAccess::ReadWrite => {
required_features |=
wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES;
@@ -1174,9 +1178,9 @@ impl<A: HalApi> Device<A> {
wgt::BufferBindingType::Storage { read_only } => (
wgt::BufferUsages::STORAGE,
if read_only {
hal::BufferUses::STORAGE_LOAD
hal::BufferUses::STORAGE_READ
} else {
hal::BufferUses::STORAGE_STORE
hal::BufferUses::STORAGE_WRITE
},
limits.max_storage_buffer_binding_size,
),
@@ -1594,18 +1598,27 @@ impl<A: HalApi> Device<A> {
});
}
let internal_use = match access {
wgt::StorageTextureAccess::ReadOnly => hal::TextureUses::STORAGE_LOAD,
wgt::StorageTextureAccess::WriteOnly => hal::TextureUses::STORAGE_STORE,
wgt::StorageTextureAccess::WriteOnly => hal::TextureUses::STORAGE_WRITE,
wgt::StorageTextureAccess::ReadOnly => {
if !view
.format_features
.flags
.contains(wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE)
{
return Err(Error::StorageReadNotSupported(view.desc.format));
}
hal::TextureUses::STORAGE_READ
}
wgt::StorageTextureAccess::ReadWrite => {
if !view
.format_features
.flags
.contains(wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE)
{
return Err(Error::StorageReadWriteNotSupported(view.desc.format));
return Err(Error::StorageReadNotSupported(view.desc.format));
}
hal::TextureUses::STORAGE_STORE | hal::TextureUses::STORAGE_LOAD
hal::TextureUses::STORAGE_WRITE | hal::TextureUses::STORAGE_READ
}
};
Ok((wgt::TextureUsages::STORAGE, internal_use))

View File

@@ -8,7 +8,7 @@ impl PendingTransition<BufferState> {
fn collapse(self) -> Result<BufferUses, Self> {
if self.usage.start.is_empty()
|| self.usage.start == self.usage.end
|| !BufferUses::WRITE_ALL.intersects(self.usage.start | self.usage.end)
|| !BufferUses::EXCLUSIVE.intersects(self.usage.start | self.usage.end)
{
Ok(self.usage.start | self.usage.end)
} else {
@@ -129,11 +129,11 @@ mod test {
};
let id = Id::dummy();
assert_eq!(
bs.change(id, (), BufferUses::STORAGE_STORE, None),
bs.change(id, (), BufferUses::STORAGE_WRITE, None),
Err(PendingTransition {
id,
selector: (),
usage: BufferUses::INDEX..BufferUses::STORAGE_STORE,
usage: BufferUses::INDEX..BufferUses::STORAGE_WRITE,
}),
);
bs.change(id, (), BufferUses::VERTEX, None).unwrap();
@@ -145,7 +145,7 @@ mod test {
fn change_replace() {
let mut bs = Unit {
first: None,
last: BufferUses::STORAGE_STORE,
last: BufferUses::STORAGE_WRITE,
};
let id = Id::dummy();
let mut list = Vec::new();
@@ -156,33 +156,33 @@ mod test {
&[PendingTransition {
id,
selector: (),
usage: BufferUses::STORAGE_STORE..BufferUses::VERTEX,
usage: BufferUses::STORAGE_WRITE..BufferUses::VERTEX,
}],
);
assert_eq!(
bs,
Unit {
first: Some(BufferUses::STORAGE_STORE),
first: Some(BufferUses::STORAGE_WRITE),
last: BufferUses::VERTEX,
}
);
list.clear();
bs.change(id, (), BufferUses::STORAGE_STORE, Some(&mut list))
bs.change(id, (), BufferUses::STORAGE_WRITE, Some(&mut list))
.unwrap();
assert_eq!(
&list,
&[PendingTransition {
id,
selector: (),
usage: BufferUses::VERTEX..BufferUses::STORAGE_STORE,
usage: BufferUses::VERTEX..BufferUses::STORAGE_WRITE,
}],
);
assert_eq!(
bs,
Unit {
first: Some(BufferUses::STORAGE_STORE),
last: BufferUses::STORAGE_STORE,
first: Some(BufferUses::STORAGE_WRITE),
last: BufferUses::STORAGE_WRITE,
}
);
}

View File

@@ -27,7 +27,7 @@ impl PendingTransition<TextureState> {
fn collapse(self) -> Result<TextureUses, Self> {
if self.usage.start.is_empty()
|| self.usage.start == self.usage.end
|| !TextureUses::WRITE_ALL.intersects(self.usage.start | self.usage.end)
|| !TextureUses::EXCLUSIVE.intersects(self.usage.start | self.usage.end)
{
Ok(self.usage.start | self.usage.end)
} else {
@@ -243,7 +243,7 @@ mod test {
ts.mips.push(PlaneStates::from_slice(&[
(1..3, Unit::new(TextureUses::SAMPLED)),
(3..5, Unit::new(TextureUses::SAMPLED)),
(5..6, Unit::new(TextureUses::STORAGE_LOAD)),
(5..6, Unit::new(TextureUses::STORAGE_READ)),
]));
assert_eq!(

View File

@@ -107,6 +107,7 @@ struct EntryPoint {
#[derive(Debug)]
pub struct Interface {
features: wgt::Features,
resources: naga::Arena<Resource>,
entry_points: FastHashMap<(naga::ShaderStage, String), EntryPoint>,
}
@@ -188,6 +189,10 @@ pub enum BindingError {
InconsistentlyDerivedType,
#[error("texture format {0:?} is not supported for storage use")]
BadStorageFormat(wgt::TextureFormat),
#[error(
"storage texture usage {0:?} doesn't have a matching supported `StorageTextureAccess`"
)]
UnsupportedTextureStorageAccess(GlobalUse),
}
#[derive(Clone, Debug, Error)]
@@ -460,7 +465,11 @@ impl Resource {
}
}
fn derive_binding_type(&self, shader_usage: GlobalUse) -> Result<BindingType, BindingError> {
fn derive_binding_type(
&self,
shader_usage: GlobalUse,
features: wgt::Features,
) -> Result<BindingType, BindingError> {
Ok(match self.ty {
ResourceType::Buffer { size } => BindingType::Buffer {
ty: match self.class {
@@ -509,10 +518,18 @@ impl Resource {
multisampled: false,
},
naga::ImageClass::Storage(format) => BindingType::StorageTexture {
access: if shader_usage.contains(GlobalUse::WRITE) {
access: if shader_usage == GlobalUse::WRITE || shader_usage.is_empty() {
wgt::StorageTextureAccess::WriteOnly
} else {
} else if !features
.contains(wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES)
{
return Err(BindingError::UnsupportedTextureStorageAccess(
shader_usage,
));
} else if shader_usage == GlobalUse::READ {
wgt::StorageTextureAccess::ReadOnly
} else {
wgt::StorageTextureAccess::ReadWrite
},
view_dimension,
format: {
@@ -783,7 +800,11 @@ impl Interface {
list.push(varying);
}
pub fn new(module: &naga::Module, info: &naga::valid::ModuleInfo) -> Self {
pub fn new(
module: &naga::Module,
info: &naga::valid::ModuleInfo,
features: wgt::Features,
) -> Self {
let mut resources = naga::Arena::new();
let mut resource_mapping = FastHashMap::default();
for (var_handle, var) in module.global_variables.iter() {
@@ -854,6 +875,7 @@ impl Interface {
}
Interface {
features,
resources,
entry_points,
}
@@ -901,7 +923,7 @@ impl Interface {
.get_mut(res.bind.group as usize)
.ok_or(BindingError::Missing)
.and_then(|set| {
let ty = res.derive_binding_type(usage)?;
let ty = res.derive_binding_type(usage, self.features)?;
match set.entry(res.bind.binding) {
Entry::Occupied(e) if e.get().ty != ty => {
return Err(BindingError::InconsistentlyDerivedType)

View File

@@ -124,7 +124,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
StateAfter: s1,
};
self.temp.barriers.push(raw);
} else if barrier.usage.start == crate::BufferUses::STORAGE_STORE {
} else if barrier.usage.start == crate::BufferUses::STORAGE_WRITE {
let mut raw = d3d12::D3D12_RESOURCE_BARRIER {
Type: d3d12::D3D12_RESOURCE_BARRIER_TYPE_UAV,
Flags: d3d12::D3D12_RESOURCE_BARRIER_FLAG_NONE,
@@ -196,7 +196,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
}
}
}
} else if barrier.usage.start == crate::TextureUses::STORAGE_STORE {
} else if barrier.usage.start == crate::TextureUses::STORAGE_WRITE {
let mut raw = d3d12::D3D12_RESOURCE_BARRIER {
Type: d3d12::D3D12_RESOURCE_BARRIER_TYPE_UAV,
Flags: d3d12::D3D12_RESOURCE_BARRIER_FLAG_NONE,

View File

@@ -185,7 +185,7 @@ pub fn map_acomposite_alpha_mode(mode: crate::CompositeAlphaMode) -> dxgi1_2::DX
pub fn map_buffer_usage_to_resource_flags(usage: crate::BufferUses) -> d3d12::D3D12_RESOURCE_FLAGS {
let mut flags = 0;
if usage.contains(crate::BufferUses::STORAGE_STORE) {
if usage.contains(crate::BufferUses::STORAGE_WRITE) {
flags |= d3d12::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
flags
@@ -211,11 +211,11 @@ pub fn map_texture_usage_to_resource_flags(
crate::TextureUses::DEPTH_STENCIL_READ | crate::TextureUses::DEPTH_STENCIL_WRITE,
) {
flags |= d3d12::D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
if !usage.intersects(crate::TextureUses::SAMPLED | crate::TextureUses::STORAGE_LOAD) {
if !usage.contains(crate::TextureUses::SAMPLED) {
flags |= d3d12::D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
}
}
if usage.contains(crate::TextureUses::STORAGE_STORE) {
if usage.contains(crate::TextureUses::STORAGE_WRITE) {
flags |= d3d12::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
@@ -283,11 +283,7 @@ pub fn map_binding_type(ty: &wgt::BindingType) -> native::DescriptorRangeType {
ty: wgt::BufferBindingType::Storage { read_only: true },
..
}
| Bt::Texture { .. }
| Bt::StorageTexture {
access: wgt::StorageTextureAccess::ReadOnly,
..
} => native::DescriptorRangeType::SRV,
| Bt::Texture { .. } => native::DescriptorRangeType::SRV,
Bt::Buffer {
ty: wgt::BufferBindingType::Storage { read_only: false },
..
@@ -316,11 +312,11 @@ pub fn map_buffer_usage_to_state(usage: crate::BufferUses) -> d3d12::D3D12_RESOU
if usage.intersects(Bu::VERTEX | Bu::UNIFORM) {
state |= d3d12::D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
}
if usage.intersects(Bu::STORAGE_LOAD) {
if usage.intersects(Bu::STORAGE_READ) {
state |= d3d12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
| d3d12::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
}
if usage.intersects(Bu::STORAGE_STORE) {
if usage.intersects(Bu::STORAGE_WRITE) {
state |= d3d12::D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
}
if usage.intersects(Bu::INDIRECT) {
@@ -344,7 +340,7 @@ pub fn map_texture_usage_to_state(usage: crate::TextureUses) -> d3d12::D3D12_RES
if usage.intersects(Tu::COPY_DST) {
state |= d3d12::D3D12_RESOURCE_STATE_COPY_DEST;
}
if usage.intersects(Tu::SAMPLED | Tu::STORAGE_LOAD) {
if usage.intersects(Tu::SAMPLED) {
state |= d3d12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
| d3d12::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
}
@@ -357,7 +353,7 @@ pub fn map_texture_usage_to_state(usage: crate::TextureUses) -> d3d12::D3D12_RES
if usage.intersects(Tu::DEPTH_STENCIL_WRITE) {
state |= d3d12::D3D12_RESOURCE_STATE_DEPTH_WRITE;
}
if usage.intersects(Tu::STORAGE_STORE) {
if usage.intersects(Tu::STORAGE_READ | Tu::STORAGE_WRITE) {
state |= d3d12::D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
}
state

View File

@@ -792,13 +792,13 @@ impl crate::Device<super::Api> for super::Device {
),
handle_srv: if desc
.usage
.intersects(crate::TextureUses::SAMPLED | crate::TextureUses::STORAGE_LOAD)
.intersects(crate::TextureUses::SAMPLED | crate::TextureUses::STORAGE_READ)
{
Some(self.view_texture_as_shader_resource(texture, desc))
} else {
None
},
handle_uav: if desc.usage.intersects(crate::TextureUses::STORAGE_STORE) {
handle_uav: if desc.usage.intersects(crate::TextureUses::STORAGE_WRITE) {
Some(self.view_texture_as_unoredered_access(texture, desc))
} else {
None
@@ -1295,11 +1295,7 @@ impl crate::Device<super::Api> for super::Device {
}
inner.stage.push(handle);
}
wgt::BindingType::Texture { .. }
| wgt::BindingType::StorageTexture {
access: wgt::StorageTextureAccess::ReadOnly,
..
} => {
wgt::BindingType::Texture { .. } => {
let data = &desc.textures[entry.resource_index as usize];
let handle = data.view.handle_srv.unwrap();
cpu_views.as_mut().unwrap().stage.push(handle.raw);

View File

@@ -196,7 +196,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
}
for bar in barriers {
// GLES only synchronizes storage -> anything explicitly
if !bar.usage.start.contains(crate::BufferUses::STORAGE_STORE) {
if !bar.usage.start.contains(crate::BufferUses::STORAGE_WRITE) {
continue;
}
self.cmd_buffer
@@ -219,7 +219,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
let mut combined_usage = crate::TextureUses::empty();
for bar in barriers {
// GLES only synchronizes storage -> anything explicitly
if !bar.usage.start.contains(crate::TextureUses::STORAGE_STORE) {
if !bar.usage.start.contains(crate::TextureUses::STORAGE_WRITE) {
continue;
}
// unlike buffers, there is no need for a concrete texture

View File

@@ -604,7 +604,7 @@ impl super::Queue {
flags |= glow::BUFFER_UPDATE_BARRIER_BIT;
}
if usage
.intersects(crate::BufferUses::STORAGE_LOAD | crate::BufferUses::STORAGE_STORE)
.intersects(crate::BufferUses::STORAGE_READ | crate::BufferUses::STORAGE_WRITE)
{
flags |= glow::SHADER_STORAGE_BARRIER_BIT;
}
@@ -616,7 +616,7 @@ impl super::Queue {
flags |= glow::TEXTURE_FETCH_BARRIER_BIT;
}
if usage.intersects(
crate::TextureUses::STORAGE_LOAD | crate::TextureUses::STORAGE_STORE,
crate::TextureUses::STORAGE_READ | crate::TextureUses::STORAGE_WRITE,
) {
flags |= glow::SHADER_IMAGE_ACCESS_BARRIER_BIT;
}

View File

@@ -515,9 +515,9 @@ bitflags!(
/// Format can be sampled with a min/max reduction sampler.
const SAMPLED_MINMAX = 0x4;
/// Format can be used as storage with exclusive read & write access.
/// Format can be used as storage with write-only access.
const STORAGE = 0x10;
/// Format can be used as storage with simultaneous read/write access.
/// Format can be used as storage with read and read/write access.
const STORAGE_READ_WRITE = 0x20;
/// Format can be used as storage with atomics.
const STORAGE_ATOMIC = 0x40;
@@ -591,19 +591,19 @@ bitflags::bitflags! {
const INDEX = 16;
const VERTEX = 32;
const UNIFORM = 64;
const STORAGE_LOAD = 128;
const STORAGE_STORE = 256;
const STORAGE_READ = 128;
const STORAGE_WRITE = 256;
const INDIRECT = 512;
/// The combination of all read-only usages.
const READ_ALL = Self::MAP_READ.bits | Self::COPY_SRC.bits |
/// The combination of usages that can be used together (read-only).
const INCLUSIVE = Self::MAP_READ.bits | Self::COPY_SRC.bits |
Self::INDEX.bits | Self::VERTEX.bits | Self::UNIFORM.bits |
Self::STORAGE_LOAD.bits | Self::INDIRECT.bits;
/// The combination of all write-only and read-write usages.
const WRITE_ALL = Self::MAP_WRITE.bits | Self::COPY_DST.bits | Self::STORAGE_STORE.bits;
Self::STORAGE_READ.bits | Self::INDIRECT.bits;
/// The combination of exclusive usages (write-only and read-write).
const EXCLUSIVE = Self::MAP_WRITE.bits | Self::COPY_DST.bits | Self::STORAGE_WRITE.bits;
/// The combination of all usages that the are guaranteed to be be ordered by the hardware.
/// If a usage is not ordered, then even if it doesn't change between draw calls, there
/// still need to be pipeline barriers inserted for synchronization.
const ORDERED = Self::READ_ALL.bits | Self::MAP_WRITE.bits | Self::COPY_DST.bits;
const ORDERED = Self::INCLUSIVE.bits | Self::MAP_WRITE.bits | Self::COPY_DST.bits;
}
}
@@ -616,16 +616,16 @@ bitflags::bitflags! {
const COLOR_TARGET = 8;
const DEPTH_STENCIL_READ = 16;
const DEPTH_STENCIL_WRITE = 32;
const STORAGE_LOAD = 64;
const STORAGE_STORE = 128;
/// The combination of all read-only usages.
const READ_ALL = Self::COPY_SRC.bits | Self::SAMPLED.bits | Self::DEPTH_STENCIL_READ.bits | Self::STORAGE_LOAD.bits;
/// The combination of all write-only and read-write usages.
const WRITE_ALL = Self::COPY_DST.bits | Self::COLOR_TARGET.bits | Self::DEPTH_STENCIL_WRITE.bits | Self::STORAGE_STORE.bits;
const STORAGE_READ = 64;
const STORAGE_WRITE = 128;
/// The combination of usages that can be used together (read-only).
const INCLUSIVE = Self::COPY_SRC.bits | Self::SAMPLED.bits | Self::DEPTH_STENCIL_READ.bits;
/// The combination of exclusive usages (write-only and read-write).
const EXCLUSIVE = Self::COPY_DST.bits | Self::COLOR_TARGET.bits | Self::DEPTH_STENCIL_WRITE.bits | Self::STORAGE_READ.bits | Self::STORAGE_WRITE.bits;
/// The combination of all usages that the are guaranteed to be be ordered by the hardware.
/// If a usage is not ordered, then even if it doesn't change between draw calls, there
/// still need to be pipeline barriers inserted for synchronization.
const ORDERED = Self::READ_ALL.bits | Self::COPY_DST.bits | Self::COLOR_TARGET.bits | Self::DEPTH_STENCIL_WRITE.bits;
const ORDERED = Self::INCLUSIVE.bits | Self::COPY_DST.bits | Self::COLOR_TARGET.bits | Self::DEPTH_STENCIL_WRITE.bits | Self::STORAGE_READ.bits;
//TODO: remove this
const UNINITIALIZED = 0xFFFF;
}

View File

@@ -9,11 +9,11 @@ pub fn map_texture_usage(usage: crate::TextureUses) -> mtl::MTLTextureUsage {
);
mtl_usage.set(
mtl::MTLTextureUsage::ShaderRead,
usage.intersects(Tu::SAMPLED | Tu::DEPTH_STENCIL_READ | Tu::STORAGE_LOAD),
usage.intersects(Tu::SAMPLED | Tu::DEPTH_STENCIL_READ | Tu::STORAGE_READ),
);
mtl_usage.set(
mtl::MTLTextureUsage::ShaderWrite,
usage.intersects(Tu::STORAGE_STORE),
usage.intersects(Tu::STORAGE_WRITE),
);
mtl_usage

View File

@@ -197,7 +197,7 @@ pub fn map_texture_usage(usage: crate::TextureUses) -> vk::ImageUsageFlags {
) {
flags |= vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT;
}
if usage.intersects(crate::TextureUses::STORAGE_LOAD | crate::TextureUses::STORAGE_STORE) {
if usage.intersects(crate::TextureUses::STORAGE_READ | crate::TextureUses::STORAGE_WRITE) {
flags |= vk::ImageUsageFlags::STORAGE;
}
flags
@@ -239,11 +239,11 @@ pub fn map_texture_usage_to_barrier(
access |= vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
| vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE;
}
if usage.contains(crate::TextureUses::STORAGE_LOAD) {
if usage.contains(crate::TextureUses::STORAGE_READ) {
stages |= shader_stages;
access |= vk::AccessFlags::SHADER_READ;
}
if usage.contains(crate::TextureUses::STORAGE_STORE) {
if usage.contains(crate::TextureUses::STORAGE_WRITE) {
stages |= shader_stages;
access |= vk::AccessFlags::SHADER_WRITE;
}
@@ -276,7 +276,7 @@ pub fn map_vk_image_usage(usage: vk::ImageUsageFlags) -> crate::TextureUses {
bits |= crate::TextureUses::DEPTH_STENCIL_READ | crate::TextureUses::DEPTH_STENCIL_WRITE;
}
if usage.contains(vk::ImageUsageFlags::STORAGE) {
bits |= crate::TextureUses::STORAGE_LOAD | crate::TextureUses::STORAGE_STORE;
bits |= crate::TextureUses::STORAGE_READ | crate::TextureUses::STORAGE_WRITE;
}
bits
}
@@ -424,7 +424,7 @@ pub fn map_buffer_usage(usage: crate::BufferUses) -> vk::BufferUsageFlags {
if usage.contains(crate::BufferUses::UNIFORM) {
flags |= vk::BufferUsageFlags::UNIFORM_BUFFER;
}
if usage.intersects(crate::BufferUses::STORAGE_LOAD | crate::BufferUses::STORAGE_STORE) {
if usage.intersects(crate::BufferUses::STORAGE_READ | crate::BufferUses::STORAGE_WRITE) {
flags |= vk::BufferUsageFlags::STORAGE_BUFFER;
}
if usage.contains(crate::BufferUses::INDEX) {
@@ -468,11 +468,11 @@ pub fn map_buffer_usage_to_barrier(
stages |= shader_stages;
access |= vk::AccessFlags::UNIFORM_READ;
}
if usage.intersects(crate::BufferUses::STORAGE_LOAD) {
if usage.intersects(crate::BufferUses::STORAGE_READ) {
stages |= shader_stages;
access |= vk::AccessFlags::SHADER_READ;
}
if usage.intersects(crate::BufferUses::STORAGE_STORE) {
if usage.intersects(crate::BufferUses::STORAGE_WRITE) {
stages |= shader_stages;
access |= vk::AccessFlags::SHADER_WRITE;
}

View File

@@ -1213,9 +1213,11 @@ bitflags::bitflags! {
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct TextureFormatFeatureFlags: u32 {
/// When used as a STORAGE texture, then a texture with this format can be bound with `StorageTextureAccess::ReadWrite`.
/// When used as a STORAGE texture, then a texture with this format can be bound with
/// [`StorageTextureAccess::ReadOnly`] or [`StorageTextureAccess::ReadWrite`].
const STORAGE_READ_WRITE = 1;
/// When used as a STORAGE texture, then a texture with this format can be written to with atomics. TODO: No access flag exposed as of writing
/// When used as a STORAGE texture, then a texture with this format can be written to with atomics.
// TODO: No access flag exposed as of writing
const STORAGE_ATOMICS = 2;
}
}
@@ -2899,13 +2901,6 @@ impl Default for TextureSampleType {
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum StorageTextureAccess {
/// The texture can only be read in the shader and it must be annotated with `readonly`.
///
/// Example GLSL syntax:
/// ```cpp,ignore
/// layout(set=0, binding=0, r32f) readonly uniform image2D myStorageImage;
/// ```
ReadOnly,
/// The texture can only be written in the shader and it must be annotated with `writeonly`.
///
/// Example GLSL syntax:
@@ -2913,6 +2908,14 @@ pub enum StorageTextureAccess {
/// layout(set=0, binding=0, r32f) writeonly uniform image2D myStorageImage;
/// ```
WriteOnly,
/// The texture can only be read in the shader and it must be annotated with `readonly`.
/// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] must be enabled to use this access mode,
///
/// Example GLSL syntax:
/// ```cpp,ignore
/// layout(set=0, binding=0, r32f) readonly uniform image2D myStorageImage;
/// ```
ReadOnly,
/// The texture can be both read and written in the shader.
/// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] must be enabled to use this access mode.
///

View File

@@ -1232,12 +1232,12 @@ impl crate::Context for Context {
view_dimension,
} => {
let mapped_access = match access {
wgt::StorageTextureAccess::ReadOnly => {
web_sys::GpuStorageTextureAccess::ReadOnly
}
wgt::StorageTextureAccess::WriteOnly => {
web_sys::GpuStorageTextureAccess::WriteOnly
}
wgt::StorageTextureAccess::ReadOnly => {
panic!("ReadOnly is not available")
}
wgt::StorageTextureAccess::ReadWrite => {
panic!("ReadWrite is not available")
}