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:
Emil Ernerfeldt 2022-03-22 16:04:06 +01:00 committed by GitHub
parent 41b178b6ec
commit 6f10e2e725
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 288 additions and 278 deletions

View file

@ -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,
);
}
}
}

View file

@ -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
}
}
}

View file

@ -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");
}
}
}

View file

@ -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) {

View file

@ -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
View 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
}
}
}

View file

@ -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);
}
}
}