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 <me@dusterthefirst.com>
This commit is contained in:
parent
41b178b6ec
commit
6f10e2e725
7 changed files with 288 additions and 278 deletions
|
@ -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",
|
||||
_ => "<unknown>",
|
||||
};
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Item = &'a glow::Shader>>(
|
|||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Painter, String> {
|
||||
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::<Vertex>() 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<glow::Context>,
|
||||
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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
185
egui_glow/src/vao.rs
Normal file
185
egui_glow/src/vao.rs
Normal file
|
@ -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<glow::Buffer>,
|
||||
buffer_infos: Vec<BufferInfo>,
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<glow::Buffer>,
|
||||
buffer_infos: Vec<BufferInfo>,
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue