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.
|
//! This library is an [`epi`] backend.
|
||||||
//! If you are writing an app, you may want to look at [`eframe`](https://docs.rs/eframe) instead.
|
//! 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::float_cmp)]
|
||||||
#![allow(clippy::manual_range_contains)]
|
#![allow(clippy::manual_range_contains)]
|
||||||
|
|
||||||
|
@ -93,7 +14,7 @@ pub use painter::Painter;
|
||||||
mod misc_util;
|
mod misc_util;
|
||||||
mod post_process;
|
mod post_process;
|
||||||
mod shader_version;
|
mod shader_version;
|
||||||
mod vao_emulate;
|
mod vao;
|
||||||
|
|
||||||
#[cfg(all(not(target_arch = "wasm32"), feature = "winit"))]
|
#[cfg(all(not(target_arch = "wasm32"), feature = "winit"))]
|
||||||
pub mod winit;
|
pub mod winit;
|
||||||
|
@ -105,3 +26,62 @@ mod epi_backend;
|
||||||
|
|
||||||
#[cfg(all(not(target_arch = "wasm32"), feature = "winit"))]
|
#[cfg(all(not(target_arch = "wasm32"), feature = "winit"))]
|
||||||
pub use epi_backend::{run, NativeOptions};
|
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)]
|
#![allow(unsafe_code)]
|
||||||
use glow::HasContext;
|
|
||||||
use std::option::Option::Some;
|
|
||||||
|
|
||||||
pub fn check_for_gl_error(gl: &glow::Context, context: &str) {
|
use glow::HasContext as _;
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) unsafe fn compile_shader(
|
pub(crate) unsafe fn compile_shader(
|
||||||
gl: &glow::Context,
|
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))
|
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,
|
emath::Rect,
|
||||||
epaint::{Color32, Mesh, Primitive, Vertex},
|
epaint::{Color32, Mesh, Primitive, Vertex},
|
||||||
};
|
};
|
||||||
use glow::HasContext;
|
use glow::HasContext as _;
|
||||||
use memoffset::offset_of;
|
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::post_process::PostProcess;
|
||||||
use crate::shader_version::ShaderVersion;
|
use crate::shader_version::ShaderVersion;
|
||||||
use crate::vao_emulate;
|
use crate::vao;
|
||||||
|
|
||||||
pub use glow::Context;
|
pub use glow::Context;
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ pub struct Painter {
|
||||||
u_sampler: glow::UniformLocation,
|
u_sampler: glow::UniformLocation,
|
||||||
is_webgl_1: bool,
|
is_webgl_1: bool,
|
||||||
is_embedded: bool,
|
is_embedded: bool,
|
||||||
vertex_array: crate::misc_util::VAO,
|
vertex_array: crate::vao::VAO,
|
||||||
srgb_support: bool,
|
srgb_support: bool,
|
||||||
/// The filter used for subsequent textures.
|
/// The filter used for subsequent textures.
|
||||||
texture_filter: TextureFilter,
|
texture_filter: TextureFilter,
|
||||||
|
@ -95,11 +96,15 @@ impl Painter {
|
||||||
pp_fb_extent: Option<[i32; 2]>,
|
pp_fb_extent: Option<[i32; 2]>,
|
||||||
shader_prefix: &str,
|
shader_prefix: &str,
|
||||||
) -> Result<Painter, String> {
|
) -> 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 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 shader_version = ShaderVersion::get(&gl);
|
||||||
let is_webgl_1 = shader_version == ShaderVersion::Es100;
|
let is_webgl_1 = shader_version == ShaderVersion::Es100;
|
||||||
let header = shader_version.version();
|
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_tc_loc = gl.get_attrib_location(program, "a_tc").unwrap();
|
||||||
let a_srgba_loc = gl.get_attrib_location(program, "a_srgba").unwrap();
|
let a_srgba_loc = gl.get_attrib_location(program, "a_srgba").unwrap();
|
||||||
let mut vertex_array = if support_vao {
|
let mut vertex_array = if support_vao {
|
||||||
crate::misc_util::VAO::native(&gl)
|
crate::vao::VAO::native(&gl)
|
||||||
} else {
|
} else {
|
||||||
crate::misc_util::VAO::emulated()
|
crate::vao::VAO::emulated()
|
||||||
};
|
};
|
||||||
vertex_array.bind_vertex_array(&gl);
|
vertex_array.bind_vertex_array(&gl);
|
||||||
vertex_array.bind_buffer(&gl, &vertex_buffer);
|
vertex_array.bind_buffer(&gl, &vertex_buffer);
|
||||||
let stride = std::mem::size_of::<Vertex>() as i32;
|
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,
|
location: a_pos_loc,
|
||||||
vector_size: 2,
|
vector_size: 2,
|
||||||
data_type: glow::FLOAT,
|
data_type: glow::FLOAT,
|
||||||
|
@ -190,7 +195,7 @@ impl Painter {
|
||||||
stride,
|
stride,
|
||||||
offset: offset_of!(Vertex, pos) as i32,
|
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,
|
location: a_tc_loc,
|
||||||
vector_size: 2,
|
vector_size: 2,
|
||||||
data_type: glow::FLOAT,
|
data_type: glow::FLOAT,
|
||||||
|
@ -198,7 +203,7 @@ impl Painter {
|
||||||
stride,
|
stride,
|
||||||
offset: offset_of!(Vertex, uv) as i32,
|
offset: offset_of!(Vertex, uv) as i32,
|
||||||
};
|
};
|
||||||
let color_buffer_info = vao_emulate::BufferInfo {
|
let color_buffer_info = vao::BufferInfo {
|
||||||
location: a_srgba_loc,
|
location: a_srgba_loc,
|
||||||
vector_size: 4,
|
vector_size: 4,
|
||||||
data_type: glow::UNSIGNED_BYTE,
|
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, position_buffer_info);
|
||||||
vertex_array.add_new_attribute(&gl, tex_coord_buffer_info);
|
vertex_array.add_new_attribute(&gl, tex_coord_buffer_info);
|
||||||
vertex_array.add_new_attribute(&gl, color_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 {
|
Ok(Painter {
|
||||||
gl,
|
gl,
|
||||||
|
@ -266,7 +271,7 @@ impl Painter {
|
||||||
|
|
||||||
if !cfg!(target_arch = "wasm32") {
|
if !cfg!(target_arch = "wasm32") {
|
||||||
self.gl.enable(glow::FRAMEBUFFER_SRGB);
|
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;
|
let width_in_points = width_in_pixels as f32 / pixels_per_point;
|
||||||
|
@ -285,6 +290,8 @@ impl Painter {
|
||||||
self.gl
|
self.gl
|
||||||
.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.element_array_buffer));
|
.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)
|
(width_in_pixels, height_in_pixels)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,6 +382,8 @@ impl Painter {
|
||||||
|
|
||||||
callback.call(self);
|
callback.call(self);
|
||||||
|
|
||||||
|
check_for_gl_error!(&self.gl, "callback");
|
||||||
|
|
||||||
// Restore state:
|
// Restore state:
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(ref mut post_process) = self.post_process {
|
if let Some(ref mut post_process) = self.post_process {
|
||||||
|
@ -396,7 +405,7 @@ impl Painter {
|
||||||
|
|
||||||
self.gl.disable(glow::SCISSOR_TEST);
|
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,
|
0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_for_gl_error!(&self.gl, "paint_mesh");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,7 +537,7 @@ impl Painter {
|
||||||
glow::TEXTURE_WRAP_T,
|
glow::TEXTURE_WRAP_T,
|
||||||
glow::CLAMP_TO_EDGE as i32,
|
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 (internal_format, src_format) = if self.is_webgl_1 {
|
||||||
let format = if self.srgb_support {
|
let format = if self.srgb_support {
|
||||||
|
@ -554,7 +565,7 @@ impl Painter {
|
||||||
glow::UNSIGNED_BYTE,
|
glow::UNSIGNED_BYTE,
|
||||||
glow::PixelUnpackData::Slice(data),
|
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 {
|
} else {
|
||||||
let border = 0;
|
let border = 0;
|
||||||
self.gl.tex_image_2d(
|
self.gl.tex_image_2d(
|
||||||
|
@ -568,7 +579,7 @@ impl Painter {
|
||||||
glow::UNSIGNED_BYTE,
|
glow::UNSIGNED_BYTE,
|
||||||
Some(data),
|
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)]
|
#![allow(unsafe_code)]
|
||||||
use crate::misc_util::{check_for_gl_error, compile_shader, link_program};
|
use crate::check_for_gl_error;
|
||||||
use crate::vao_emulate::BufferInfo;
|
use crate::misc_util::{compile_shader, link_program};
|
||||||
use glow::HasContext;
|
use crate::vao::BufferInfo;
|
||||||
|
use glow::HasContext as _;
|
||||||
|
|
||||||
/// Uses a framebuffer to render everything in linear color space and convert it back to `sRGB`
|
/// Uses a framebuffer to render everything in linear color space and convert it back to `sRGB`
|
||||||
/// in a separate "post processing" step
|
/// in a separate "post processing" step
|
||||||
|
@ -9,7 +10,7 @@ pub(crate) struct PostProcess {
|
||||||
gl: std::rc::Rc<glow::Context>,
|
gl: std::rc::Rc<glow::Context>,
|
||||||
pos_buffer: glow::Buffer,
|
pos_buffer: glow::Buffer,
|
||||||
index_buffer: glow::Buffer,
|
index_buffer: glow::Buffer,
|
||||||
vertex_array: crate::misc_util::VAO,
|
vertex_array: crate::vao::VAO,
|
||||||
is_webgl_1: bool,
|
is_webgl_1: bool,
|
||||||
texture: glow::Texture,
|
texture: glow::Texture,
|
||||||
texture_size: (i32, i32),
|
texture_size: (i32, i32),
|
||||||
|
@ -77,7 +78,7 @@ impl PostProcess {
|
||||||
glow::UNSIGNED_BYTE,
|
glow::UNSIGNED_BYTE,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
check_for_gl_error(&gl, "post process texture initialization");
|
check_for_gl_error!(&gl, "post process texture initialization");
|
||||||
|
|
||||||
gl.framebuffer_texture_2d(
|
gl.framebuffer_texture_2d(
|
||||||
glow::FRAMEBUFFER,
|
glow::FRAMEBUFFER,
|
||||||
|
@ -125,9 +126,9 @@ impl PostProcess {
|
||||||
.get_attrib_location(program, "a_pos")
|
.get_attrib_location(program, "a_pos")
|
||||||
.ok_or_else(|| "failed to get location of a_pos".to_string())?;
|
.ok_or_else(|| "failed to get location of a_pos".to_string())?;
|
||||||
let mut vertex_array = if need_to_emulate_vao {
|
let mut vertex_array = if need_to_emulate_vao {
|
||||||
crate::misc_util::VAO::emulated()
|
crate::vao::VAO::emulated()
|
||||||
} else {
|
} else {
|
||||||
crate::misc_util::VAO::native(&gl)
|
crate::vao::VAO::native(&gl)
|
||||||
};
|
};
|
||||||
vertex_array.bind_vertex_array(&gl);
|
vertex_array.bind_vertex_array(&gl);
|
||||||
vertex_array.bind_buffer(&gl, &pos_buffer);
|
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.buffer_data_u8_slice(glow::ELEMENT_ARRAY_BUFFER, &indices, glow::STATIC_DRAW);
|
||||||
|
|
||||||
gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None);
|
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 {
|
Ok(PostProcess {
|
||||||
gl,
|
gl,
|
||||||
|
@ -190,6 +191,8 @@ impl PostProcess {
|
||||||
self.gl.bind_framebuffer(glow::FRAMEBUFFER, Some(self.fbo));
|
self.gl.bind_framebuffer(glow::FRAMEBUFFER, Some(self.fbo));
|
||||||
self.gl.clear_color(0.0, 0.0, 0.0, 0.0);
|
self.gl.clear_color(0.0, 0.0, 0.0, 0.0);
|
||||||
self.gl.clear(glow::COLOR_BUFFER_BIT);
|
self.gl.clear(glow::COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
check_for_gl_error!(&self.gl, "PostProcess::begin");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn bind(&self) {
|
pub(crate) unsafe fn bind(&self) {
|
||||||
|
@ -219,6 +222,8 @@ impl PostProcess {
|
||||||
self.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None);
|
self.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None);
|
||||||
self.gl.bind_texture(glow::TEXTURE_2D, None);
|
self.gl.bind_texture(glow::TEXTURE_2D, None);
|
||||||
self.gl.use_program(None);
|
self.gl.use_program(None);
|
||||||
|
|
||||||
|
check_for_gl_error!(&self.gl, "PostProcess::end");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn destroy(&self) {
|
pub(crate) unsafe fn destroy(&self) {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#![allow(unsafe_code)]
|
#![allow(unsafe_code)]
|
||||||
|
|
||||||
use glow::HasContext;
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
@ -14,6 +13,7 @@ pub(crate) enum ShaderVersion {
|
||||||
|
|
||||||
impl ShaderVersion {
|
impl ShaderVersion {
|
||||||
pub(crate) fn get(gl: &glow::Context) -> Self {
|
pub(crate) fn get(gl: &glow::Context) -> Self {
|
||||||
|
use glow::HasContext as _;
|
||||||
let shading_lang_string =
|
let shading_lang_string =
|
||||||
unsafe { gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION) };
|
unsafe { gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION) };
|
||||||
let shader_version = Self::parse(&shading_lang_string);
|
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