hal/gles: object labels, view dimensions, and buffer clears

This commit is contained in:
Dzmitry Malyshau 2021-06-28 15:41:08 -04:00
parent 403ff6faf8
commit e4aee90341
13 changed files with 148 additions and 34 deletions

4
Cargo.lock generated
View File

@ -690,7 +690,7 @@ dependencies = [
[[package]]
name = "glow"
version = "0.10.0"
source = "git+https://github.com/kvark/glow?branch=missing-stuff#23a3f95b396ef7b3a99054494f331af25c071705"
source = "git+https://github.com/grovesNL/glow?rev=57177a01b1dd91a82ccfd2d7b687fcc36116157c#57177a01b1dd91a82ccfd2d7b687fcc36116157c"
dependencies = [
"js-sys",
"slotmap",
@ -1040,7 +1040,7 @@ dependencies = [
[[package]]
name = "naga"
version = "0.5.0"
source = "git+https://github.com/gfx-rs/naga?rev=57b325602015ce6445749a4d8ee5d491edc818d7#57b325602015ce6445749a4d8ee5d491edc818d7"
source = "git+https://github.com/gfx-rs/naga?rev=e8b71b8dc5cd70535308591f1dd2dba5f92f44eb#e8b71b8dc5cd70535308591f1dd2dba5f92f44eb"
dependencies = [
"bit-set",
"bitflags",

View File

@ -36,7 +36,7 @@ thiserror = "1"
[dependencies.naga]
git = "https://github.com/gfx-rs/naga"
rev = "57b325602015ce6445749a4d8ee5d491edc818d7"
rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb"
features = ["wgsl-in"]
[dependencies.wgt]

View File

@ -210,7 +210,12 @@ impl<A: HalApi> Adapter<A> {
let caps = &self.raw.capabilities;
if !caps.downlevel.is_webgpu_compliant() {
log::warn!("{}", DOWNLEVEL_WARNING_MESSAGE);
let missing_flags = wgt::DownlevelFlags::COMPLIANT - caps.downlevel.flags;
log::warn!(
"Missing downlevel flags: {:?}\n{}",
missing_flags,
DOWNLEVEL_WARNING_MESSAGE
);
}
// Verify feature preconditions

View File

@ -38,7 +38,7 @@ gpu-descriptor = { version = "0.1", optional = true }
inplace_it = { version ="0.3.3", optional = true }
renderdoc-sys = { version = "0.7.1", optional = true }
# backend: Gles
glow = { git = "https://github.com/kvark/glow", branch = "missing-stuff", optional = true }
glow = { git = "https://github.com/grovesNL/glow", rev = "57177a01b1dd91a82ccfd2d7b687fcc36116157c", optional = true }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], optional = true }
@ -54,11 +54,11 @@ core-graphics-types = "0.1"
[dependencies.naga]
git = "https://github.com/gfx-rs/naga"
rev = "57b325602015ce6445749a4d8ee5d491edc818d7"
rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb"
[dev-dependencies.naga]
git = "https://github.com/gfx-rs/naga"
rev = "57b325602015ce6445749a4d8ee5d491edc818d7"
rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb"
features = ["wgsl-in"]
[dev-dependencies]

View File

@ -247,6 +247,10 @@ impl super::Adapter {
super::PrivateCapability::SHADER_BINDING_LAYOUT,
ver >= (3, 1),
);
private_caps.set(
super::PrivateCapability::SHADER_TEXTURE_SHADOW_LOD,
extensions.contains("GL_EXT_texture_shadow_lod"),
);
private_caps.set(super::PrivateCapability::MEMORY_BARRIERS, ver >= (3, 1));
Some(crate::ExposedAdapter {
@ -295,6 +299,13 @@ impl crate::Adapter<super::Api> for super::Adapter {
.map_err(|_| crate::DeviceError::OutOfMemory)?;
gl.bind_vertex_array(Some(main_vao));
let zero_buffer = gl
.create_buffer()
.map_err(|_| crate::DeviceError::OutOfMemory)?;
gl.bind_buffer(glow::COPY_READ_BUFFER, Some(zero_buffer));
let zeroes = vec![0u8; super::ZERO_BUFFER_SIZE];
gl.buffer_data_u8_slice(glow::COPY_READ_BUFFER, &zeroes, glow::STATIC_DRAW);
Ok(crate::OpenDevice {
device: super::Device {
shared: Arc::clone(&self.shared),
@ -309,6 +320,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
copy_fbo: gl
.create_framebuffer()
.map_err(|_| crate::DeviceError::OutOfMemory)?,
zero_buffer,
temp_query_results: Vec::new(),
},
})

View File

@ -214,6 +214,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
unsafe fn fill_buffer(&mut self, buffer: &super::Buffer, range: crate::MemoryRange, value: u8) {
self.cmd_buffer.commands.push(C::FillBuffer {
dst: buffer.raw,
dst_target: buffer.target,
range,
value,
});
@ -346,6 +347,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
range: Range<u32>,
buffer: &super::Buffer,
offset: wgt::BufferAddress,
_stride: wgt::BufferSize,
) {
let start = self.cmd_buffer.data_words.len();
self.cmd_buffer

View File

@ -238,7 +238,7 @@ pub(super) fn map_primitive_state(state: &wgt::PrimitiveState) -> super::Primiti
}
}
pub fn map_view_dimension(dim: wgt::TextureViewDimension) -> u32 {
pub fn _map_view_dimension(dim: wgt::TextureViewDimension) -> u32 {
use wgt::TextureViewDimension as Tvd;
match dim {
Tvd::D1 | Tvd::D2 => glow::TEXTURE_2D,

View File

@ -76,6 +76,7 @@ impl super::Device {
&self,
shader: &str,
naga_stage: naga::ShaderStage,
label: Option<&str>,
) -> Result<glow::Shader, crate::PipelineError> {
let gl = &self.shared.context;
let target = match naga_stage {
@ -85,6 +86,10 @@ impl super::Device {
};
let raw = gl.create_shader(target).unwrap();
if gl.supports_debug() {
gl.object_label(glow::SHADER, raw, label);
}
gl.shader_source(raw, shader);
gl.compile_shader(raw);
@ -112,10 +117,6 @@ impl super::Device {
context: CompilationContext,
) -> Result<glow::Shader, crate::PipelineError> {
use naga::back::glsl;
let options = glsl::Options {
version: self.shared.shading_language_version,
binding_map: Default::default(), //TODO
};
let pipeline_options = glsl::PipelineOptions {
shader_stage: naga_stage,
entry_point: stage.entry_point.to_string(),
@ -134,7 +135,7 @@ impl super::Device {
&mut output,
&shader.module,
&shader.info,
&options,
&context.layout.naga_options,
&pipeline_options,
)
.map_err(|e| {
@ -155,16 +156,22 @@ impl super::Device {
reflection_info,
);
unsafe { self.compile_shader(&output, naga_stage) }
unsafe { self.compile_shader(&output, naga_stage, stage.module.label.as_deref()) }
}
unsafe fn create_pipeline<'a, I: Iterator<Item = ShaderStage<'a>>>(
&self,
shaders: I,
layout: &super::PipelineLayout,
label: crate::Label,
) -> Result<super::PipelineInner, crate::PipelineError> {
let gl = &self.shared.context;
let program = gl.create_program().unwrap();
if let Some(label) = label {
if gl.supports_debug() {
gl.object_label(glow::PROGRAM, program, Some(label));
}
}
let mut name_binding_map = NameBindingMap::default();
let mut sampler_map = [None; super::MAX_TEXTURE_SLOTS];
@ -191,7 +198,8 @@ impl super::Device {
};
let shader_src = format!("#version {} es \n void main(void) {{}}", version,);
log::info!("Only vertex shader is present. Creating an empty fragment shader",);
let shader = self.compile_shader(&shader_src, naga::ShaderStage::Fragment)?;
let shader =
self.compile_shader(&shader_src, naga::ShaderStage::Fragment, Some("_dummy"))?;
shaders_to_delete.push(shader);
}
@ -327,6 +335,12 @@ impl crate::Device<super::Api> for super::Device {
gl.buffer_storage(target, raw_size, None, map_flags);
gl.bind_buffer(target, None);
if let Some(label) = desc.label {
if gl.supports_debug() {
gl.object_label(glow::BUFFER, raw, Some(label));
}
}
Ok(super::Buffer {
raw,
target,
@ -436,6 +450,12 @@ impl crate::Device<super::Api> for super::Device {
);
}
if let Some(label) = desc.label {
if gl.supports_debug() {
gl.object_label(glow::RENDERBUFFER, raw, Some(label));
}
}
gl.bind_renderbuffer(glow::RENDERBUFFER, None);
super::TextureInner::Renderbuffer { raw }
} else {
@ -494,6 +514,12 @@ impl crate::Device<super::Api> for super::Device {
}
};
if let Some(label) = desc.label {
if gl.supports_debug() {
gl.object_label(glow::TEXTURE, raw, Some(label));
}
}
match desc.format.describe().sample_type {
wgt::TextureSampleType::Float { filterable: false }
| wgt::TextureSampleType::Uint
@ -548,15 +574,8 @@ impl crate::Device<super::Api> for super::Device {
None => texture.mip_level_count,
};
Ok(super::TextureView {
inner: match texture.inner {
super::TextureInner::Renderbuffer { raw } => {
super::TextureInner::Renderbuffer { raw }
}
super::TextureInner::Texture { raw, target: _ } => super::TextureInner::Texture {
raw,
target: conv::map_view_dimension(desc.dimension),
},
},
//TODO: use `conv::map_view_dimension(desc.dimension)`?
inner: texture.inner.clone(),
sample_type: texture.format.describe().sample_type,
aspects: crate::FormatAspect::from(texture.format)
& crate::FormatAspect::from(desc.range.aspect),
@ -573,6 +592,11 @@ impl crate::Device<super::Api> for super::Device {
let gl = &self.shared.context;
let raw = gl.create_sampler().unwrap();
if let Some(label) = desc.label {
if gl.supports_debug() {
gl.object_label(glow::SAMPLER, raw, Some(label));
}
}
let (min, mag) =
conv::map_filter_modes(desc.min_filter, desc.mag_filter, desc.mipmap_filter);
@ -661,6 +685,8 @@ impl crate::Device<super::Api> for super::Device {
&self,
desc: &crate::PipelineLayoutDescriptor<super::Api>,
) -> Result<super::PipelineLayout, crate::DeviceError> {
use naga::back::glsl;
let mut group_infos = Vec::with_capacity(desc.bind_group_layouts.len());
let mut num_samplers = 0u8;
let mut num_textures = 0u8;
@ -668,7 +694,16 @@ impl crate::Device<super::Api> for super::Device {
let mut num_uniform_buffers = 0u8;
let mut num_storage_buffers = 0u8;
for bg_layout in desc.bind_group_layouts {
let mut writer_flags = glsl::WriterFlags::ADJUST_COORDINATE_SPACE;
writer_flags.set(
glsl::WriterFlags::TEXTURE_SHADOW_LOD,
self.shared
.private_caps
.contains(super::PrivateCapability::SHADER_TEXTURE_SHADOW_LOD),
);
let mut binding_map = glsl::BindingMap::default();
for (group_index, bg_layout) in desc.bind_group_layouts.iter().enumerate() {
// create a vector with the size enough to hold all the bindings, filled with `!0`
let mut binding_to_slot = vec![
!0;
@ -695,6 +730,11 @@ impl crate::Device<super::Api> for super::Device {
};
binding_to_slot[entry.binding as usize] = *counter;
let br = naga::ResourceBinding {
group: group_index as u32,
binding: entry.binding,
};
binding_map.insert(br, *counter);
*counter += entry.count.map_or(1, |c| c.get() as u8);
}
@ -706,6 +746,11 @@ impl crate::Device<super::Api> for super::Device {
Ok(super::PipelineLayout {
group_infos: group_infos.into_boxed_slice(),
naga_options: glsl::Options {
version: self.shared.shading_language_version,
writer_flags,
binding_map,
},
})
}
unsafe fn destroy_pipeline_layout(&self, _pipeline_layout: super::PipelineLayout) {}
@ -782,7 +827,7 @@ impl crate::Device<super::Api> for super::Device {
unsafe fn create_shader_module(
&self,
_desc: &crate::ShaderModuleDescriptor,
desc: &crate::ShaderModuleDescriptor,
shader: crate::ShaderInput,
) -> Result<super::ShaderModule, crate::ShaderError> {
Ok(super::ShaderModule {
@ -792,6 +837,7 @@ impl crate::Device<super::Api> for super::Device {
}
crate::ShaderInput::Naga(naga) => naga,
},
label: desc.label.map(|str| str.to_string()),
})
}
unsafe fn destroy_shader_module(&self, _module: super::ShaderModule) {}
@ -805,7 +851,7 @@ impl crate::Device<super::Api> for super::Device {
.as_ref()
.map(|fs| (naga::ShaderStage::Fragment, fs)),
);
let inner = self.create_pipeline(shaders, desc.layout)?;
let inner = self.create_pipeline(shaders, desc.layout, desc.label)?;
let (vertex_buffers, vertex_attributes) = {
let mut buffers = Vec::new();
@ -872,7 +918,7 @@ impl crate::Device<super::Api> for super::Device {
desc: &crate::ComputePipelineDescriptor<super::Api>,
) -> Result<super::ComputePipeline, crate::PipelineError> {
let shaders = iter::once((naga::ShaderStage::Compute, &desc.stage));
let inner = self.create_pipeline(shaders, desc.layout)?;
let inner = self.create_pipeline(shaders, desc.layout, desc.label)?;
Ok(super::ComputePipeline { inner })
}
@ -885,13 +931,22 @@ impl crate::Device<super::Api> for super::Device {
&self,
desc: &wgt::QuerySetDescriptor<crate::Label>,
) -> Result<super::QuerySet, crate::DeviceError> {
use std::fmt::Write;
let gl = &self.shared.context;
let mut temp_string = String::new();
let mut queries = Vec::with_capacity(desc.count as usize);
for _ in 0..desc.count {
for i in 0..desc.count {
let query = gl
.create_query()
.map_err(|_| crate::DeviceError::OutOfMemory)?;
if gl.supports_debug() {
if let Some(label) = desc.label {
temp_string.clear();
let _ = write!(temp_string, "{}[{}]", label, i);
gl.object_label(glow::QUERY, query, Some(&temp_string));
}
}
queries.push(query);
}

View File

@ -609,6 +609,13 @@ impl crate::Instance<super::Api> for Instance {
.map_or(ptr::null(), |p| p as *const _)
});
if self.flags.contains(crate::InstanceFlag::DEBUG) && gl.supports_debug() {
log::info!(
"Max label length: {}",
gl.get_parameter_i32(glow::MAX_LABEL_LENGTH)
);
}
if self.flags.contains(crate::InstanceFlag::VALIDATION) && gl.supports_debug() {
log::info!("Enabling GLES debug output");
gl.enable(glow::DEBUG_OUTPUT);

View File

@ -22,6 +22,7 @@ pub struct Api;
const MAX_TEXTURE_SLOTS: usize = 16;
const MAX_SAMPLERS: usize = 16;
const MAX_VERTEX_ATTRIBUTES: usize = 16;
const ZERO_BUFFER_SIZE: usize = 256 << 10;
impl crate::Api for Api {
type Instance = Instance;
@ -55,8 +56,10 @@ bitflags::bitflags! {
struct PrivateCapability: u32 {
/// Support explicit layouts in shader.
const SHADER_BINDING_LAYOUT = 0x0001;
/// Support extended shadow sampling instructions.
const SHADER_TEXTURE_SHADOW_LOD = 0x0002;
/// Support memory barriers.
const MEMORY_BARRIERS = 0x0002;
const MEMORY_BARRIERS = 0x0004;
}
}
@ -102,6 +105,10 @@ pub struct Queue {
features: wgt::Features,
draw_fbo: glow::Framebuffer,
copy_fbo: glow::Framebuffer,
/// Keep a reasonably large buffer filled with zeroes,
/// so that we can implement `FillBuffer` of zeroes
/// by copying from it.
zero_buffer: glow::Buffer,
temp_query_results: Vec<u64>,
}
@ -172,6 +179,7 @@ struct BindGroupLayoutInfo {
pub struct PipelineLayout {
group_infos: Box<[BindGroupLayoutInfo]>,
naga_options: naga::back::glsl::Options,
}
impl PipelineLayout {
@ -213,6 +221,7 @@ pub struct BindGroup {
#[derive(Debug)]
pub struct ShaderModule {
naga: crate::NagaShader,
label: Option<String>,
}
#[derive(Clone, Debug, Default)]
@ -443,6 +452,7 @@ enum Command {
},
FillBuffer {
dst: glow::Buffer,
dst_target: BindTarget,
range: crate::MemoryRange,
value: u8,
},

View File

@ -144,7 +144,28 @@ impl super::Queue {
gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf));
gl.dispatch_compute_indirect(indirect_offset as i32);
}
C::FillBuffer { .. } => unimplemented!(),
C::FillBuffer {
dst,
dst_target,
ref range,
value,
} => {
assert_eq!(value, 0); // other values require `wgt::Features::CLEAR_COMMANDS`.
gl.bind_buffer(glow::COPY_READ_BUFFER, Some(self.zero_buffer));
gl.bind_buffer(dst_target, Some(dst));
let mut dst_offset = range.start;
while dst_offset < range.end {
let size = (range.end - dst_offset).min(super::ZERO_BUFFER_SIZE as u64);
gl.copy_buffer_sub_data(
glow::COPY_READ_BUFFER,
dst_target,
0,
dst_offset as i32,
size as i32,
);
dst_offset += size;
}
}
C::CopyBufferToBuffer {
src,
src_target,

View File

@ -337,6 +337,8 @@ pub trait CommandEncoder<A: Api>: Send + Sync {
// copy operations
/// This is valid to call with `value == 0`.
/// Otherwise `wgt::Features::CLEAR_COMMANDS` is required.
unsafe fn fill_buffer(&mut self, buffer: &A::Buffer, range: MemoryRange, value: u8);
unsafe fn copy_buffer_to_buffer<T>(&mut self, src: &A::Buffer, dst: &A::Buffer, regions: T)

View File

@ -73,19 +73,19 @@ env_logger = "0.8"
[dependencies.naga]
git = "https://github.com/gfx-rs/naga"
rev = "57b325602015ce6445749a4d8ee5d491edc818d7"
rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb"
optional = true
# used to test all the example shaders
[dev-dependencies.naga]
git = "https://github.com/gfx-rs/naga"
rev = "57b325602015ce6445749a4d8ee5d491edc818d7"
rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb"
features = ["wgsl-in"]
# used to generate SPIR-V for the Web target
[target.'cfg(target_arch = "wasm32")'.dependencies.naga]
git = "https://github.com/gfx-rs/naga"
rev = "57b325602015ce6445749a4d8ee5d491edc818d7"
rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb"
features = ["wgsl-in", "spv-out"]
[[example]]