Add more downlevel flags, implement device opening on Gles

This commit is contained in:
Dzmitry Malyshau 2021-06-21 00:26:17 -04:00 committed by Dzmitry Malyshau
parent 804b17bb29
commit 5083f56149
9 changed files with 186 additions and 59 deletions

3
Cargo.lock generated
View File

@ -690,8 +690,7 @@ dependencies = [
[[package]]
name = "glow"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "945be163fdb893227410c8b44c2412dade922585b262d1daa6a7e96135217d4c"
source = "git+https://github.com/grovesNL/glow?rev=23d16276aaa8095d9ae507b1f70d0c9edfe3527f#23d16276aaa8095d9ae507b1f70d0c9edfe3527f"
dependencies = [
"js-sys",
"slotmap",

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 = { version = "0.10", optional = true }
glow = { git = "https://github.com/grovesNL/glow", rev = "23d16276aaa8095d9ae507b1f70d0c9edfe3527f", optional = true }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], optional = true }

View File

@ -161,10 +161,36 @@ impl super::Adapter {
let vendor = gl.get_parameter_string(glow::VENDOR);
let renderer = gl.get_parameter_string(glow::RENDERER);
let version = gl.get_parameter_string(glow::VERSION);
log::info!("Vendor: {}", vendor);
log::info!("Renderer: {}", renderer);
log::info!("Version: {}", version);
let ver = Self::parse_version(&version).ok()?;
let extensions = gl.supported_extensions();
log::info!("Extensions: {:?}", extensions);
let mut features = wgt::Features::empty() | wgt::Features::NON_FILL_POLYGON_MODE;
features.set(
wgt::Features::DEPTH_CLAMPING,
extensions.contains("GL_EXT_depth_clamp"),
);
features.set(wgt::Features::VERTEX_WRITABLE_STORAGE, ver >= (3, 1));
let mut downlevel_flags = wgt::DownlevelFlags::empty()
| wgt::DownlevelFlags::DEVICE_LOCAL_IMAGE_COPIES
| wgt::DownlevelFlags::NON_POWER_OF_TWO_MIPMAPPED_TEXTURES
| wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES
| wgt::DownlevelFlags::COMPARISON_SAMPLERS;
downlevel_flags.set(wgt::DownlevelFlags::COMPUTE_SHADERS, ver >= (3, 1));
downlevel_flags.set(
wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE,
ver >= (3, 1),
);
downlevel_flags.set(wgt::DownlevelFlags::INDIRECT_EXECUTION, ver >= (3, 1));
downlevel_flags.set(wgt::DownlevelFlags::BASE_VERTEX, ver >= (3, 2));
let max_texture_size = gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) as u32;
let max_texture_3d_size = gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) as u32;
let min_uniform_buffer_offset_alignment =
gl.get_parameter_i32(glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT);
@ -173,29 +199,36 @@ impl super::Adapter {
} else {
gl.get_parameter_i32(glow::SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT)
};
let max_uniform_buffers_per_shader_stage =
gl.get_parameter_i32(glow::MAX_VERTEX_UNIFORM_BLOCKS)
.min(gl.get_parameter_i32(glow::MAX_FRAGMENT_UNIFORM_BLOCKS)) as u32;
let limits = wgt::Limits {
max_texture_dimension_1d: max_texture_size,
max_texture_dimension_2d: max_texture_size,
max_texture_dimension_3d: max_texture_size,
max_texture_dimension_3d: max_texture_3d_size,
max_texture_array_layers: gl.get_parameter_i32(glow::MAX_ARRAY_TEXTURE_LAYERS) as u32,
max_bind_groups: 4,
max_bind_groups: crate::MAX_BIND_GROUPS as u32,
max_dynamic_uniform_buffers_per_pipeline_layout: 8,
max_dynamic_storage_buffers_per_pipeline_layout: 4,
max_sampled_textures_per_shader_stage: 16,
max_samplers_per_shader_stage: 16,
max_storage_buffers_per_shader_stage: 8,
max_storage_textures_per_shader_stage: 8,
max_uniform_buffers_per_shader_stage: 12,
max_uniform_buffer_binding_size: 16384,
max_storage_buffer_binding_size: 128 << 20,
max_vertex_buffers: 8,
max_vertex_attributes: 16,
max_uniform_buffers_per_shader_stage,
max_uniform_buffer_binding_size: gl.get_parameter_i32(glow::MAX_UNIFORM_BLOCK_SIZE)
as u32,
max_storage_buffer_binding_size: if ver >= (3, 1) {
gl.get_parameter_i32(glow::MAX_SHADER_STORAGE_BLOCK_SIZE) as u32
} else {
0
},
max_vertex_buffers: gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_BINDINGS) as u32,
max_vertex_attributes: gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIBS) as u32,
max_vertex_buffer_array_stride: 2048,
max_push_constant_size: 0,
};
let features = wgt::Features::empty(); //TODO
let mut private_caps = super::PrivateCapability::empty();
private_caps.set(
super::PrivateCapability::EXPLICIT_LAYOUTS_IN_SHADER,
@ -207,14 +240,16 @@ impl super::Adapter {
shared: Arc::new(super::AdapterShared {
context: gl,
private_caps,
extra_flags: super::ExtraDownlevelFlag::empty(),
}),
},
info: Self::make_info(vendor, renderer),
features,
capabilities: crate::Capabilities {
limits,
downlevel: wgt::DownlevelCapabilities::default(), //TODO
downlevel: wgt::DownlevelCapabilities {
flags: downlevel_flags,
shader_model: wgt::ShaderModel::Sm5,
},
alignments: crate::Alignments {
buffer_copy_offset: wgt::BufferSize::new(4).unwrap(),
buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(),
@ -232,6 +267,66 @@ impl super::Adapter {
}
}
impl crate::Adapter<super::Api> for super::Adapter {
unsafe fn open(
&self,
features: wgt::Features,
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
let gl = &self.shared.context;
gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1);
let main_vao = gl.create_vertex_array().unwrap();
gl.bind_vertex_array(Some(main_vao));
Ok(crate::OpenDevice {
device: super::Device {
shared: Arc::clone(&self.shared),
main_vao,
},
queue: super::Queue {
shared: Arc::clone(&self.shared),
features,
},
})
}
unsafe fn texture_format_capabilities(
&self,
format: wgt::TextureFormat,
) -> crate::TextureFormatCapability {
crate::TextureFormatCapability::empty() //TODO
}
unsafe fn surface_capabilities(
&self,
surface: &super::Surface,
) -> Option<crate::SurfaceCapabilities> {
if surface.presentable {
Some(crate::SurfaceCapabilities {
formats: vec![
wgt::TextureFormat::Rgba8UnormSrgb,
wgt::TextureFormat::Bgra8UnormSrgb,
],
present_modes: vec![wgt::PresentMode::Fifo], //TODO
composite_alpha_modes: vec![crate::CompositeAlphaMode::Opaque], //TODO
swap_chain_sizes: 2..=2,
current_extent: None,
extents: wgt::Extent3d {
width: 4,
height: 4,
depth_or_array_layers: 1,
}..=wgt::Extent3d {
width: 4096,
height: 4096,
depth_or_array_layers: 1,
},
usage: crate::TextureUse::COLOR_TARGET,
})
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::super::Adapter;

View File

@ -112,6 +112,48 @@ fn choose_config(
Err(crate::InstanceError)
}
fn debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, message: &str) {
let source_str = match source {
glow::DEBUG_SOURCE_API => "API",
glow::DEBUG_SOURCE_WINDOW_SYSTEM => "Window System",
glow::DEBUG_SOURCE_SHADER_COMPILER => "ShaderCompiler",
glow::DEBUG_SOURCE_THIRD_PARTY => "Third Party",
glow::DEBUG_SOURCE_APPLICATION => "Application",
glow::DEBUG_SOURCE_OTHER => "Other",
_ => unreachable!(),
};
let log_severity = match severity {
glow::DEBUG_SEVERITY_HIGH => log::Level::Error,
glow::DEBUG_SEVERITY_MEDIUM => log::Level::Warn,
glow::DEBUG_SEVERITY_LOW => log::Level::Info,
glow::DEBUG_SEVERITY_NOTIFICATION => log::Level::Trace,
_ => unreachable!(),
};
let type_str = match gltype {
glow::DEBUG_TYPE_DEPRECATED_BEHAVIOR => "Deprecated Behavior",
glow::DEBUG_TYPE_ERROR => "Error",
glow::DEBUG_TYPE_MARKER => "Marker",
glow::DEBUG_TYPE_OTHER => "Other",
glow::DEBUG_TYPE_PERFORMANCE => "Performance",
glow::DEBUG_TYPE_POP_GROUP => "Pop Group",
glow::DEBUG_TYPE_PORTABILITY => "Portability",
glow::DEBUG_TYPE_PUSH_GROUP => "Push Group",
glow::DEBUG_TYPE_UNDEFINED_BEHAVIOR => "Undefined Behavior",
_ => unreachable!(),
};
log::log!(
log_severity,
"[{}/{}] ID {} : {}",
source_str,
type_str,
id,
message
);
}
#[derive(Debug)]
struct Inner {
egl: Arc<egl::DynamicInstance<egl::EGL1_4>>,
@ -477,14 +519,19 @@ impl crate::Instance<super::Api> for Instance {
)
.unwrap();
let context = glow::Context::from_loader_function(|name| {
let gl = glow::Context::from_loader_function(|name| {
inner
.egl
.get_proc_address(name)
.map_or(ptr::null(), |p| p as *const _)
});
super::Adapter::expose(context).into_iter().collect()
if self.flags.contains(crate::InstanceFlag::DEBUG) && gl.supports_debug() {
gl.enable(glow::DEBUG_OUTPUT);
gl.debug_message_callback(debug_message_callback);
}
super::Adapter::expose(gl).into_iter().collect()
}
}
@ -505,7 +552,7 @@ pub struct Surface {
display: egl::Display,
context: egl::Context,
pbuffer: Option<egl::Surface>,
presentable: bool,
pub(super) presentable: bool,
wl_window: Option<*mut raw::c_void>,
swapchain: Option<Swapchain>,
}

View File

@ -26,7 +26,7 @@ impl crate::Api for Api {
type Adapter = Adapter;
type Device = Device;
type Queue = Context;
type Queue = Queue;
type CommandEncoder = Encoder;
type CommandBuffer = Resource;
@ -46,20 +46,6 @@ impl crate::Api for Api {
type ComputePipeline = Resource;
}
//TODO: uplift these to `DownlevelFlags`
bitflags::bitflags! {
/// Flags for features that are required for Vulkan but may not
/// be supported by legacy backends (GL/DX11).
struct ExtraDownlevelFlag: u32 {
/// Support indirect drawing and dispatching.
const INDIRECT_EXECUTION = 0x00000001;
/// Support indexed drawing with base vertex.
const BASE_VERTEX = 0x00000010;
/// Support offsets for instanced drawing with base instance.
const BASE_INSTANCE = 0x0000020;
}
}
bitflags::bitflags! {
/// Flags that affect internal code paths but do not
/// change the exposed feature set.
@ -88,7 +74,6 @@ struct FormatDescription {
struct AdapterShared {
context: glow::Context,
extra_flags: ExtraDownlevelFlag,
private_caps: PrivateCapability,
}
@ -98,24 +83,15 @@ pub struct Adapter {
pub struct Device {
shared: Arc<AdapterShared>,
main_vao: glow::VertexArray,
}
impl crate::Adapter<Api> for Adapter {
unsafe fn open(&self, features: wgt::Features) -> DeviceResult<crate::OpenDevice<Api>> {
Err(crate::DeviceError::Lost)
}
unsafe fn texture_format_capabilities(
&self,
format: wgt::TextureFormat,
) -> crate::TextureFormatCapability {
crate::TextureFormatCapability::empty()
}
unsafe fn surface_capabilities(&self, surface: &Surface) -> Option<crate::SurfaceCapabilities> {
None
}
pub struct Queue {
shared: Arc<AdapterShared>,
features: wgt::Features,
}
impl crate::Queue<Api> for Context {
impl crate::Queue<Api> for Queue {
unsafe fn submit(
&mut self,
command_buffers: &[&Resource],
@ -201,7 +177,7 @@ impl crate::Device<Api> for Device {
unsafe fn create_shader_module(
&self,
desc: &crate::ShaderModuleDescriptor,
shader: crate::NagaShader,
shader: crate::ShaderInput,
) -> Result<Resource, crate::ShaderError> {
Ok(Resource)
}

View File

@ -45,11 +45,12 @@
compile_error!("Metal backend enabled on non-Apple OS. If your project is not using resolver=\"2\" in Cargo.toml, it should.");
mod empty;
#[cfg(feature = "gles")]
mod gles;
#[cfg(all(feature = "metal", any(target_os = "macos", target_os = "ios")))]
mod metal;
#[cfg(feature = "vulkan")]
mod vulkan;#[cfg(feature = "gles")]
mod gles;
mod vulkan;
pub mod util;
pub mod api {

View File

@ -880,6 +880,9 @@ impl super::PrivateCapabilities {
wgt::DownlevelFlags::COMPARISON_SAMPLERS,
self.mutable_comparison_samplers,
);
downlevel
.flags
.set(wgt::DownlevelFlags::ANISOTROPIC_FILTERING, true);
crate::Capabilities {
limits: wgt::Limits {

View File

@ -99,7 +99,7 @@ impl PhysicalDeviceFeatures {
requested_features.contains(wgt::Features::VERTEX_WRITABLE_STORAGE),
)
.fragment_stores_and_atomics(
downlevel_flags.contains(wgt::DownlevelFlags::STORAGE_IMAGES),
downlevel_flags.contains(wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE),
)
//.shader_image_gather_extended(
//.shader_storage_image_extended_formats(
@ -239,7 +239,7 @@ impl PhysicalDeviceFeatures {
dl_flags.set(Df::CUBE_ARRAY_TEXTURES, self.core.image_cube_array != 0);
dl_flags.set(Df::ANISOTROPIC_FILTERING, self.core.sampler_anisotropy != 0);
dl_flags.set(
Df::STORAGE_IMAGES,
Df::FRAGMENT_WRITABLE_STORAGE,
self.core.fragment_stores_and_atomics != 0,
);

View File

@ -619,24 +619,30 @@ bitflags::bitflags! {
pub struct DownlevelFlags: u32 {
/// The device supports compiling and using compute shaders.
const COMPUTE_SHADERS = 0x0000_0001;
/// Supports creating storage images.
const STORAGE_IMAGES = 0x0000_0002;
/// Supports binding storage buffers and textures to fragment shaders.
const FRAGMENT_WRITABLE_STORAGE = 0x0000_0002;
/// Supports indirect drawing and dispatching.
const INDIRECT_EXECUTION = 0x0000_0004;
/// Supports non-zero `base_vertex` parameter to indexed draw calls.
const BASE_VERTEX = 0x0000_0008;
/// Supports non-zero `base_instance` parameter to draw calls.
const BASE_INSTANCE = 0x0000_0010;
/// Supports reading from a depth/stencil buffer while using as a read-only depth/stencil attachment.
const READ_ONLY_DEPTH_STENCIL = 0x0000_0004;
const READ_ONLY_DEPTH_STENCIL = 0x0000_0020;
/// Supports:
/// - copy_image_to_image
/// - copy_buffer_to_image and copy_image_to_buffer with a buffer without a MAP_* usage
const DEVICE_LOCAL_IMAGE_COPIES = 0x0000_0008;
const DEVICE_LOCAL_IMAGE_COPIES = 0x0000_0040;
/// Supports textures with mipmaps which have a non power of two size.
const NON_POWER_OF_TWO_MIPMAPPED_TEXTURES = 0x0000_0010;
const NON_POWER_OF_TWO_MIPMAPPED_TEXTURES = 0x0000_0080;
/// Supports textures that are cube arrays.
const CUBE_ARRAY_TEXTURES = 0x0000_0020;
const CUBE_ARRAY_TEXTURES = 0x0000_0100;
/// Supports comparison samplers.
const COMPARISON_SAMPLERS = 0x0000_0040;
const COMPARISON_SAMPLERS = 0x0000_0200;
/// Supports samplers with anisotropic filtering
const ANISOTROPIC_FILTERING = 0x0001_0000;
/// All flags are in their compliant state.
const COMPLIANT = 0x0000_007F;
const COMPLIANT = 0x0000_02FF;
}
}