From 56a5bb05f03d5485377f55b534e33ca8ea7064b6 Mon Sep 17 00:00:00 2001 From: Fedor Logachev Date: Mon, 3 Jun 2024 21:56:24 -0600 Subject: [PATCH] native/wasm: optional WebGL2 support --- examples/quad.rs | 1 + js/gl.js | 141 ++++++++++++++++++++++++--------------------- src/conf.rs | 13 +++++ src/graphics/gl.rs | 10 +++- src/native/wasm.rs | 14 +++-- 5 files changed, 107 insertions(+), 72 deletions(-) diff --git a/examples/quad.rs b/examples/quad.rs index 821acb11..dfb938b0 100644 --- a/examples/quad.rs +++ b/examples/quad.rs @@ -123,6 +123,7 @@ fn main() { } else { conf::AppleGfxApi::OpenGl }; + conf.platform.webgl_version = conf::WebGLVersion::WebGL2; miniquad::start(conf, move || Box::new(Stage::new())); } diff --git a/js/gl.js b/js/gl.js index 43185c59..9262fc9a 100644 --- a/js/gl.js +++ b/js/gl.js @@ -8,13 +8,10 @@ "use strict"; -const version = 1; +const version = 2; const canvas = document.querySelector("#glcanvas"); -const gl = canvas.getContext("webgl"); -if (gl === null) { - alert("Unable to initialize WebGL. Your browser or machine may not support it."); -} +var gl; var clipboard = null; @@ -27,6 +24,77 @@ var high_dpi = false; // if false, requestAnimationFrame will be called at the end of each frame var blocking_event_loop = false; +function init_webgl(version) { + if (version == 1) { + gl = canvas.getContext("webgl"); + + function acquireVertexArrayObjectExtension(ctx) { + // Extension available in WebGL 1 from Firefox 25 and WebKit 536.28/desktop Safari 6.0.3 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension('OES_vertex_array_object'); + if (ext) { + ctx['createVertexArray'] = function () { return ext['createVertexArrayOES'](); }; + ctx['deleteVertexArray'] = function (vao) { ext['deleteVertexArrayOES'](vao); }; + ctx['bindVertexArray'] = function (vao) { ext['bindVertexArrayOES'](vao); }; + ctx['isVertexArray'] = function (vao) { return ext['isVertexArrayOES'](vao); }; + } + else { + alert("Unable to get OES_vertex_array_object extension"); + } + } + + + function acquireInstancedArraysExtension(ctx) { + // Extension available in WebGL 1 from Firefox 26 and Google Chrome 30 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension('ANGLE_instanced_arrays'); + if (ext) { + ctx['vertexAttribDivisor'] = function (index, divisor) { ext['vertexAttribDivisorANGLE'](index, divisor); }; + ctx['drawArraysInstanced'] = function (mode, first, count, primcount) { ext['drawArraysInstancedANGLE'](mode, first, count, primcount); }; + ctx['drawElementsInstanced'] = function (mode, count, type, indices, primcount) { ext['drawElementsInstancedANGLE'](mode, count, type, indices, primcount); }; + } + } + + function acquireDisjointTimerQueryExtension(ctx) { + var ext = ctx.getExtension('EXT_disjoint_timer_query'); + if (ext) { + ctx['createQuery'] = function () { return ext['createQueryEXT'](); }; + ctx['beginQuery'] = function (target, query) { return ext['beginQueryEXT'](target, query); }; + ctx['endQuery'] = function (target) { return ext['endQueryEXT'](target); }; + ctx['deleteQuery'] = function (query) { ext['deleteQueryEXT'](query); }; + ctx['getQueryObject'] = function (query, pname) { return ext['getQueryObjectEXT'](query, pname); }; + } + } + + function acquireDrawBuffers(ctx) { + var ext = ctx.getExtension('WEBGL_draw_buffers'); + if (ext) { + ctx['drawBuffers'] = function (bufs) { return ext['drawBuffersWEBGL'](bufs); }; + } + } + + try { + gl.getExtension("EXT_shader_texture_lod"); + gl.getExtension("OES_standard_derivatives"); + } catch (e) { + console.warn(e); + } + + acquireVertexArrayObjectExtension(gl); + acquireInstancedArraysExtension(gl); + acquireDisjointTimerQueryExtension(gl); + acquireDrawBuffers(gl); + + // https://developer.mozilla.org/en-US/docs/Web/API/WEBGL_depth_texture + if (gl.getExtension('WEBGL_depth_texture') == null) { + alert("Cant initialize WEBGL_depth_texture extension"); + } + } else { + gl = canvas.getContext("webgl2"); + } + if (gl === null) { + alert("Unable to initialize WebGL. Your browser or machine may not support it."); + } +} + canvas.focus(); canvas.requestPointerLock = canvas.requestPointerLock || @@ -45,66 +113,6 @@ function assert(flag, message) { } } -function acquireVertexArrayObjectExtension(ctx) { - // Extension available in WebGL 1 from Firefox 25 and WebKit 536.28/desktop Safari 6.0.3 onwards. Core feature in WebGL 2. - var ext = ctx.getExtension('OES_vertex_array_object'); - if (ext) { - ctx['createVertexArray'] = function () { return ext['createVertexArrayOES'](); }; - ctx['deleteVertexArray'] = function (vao) { ext['deleteVertexArrayOES'](vao); }; - ctx['bindVertexArray'] = function (vao) { ext['bindVertexArrayOES'](vao); }; - ctx['isVertexArray'] = function (vao) { return ext['isVertexArrayOES'](vao); }; - } - else { - alert("Unable to get OES_vertex_array_object extension"); - } -} - - -function acquireInstancedArraysExtension(ctx) { - // Extension available in WebGL 1 from Firefox 26 and Google Chrome 30 onwards. Core feature in WebGL 2. - var ext = ctx.getExtension('ANGLE_instanced_arrays'); - if (ext) { - ctx['vertexAttribDivisor'] = function (index, divisor) { ext['vertexAttribDivisorANGLE'](index, divisor); }; - ctx['drawArraysInstanced'] = function (mode, first, count, primcount) { ext['drawArraysInstancedANGLE'](mode, first, count, primcount); }; - ctx['drawElementsInstanced'] = function (mode, count, type, indices, primcount) { ext['drawElementsInstancedANGLE'](mode, count, type, indices, primcount); }; - } -} - -function acquireDisjointTimerQueryExtension(ctx) { - var ext = ctx.getExtension('EXT_disjoint_timer_query'); - if (ext) { - ctx['createQuery'] = function () { return ext['createQueryEXT'](); }; - ctx['beginQuery'] = function (target, query) { return ext['beginQueryEXT'](target, query); }; - ctx['endQuery'] = function (target) { return ext['endQueryEXT'](target); }; - ctx['deleteQuery'] = function (query) { ext['deleteQueryEXT'](query); }; - ctx['getQueryObject'] = function (query, pname) { return ext['getQueryObjectEXT'](query, pname); }; - } -} - -function acquireDrawBuffers(ctx) { - var ext = ctx.getExtension('WEBGL_draw_buffers'); - if (ext) { - ctx['drawBuffers'] = function (bufs) { return ext['drawBuffersWEBGL'](bufs); }; - } -} - -try { - gl.getExtension("EXT_shader_texture_lod"); - gl.getExtension("OES_standard_derivatives"); -} catch (e) { - console.warn(e); -} - -acquireVertexArrayObjectExtension(gl); -acquireInstancedArraysExtension(gl); -acquireDisjointTimerQueryExtension(gl); -acquireDrawBuffers(gl); - -// https://developer.mozilla.org/en-US/docs/Web/API/WEBGL_depth_texture -if (gl.getExtension('WEBGL_depth_texture') == null) { - alert("Cant initialize WEBGL_depth_texture extension"); -} - function getArray(ptr, arr, n) { return new arr(wasm_memory.buffer, ptr, n); } @@ -1403,7 +1411,8 @@ var importObject = { window.cancelAnimationFrame(animation_frame_timeout); } animation_frame_timeout = window.requestAnimationFrame(animation); - } + }, + init_webgl } }; diff --git a/src/conf.rs b/src/conf.rs index 96c00ac1..65270c49 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -68,6 +68,12 @@ pub enum AppleGfxApi { Metal, } +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum WebGLVersion { + WebGL1, + WebGL2 +} + /// Platform specific settings. #[derive(Debug)] pub struct Platform { @@ -84,6 +90,12 @@ pub struct Platform { /// Defaults to X11Only. Wayland implementation is way too unstable right now. pub linux_backend: LinuxBackend, + /// While miniquad itself only use webgl1 features, withing webgl2 context it + /// is possible to: + /// - use gles3 shaders + /// - do raw webgl2 opengl calls + pub webgl_version: WebGLVersion, + /// Which rendering context to create, Metal or OpenGL. /// Miniquad always links with Metal.framework (assuming it is always present) /// but it links with OpenGL dynamically and only if required. @@ -122,6 +134,7 @@ impl Default for Platform { linux_x11_gl: LinuxX11Gl::GLXWithEGLFallback, linux_backend: LinuxBackend::X11Only, apple_gfx_api: AppleGfxApi::OpenGl, + webgl_version: WebGLVersion::WebGL1, blocking_event_loop: false, swap_interval: None, framebuffer_alpha: false, diff --git a/src/graphics/gl.rs b/src/graphics/gl.rs index 26bb3e1b..26476679 100644 --- a/src/graphics/gl.rs +++ b/src/graphics/gl.rs @@ -745,7 +745,6 @@ impl RenderingBackend for GlContext { .to_str() .unwrap() .to_string(); - let gles3 = gl_version_string.contains("OpenGL ES 3"); //let gles2 = !gles3 && gl_version_string.contains("OpenGL ES"); let mut glsl_support = GlslSupport::default(); @@ -760,10 +759,17 @@ impl RenderingBackend for GlContext { { // on web, miniquad always loads EXT_shader_texture_lod and OES_standard_derivatives glsl_support.v100_ext = true; + + let webgl2 = gl_version_string.contains("WebGL 2.0"); + if webgl2 { + glsl_support.v300es = true; + } } #[cfg(not(target_arch = "wasm32"))] { + let gles3 = gl_version_string.contains("OpenGL ES 3"); + if gles3 { glsl_support.v300es = true; } @@ -810,7 +816,7 @@ impl RenderingBackend for GlContext { } fn delete_texture(&mut self, texture: TextureId) { - self.cache.clear_texture_bindings(); + //self.cache.clear_texture_bindings(); let t = self.textures.get(texture); unsafe { diff --git a/src/native/wasm.rs b/src/native/wasm.rs index 8d3afc6e..3da4f83a 100644 --- a/src/native/wasm.rs +++ b/src/native/wasm.rs @@ -3,8 +3,6 @@ pub mod webgl; mod keycodes; -pub use webgl::*; - use std::{ cell::RefCell, path::PathBuf, @@ -67,6 +65,14 @@ where })); } + let version = match conf.platform.webgl_version { + crate::conf::WebGLVersion::WebGL1 => 1, + crate::conf::WebGLVersion::WebGL2 => 2, + }; + unsafe { + init_webgl(version); + } + // setup initial canvas size unsafe { setup_canvas_size(conf.high_dpi); @@ -128,6 +134,7 @@ extern "C" { pub fn sapp_is_fullscreen() -> bool; pub fn sapp_set_window_size(new_width: u32, new_height: u32); pub fn sapp_schedule_update(); + pub fn init_webgl(version: i32); pub fn now() -> f64; } @@ -173,7 +180,7 @@ pub unsafe fn update_cursor() { // "crate_version" is a misleading, but it can't be changed for legacy reasons. #[no_mangle] pub extern "C" fn crate_version() -> u32 { - 1 + 2 } #[no_mangle] @@ -213,7 +220,6 @@ pub extern "C" fn on_clipboard_paste(msg: *mut u8, len: usize) { pub extern "C" fn frame() { REQUESTS.with(|r| { while let Ok(request) = r.borrow_mut().as_mut().unwrap().try_recv() { - use Request::*; match request { Request::SetCursorGrab(grab) => unsafe { sapp_set_cursor_grab(grab) }, Request::ShowMouse(show) => unsafe { show_mouse(show) },