summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wgpu-hal/src/gles
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/wgpu-hal/src/gles')
-rw-r--r--third_party/rust/wgpu-hal/src/gles/adapter.rs73
-rw-r--r--third_party/rust/wgpu-hal/src/gles/command.rs7
-rw-r--r--third_party/rust/wgpu-hal/src/gles/device.rs5
-rw-r--r--third_party/rust/wgpu-hal/src/gles/egl.rs69
-rw-r--r--third_party/rust/wgpu-hal/src/gles/mod.rs53
-rw-r--r--third_party/rust/wgpu-hal/src/gles/queue.rs8
-rw-r--r--third_party/rust/wgpu-hal/src/gles/wgl.rs3
7 files changed, 179 insertions, 39 deletions
diff --git a/third_party/rust/wgpu-hal/src/gles/adapter.rs b/third_party/rust/wgpu-hal/src/gles/adapter.rs
index afa4023797..c09725e85f 100644
--- a/third_party/rust/wgpu-hal/src/gles/adapter.rs
+++ b/third_party/rust/wgpu-hal/src/gles/adapter.rs
@@ -4,6 +4,7 @@ use std::sync::{atomic::AtomicU8, Arc};
use wgt::AstcChannel;
use crate::auxil::db;
+use crate::gles::ShaderClearProgram;
// https://webgl2fundamentals.org/webgl/lessons/webgl-data-textures.html
@@ -435,7 +436,8 @@ impl super::Adapter {
let mut features = wgt::Features::empty()
| wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
| wgt::Features::CLEAR_TEXTURE
- | wgt::Features::PUSH_CONSTANTS;
+ | wgt::Features::PUSH_CONSTANTS
+ | wgt::Features::DEPTH32FLOAT_STENCIL8;
features.set(
wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER | wgt::Features::ADDRESS_MODE_CLAMP_TO_ZERO,
extensions.contains("GL_EXT_texture_border_clamp")
@@ -472,6 +474,7 @@ impl super::Adapter {
features.set(wgt::Features::SHADER_UNUSED_VERTEX_OUTPUT, true);
if extensions.contains("GL_ARB_timer_query") {
features.set(wgt::Features::TIMESTAMP_QUERY, true);
+ features.set(wgt::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS, true);
features.set(wgt::Features::TIMESTAMP_QUERY_INSIDE_PASSES, true);
}
let gl_bcn_exts = [
@@ -652,6 +655,15 @@ impl super::Adapter {
0
};
+ let max_color_attachments = unsafe {
+ gl.get_parameter_i32(glow::MAX_COLOR_ATTACHMENTS)
+ .min(gl.get_parameter_i32(glow::MAX_DRAW_BUFFERS))
+ .min(crate::MAX_COLOR_ATTACHMENTS as i32) as u32
+ };
+
+ // TODO: programmatically determine this.
+ let max_color_attachment_bytes_per_sample = 32;
+
let limits = wgt::Limits {
max_texture_dimension_1d: max_texture_size,
max_texture_dimension_2d: max_texture_size,
@@ -719,9 +731,21 @@ impl super::Adapter {
max_push_constant_size: super::MAX_PUSH_CONSTANTS as u32 * 4,
min_uniform_buffer_offset_alignment,
min_storage_buffer_offset_alignment,
- max_inter_stage_shader_components: unsafe {
- gl.get_parameter_i32(glow::MAX_VARYING_COMPONENTS)
- } as u32,
+ max_inter_stage_shader_components: {
+ // MAX_VARYING_COMPONENTS may return 0, because it is deprecated since OpenGL 3.2 core,
+ // and an OpenGL Context with the core profile and with forward-compatibility=true,
+ // will make deprecated constants unavailable.
+ let max_varying_components =
+ unsafe { gl.get_parameter_i32(glow::MAX_VARYING_COMPONENTS) } as u32;
+ if max_varying_components == 0 {
+ // default value for max_inter_stage_shader_components
+ 60
+ } else {
+ max_varying_components
+ }
+ },
+ max_color_attachments,
+ max_color_attachment_bytes_per_sample,
max_compute_workgroup_storage_size: if supports_work_group_params {
(unsafe { gl.get_parameter_i32(glow::MAX_COMPUTE_SHARED_MEMORY_SIZE) } as u32)
} else {
@@ -779,6 +803,7 @@ impl super::Adapter {
}
let downlevel_defaults = wgt::DownlevelLimits {};
+ let max_samples = unsafe { gl.get_parameter_i32(glow::MAX_SAMPLES) };
// Drop the GL guard so we can move the context into AdapterShared
// ( on Wasm the gl handle is just a ref so we tell clippy to allow
@@ -797,6 +822,7 @@ impl super::Adapter {
next_shader_id: Default::default(),
program_cache: Default::default(),
es: es_ver.is_some(),
+ max_msaa_samples: max_samples,
}),
},
info: Self::make_info(vendor, renderer),
@@ -825,7 +851,14 @@ impl super::Adapter {
let source = if es {
format!("#version 300 es\nprecision lowp float;\n{source}")
} else {
- format!("#version 130\n{source}")
+ let version = gl.version();
+ if version.major == 3 && version.minor == 0 {
+ // OpenGL 3.0 only supports this format
+ format!("#version 130\n{source}")
+ } else {
+ // OpenGL 3.1+ support this format
+ format!("#version 140\n{source}")
+ }
};
let shader = unsafe { gl.create_shader(shader_type) }.expect("Could not create shader");
unsafe { gl.shader_source(shader, &source) };
@@ -846,7 +879,7 @@ impl super::Adapter {
unsafe fn create_shader_clear_program(
gl: &glow::Context,
es: bool,
- ) -> Option<(glow::Program, glow::UniformLocation)> {
+ ) -> Option<ShaderClearProgram> {
let program = unsafe { gl.create_program() }.expect("Could not create shader program");
let vertex = unsafe {
Self::compile_shader(
@@ -882,7 +915,10 @@ impl super::Adapter {
unsafe { gl.delete_shader(vertex) };
unsafe { gl.delete_shader(fragment) };
- Some((program, color_uniform_location))
+ Some(ShaderClearProgram {
+ program,
+ color_uniform_location,
+ })
}
}
@@ -908,9 +944,18 @@ impl crate::Adapter<super::Api> for super::Adapter {
// Compile the shader program we use for doing manual clears to work around Mesa fastclear
// bug.
- let (shader_clear_program, shader_clear_program_color_uniform_location) = unsafe {
- Self::create_shader_clear_program(gl, self.shared.es)
- .ok_or(crate::DeviceError::ResourceCreationFailed)?
+ let shader_clear_program = if self
+ .shared
+ .workarounds
+ .contains(super::Workarounds::MESA_I915_SRGB_SHADER_CLEAR)
+ {
+ Some(unsafe {
+ Self::create_shader_clear_program(gl, self.shared.es)
+ .ok_or(crate::DeviceError::ResourceCreationFailed)?
+ })
+ } else {
+ // If we don't need the workaround, don't waste time and resources compiling the clear program
+ None
};
Ok(crate::OpenDevice {
@@ -928,7 +973,6 @@ impl crate::Adapter<super::Api> for super::Adapter {
copy_fbo: unsafe { gl.create_framebuffer() }
.map_err(|_| crate::DeviceError::OutOfMemory)?,
shader_clear_program,
- shader_clear_program_color_uniform_location,
zero_buffer,
temp_query_results: Mutex::new(Vec::new()),
draw_buffer_count: AtomicU8::new(1),
@@ -945,12 +989,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
use wgt::TextureFormat as Tf;
let sample_count = {
- let max_samples = unsafe {
- self.shared
- .context
- .lock()
- .get_parameter_i32(glow::MAX_SAMPLES)
- };
+ let max_samples = self.shared.max_msaa_samples;
if max_samples >= 16 {
Tfc::MULTISAMPLE_X2
| Tfc::MULTISAMPLE_X4
diff --git a/third_party/rust/wgpu-hal/src/gles/command.rs b/third_party/rust/wgpu-hal/src/gles/command.rs
index 926122e4ad..4385e2a31e 100644
--- a/third_party/rust/wgpu-hal/src/gles/command.rs
+++ b/third_party/rust/wgpu-hal/src/gles/command.rs
@@ -93,6 +93,13 @@ impl super::CommandBuffer {
}
}
+impl Drop for super::CommandEncoder {
+ fn drop(&mut self) {
+ use crate::CommandEncoder;
+ unsafe { self.discard_encoding() }
+ }
+}
+
impl super::CommandEncoder {
fn rebind_stencil_func(&mut self) {
fn make(s: &super::StencilSide, face: u32) -> C {
diff --git a/third_party/rust/wgpu-hal/src/gles/device.rs b/third_party/rust/wgpu-hal/src/gles/device.rs
index d0abe2c169..2678488cf8 100644
--- a/third_party/rust/wgpu-hal/src/gles/device.rs
+++ b/third_party/rust/wgpu-hal/src/gles/device.rs
@@ -1194,13 +1194,16 @@ impl crate::Device<super::Api> for super::Device {
let sampler = desc.samplers[entry.resource_index as usize];
super::RawBinding::Sampler(sampler.raw)
}
- wgt::BindingType::Texture { .. } => {
+ wgt::BindingType::Texture { view_dimension, .. } => {
let view = desc.textures[entry.resource_index as usize].view;
if view.array_layers.start != 0 {
log::error!("Unable to create a sampled texture binding for non-zero array layer.\n{}",
"This is an implementation problem of wgpu-hal/gles backend.")
}
let (raw, target) = view.inner.as_native();
+
+ super::Texture::log_failing_target_heuristics(view_dimension, target);
+
super::RawBinding::Texture {
raw,
target,
diff --git a/third_party/rust/wgpu-hal/src/gles/egl.rs b/third_party/rust/wgpu-hal/src/gles/egl.rs
index aa985d8121..f4bfcf5487 100644
--- a/third_party/rust/wgpu-hal/src/gles/egl.rs
+++ b/third_party/rust/wgpu-hal/src/gles/egl.rs
@@ -1,7 +1,8 @@
use glow::HasContext;
+use once_cell::sync::Lazy;
use parking_lot::{Mutex, MutexGuard, RwLock};
-use std::{ffi, os::raw, ptr, rc::Rc, sync::Arc, time::Duration};
+use std::{collections::HashMap, ffi, os::raw, ptr, rc::Rc, sync::Arc, time::Duration};
/// The amount of time to wait while trying to obtain a lock to the adapter context
const CONTEXT_LOCK_TIMEOUT_SECS: u64 = 1;
@@ -50,16 +51,6 @@ type WlEglWindowResizeFun = unsafe extern "system" fn(
type WlEglWindowDestroyFun = unsafe extern "system" fn(window: *const raw::c_void);
-#[cfg(target_os = "android")]
-extern "C" {
- pub fn ANativeWindow_setBuffersGeometry(
- window: *mut raw::c_void,
- width: i32,
- height: i32,
- format: i32,
- ) -> i32;
-}
-
type EglLabel = *const raw::c_void;
#[allow(clippy::upper_case_acronyms)]
@@ -161,7 +152,7 @@ impl Drop for DisplayOwner {
fn open_x_display() -> Option<DisplayOwner> {
log::debug!("Loading X11 library to get the current display");
unsafe {
- let library = libloading::Library::new("libX11.so").ok()?;
+ let library = find_library(&["libX11.so.6", "libX11.so"])?;
let func: libloading::Symbol<XOpenDisplayFun> = library.get(b"XOpenDisplay").unwrap();
let result = func(ptr::null());
ptr::NonNull::new(result).map(|ptr| DisplayOwner {
@@ -442,6 +433,45 @@ struct Inner {
srgb_kind: SrgbFrameBufferKind,
}
+// Different calls to `eglGetPlatformDisplay` may return the same `Display`, making it a global
+// state of all our `EglContext`s. This forces us to track the number of such context to prevent
+// terminating the display if it's currently used by another `EglContext`.
+static DISPLAYS_REFERENCE_COUNT: Lazy<Mutex<HashMap<usize, usize>>> = Lazy::new(Default::default);
+
+fn initialize_display(
+ egl: &EglInstance,
+ display: khronos_egl::Display,
+) -> Result<(i32, i32), khronos_egl::Error> {
+ let mut guard = DISPLAYS_REFERENCE_COUNT.lock();
+ *guard.entry(display.as_ptr() as usize).or_default() += 1;
+
+ // We don't need to check the reference count here since according to the `eglInitialize`
+ // documentation, initializing an already initialized EGL display connection has no effect
+ // besides returning the version numbers.
+ egl.initialize(display)
+}
+
+fn terminate_display(
+ egl: &EglInstance,
+ display: khronos_egl::Display,
+) -> Result<(), khronos_egl::Error> {
+ let key = &(display.as_ptr() as usize);
+ let mut guard = DISPLAYS_REFERENCE_COUNT.lock();
+ let count_ref = guard
+ .get_mut(key)
+ .expect("Attempted to decref a display before incref was called");
+
+ if *count_ref > 1 {
+ *count_ref -= 1;
+
+ Ok(())
+ } else {
+ guard.remove(key);
+
+ egl.terminate(display)
+ }
+}
+
impl Inner {
fn create(
flags: wgt::InstanceFlags,
@@ -449,7 +479,7 @@ impl Inner {
display: khronos_egl::Display,
force_gles_minor_version: wgt::Gles3MinorVersion,
) -> Result<Self, crate::InstanceError> {
- let version = egl.initialize(display).map_err(|e| {
+ let version = initialize_display(&egl, display).map_err(|e| {
crate::InstanceError::with_source(
String::from("failed to initialize EGL display connection"),
e,
@@ -618,7 +648,8 @@ impl Drop for Inner {
{
log::warn!("Error in destroy_context: {:?}", e);
}
- if let Err(e) = self.egl.instance.terminate(self.egl.display) {
+
+ if let Err(e) = terminate_display(&self.egl.instance, self.egl.display) {
log::warn!("Error in terminate: {:?}", e);
}
}
@@ -783,11 +814,12 @@ impl crate::Instance<super::Api> for Instance {
(display, Some(Rc::new(display_owner)), WindowKind::AngleX11)
} else if client_ext_str.contains("EGL_MESA_platform_surfaceless") {
log::warn!("No windowing system present. Using surfaceless platform");
+ #[allow(clippy::unnecessary_literal_unwrap)] // This is only a literal on Emscripten
let egl = egl1_5.expect("Failed to get EGL 1.5 for surfaceless");
let display = unsafe {
egl.get_platform_display(
EGL_PLATFORM_SURFACELESS_MESA,
- std::ptr::null_mut(),
+ khronos_egl::DEFAULT_DISPLAY,
&[khronos_egl::ATTRIB_NONE],
)
}
@@ -863,7 +895,12 @@ impl crate::Instance<super::Api> for Instance {
.unwrap();
let ret = unsafe {
- ANativeWindow_setBuffersGeometry(handle.a_native_window.as_ptr(), 0, 0, format)
+ ndk_sys::ANativeWindow_setBuffersGeometry(
+ handle.a_native_window.as_ptr() as *mut ndk_sys::ANativeWindow,
+ 0,
+ 0,
+ format,
+ )
};
if ret != 0 {
diff --git a/third_party/rust/wgpu-hal/src/gles/mod.rs b/third_party/rust/wgpu-hal/src/gles/mod.rs
index 646419c7fe..6f41f7c000 100644
--- a/third_party/rust/wgpu-hal/src/gles/mod.rs
+++ b/third_party/rust/wgpu-hal/src/gles/mod.rs
@@ -251,6 +251,11 @@ struct AdapterShared {
next_shader_id: AtomicU32,
program_cache: Mutex<ProgramCache>,
es: bool,
+
+ /// Result of `gl.get_parameter_i32(glow::MAX_SAMPLES)`.
+ /// Cached here so it doesn't need to be queried every time texture format capabilities are requested.
+ /// (this has been shown to be a significant enough overhead)
+ max_msaa_samples: i32,
}
pub struct Adapter {
@@ -264,6 +269,11 @@ pub struct Device {
render_doc: crate::auxil::renderdoc::RenderDoc,
}
+pub struct ShaderClearProgram {
+ pub program: glow::Program,
+ pub color_uniform_location: glow::UniformLocation,
+}
+
pub struct Queue {
shared: Arc<AdapterShared>,
features: wgt::Features,
@@ -271,9 +281,7 @@ pub struct Queue {
copy_fbo: glow::Framebuffer,
/// Shader program used to clear the screen for [`Workarounds::MESA_I915_SRGB_SHADER_CLEAR`]
/// devices.
- shader_clear_program: glow::Program,
- /// The uniform location of the color uniform in the shader clear program
- shader_clear_program_color_uniform_location: glow::UniformLocation,
+ shader_clear_program: Option<ShaderClearProgram>,
/// Keep a reasonably large buffer filled with zeroes, so that we can implement `ClearBuffer` of
/// zeroes by copying from it.
zero_buffer: glow::Buffer,
@@ -366,6 +374,8 @@ impl Texture {
/// Returns the `target`, whether the image is 3d and whether the image is a cubemap.
fn get_info_from_desc(desc: &TextureDescriptor) -> u32 {
match desc.dimension {
+ // WebGL (1 and 2) as well as some GLES versions do not have 1D textures, so we are
+ // doing `TEXTURE_2D` instead
wgt::TextureDimension::D1 => glow::TEXTURE_2D,
wgt::TextureDimension::D2 => {
// HACK: detect a cube map; forces cube compatible textures to be cube textures
@@ -379,6 +389,43 @@ impl Texture {
wgt::TextureDimension::D3 => glow::TEXTURE_3D,
}
}
+
+ /// More information can be found in issues #1614 and #1574
+ fn log_failing_target_heuristics(view_dimension: wgt::TextureViewDimension, target: u32) {
+ let expected_target = match view_dimension {
+ wgt::TextureViewDimension::D1 => glow::TEXTURE_2D,
+ wgt::TextureViewDimension::D2 => glow::TEXTURE_2D,
+ wgt::TextureViewDimension::D2Array => glow::TEXTURE_2D_ARRAY,
+ wgt::TextureViewDimension::Cube => glow::TEXTURE_CUBE_MAP,
+ wgt::TextureViewDimension::CubeArray => glow::TEXTURE_CUBE_MAP_ARRAY,
+ wgt::TextureViewDimension::D3 => glow::TEXTURE_3D,
+ };
+
+ if expected_target == target {
+ return;
+ }
+
+ let buffer;
+ let got = match target {
+ glow::TEXTURE_2D => "D2",
+ glow::TEXTURE_2D_ARRAY => "D2Array",
+ glow::TEXTURE_CUBE_MAP => "Cube",
+ glow::TEXTURE_CUBE_MAP_ARRAY => "CubeArray",
+ glow::TEXTURE_3D => "D3",
+ target => {
+ buffer = target.to_string();
+ &buffer
+ }
+ };
+
+ log::error!(
+ "wgpu-hal heuristics assumed that the view dimension will be equal to `{got}` rather than `{view_dimension:?}`.\n{}\n{}\n{}\n{}",
+ "`D2` textures with `depth_or_array_layers == 1` are assumed to have view dimension `D2`",
+ "`D2` textures with `depth_or_array_layers > 1` are assumed to have view dimension `D2Array`",
+ "`D2` textures with `depth_or_array_layers == 6` are assumed to have view dimension `Cube`",
+ "`D2` textures with `depth_or_array_layers > 6 && depth_or_array_layers % 6 == 0` are assumed to have view dimension `CubeArray`",
+ );
+ }
}
#[derive(Clone, Debug)]
diff --git a/third_party/rust/wgpu-hal/src/gles/queue.rs b/third_party/rust/wgpu-hal/src/gles/queue.rs
index 6ec553bd29..5db5af9a16 100644
--- a/third_party/rust/wgpu-hal/src/gles/queue.rs
+++ b/third_party/rust/wgpu-hal/src/gles/queue.rs
@@ -40,10 +40,14 @@ fn get_z_offset(target: u32, base: &crate::TextureCopyBase) -> u32 {
impl super::Queue {
/// Performs a manual shader clear, used as a workaround for a clearing bug on mesa
unsafe fn perform_shader_clear(&self, gl: &glow::Context, draw_buffer: u32, color: [f32; 4]) {
- unsafe { gl.use_program(Some(self.shader_clear_program)) };
+ let shader_clear = self
+ .shader_clear_program
+ .as_ref()
+ .expect("shader_clear_program should always be set if the workaround is enabled");
+ unsafe { gl.use_program(Some(shader_clear.program)) };
unsafe {
gl.uniform_4_f32(
- Some(&self.shader_clear_program_color_uniform_location),
+ Some(&shader_clear.color_uniform_location),
color[0],
color[1],
color[2],
diff --git a/third_party/rust/wgpu-hal/src/gles/wgl.rs b/third_party/rust/wgpu-hal/src/gles/wgl.rs
index 6243430dc2..c9039090b7 100644
--- a/third_party/rust/wgpu-hal/src/gles/wgl.rs
+++ b/third_party/rust/wgpu-hal/src/gles/wgl.rs
@@ -160,6 +160,9 @@ struct Inner {
context: WglContext,
}
+unsafe impl Send for Inner {}
+unsafe impl Sync for Inner {}
+
pub struct Instance {
srgb_capable: bool,
inner: Arc<Mutex<Inner>>,