From 6f10e2e7255d60e8948a1617e91a15fb309347a2 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 22 Mar 2022 16:04:06 +0100 Subject: [PATCH] Improve glow error reporting (#1403) * Improve glow error reporting * Add more check_for_gl_error calls * Remove clippy lint list from egui_glow lib.rs - Forgotten in https://github.com/emilk/egui/pull/1394 * egui_glow: move vao code to own file * Cleanup: `use glow::HasContext as _;` Co-authored-by: Zachary Kohnen --- egui_glow/src/lib.rs | 140 +++++++++++------------- egui_glow/src/misc_util.rs | 116 +------------------- egui_glow/src/painter.rs | 45 +++++--- egui_glow/src/post_process.rs | 21 ++-- egui_glow/src/shader_version.rs | 2 +- egui_glow/src/vao.rs | 185 ++++++++++++++++++++++++++++++++ egui_glow/src/vao_emulate.rs | 57 ---------- 7 files changed, 288 insertions(+), 278 deletions(-) create mode 100644 egui_glow/src/vao.rs delete mode 100644 egui_glow/src/vao_emulate.rs diff --git a/egui_glow/src/lib.rs b/egui_glow/src/lib.rs index 227b65276ce..29a6cf2bf2d 100644 --- a/egui_glow/src/lib.rs +++ b/egui_glow/src/lib.rs @@ -5,85 +5,6 @@ //! This library is an [`epi`] backend. //! If you are writing an app, you may want to look at [`eframe`](https://docs.rs/eframe) instead. -// Forbid warnings in release builds: -#![cfg_attr(not(debug_assertions), deny(warnings))] -#![deny(unsafe_code)] -#![warn( - clippy::all, - clippy::await_holding_lock, - clippy::char_lit_as_u8, - clippy::checked_conversions, - clippy::dbg_macro, - clippy::debug_assert_with_mut_call, - clippy::disallowed_method, - clippy::doc_markdown, - clippy::empty_enum, - clippy::enum_glob_use, - clippy::exit, - clippy::expl_impl_clone_on_copy, - clippy::explicit_deref_methods, - clippy::explicit_into_iter_loop, - clippy::fallible_impl_from, - clippy::filter_map_next, - clippy::flat_map_option, - clippy::float_cmp_const, - clippy::fn_params_excessive_bools, - clippy::from_iter_instead_of_collect, - clippy::if_let_mutex, - clippy::implicit_clone, - clippy::imprecise_flops, - clippy::inefficient_to_string, - clippy::invalid_upcast_comparisons, - clippy::large_digit_groups, - clippy::large_stack_arrays, - clippy::large_types_passed_by_value, - clippy::let_unit_value, - clippy::linkedlist, - clippy::lossy_float_literal, - clippy::macro_use_imports, - clippy::manual_ok_or, - clippy::map_err_ignore, - clippy::map_flatten, - clippy::map_unwrap_or, - clippy::match_on_vec_items, - clippy::match_same_arms, - clippy::match_wild_err_arm, - clippy::match_wildcard_for_single_variants, - clippy::mem_forget, - clippy::mismatched_target_os, - clippy::missing_errors_doc, - clippy::missing_safety_doc, - clippy::mut_mut, - clippy::mutex_integer, - clippy::needless_borrow, - clippy::needless_continue, - clippy::needless_for_each, - clippy::needless_pass_by_value, - clippy::option_option, - clippy::path_buf_push_overwrite, - clippy::ptr_as_ptr, - clippy::ref_option_ref, - clippy::rest_pat_in_fully_bound_structs, - clippy::same_functions_in_if_condition, - clippy::semicolon_if_nothing_returned, - clippy::single_match_else, - clippy::string_add_assign, - clippy::string_add, - clippy::string_lit_as_bytes, - clippy::string_to_string, - clippy::todo, - clippy::trait_duplication_in_bounds, - clippy::unimplemented, - clippy::unnested_or_patterns, - clippy::unused_self, - clippy::useless_transmute, - clippy::verbose_file_reads, - clippy::zero_sized_map_values, - future_incompatible, - nonstandard_style, - rust_2018_idioms, - rustdoc::missing_crate_level_docs -)] #![allow(clippy::float_cmp)] #![allow(clippy::manual_range_contains)] @@ -93,7 +14,7 @@ pub use painter::Painter; mod misc_util; mod post_process; mod shader_version; -mod vao_emulate; +mod vao; #[cfg(all(not(target_arch = "wasm32"), feature = "winit"))] pub mod winit; @@ -105,3 +26,62 @@ mod epi_backend; #[cfg(all(not(target_arch = "wasm32"), feature = "winit"))] pub use epi_backend::{run, NativeOptions}; + +/// Check for OpenGL error and report it using `tracing::error`. +/// +/// ``` no_run +/// # let glow_context = todo!(); +/// use egui_glow::check_for_gl_error; +/// check_for_gl_error!(glow_context); +/// check_for_gl_error!(glow_context, "during painting"); +/// ``` +#[macro_export] +macro_rules! check_for_gl_error { + ($gl: expr) => {{ + $crate::check_for_gl_error_impl($gl, file!(), line!(), "") + }}; + ($gl: expr, $context: literal) => {{ + $crate::check_for_gl_error_impl($gl, file!(), line!(), $context) + }}; +} + +#[doc(hidden)] +pub fn check_for_gl_error_impl(gl: &glow::Context, file: &str, line: u32, context: &str) { + use glow::HasContext as _; + #[allow(unsafe_code)] + let error_code = unsafe { gl.get_error() }; + if error_code != glow::NO_ERROR { + let error_str = match error_code { + glow::INVALID_ENUM => "GL_INVALID_ENUM", + glow::INVALID_VALUE => "GL_INVALID_VALUE", + glow::INVALID_OPERATION => "GL_INVALID_OPERATION", + glow::STACK_OVERFLOW => "GL_STACK_OVERFLOW", + glow::STACK_UNDERFLOW => "GL_STACK_UNDERFLOW", + glow::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY", + glow::INVALID_FRAMEBUFFER_OPERATION => "GL_INVALID_FRAMEBUFFER_OPERATION", + glow::CONTEXT_LOST => "GL_CONTEXT_LOST", + 0x8031 => "GL_TABLE_TOO_LARGE1", + 0x9242 => "CONTEXT_LOST_WEBGL", + _ => "", + }; + + if context.is_empty() { + tracing::error!( + "GL error, at {}:{}: {} (0x{:X}). Please file a bug at https://github.com/emilk/egui/issues", + file, + line, + error_str, + error_code, + ); + } else { + tracing::error!( + "GL error, at {}:{} ({}): {} (0x{:X}). Please file a bug at https://github.com/emilk/egui/issues", + file, + line, + context, + error_str, + error_code, + ); + } + } +} diff --git a/egui_glow/src/misc_util.rs b/egui_glow/src/misc_util.rs index 4547c26187e..ee22f58bd8d 100644 --- a/egui_glow/src/misc_util.rs +++ b/egui_glow/src/misc_util.rs @@ -1,18 +1,6 @@ #![allow(unsafe_code)] -use glow::HasContext; -use std::option::Option::Some; -pub fn check_for_gl_error(gl: &glow::Context, context: &str) { - let error_code = unsafe { gl.get_error() }; - if error_code != glow::NO_ERROR { - tracing::error!( - "GL error, at: '{}', code: {} (0x{:X})", - context, - error_code, - error_code - ); - } -} +use glow::HasContext as _; pub(crate) unsafe fn compile_shader( gl: &glow::Context, @@ -50,105 +38,3 @@ pub(crate) unsafe fn link_program<'a, T: IntoIterator>( Err(gl.get_program_info_log(program)) } } -///Wrapper around Emulated VAO and GL's VAO -pub(crate) enum VAO { - Emulated(crate::vao_emulate::EmulatedVao), - Native(crate::glow::VertexArray), -} - -impl VAO { - pub(crate) unsafe fn native(gl: &glow::Context) -> Self { - Self::Native(gl.create_vertex_array().unwrap()) - } - - pub(crate) unsafe fn emulated() -> Self { - Self::Emulated(crate::vao_emulate::EmulatedVao::new()) - } - - pub(crate) unsafe fn bind_vertex_array(&self, gl: &glow::Context) { - match self { - VAO::Emulated(vao) => vao.bind_vertex_array(gl), - VAO::Native(vao) => gl.bind_vertex_array(Some(*vao)), - } - } - - pub(crate) unsafe fn bind_buffer(&mut self, gl: &glow::Context, buffer: &glow::Buffer) { - match self { - VAO::Emulated(vao) => vao.bind_buffer(buffer), - VAO::Native(_) => gl.bind_buffer(glow::ARRAY_BUFFER, Some(*buffer)), - } - } - - pub(crate) unsafe fn add_new_attribute( - &mut self, - gl: &glow::Context, - buffer_info: crate::vao_emulate::BufferInfo, - ) { - match self { - VAO::Emulated(vao) => vao.add_new_attribute(buffer_info), - VAO::Native(_) => { - gl.vertex_attrib_pointer_f32( - buffer_info.location, - buffer_info.vector_size, - buffer_info.data_type, - buffer_info.normalized, - buffer_info.stride, - buffer_info.offset, - ); - gl.enable_vertex_attrib_array(buffer_info.location); - } - } - } - - pub(crate) unsafe fn unbind_vertex_array(&self, gl: &glow::Context) { - match self { - VAO::Emulated(vao) => vao.unbind_vertex_array(gl), - VAO::Native(_) => { - gl.bind_vertex_array(None); - } - } - } -} - -/// If returned true no need to emulate vao -pub(crate) fn supports_vao(gl: &glow::Context) -> bool { - const WEBGL_PREFIX: &str = "WebGL "; - const OPENGL_ES_PREFIX: &str = "OpenGL ES "; - - let version_string = unsafe { gl.get_parameter_string(glow::VERSION) }; - tracing::debug!("GL version: {:?}.", version_string); - - // Examples: - // * "WebGL 2.0 (OpenGL ES 3.0 Chromium)" - // * "WebGL 2.0" - - if let Some(pos) = version_string.rfind(WEBGL_PREFIX) { - let version_str = &version_string[pos + WEBGL_PREFIX.len()..]; - if version_str.contains("1.0") { - // need to test OES_vertex_array_object . - gl.supported_extensions() - .contains("OES_vertex_array_object") - } else { - true - } - } else if version_string.contains(OPENGL_ES_PREFIX) { - // glow targets es2.0+ so we don't concern about OpenGL ES-CM,OpenGL ES-CL - if version_string.contains("2.0") { - // need to test OES_vertex_array_object . - gl.supported_extensions() - .contains("OES_vertex_array_object") - } else { - true - } - } else { - // from OpenGL 3 vao into core - if version_string.starts_with('2') { - // I found APPLE_vertex_array_object , GL_ATI_vertex_array_object ,ARB_vertex_array_object - // but APPLE's and ATI's very old extension. - gl.supported_extensions() - .contains("ARB_vertex_array_object") - } else { - true - } - } -} diff --git a/egui_glow/src/painter.rs b/egui_glow/src/painter.rs index 804bc19ed66..69d5123df52 100644 --- a/egui_glow/src/painter.rs +++ b/egui_glow/src/painter.rs @@ -6,13 +6,14 @@ use egui::{ emath::Rect, epaint::{Color32, Mesh, Primitive, Vertex}, }; -use glow::HasContext; +use glow::HasContext as _; use memoffset::offset_of; -use crate::misc_util::{check_for_gl_error, compile_shader, link_program}; +use crate::check_for_gl_error; +use crate::misc_util::{compile_shader, link_program}; use crate::post_process::PostProcess; use crate::shader_version::ShaderVersion; -use crate::vao_emulate; +use crate::vao; pub use glow::Context; @@ -36,7 +37,7 @@ pub struct Painter { u_sampler: glow::UniformLocation, is_webgl_1: bool, is_embedded: bool, - vertex_array: crate::misc_util::VAO, + vertex_array: crate::vao::VAO, srgb_support: bool, /// The filter used for subsequent textures. texture_filter: TextureFilter, @@ -95,11 +96,15 @@ impl Painter { pp_fb_extent: Option<[i32; 2]>, shader_prefix: &str, ) -> Result { - check_for_gl_error(&gl, "before Painter::new"); + check_for_gl_error!(&gl, "before Painter::new"); let max_texture_side = unsafe { gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) } as usize; - let support_vao = crate::misc_util::supports_vao(&gl); + let support_vao = crate::vao::supports_vao(&gl); + if !support_vao { + tracing::debug!("VAO not supported"); + } + let shader_version = ShaderVersion::get(&gl); let is_webgl_1 = shader_version == ShaderVersion::Es100; let header = shader_version.version(); @@ -175,14 +180,14 @@ impl Painter { let a_tc_loc = gl.get_attrib_location(program, "a_tc").unwrap(); let a_srgba_loc = gl.get_attrib_location(program, "a_srgba").unwrap(); let mut vertex_array = if support_vao { - crate::misc_util::VAO::native(&gl) + crate::vao::VAO::native(&gl) } else { - crate::misc_util::VAO::emulated() + crate::vao::VAO::emulated() }; vertex_array.bind_vertex_array(&gl); vertex_array.bind_buffer(&gl, &vertex_buffer); let stride = std::mem::size_of::() as i32; - let position_buffer_info = vao_emulate::BufferInfo { + let position_buffer_info = vao::BufferInfo { location: a_pos_loc, vector_size: 2, data_type: glow::FLOAT, @@ -190,7 +195,7 @@ impl Painter { stride, offset: offset_of!(Vertex, pos) as i32, }; - let tex_coord_buffer_info = vao_emulate::BufferInfo { + let tex_coord_buffer_info = vao::BufferInfo { location: a_tc_loc, vector_size: 2, data_type: glow::FLOAT, @@ -198,7 +203,7 @@ impl Painter { stride, offset: offset_of!(Vertex, uv) as i32, }; - let color_buffer_info = vao_emulate::BufferInfo { + let color_buffer_info = vao::BufferInfo { location: a_srgba_loc, vector_size: 4, data_type: glow::UNSIGNED_BYTE, @@ -209,7 +214,7 @@ impl Painter { vertex_array.add_new_attribute(&gl, position_buffer_info); vertex_array.add_new_attribute(&gl, tex_coord_buffer_info); vertex_array.add_new_attribute(&gl, color_buffer_info); - check_for_gl_error(&gl, "after Painter::new"); + check_for_gl_error!(&gl, "after Painter::new"); Ok(Painter { gl, @@ -266,7 +271,7 @@ impl Painter { if !cfg!(target_arch = "wasm32") { self.gl.enable(glow::FRAMEBUFFER_SRGB); - check_for_gl_error(&self.gl, "FRAMEBUFFER_SRGB"); + check_for_gl_error!(&self.gl, "FRAMEBUFFER_SRGB"); } let width_in_points = width_in_pixels as f32 / pixels_per_point; @@ -285,6 +290,8 @@ impl Painter { self.gl .bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.element_array_buffer)); + check_for_gl_error!(&self.gl, "prepare_painting"); + (width_in_pixels, height_in_pixels) } @@ -375,6 +382,8 @@ impl Painter { callback.call(self); + check_for_gl_error!(&self.gl, "callback"); + // Restore state: unsafe { if let Some(ref mut post_process) = self.post_process { @@ -396,7 +405,7 @@ impl Painter { self.gl.disable(glow::SCISSOR_TEST); - check_for_gl_error(&self.gl, "painting"); + check_for_gl_error!(&self.gl, "painting"); } } @@ -432,6 +441,8 @@ impl Painter { 0, ); } + + check_for_gl_error!(&self.gl, "paint_mesh"); } } @@ -526,7 +537,7 @@ impl Painter { glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32, ); - check_for_gl_error(&self.gl, "tex_parameter"); + check_for_gl_error!(&self.gl, "tex_parameter"); let (internal_format, src_format) = if self.is_webgl_1 { let format = if self.srgb_support { @@ -554,7 +565,7 @@ impl Painter { glow::UNSIGNED_BYTE, glow::PixelUnpackData::Slice(data), ); - check_for_gl_error(&self.gl, "tex_sub_image_2d"); + check_for_gl_error!(&self.gl, "tex_sub_image_2d"); } else { let border = 0; self.gl.tex_image_2d( @@ -568,7 +579,7 @@ impl Painter { glow::UNSIGNED_BYTE, Some(data), ); - check_for_gl_error(&self.gl, "tex_image_2d"); + check_for_gl_error!(&self.gl, "tex_image_2d"); } } } diff --git a/egui_glow/src/post_process.rs b/egui_glow/src/post_process.rs index 0706b2a609d..97b2e0c979a 100644 --- a/egui_glow/src/post_process.rs +++ b/egui_glow/src/post_process.rs @@ -1,7 +1,8 @@ #![allow(unsafe_code)] -use crate::misc_util::{check_for_gl_error, compile_shader, link_program}; -use crate::vao_emulate::BufferInfo; -use glow::HasContext; +use crate::check_for_gl_error; +use crate::misc_util::{compile_shader, link_program}; +use crate::vao::BufferInfo; +use glow::HasContext as _; /// Uses a framebuffer to render everything in linear color space and convert it back to `sRGB` /// in a separate "post processing" step @@ -9,7 +10,7 @@ pub(crate) struct PostProcess { gl: std::rc::Rc, pos_buffer: glow::Buffer, index_buffer: glow::Buffer, - vertex_array: crate::misc_util::VAO, + vertex_array: crate::vao::VAO, is_webgl_1: bool, texture: glow::Texture, texture_size: (i32, i32), @@ -77,7 +78,7 @@ impl PostProcess { glow::UNSIGNED_BYTE, None, ); - check_for_gl_error(&gl, "post process texture initialization"); + check_for_gl_error!(&gl, "post process texture initialization"); gl.framebuffer_texture_2d( glow::FRAMEBUFFER, @@ -125,9 +126,9 @@ impl PostProcess { .get_attrib_location(program, "a_pos") .ok_or_else(|| "failed to get location of a_pos".to_string())?; let mut vertex_array = if need_to_emulate_vao { - crate::misc_util::VAO::emulated() + crate::vao::VAO::emulated() } else { - crate::misc_util::VAO::native(&gl) + crate::vao::VAO::native(&gl) }; vertex_array.bind_vertex_array(&gl); vertex_array.bind_buffer(&gl, &pos_buffer); @@ -146,7 +147,7 @@ impl PostProcess { gl.buffer_data_u8_slice(glow::ELEMENT_ARRAY_BUFFER, &indices, glow::STATIC_DRAW); gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None); - check_for_gl_error(&gl, "post process initialization"); + check_for_gl_error!(&gl, "post process initialization"); Ok(PostProcess { gl, @@ -190,6 +191,8 @@ impl PostProcess { self.gl.bind_framebuffer(glow::FRAMEBUFFER, Some(self.fbo)); self.gl.clear_color(0.0, 0.0, 0.0, 0.0); self.gl.clear(glow::COLOR_BUFFER_BIT); + + check_for_gl_error!(&self.gl, "PostProcess::begin"); } pub(crate) unsafe fn bind(&self) { @@ -219,6 +222,8 @@ impl PostProcess { self.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None); self.gl.bind_texture(glow::TEXTURE_2D, None); self.gl.use_program(None); + + check_for_gl_error!(&self.gl, "PostProcess::end"); } pub(crate) unsafe fn destroy(&self) { diff --git a/egui_glow/src/shader_version.rs b/egui_glow/src/shader_version.rs index ae4af65ed86..84c2434f21e 100644 --- a/egui_glow/src/shader_version.rs +++ b/egui_glow/src/shader_version.rs @@ -1,6 +1,5 @@ #![allow(unsafe_code)] -use glow::HasContext; use std::convert::TryInto; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -14,6 +13,7 @@ pub(crate) enum ShaderVersion { impl ShaderVersion { pub(crate) fn get(gl: &glow::Context) -> Self { + use glow::HasContext as _; let shading_lang_string = unsafe { gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION) }; let shader_version = Self::parse(&shading_lang_string); diff --git a/egui_glow/src/vao.rs b/egui_glow/src/vao.rs new file mode 100644 index 00000000000..d3a5d8968ff --- /dev/null +++ b/egui_glow/src/vao.rs @@ -0,0 +1,185 @@ +#![allow(unsafe_code)] + +use glow::HasContext as _; + +use crate::check_for_gl_error; + +// ---------------------------------------------------------------------------- + +#[derive(Debug)] +pub(crate) struct BufferInfo { + pub location: u32, // + pub vector_size: i32, + pub data_type: u32, //GL_FLOAT,GL_UNSIGNED_BYTE + pub normalized: bool, + pub stride: i32, + pub offset: i32, +} + +// ---------------------------------------------------------------------------- + +pub struct EmulatedVao { + buffer: Option, + buffer_infos: Vec, +} + +impl EmulatedVao { + pub(crate) fn new() -> Self { + Self { + buffer: None, + buffer_infos: vec![], + } + } + + pub(crate) fn bind_buffer(&mut self, buffer: &glow::Buffer) { + let _old = self.buffer.replace(*buffer); + } + + pub(crate) fn add_new_attribute(&mut self, buffer_info: BufferInfo) { + self.buffer_infos.push(buffer_info); + } + + pub(crate) fn bind_vertex_array(&self, gl: &glow::Context) { + unsafe { + gl.bind_buffer(glow::ARRAY_BUFFER, self.buffer); + check_for_gl_error!(gl, "bind_buffer"); + } + for attribute in &self.buffer_infos { + dbg!(attribute); + unsafe { + gl.vertex_attrib_pointer_f32( + attribute.location, + attribute.vector_size, + attribute.data_type, + attribute.normalized, + attribute.stride, + attribute.offset, + ); + check_for_gl_error!(gl, "vertex_attrib_pointer_f32"); + gl.enable_vertex_attrib_array(attribute.location); + check_for_gl_error!(gl, "enable_vertex_attrib_array"); + } + } + } + + pub(crate) fn unbind_vertex_array(&self, gl: &glow::Context) { + for attribute in &self.buffer_infos { + unsafe { + gl.disable_vertex_attrib_array(attribute.location); + } + } + unsafe { + gl.bind_buffer(glow::ARRAY_BUFFER, None); + } + } +} + +// ---------------------------------------------------------------------------- + +/// Wrapper around either Emulated VAO and GL's VAO +pub(crate) enum VAO { + Emulated(crate::vao::EmulatedVao), + Native(crate::glow::VertexArray), +} + +impl VAO { + pub(crate) unsafe fn native(gl: &glow::Context) -> Self { + Self::Native(gl.create_vertex_array().unwrap()) + } + + pub(crate) unsafe fn emulated() -> Self { + Self::Emulated(crate::vao::EmulatedVao::new()) + } + + pub(crate) unsafe fn bind_vertex_array(&self, gl: &glow::Context) { + match self { + VAO::Emulated(emulated_vao) => emulated_vao.bind_vertex_array(gl), + VAO::Native(vao) => { + gl.bind_vertex_array(Some(*vao)); + check_for_gl_error!(gl, "bind_vertex_array"); + } + } + } + + pub(crate) unsafe fn bind_buffer(&mut self, gl: &glow::Context, buffer: &glow::Buffer) { + match self { + VAO::Emulated(emulated_vao) => emulated_vao.bind_buffer(buffer), + VAO::Native(_) => gl.bind_buffer(glow::ARRAY_BUFFER, Some(*buffer)), + } + } + + pub(crate) unsafe fn add_new_attribute( + &mut self, + gl: &glow::Context, + buffer_info: crate::vao::BufferInfo, + ) { + match self { + VAO::Emulated(emulated_vao) => emulated_vao.add_new_attribute(buffer_info), + VAO::Native(_) => { + gl.vertex_attrib_pointer_f32( + buffer_info.location, + buffer_info.vector_size, + buffer_info.data_type, + buffer_info.normalized, + buffer_info.stride, + buffer_info.offset, + ); + gl.enable_vertex_attrib_array(buffer_info.location); + } + } + } + + pub(crate) unsafe fn unbind_vertex_array(&self, gl: &glow::Context) { + match self { + VAO::Emulated(emulated_vao) => emulated_vao.unbind_vertex_array(gl), + VAO::Native(_) => { + gl.bind_vertex_array(None); + } + } + } +} + +// ---------------------------------------------------------------------------- + +/// If returned true no need to emulate vao +pub(crate) fn supports_vao(gl: &glow::Context) -> bool { + const WEBGL_PREFIX: &str = "WebGL "; + const OPENGL_ES_PREFIX: &str = "OpenGL ES "; + + let version_string = unsafe { gl.get_parameter_string(glow::VERSION) }; + tracing::debug!("GL version: {:?}.", version_string); + + // Examples: + // * "WebGL 2.0 (OpenGL ES 3.0 Chromium)" + // * "WebGL 2.0" + + if let Some(pos) = version_string.rfind(WEBGL_PREFIX) { + let version_str = &version_string[pos + WEBGL_PREFIX.len()..]; + if version_str.contains("1.0") { + // need to test OES_vertex_array_object . + gl.supported_extensions() + .contains("OES_vertex_array_object") + } else { + true + } + } else if version_string.contains(OPENGL_ES_PREFIX) { + // glow targets es2.0+ so we don't concern about OpenGL ES-CM,OpenGL ES-CL + if version_string.contains("2.0") { + // need to test OES_vertex_array_object . + gl.supported_extensions() + .contains("OES_vertex_array_object") + } else { + true + } + } else { + // from OpenGL 3 vao into core + if version_string.starts_with('2') { + // I found APPLE_vertex_array_object , GL_ATI_vertex_array_object ,ARB_vertex_array_object + // but APPLE's and ATI's very old extension. + gl.supported_extensions() + .contains("ARB_vertex_array_object") + } else { + true + } + } +} diff --git a/egui_glow/src/vao_emulate.rs b/egui_glow/src/vao_emulate.rs deleted file mode 100644 index 590134945e5..00000000000 --- a/egui_glow/src/vao_emulate.rs +++ /dev/null @@ -1,57 +0,0 @@ -#![allow(unsafe_code)] -use glow::HasContext; - -pub(crate) struct BufferInfo { - pub location: u32, // - pub vector_size: i32, - pub data_type: u32, //GL_FLOAT,GL_UNSIGNED_BYTE - pub normalized: bool, - pub stride: i32, - pub offset: i32, -} -pub struct EmulatedVao { - buffer: Option, - buffer_infos: Vec, -} -impl EmulatedVao { - pub(crate) fn new() -> Self { - Self { - buffer: None, - buffer_infos: vec![], - } - } - pub(crate) fn bind_buffer(&mut self, buffer: &glow::Buffer) { - let _old = self.buffer.replace(*buffer); - } - pub(crate) fn add_new_attribute(&mut self, buffer_info: BufferInfo) { - self.buffer_infos.push(buffer_info); - } - pub(crate) fn bind_vertex_array(&self, gl: &glow::Context) { - unsafe { - gl.bind_buffer(glow::ARRAY_BUFFER, self.buffer); - } - for attribute in self.buffer_infos.iter() { - unsafe { - gl.vertex_attrib_pointer_f32( - attribute.location, - attribute.vector_size, - attribute.data_type, - attribute.normalized, - attribute.stride, - attribute.offset, - ); - gl.enable_vertex_attrib_array(attribute.location); - } - } - } - pub(crate) fn unbind_vertex_array(&self, gl: &glow::Context) { - for attribute in self.buffer_infos.iter() { - unsafe { - gl.disable_vertex_attrib_array(attribute.location); - } - } - unsafe { - gl.bind_buffer(glow::ARRAY_BUFFER, None); - } - } -}