Skip to content

Commit

Permalink
webgl: new surface API
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Nov 17, 2024
1 parent f215e85 commit 04cca76
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 119 deletions.
32 changes: 15 additions & 17 deletions blade-graphics/src/gles/egl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,6 @@ pub struct PlatformFrame {
pub struct PlatformSurface {
library: Option<libloading::Library>,
window_handle: raw_window_handle::RawWindowHandle,
renderbuf: glow::Renderbuffer,
framebuf: glow::Framebuffer,
swapchain: Mutex<Option<Swapchain>>,
}

Expand Down Expand Up @@ -272,17 +270,17 @@ impl super::Context {
_ => None,
};

let mut surface = super::Surface {
platform: unsafe {
let guard = self.lock();
PlatformSurface {
let mut surface = unsafe {
let guard = self.lock();
super::Surface {
platform: PlatformSurface {
library,
window_handle: window.window_handle().unwrap().as_raw(),
renderbuf: guard.create_renderbuffer().unwrap(),
framebuf: guard.create_framebuffer().unwrap(),
swapchain: Mutex::new(None),
}
},
},
renderbuf: guard.create_renderbuffer().unwrap(),
framebuf: guard.create_framebuffer().unwrap(),
}
};
self.reconfigure_surface(&mut surface, config);
Ok(surface)
Expand Down Expand Up @@ -425,19 +423,19 @@ impl super::Context {
inner.egl.make_current();
unsafe {
let gl = &inner.glow;
gl.bind_renderbuffer(glow::RENDERBUFFER, Some(surface.platform.renderbuf));
gl.bind_renderbuffer(glow::RENDERBUFFER, Some(surface.renderbuf));
gl.renderbuffer_storage(
glow::RENDERBUFFER,
format_desc.internal,
config.size.width as _,
config.size.height as _,
);
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(surface.platform.framebuf));
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(surface.framebuf));
gl.framebuffer_renderbuffer(
glow::READ_FRAMEBUFFER,
glow::COLOR_ATTACHMENT0,
glow::RENDERBUFFER,
Some(surface.platform.renderbuf),
Some(surface.renderbuf),
);
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);
gl.bind_renderbuffer(glow::RENDERBUFFER, None);
Expand Down Expand Up @@ -471,8 +469,8 @@ impl super::Context {
}
inner.egl.make_current();
unsafe {
inner.glow.delete_renderbuffer(surface.platform.renderbuf);
inner.glow.delete_framebuffer(surface.platform.framebuf);
inner.glow.delete_renderbuffer(surface.renderbuf);
inner.glow.delete_framebuffer(surface.framebuf);
}
inner.egl.unmake_current();
}
Expand Down Expand Up @@ -533,11 +531,11 @@ impl super::Surface {
super::Frame {
platform: PlatformFrame {
swapchain: sc.clone(),
framebuf: self.platform.framebuf,
framebuf: self.framebuf,
},
texture: super::Texture {
inner: super::TextureInner::Renderbuffer {
raw: self.platform.renderbuf,
raw: self.renderbuf,
},
target_size: [sc.extent.width as u16, sc.extent.height as u16],
format: sc.info.format,
Expand Down
2 changes: 2 additions & 0 deletions blade-graphics/src/gles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub struct Context {

pub struct Surface {
platform: platform::PlatformSurface,
renderbuf: glow::Renderbuffer,
framebuf: glow::Framebuffer,
}

#[derive(Clone, Copy, Debug, Hash, PartialEq)]
Expand Down
181 changes: 93 additions & 88 deletions blade-graphics/src/gles/web.rs
Original file line number Diff line number Diff line change
@@ -1,149 +1,154 @@
use glow::HasContext as _;
use std::cell::Cell;
use wasm_bindgen::JsCast;

//TODO: consider sharing this struct with EGL
struct Swapchain {
renderbuf: glow::Renderbuffer,
framebuf: glow::Framebuffer,
format: crate::TextureFormat,
extent: Cell<crate::Extent>,
}

pub struct PlatformContext {
#[allow(unused)]
webgl2: web_sys::WebGl2RenderingContext,
glow: glow::Context,
swapchain: Swapchain,
}

impl super::Context {
pub unsafe fn init(_desc: crate::ContextDesc) -> Result<Self, crate::NotSupportedError> {
Err(crate::NotSupportedError::PlatformNotSupported)
pub struct PlatformSurface {
info: crate::SurfaceInfo,
extent: crate::Extent,
}
#[derive(Debug)]
pub struct PlatformFrame {
framebuf: glow::Framebuffer,
extent: crate::Extent,
}

impl super::Surface {
pub fn info(&self) -> crate::SurfaceInfo {
self.platform.info
}
pub fn acquire_frame(&self) -> super::Frame {
let size = self.platform.extent;
super::Frame {
platform: PlatformFrame {
framebuf: self.framebuf,
extent: self.platform.extent,
},
texture: super::Texture {
inner: super::TextureInner::Renderbuffer {
raw: self.renderbuf,
},
target_size: [size.width as u16, size.height as u16],
format: self.platform.info.format,
},
}
}
}

pub unsafe fn init_windowed<
I: raw_window_handle::HasWindowHandle + raw_window_handle::HasDisplayHandle,
>(
window: I,
desc: crate::ContextDesc,
) -> Result<Self, crate::NotSupportedError> {
let webgl2 = match window.window_handle().unwrap().as_raw() {
raw_window_handle::RawWindowHandle::Web(handle) => {
let canvas: web_sys::HtmlCanvasElement = web_sys::window()
.and_then(|win| win.document())
.expect("Cannot get document")
.query_selector(&format!("canvas[data-raw-handle=\"{}\"]", handle.id))
.expect("Cannot query for canvas")
.expect("Canvas is not found")
.dyn_into()
.expect("Failed to downcast to canvas type");
impl PlatformContext {
pub(super) fn present(&self, frame: PlatformFrame) {
unsafe {
super::present_blit(&self.glow, frame.framebuf, frame.extent);
}
}
}

let context_options = js_sys::Object::new();
js_sys::Reflect::set(
&context_options,
&"antialias".into(),
&wasm_bindgen::JsValue::FALSE,
)
.expect("Cannot create context options");
//Note: could also set: "alpha", "premultipliedAlpha"
impl super::Context {
pub unsafe fn init(_desc: crate::ContextDesc) -> Result<Self, crate::NotSupportedError> {
let canvas = web_sys::window()
.and_then(|win| win.document())
.expect("Cannot get document")
.get_element_by_id("blade")
.expect("Canvas is not found")
.dyn_into::<web_sys::HtmlCanvasElement>()
.expect("Failed to downcast to canvas type");

canvas
.get_context_with_context_options("webgl2", &context_options)
.expect("Cannot create WebGL2 context")
.and_then(|context| context.dyn_into::<web_sys::WebGl2RenderingContext>().ok())
.expect("Cannot convert into WebGL2 context")
}
_ => return Err(crate::NotSupportedError::PlatformNotSupported),
};
let context_options = js_sys::Object::new();
js_sys::Reflect::set(
&context_options,
&"antialias".into(),
&wasm_bindgen::JsValue::FALSE,
)
.expect("Cannot create context options");
//Note: could also set: "alpha", "premultipliedAlpha"

let webgl2 = canvas
.get_context_with_context_options("webgl2", &context_options)
.expect("Cannot create WebGL2 context")
.and_then(|context| context.dyn_into::<web_sys::WebGl2RenderingContext>().ok())
.expect("Cannot convert into WebGL2 context");

let glow = glow::Context::from_webgl2_context(webgl2.clone());

let capabilities = super::Capabilities::empty();
let limits = super::Limits {
uniform_buffer_alignment: unsafe {
glow.get_parameter_i32(glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT) as u32
},
};
let swapchain = Swapchain {
renderbuf: unsafe { glow.create_renderbuffer().unwrap() },
framebuf: unsafe { glow.create_framebuffer().unwrap() },
format: crate::TextureFormat::Rgba8Unorm,
extent: Cell::default(),
};

let device_information = crate::DeviceInformation {
is_software_emulated: false,
device_name: glow.get_parameter_string(glow::VENDOR),
driver_name: glow.get_parameter_string(glow::RENDERER),
driver_info: glow.get_parameter_string(glow::VERSION),
};

Ok(Self {
platform: PlatformContext {
webgl2,
glow,
swapchain,
},
Ok(super::Context {
platform: PlatformContext { webgl2, glow },
capabilities,
toggles: super::Toggles::default(),
limits,
device_information,
})
}

pub fn resize(&self, config: crate::SurfaceConfig) -> crate::SurfaceInfo {
pub fn create_surface<I>(
&self,
_window: &I,
config: crate::SurfaceConfig,
) -> Result<super::Surface, crate::NotSupportedError> {
let platform = PlatformSurface {
info: crate::SurfaceInfo {
format: crate::TextureFormat::Rgba8Unorm,
alpha: crate::AlphaMode::PreMultiplied,
},
extent: crate::Extent::default(),
};
let mut surface = unsafe {
super::Surface {
platform,
renderbuf: self.platform.glow.create_renderbuffer().unwrap(),
framebuf: self.platform.glow.create_framebuffer().unwrap(),
}
};
self.reconfigure_surface(&mut surface, config);
Ok(surface)
}

pub fn reconfigure_surface(&self, surface: &mut super::Surface, config: crate::SurfaceConfig) {
//TODO: create WebGL context here
let sc = &self.platform.swapchain;
let format_desc = super::describe_texture_format(sc.format);
let format_desc = super::describe_texture_format(surface.platform.info.format);
let gl = &self.platform.glow;
//Note: this code can be shared with EGL
unsafe {
gl.bind_renderbuffer(glow::RENDERBUFFER, Some(sc.renderbuf));
gl.bind_renderbuffer(glow::RENDERBUFFER, Some(surface.renderbuf));
gl.renderbuffer_storage(
glow::RENDERBUFFER,
format_desc.internal,
config.size.width as _,
config.size.height as _,
);
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuf));
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(surface.framebuf));
gl.framebuffer_renderbuffer(
glow::READ_FRAMEBUFFER,
glow::COLOR_ATTACHMENT0,
glow::RENDERBUFFER,
Some(sc.renderbuf),
Some(surface.renderbuf),
);
gl.bind_renderbuffer(glow::RENDERBUFFER, None);
}
sc.extent.set(config.size);

crate::SurfaceInfo {
format: sc.format,
alpha: crate::AlphaMode::PreMultiplied,
}
surface.platform.extent = config.size;
}

pub fn acquire_frame(&self) -> super::Frame {
let sc = &self.platform.swapchain;
let size = sc.extent.get();
super::Frame {
texture: super::Texture {
inner: super::TextureInner::Renderbuffer { raw: sc.renderbuf },
target_size: [size.width as u16, size.height as u16],
format: sc.format,
},
}
}
pub fn destroy_surface(&self, _surface: &mut super::Surface) {}

/// Obtain a lock to the EGL context and get handle to the [`glow::Context`] that can be used to
/// do rendering.
pub(super) fn lock(&self) -> &glow::Context {
&self.platform.glow
}

pub(super) fn present(&self) {
let sc = &self.platform.swapchain;
unsafe {
super::present_blit(&self.platform.glow, sc.framebuf, sc.extent.get());
}
}
}
7 changes: 5 additions & 2 deletions blade-graphics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ pub mod limits {

pub use hal::*;

#[cfg(target_arch = "wasm32")]
pub const CANVAS_ID: &str = "blade";

use std::{fmt, num::NonZeroU32};

#[derive(Clone, Debug, Default)]
Expand Down Expand Up @@ -128,9 +131,9 @@ pub enum NotSupportedError {
))]
VulkanError(ash::vk::Result),

#[cfg(gles)]
#[cfg(all(gles, not(target_arch = "wasm32")))]
GLESLoadingError(egl::LoadError<libloading::Error>),
#[cfg(gles)]
#[cfg(all(gles, not(target_arch = "wasm32")))]
GLESError(egl::Error),

NoSupportedDeviceFound,
Expand Down
Loading

0 comments on commit 04cca76

Please sign in to comment.