-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Description
When attempting to create a bind group with the surface texture as a resource, a validation error is thrown:
wgpu error: Validation Error
Caused by:
In Device::create_bind_group, label = 'Copy texture bind group layout'
The adapter does not support write access for storage textures of format Bgra8Unorm
Example code:
let output = self.surface.get_current_texture()?;
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
let copy_texture_bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Copy texture bind group layout"),
layout: &self.write_texture_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&view)
}
]
});However, this error is confusing "The adapter does not support write access for storage textures of format Bgra8Unorm". This is simple not the case.
The BGRA8UNORM_STORAGE feature was passed when creating the device:
let (device, queue) = adapter.request_device(&wgpu::DeviceDescriptor {
label: None,
required_features: wgpu::Features::BGRA8UNORM_STORAGE,
experimental_features: wgpu::ExperimentalFeatures::disabled(),
required_limits: wgpu::Limits::defaults(),
memory_hints: wgpu::MemoryHints::Performance,
trace: wgpu::Trace::Off,
}).await?;And I've also checked STORAGE_WRITE_ONLY is available for the texture format Bgra8Unorm:
assert!(
adapter.get_texture_format_features(surface_format)
.flags.contains(wgpu::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY)
);Quite confusing.
When I create a texture with format Bgra8Unorm, then it works fine without errors.
Example code
use wgpu::include_wgsl;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
backends: wgpu::Backends::PRIMARY,
..Default::default()
});
let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(),
compatible_surface: None,
force_fallback_adapter: false,
}).await?;
let (device, queue) = adapter.request_device(&wgpu::DeviceDescriptor {
label: None,
required_features: wgpu::Features::BGRA8UNORM_STORAGE,
experimental_features: wgpu::ExperimentalFeatures::disabled(),
required_limits: wgpu::Limits::defaults(),
..Default::default()
}).await?;
assert!(
adapter.get_texture_format_features(wgpu::TextureFormat::Bgra8Unorm)
.flags.contains(wgpu::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY)
);
let size = wgpu::Extent3d {
width: 100, height: 100,
depth_or_array_layers: 1
};
let texture = device.create_texture(&wgpu::TextureDescriptor {
label: None,
size: size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Bgra8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::STORAGE_BINDING,
view_formats: &[]
});
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let write_texture_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Copy texture bind group layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::StorageTexture {
access: wgpu::StorageTextureAccess::WriteOnly,
format: wgpu::TextureFormat::Bgra8Unorm,
view_dimension: wgpu::TextureViewDimension::D2,
},
count: None
},
]
});
let write_texture_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Copy texture pipeline layout"),
bind_group_layouts: &[&write_texture_bind_group_layout],
..Default::default()
});
let write_texture_pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: Some("Copy texture pipeline layout"),
layout: Some(&write_texture_pipeline_layout),
module: &device.create_shader_module(include_wgsl!("shaders/copy_texture.wgsl")),
entry_point: None,
compilation_options: Default::default(),
cache: Default::default(),
});
let copy_texture_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Copy texture bind group layout"),
layout: &write_texture_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&view)
}
]
});
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render encoder")
});
{
let mut pass = encoder.begin_compute_pass(&Default::default());
pass.set_pipeline(&write_texture_pipeline);
pass.set_bind_group(0, ©_texture_bind_group, &[]);
pass.dispatch_workgroups(texture.width().div_ceil(16), texture.height().div_ceil(16), 0);
}
queue.submit(std::iter::once(encoder.finish()));
Ok(())
}This means the error is wrong. I am not sure if wgpu can't write to the surface texture directly, or if something else is causing the error to be thrown.
Repro steps
I have a minimal reproducable example here: repo
Expected vs observed behavior
Expected either the example to work, or an error message which describes what the user is doing wrong.
Observed an error message which is wrong.
Platform
OS: macOS
wgpu: 28
tech stech:
- rust
- anyhow for errors
- env_logger for printing the wgpu errors
- winit for window handling
- pollster for awaiting async functions
- in the compute example I used tokio instead of pollster