diff --git a/examples/msaa_render_texture.rs b/examples/msaa_render_texture.rs index b99f5d31..d81ba16a 100644 --- a/examples/msaa_render_texture.rs +++ b/examples/msaa_render_texture.rs @@ -37,7 +37,13 @@ impl Stage { sample_count: 4, ..Default::default() }); - + // Without this check, new_render_pass_mrt might panic on GL2/WebGl1. + // It is recommended to handle it and create a normal, + // non-msaa render pass instead. + assert!( + ctx.info().features.resolve_attachments, + "MSAA render targets are not supported on current rendering backend!" + ); let offscreen_pass = ctx.new_render_pass_mrt(&[color_img], Some(&[color_resolve_img]), Some(depth_img)); @@ -235,7 +241,7 @@ impl EventHandler for Stage { self.ctx.apply_pipeline(&self.display_pipeline); self.ctx.apply_bindings(&self.display_bind); self.ctx.apply_uniforms(UniformsSource::table(&vs_params)); - self.ctx.draw(0, 36, 1); + self.ctx.draw(0, 6, 1); self.ctx.end_render_pass(); self.ctx.commit_frame(); @@ -245,6 +251,7 @@ impl EventHandler for Stage { fn main() { let mut conf = conf::Conf::default(); let metal = std::env::args().nth(1).as_deref() == Some("metal"); + conf.platform.webgl_version = conf::WebGLVersion::WebGL2; conf.platform.apple_gfx_api = if metal { conf::AppleGfxApi::Metal } else { diff --git a/examples/quad.rs b/examples/quad.rs index dfb938b0..821acb11 100644 --- a/examples/quad.rs +++ b/examples/quad.rs @@ -123,7 +123,6 @@ 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 4358b7c3..7357af3d 100644 --- a/js/gl.js +++ b/js/gl.js @@ -818,6 +818,9 @@ var importObject = { glGenFramebuffers: function (n, ids) { _glGenObject(n, ids, 'createFramebuffer', GL.framebuffers, 'glGenFramebuffers'); }, + glGenRenderbuffers: function (n, ids) { + _glGenObject(n, ids, 'createRenderbuffer', GL.renderbuffers, 'glGenRenderbuffers'); + }, glBindVertexArray: function (vao) { gl.bindVertexArray(GL.vaos[vao]); }, @@ -826,7 +829,11 @@ var importObject = { gl.bindFramebuffer(target, GL.framebuffers[framebuffer]); }, + glBindRenderbuffer: function (target, renderbuffer) { + GL.validateGLObjectID(GL.renderbuffers, renderbuffer, 'glBindRenderbuffer', 'renderbuffer'); + gl.bindRenderbuffer(target, GL.renderbuffers[renderbuffer]); + }, glGenBuffers: function (n, buffers) { _glGenObject(n, buffers, 'createBuffer', GL.buffers, 'glGenBuffers'); }, @@ -1129,6 +1136,26 @@ var importObject = { glGenerateMipmap: function (index) { gl.generateMipmap(index); }, + glRenderbufferStorageMultisample: function(target, samples, internalformat, width, height) { + gl.renderbufferStorageMultisample(target, samples, internalformat, width, height); + }, + glFramebufferRenderbuffer: function(target, attachment, renderbuffertarget, renderbuffer) { + GL.validateGLObjectID(GL.renderbuffers, renderbuffer, 'glFramebufferRenderbuffer', 'renderbuffer'); + gl.framebufferRenderbuffer(target, attachment, renderbuffertarget, GL.renderbuffers[renderbuffer]); + }, + glCheckFramebufferStatus: function(target) { + return gl.checkFramebufferStatus(target); + }, + glReadBuffer: function(source) { + gl.readBuffer(source) + }, + glBlitFramebuffer: function(srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, filter) { + gl.blitFramebuffer(srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, filter); + }, setup_canvas_size: function (high_dpi) { window.high_dpi = high_dpi; diff --git a/src/graphics.rs b/src/graphics.rs index 28f9e304..c2a270a1 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -392,7 +392,7 @@ pub struct TextureParams { /// On OpenGL, for a `sample_count > 1` render texture, render buffer object will /// be created instead of a regulat texture. /// - /// The only way to use + /// The only way to use pub sample_count: i32, } @@ -569,11 +569,21 @@ pub const MAX_SHADERSTAGE_IMAGES: usize = 12; #[derive(Clone, Debug)] pub struct Features { pub instancing: bool, + /// Does current rendering backend support automatic resolve of + /// multisampled render passes on end_render_pass. + /// Would be false on WebGl1 and GL2. + /// + /// With resolve_attachments: false, not-none resolve_img in new_render_pass will + /// result in a runtime panic. + pub resolve_attachments: bool, } impl Default for Features { fn default() -> Features { - Features { instancing: true } + Features { + instancing: true, + resolve_attachments: true, + } } } @@ -1203,7 +1213,10 @@ pub trait RenderingBackend { /// Same as "new_render_pass", but allows multiple color attachments. /// if `resolve_img` is set, MSAA-resolve operation will happen in `end_render_pass` /// this operation require `color_img` to have sample_count > 1,resolve_img have - /// sample_count == 1, and color_img.len() should be equal to resolve_img.len() + /// sample_count == 1, and color_img.len() should be equal to resolve_img.len() + /// + /// Note that resolve attachments may be not supported by current backend! + /// They are only available when `ctx.info().features.resolve_attachments` is true. fn new_render_pass_mrt( &mut self, color_img: &[TextureId], diff --git a/src/graphics/gl.rs b/src/graphics/gl.rs index 0a7d1cf5..1bc24708 100644 --- a/src/graphics/gl.rs +++ b/src/graphics/gl.rs @@ -51,6 +51,22 @@ struct Texture { params: TextureParams, } +impl TextureFormat { + fn sized_internal_format(&self) -> GLenum { + match self { + TextureFormat::RGB8 => GL_RGB8, + TextureFormat::RGBA8 => GL_RGBA8, + TextureFormat::RGBA16F => GL_RGBA16F, + TextureFormat::Depth => GL_DEPTH_COMPONENT16, + TextureFormat::Depth32 => GL_DEPTH_COMPONENT32, + #[cfg(target_arch = "wasm32")] + TextureFormat::Alpha => GL_ALPHA, + #[cfg(not(target_arch = "wasm32"))] + TextureFormat::Alpha => GL_R8, + } + } +} + /// Converts from TextureFormat to (internal_format, format, pixel_type) impl From for (GLenum, GLenum, GLenum) { fn from(format: TextureFormat) -> Self { @@ -160,6 +176,7 @@ impl Texture { unsafe { glGenRenderbuffers(1, &mut renderbuffer as *mut _); glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer as _); + let internal_format = params.format.sized_internal_format(); glRenderbufferStorageMultisample( GL_RENDERBUFFER, params.sample_count, @@ -484,11 +501,7 @@ impl GlContext { glGenVertexArrays(1, &mut vao as *mut _); glBindVertexArray(vao); - let features = Features { - instancing: !crate::native::gl::is_gl2(), - ..Default::default() - }; - let info = gl_info(features); + let info = gl_info(); GlContext { default_framebuffer, shaders: ResourceManager::default(), @@ -765,7 +778,7 @@ impl GlContext { } } -fn gl_info(features: Features) -> ContextInfo { +fn gl_info() -> ContextInfo { let version_string = unsafe { glGetString(super::gl::GL_VERSION) }; let gl_version_string = unsafe { std::ffi::CStr::from_ptr(version_string as _) } .to_str() @@ -773,6 +786,17 @@ fn gl_info(features: Features) -> ContextInfo { .to_string(); //let gles2 = !gles3 && gl_version_string.contains("OpenGL ES"); + let gl2 = gl_version_string.is_empty() + || gl_version_string.starts_with("2") + || gl_version_string.starts_with("OpenGL ES 2"); + let webgl1 = gl_version_string == "WebGL 1.0"; + + let features = Features { + instancing: !gl2, + resolve_attachments: !webgl1 && !gl2, + ..Default::default() + }; + let mut glsl_support = GlslSupport::default(); // this is not quite documented, diff --git a/src/graphics/metal.rs b/src/graphics/metal.rs index 69741be5..71c98e23 100644 --- a/src/graphics/metal.rs +++ b/src/graphics/metal.rs @@ -378,7 +378,10 @@ impl RenderingBackend for MetalContext { backend: Backend::Metal, gl_version_string: Default::default(), glsl_support: Default::default(), - features: Features { instancing: true }, + features: Features { + instancing: true, + resolve_attachments: false, + }, } } fn buffer_size(&mut self, buffer: BufferId) -> usize { diff --git a/src/native/gl.rs b/src/native/gl.rs index 2e0e4884..e081d659 100644 --- a/src/native/gl.rs +++ b/src/native/gl.rs @@ -136,6 +136,8 @@ pub const GL_LEQUAL: u32 = 0x0203; pub const GL_STENCIL_TEST: u32 = 0x0B90; pub const GL_DITHER: u32 = 0x0BD0; pub const GL_DEPTH_COMPONENT16: u32 = 0x81A5; +pub const GL_DEPTH_COMPONENT24: u32 = 0x81A6; +pub const GL_DEPTH_COMPONENT32: u32 = 0x81A7; pub const GL_EQUAL: u32 = 0x0202; pub const GL_FRAMEBUFFER: u32 = 0x8D40; pub const GL_RGB5: u32 = 0x8050; diff --git a/src/native/wasm/webgl.rs b/src/native/wasm/webgl.rs index 47aba1d2..6538aa88 100644 --- a/src/native/wasm/webgl.rs +++ b/src/native/wasm/webgl.rs @@ -141,6 +141,8 @@ pub const GL_LEQUAL: u32 = 0x0203; pub const GL_STENCIL_TEST: u32 = 0x0B90; pub const GL_DITHER: u32 = 0x0BD0; pub const GL_DEPTH_COMPONENT16: u32 = 0x81A5; +pub const GL_DEPTH_COMPONENT24: u32 = 0x81A6; +pub const GL_DEPTH_COMPONENT32: u32 = 0x81A7; pub const GL_EQUAL: u32 = 0x0202; pub const GL_FRAMEBUFFER: u32 = 0x8D40; pub const GL_RGB5: u32 = 0x8050;