diff --git a/Makefile b/Makefile index 4250d0e2768..89ebcc0e9d8 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ RUST_BACKTRACE:=1 EXCLUDES:= +FEATURES_GL:= FEATURES_HAL:= FEATURES_HAL2:= -FEATURES_HAL3:= ifeq (,$(TARGET)) CHECK_TARGET_FLAG= @@ -13,6 +13,7 @@ endif ifeq ($(OS),Windows_NT) EXCLUDES+= --exclude gfx-backend-metal FEATURES_HAL=vulkan + FEATURES_GL=gl ifeq ($(TARGET),x86_64-pc-windows-gnu) # No d3d12 support on GNU windows ATM # context: https://github.com/gfx-rs/gfx/pull/1417 @@ -21,7 +22,6 @@ ifeq ($(OS),Windows_NT) else FEATURES_HAL2=dx12 endif - FEATURES_HAL3=wgl else UNAME_S:=$(shell uname -s) EXCLUDES+= --exclude gfx-backend-dx12 @@ -31,7 +31,9 @@ else FEATURES_HAL=vulkan endif ifeq ($(TARGET),aarch64-apple-ios) - EXCLUDES+= --exclude gfx-backend-vulkan + EXCLUDES+= --exclude gfx-backend-vulkan --exclude gfx-backend-gl + else + FEATURES_GL=gl endif ifeq ($(UNAME_S),Darwin) FEATURES_HAL=metal @@ -44,17 +46,16 @@ endif all: check test help: - @echo "Supported backends: gl $(FEATURES_HAL) $(FEATURES_HAL2)" + @echo "Supported backends: $(FEATURES_GL) $(FEATURES_HAL) $(FEATURES_HAL2)" check: @echo "Note: excluding \`warden\` here, since it depends on serialization" cargo check --all $(CHECK_TARGET_FLAG) $(EXCLUDES) --exclude gfx-warden - cd examples && cargo check $(CHECK_TARGET_FLAG) --features "gl" + cd examples && cargo check $(CHECK_TARGET_FLAG) --features "$(FEATURES_GL)" cd examples && cargo check $(CHECK_TARGET_FLAG) --features "$(FEATURES_HAL)" cd examples && cargo check $(CHECK_TARGET_FLAG) --features "$(FEATURES_HAL2)" - cd examples && cargo check $(CHECK_TARGET_FLAG) --features "$(FEATURES_HAL3)" cd src/warden && cargo check $(CHECK_TARGET_FLAG) --no-default-features - cd src/warden && cargo check $(CHECK_TARGET_FLAG) --features "env_logger gl gl-ci $(FEATURES_HAL) $(FEATURES_HAL2)" + cd src/warden && cargo check $(CHECK_TARGET_FLAG) --features "env_logger $(FEATURES_GL) $(FEATURES_HAL) $(FEATURES_HAL2)" test: cargo test --all $(EXCLUDES) @@ -63,20 +64,20 @@ doc: cargo doc --all $(EXCLUDES) reftests: - cd src/warden && cargo run --bin reftest --features "$(FEATURES_HAL) $(FEATURES_HAL2)" -- local #TODO: gl + cd src/warden && cargo run --bin reftest --features "$(FEATURES_GL) $(FEATURES_HAL) $(FEATURES_HAL2)" -- local benches: - cd src/warden && cargo run --release --bin bench --features "$(FEATURES_HAL) $(FEATURES_HAL2)" -- blit + cd src/warden && cargo run --release --bin bench --features "$(FEATURES_GL) $(FEATURES_HAL) $(FEATURES_HAL2)" -- blit reftests-ci: cd src/warden && cargo test - cd src/warden && cargo run --features "gl-ci" -- ci + cd src/warden && cargo run --features "gl" -- ci quad: cd examples && cargo run --bin quad --features ${FEATURES_HAL} quad-wasm: - cd examples && cargo +nightly build --target wasm32-unknown-unknown --features gl --bin quad && wasm-bindgen ../target/wasm32-unknown-unknown/debug/quad.wasm --out-dir ../examples/generated-wasm --web + cd examples && cargo +nightly build --features gl --target wasm32-unknown-unknown --bin quad && wasm-bindgen ../target/wasm32-unknown-unknown/debug/quad.wasm --out-dir ../examples/generated-wasm --web shader-binaries: ifeq ($(UNAME_S),Darwin) diff --git a/examples/Cargo.toml b/examples/Cargo.toml index dea086f0848..bc888c3cd22 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -8,8 +8,7 @@ edition = "2018" [features] default = [] metal = ["gfx-backend-metal"] -gl = ["gfx-backend-gl", "gfx-backend-gl/glutin"] -wgl = ["gfx-backend-gl", "gfx-backend-gl/wgl"] +gl = ["gfx-backend-gl"] dx11 = ["gfx-backend-dx11"] dx12 = ["gfx-backend-dx12"] vulkan = ["gfx-backend-vulkan"] @@ -28,21 +27,17 @@ name = "compute" path = "compute/main.rs" [dependencies] -env_logger = "0.6" image = "0.21" log = "0.4" hal = { path = "../src/hal", version = "0.5", package = "gfx-hal" } +gfx-backend-gl = { path = "../src/backend/gl", version = "0.5", optional = true } gfx-backend-empty = { path = "../src/backend/empty", version = "0.5" } winit = { version = "0.21.0", features = ["web-sys"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] +env_logger = "0.6" glsl-to-spirv = "0.1.4" -[dependencies.gfx-backend-gl] -path = "../src/backend/gl" -version = "0.5" -optional = true - [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2.55" console_error_panic_hook = "0.1.6" diff --git a/examples/colour-uniform/main.rs b/examples/colour-uniform/main.rs index 99b03c7e1b7..47d62074ebc 100644 --- a/examples/colour-uniform/main.rs +++ b/examples/colour-uniform/main.rs @@ -105,18 +105,6 @@ const COLOR_RANGE: i::SubresourceRange = i::SubresourceRange { layers: 0 .. 1, }; -trait SurfaceTrait { - #[cfg(feature = "gl")] - fn get_context_t(&self) -> &back::glutin::RawContext; -} - -impl SurfaceTrait for ::Surface { - #[cfg(feature = "gl")] - fn get_context_t(&self) -> &back::glutin::RawContext { - self.context() - } -} - struct RendererState { uniform_desc_pool: Option, img_desc_pool: Option, @@ -362,10 +350,7 @@ impl RendererState { } } - fn draw(&mut self) - where - B::Surface: SurfaceTrait, - { + fn draw(&mut self) { if self.recreate_swapchain { self.recreate_swapchain(); self.recreate_swapchain = false; @@ -592,7 +577,8 @@ impl Drop for BackendState { feature = "vulkan", feature = "dx11", feature = "dx12", - feature = "metal" + feature = "metal", + feature = "gl", ))] fn create_backend( wb: winit::window::WindowBuilder, @@ -615,34 +601,6 @@ fn create_backend( } } -#[cfg(feature = "gl")] -fn create_backend( - wb: winit::window::WindowBuilder, - event_loop: &winit::event_loop::EventLoop<()>, -) -> BackendState { - let (context, window) = { - let builder = - back::config_context(back::glutin::ContextBuilder::new(), ColorFormat::SELF, None) - .with_vsync(true); - let windowed_context = builder.build_windowed(wb, event_loop).unwrap(); - unsafe { - windowed_context - .make_current() - .expect("Unable to make context current") - .split() - } - }; - - let surface = back::Surface::from_context(context); - let mut adapters = surface.enumerate_adapters(); - BackendState { - instance: None, - adapter: AdapterState::new(&mut adapters), - surface: ManuallyDrop::new(surface), - window, - } -} - struct AdapterState { adapter: Option>, memory_types: Vec, @@ -1672,8 +1630,6 @@ fn main() { *control_flow = winit::event_loop::ControlFlow::Exit } winit::event::WindowEvent::Resized(dims) => { - #[cfg(feature = "gl")] - renderer_state.backend.surface.get_context_t().resize(dims); println!("RESIZE EVENT"); renderer_state.recreate_swapchain = true; } diff --git a/examples/quad/main.rs b/examples/quad/main.rs index 79ee351fa7f..f292762d05d 100644 --- a/examples/quad/main.rs +++ b/examples/quad/main.rs @@ -5,7 +5,6 @@ feature = "dx12", feature = "metal", feature = "gl", - feature = "wgl" )), allow(dead_code, unused_extern_crates, unused_imports) )] @@ -14,7 +13,7 @@ extern crate gfx_backend_dx11 as back; #[cfg(feature = "dx12")] extern crate gfx_backend_dx12 as back; -#[cfg(any(feature = "gl", feature = "wgl"))] +#[cfg(any(feature = "gl"))] extern crate gfx_backend_gl as back; #[cfg(feature = "metal")] extern crate gfx_backend_metal as back; @@ -91,11 +90,12 @@ const COLOR_RANGE: i::SubresourceRange = i::SubresourceRange { feature = "dx12", feature = "metal", feature = "gl", - feature = "wgl" ))] fn main() { #[cfg(target_arch = "wasm32")] console_log::init_with_level(log::Level::Debug).unwrap(); + + #[cfg(not(target_arch = "wasm32"))] env_logger::init(); let event_loop = winit::event_loop::EventLoop::new(); @@ -111,38 +111,23 @@ fn main() { .with_title("quad".to_string()); // instantiate backend - #[cfg(not(feature = "gl"))] + #[cfg(not(target_arch = "wasm32"))] let (_window, instance, mut adapters, surface) = { let window = wb.build(&event_loop).unwrap(); let instance = back::Instance::create("gfx-rs quad", 1).expect("Failed to create an instance!"); + let adapters = instance.enumerate_adapters(); let surface = unsafe { instance .create_surface(&window) .expect("Failed to create a surface!") }; - let adapters = instance.enumerate_adapters(); // Return `window` so it is not dropped: dropping it invalidates `surface`. (window, Some(instance), adapters, surface) }; - #[cfg(feature = "gl")] + + #[cfg(target_arch = "wasm32")] let (_window, instance, mut adapters, surface) = { - #[cfg(not(target_arch = "wasm32"))] - let (window, surface) = { - let builder = - back::config_context(back::glutin::ContextBuilder::new(), ColorFormat::SELF, None) - .with_vsync(true); - let windowed_context = builder.build_windowed(wb, &event_loop).unwrap(); - let (context, window) = unsafe { - windowed_context - .make_current() - .expect("Unable to make context current") - .split() - }; - let surface = back::Surface::from_context(context); - (window, surface) - }; - #[cfg(target_arch = "wasm32")] let (window, surface) = { let window = wb.build(&event_loop).unwrap(); web_sys::window() @@ -151,7 +136,8 @@ fn main() { .unwrap() .body() .unwrap() - .append_child(&winit::platform::web::WindowExtWebSys::canvas(&window)); + .append_child(&winit::platform::web::WindowExtWebSys::canvas(&window)) + .unwrap(); let surface = back::Surface::from_raw_handle(&window); (window, surface) }; @@ -190,11 +176,6 @@ fn main() { } => *control_flow = winit::event_loop::ControlFlow::Exit, winit::event::WindowEvent::Resized(dims) => { println!("resized to {:?}", dims); - #[cfg(all(feature = "gl", not(target_arch = "wasm32")))] - { - let context = renderer.surface.context(); - context.resize(dims); - } renderer.dimensions = window::Extent2D { width: dims.width, height: dims.height, @@ -985,8 +966,7 @@ where feature = "dx12", feature = "metal", feature = "gl", - feature = "wgl" )))] fn main() { - println!("You need to enable the native API feature (vulkan/metal/dx11/dx12/gl/wgl) in order to run the example"); + println!("You need to enable the native API feature (vulkan/metal/dx11/dx12/gl) in order to run the example"); } diff --git a/src/backend/gl/Cargo.toml b/src/backend/gl/Cargo.toml index f43968c6ea4..383eb36476e 100644 --- a/src/backend/gl/Cargo.toml +++ b/src/backend/gl/Cargo.toml @@ -17,8 +17,9 @@ build = "build.rs" name = "gfx_backend_gl" [features] -default = [] -wgl = [] +default = ["wgl", "surfman", "surfman-x11"] +wgl = ["winapi"] +surfman-x11 = ["surfman/sm-x11"] [dependencies] arrayvec = "0.5" @@ -32,10 +33,12 @@ parking_lot = "0.10" spirv_cross = { version = "0.18", features = ["glsl"] } lazy_static = "1" raw-window-handle = "0.3" - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] glutin = { version = "0.23.0", optional = true } +[target.'cfg(all(unix, not(target_os = "ios")))'.dependencies] +# TODO: Update to released version when it comes out +surfman = { git = "https://github.com/servo/surfman.git", rev = "41ac1ee", features = ["sm-raw-window-handle"], optional = true } + [target.'cfg(target_arch = "wasm32")'.dependencies] js-sys = "0.3.6" wasm-bindgen = "0.2.51" @@ -61,7 +64,8 @@ features = [ ] [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["libloaderapi", "windef", "wingdi", "winuser"] } +winapi = { version = "0.3", features = ["libloaderapi", "windef", "wingdi", "winuser"], optional = true } [build-dependencies] gl_generator = "0.11" +cfg_aliases = "0.1.0" diff --git a/src/backend/gl/build.rs b/src/backend/gl/build.rs index 9fbd3c4a584..a58e344acfa 100644 --- a/src/backend/gl/build.rs +++ b/src/backend/gl/build.rs @@ -4,6 +4,21 @@ use std::fs::File; use std::path::PathBuf; fn main() { + // Setup cfg aliases + cfg_aliases::cfg_aliases! { + // Platforms + wasm: { target_arch = "wasm32" }, + android: { target_os = "android" }, + macos: { target_os = "macos" }, + ios: { target_os = "ios" }, + linux: { target_os = "linux" }, + // Backends + surfman: { all(unix, feature = "surfman", not(ios)) }, + wgl: { all(windows, feature = "wgl") }, + glutin: { all(feature = "glutin", not(any(wasm, surfman))) }, + dummy: { not(any(wasm, glutin, wgl, surfman)) }, + } + let target = env::var("TARGET").unwrap(); let dest = PathBuf::from(&env::var("OUT_DIR").unwrap()); diff --git a/src/backend/gl/src/device.rs b/src/backend/gl/src/device.rs index 160e334a3b5..ba334970451 100644 --- a/src/backend/gl/src/device.rs +++ b/src/backend/gl/src/device.rs @@ -874,7 +874,7 @@ impl d::Device for Device { // Sampler2D won't show up in UniformLocation and the only other uniforms // should be push constants uniforms.push(n::UniformDesc { - location: location as _, + location: Starc::new(location), offset, utype, }); @@ -1669,7 +1669,7 @@ impl d::Device for Device { } } - #[cfg(target_arch = "wasm32")] + #[cfg(wasm)] unsafe fn wait_for_fences( &self, fences: I, @@ -1860,9 +1860,10 @@ impl d::Device for Device { config: SwapchainConfig, _old_swapchain: Option, ) -> Result<(Swapchain, Vec), hal::window::CreationError> { + let gl = &self.share.context; - #[cfg(all(feature = "wgl", not(target_arch = "wasm32")))] + #[cfg(wgl)] let context = { use crate::window::wgl::PresentContext; @@ -1926,17 +1927,17 @@ impl d::Device for Device { images.push(image); } - #[cfg(all(feature = "wgl", not(target_arch = "wasm32")))] - let swapchain = { - self.share.instance_context.make_current(); - Swapchain { - fbos, - context, - extent: config.extent, - } + // Web + #[cfg(wasm)] + let _ = surface; + #[cfg(wasm)] + let swapchain = Swapchain { + fbos, + extent: config.extent, }; - #[cfg(all(feature = "glutin", not(target_arch = "wasm32")))] + // Glutin + #[cfg(glutin)] let swapchain = Swapchain { fbos, extent: config.extent, @@ -1949,16 +1950,28 @@ impl d::Device for Device { }, }; - #[cfg(target_arch = "wasm32")] - let _ = surface; - - #[cfg(target_arch = "wasm32")] + // Surfman + #[cfg(surfman)] let swapchain = Swapchain { fbos, extent: config.extent, + // TODO: Resize the context to the extent + context: surface.context.clone(), + }; + + // WGL + #[cfg(wgl)] + let swapchain = { + self.share.instance_context.make_current(); + Swapchain { + fbos, + context, + extent: config.extent, + } }; - #[cfg(not(any(target_arch = "wasm32", feature = "glutin", feature = "wgl")))] + // Dummy + #[cfg(dummy)] let swapchain = Swapchain { extent: { let _ = surface; diff --git a/src/backend/gl/src/info.rs b/src/backend/gl/src/info.rs index eba2a4192b4..c7136d898c8 100644 --- a/src/backend/gl/src/info.rs +++ b/src/backend/gl/src/info.rs @@ -262,17 +262,17 @@ impl Info { fn get(gl: &GlContainer) -> Info { let platform_name = PlatformName::get(gl); let version = Version::parse(get_string(gl, glow::VERSION).unwrap_or_default()).unwrap(); - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(wasm))] let shading_language = Version::parse(get_string(gl, glow::SHADING_LANGUAGE_VERSION).unwrap_or_default()) .unwrap(); - #[cfg(target_arch = "wasm32")] + #[cfg(wasm)] let shading_language = Version::new_embedded(3, 0, String::from("")); // TODO: Use separate path for WebGL extensions in `glow` somehow // Perhaps automatic fallback for NUM_EXTENSIONS to EXTENSIONS on native - #[cfg(target_arch = "wasm32")] + #[cfg(wasm)] let extensions = HashSet::new(); - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(wasm))] let extensions = if version >= Version::new(3, 0, None, String::from("")) { let num_exts = get_usize(gl, glow::NUM_EXTENSIONS).unwrap(); (0 .. num_exts) @@ -331,7 +331,7 @@ impl Info { } } -const IS_WEBGL: bool = cfg!(target_arch = "wasm32"); +const IS_WEBGL: bool = cfg!(wasm); /// Load the information pertaining to the driver and the corresponding device /// capabilities. @@ -351,7 +351,7 @@ pub(crate) fn query_all( let min_storage_buffer_offset_alignment = if IS_WEBGL { 1024 } else { - get_u64(gl, glow::SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT).unwrap_or(1024) + get_u64(gl, glow::SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT).unwrap_or(256) }; let mut limits = Limits { diff --git a/src/backend/gl/src/lib.rs b/src/backend/gl/src/lib.rs index 56ab936a1dc..98f16dc00a1 100644 --- a/src/backend/gl/src/lib.rs +++ b/src/backend/gl/src/lib.rs @@ -8,8 +8,9 @@ extern crate bitflags; #[macro_use] extern crate log; extern crate gfx_hal as hal; -#[cfg(all(feature = "glutin", not(target_arch = "wasm32")))] -pub extern crate glutin; + +#[cfg(surfman)] +use parking_lot::RwLock; use std::cell::Cell; use std::fmt; @@ -32,18 +33,33 @@ mod queue; mod state; mod window; -#[cfg(all(not(target_arch = "wasm32"), feature = "glutin"))] -pub use crate::window::glutin::{config_context, Headless, Surface, Swapchain}; -#[cfg(target_arch = "wasm32")] +// Web implementation +#[cfg(wasm)] pub use window::web::{Surface, Swapchain}; -#[cfg(all(feature = "wgl", not(target_arch = "wasm32")))] +// Glutin implementation +#[cfg(glutin)] +pub use crate::window::glutin::{Instance, Surface, Swapchain}; +#[cfg(glutin)] +pub use glutin; +#[cfg(glutin)] +pub use crate::window::glutin::config_context; + +// Surfman implementation +#[cfg(surfman)] +pub use crate::window::surfman::{Instance, Surface, Swapchain}; +// Helps windows detect discrete GPUs +#[cfg(surfman)] +surfman::declare_surfman!(); + +// WGL implementation +#[cfg(wgl)] use window::wgl::DeviceContext; - -#[cfg(all(feature = "wgl", not(target_arch = "wasm32")))] +#[cfg(wgl)] pub use window::wgl::{Instance, Surface, Swapchain}; -#[cfg(not(any(target_arch = "wasm32", feature = "glutin", feature = "wgl")))] +// Catch-all dummy implementation +#[cfg(dummy)] pub use window::dummy::{Surface, Swapchain}; pub use glow::Context as GlContext; @@ -53,15 +69,23 @@ type ColorSlot = u8; pub(crate) struct GlContainer { context: GlContext, + + #[cfg(surfman)] + surfman_device: Starc>, + + #[cfg(surfman)] + surfman_context: Starc>, } impl GlContainer { - #[cfg(feature = "glutin")] + #[cfg(not(wasm))] fn make_current(&self) { - // Unimplemented + // TODO: + // NOTE: Beware, calling this on dereference breaks the surfman backend + // I'm not sure if there would be similar concequences with other backends. } - #[cfg(not(target_arch = "wasm32"))] + #[cfg(any(glutin, wgl))] fn from_fn_proc(fn_proc: F) -> GlContainer where F: FnMut(&str) -> *const std::os::raw::c_void, @@ -70,7 +94,24 @@ impl GlContainer { GlContainer { context } } - #[cfg(target_arch = "wasm32")] + #[cfg(surfman)] + fn from_fn_proc( + fn_proc: F, + surfman_device: Starc>, + surfman_context: Starc>, + ) -> GlContainer + where + F: FnMut(&str) -> *const std::os::raw::c_void, + { + let context = glow::Context::from_loader_function(fn_proc); + GlContainer { + context, + surfman_device, + surfman_context, + } + } + + #[cfg(wasm)] fn from_canvas(canvas: &web_sys::HtmlCanvasElement) -> GlContainer { let context = { use wasm_bindgen::JsCast; @@ -102,23 +143,34 @@ impl GlContainer { impl Deref for GlContainer { type Target = GlContext; fn deref(&self) -> &GlContext { - #[cfg(all(feature = "glutin", not(target_arch = "wasm32")))] + #[cfg(not(wasm))] self.make_current(); &self.context } } +#[cfg(surfman)] +impl Drop for GlContainer { + fn drop(&mut self) { + // Contexts must be manually destroyed to prevent a panic + self.surfman_device + .read() + .destroy_context(&mut self.surfman_context.write()) + .expect("TODO"); + } +} + #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] pub enum Backend {} impl hal::Backend for Backend { - #[cfg(any(all(not(target_arch = "wasm32"), feature = "glutin"), feature = "wgl"))] + #[cfg(not(any(wasm, dummy)))] type Instance = Instance; - #[cfg(all(target_arch = "wasm32", not(feature = "wgl")))] + #[cfg(wasm)] type Instance = Surface; - #[cfg(not(any(target_arch = "wasm32", feature = "glutin", feature = "wgl")))] + #[cfg(dummy)] type Instance = DummyInstance; type PhysicalDevice = PhysicalDevice; @@ -183,6 +235,7 @@ impl Error { } } +#[cfg(not(wasm))] fn debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, message: &str) { let source_str = match source { glow::DEBUG_SOURCE_API => "API", @@ -397,7 +450,7 @@ unsafe impl Sync for Wstarc {} #[derive(Debug)] pub struct PhysicalDevice(Starc); -#[cfg(any(target_arch = "wasm32", not(feature = "wgl")))] +#[cfg(not(wgl))] type DeviceContext = (); impl PhysicalDevice { @@ -595,7 +648,7 @@ impl adapter::PhysicalDevice for PhysicalDevice { // initialize permanent states let gl = &self.0.context; - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(wasm))] { if cfg!(debug_assertions) && gl.supports_debug() { gl.enable(glow::DEBUG_OUTPUT); @@ -714,10 +767,10 @@ impl q::QueueFamily for QueueFamily { } } -#[cfg(not(any(target_arch = "wasm32", feature = "glutin", feature = "wgl")))] +#[cfg(dummy)] pub struct DummyInstance; -#[cfg(not(any(target_arch = "wasm32", feature = "glutin", feature = "wgl")))] +#[cfg(dummy)] impl hal::Instance for DummyInstance { fn create(_: &str, _: u32) -> Result { unimplemented!() @@ -736,42 +789,10 @@ impl hal::Instance for DummyInstance { } } -#[cfg(all(feature = "glutin", not(target_arch = "wasm32")))] -#[derive(Debug)] -pub enum Instance { - Headless(Headless), - Surface(Surface), -} - -#[cfg(all(feature = "glutin", not(target_arch = "wasm32")))] -impl hal::Instance for Instance { - fn create(name: &str, version: u32) -> Result { - Headless::create(name, version).map(Instance::Headless) - } - - fn enumerate_adapters(&self) -> Vec> { - match self { - Instance::Headless(instance) => instance.enumerate_adapters(), - Instance::Surface(instance) => instance.enumerate_adapters(), - } - } - - unsafe fn create_surface( - &self, - _: &impl raw_window_handle::HasRawWindowHandle, - ) -> Result { - unimplemented!() - } - - unsafe fn destroy_surface(&self, _surface: Surface) { - // TODO: Implement Surface cleanup - } -} - fn resolve_sub_range( sub: &buffer::SubRange, whole: Range, ) -> Range { let end = sub.size.map_or(whole.end, |s| whole.start + sub.offset + s); whole.start + sub.offset .. end -} +} \ No newline at end of file diff --git a/src/backend/gl/src/native.rs b/src/backend/gl/src/native.rs index 59d8337148f..654647ee3a3 100644 --- a/src/backend/gl/src/native.rs +++ b/src/backend/gl/src/native.rs @@ -21,7 +21,9 @@ pub type Program = ::Program; pub type Renderbuffer = ::Renderbuffer; pub type Texture = ::Texture; pub type Sampler = ::Sampler; -pub type UniformLocation = ::UniformLocation; +// TODO: UniformLocation was copy in glow 0.3, but in 0.4 it isn't. Wrap it in a Starc for now +// to make it `Sync + Send` instead. +pub type UniformLocation = crate::Starc<::UniformLocation>; pub type DescriptorSetLayout = Vec; pub type RawFrameBuffer = ::Framebuffer; @@ -312,7 +314,7 @@ pub struct AttributeDesc { pub(crate) vertex_attrib_fn: VertexAttribFunction, } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Debug)] pub struct UniformDesc { pub(crate) location: UniformLocation, pub(crate) offset: u32, diff --git a/src/backend/gl/src/queue.rs b/src/backend/gl/src/queue.rs index 17dcf93d8b1..5533a20a88f 100644 --- a/src/backend/gl/src/queue.rs +++ b/src/backend/gl/src/queue.rs @@ -5,17 +5,8 @@ use glow::HasContext; use smallvec::SmallVec; use crate::{ - command as com, - device, - info::LegacyFeatures, - native, - state, - Backend, - GlContext, - Share, - Starc, - Surface, - Swapchain, + command as com, device, info::LegacyFeatures, native, state, Backend, GlContext, Share, Starc, + Surface, Swapchain, }; // State caching system for command queue. @@ -209,19 +200,44 @@ impl CommandQueue { /// Return a reference to a stored data object. fn get_raw(data: &[u8], ptr: com::BufferSlice) -> &[u8] { assert!(data.len() >= (ptr.offset + ptr.size) as usize); - &data[ptr.offset as usize .. (ptr.offset + ptr.size) as usize] + &data[ptr.offset as usize..(ptr.offset + ptr.size) as usize] } fn present_by_copy(&self, swapchain: &Swapchain, index: hal::window::SwapImageIndex) { let gl = &self.share.context; let extent = swapchain.extent; - #[cfg(feature = "wgl")] + #[cfg(wgl)] swapchain.make_current(); + #[cfg(surfman)] + gl.surfman_device + .write() + .make_context_current(&swapchain.context.read()) + .unwrap(); + + // Use the framebuffer from the surfman context + #[cfg(surfman)] + let fbo = gl + .surfman_device + .read() + .context_surface_info(&swapchain.context.read()) + .unwrap() + .unwrap() + .framebuffer_object; + unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(swapchain.fbos[index as usize])); - gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None); + gl.bind_framebuffer( + glow::DRAW_FRAMEBUFFER, + #[cfg(surfman)] + match fbo { + 0 => None, + other => Some(other), + }, + #[cfg(not(surfman))] + None, + ); gl.blit_framebuffer( 0, 0, @@ -236,9 +252,29 @@ impl CommandQueue { ); } - #[cfg(all(feature = "glutin", not(target_arch = "wasm32")))] + // Present the surfman surface + #[cfg(surfman)] + { + let mut surface = gl + .surfman_device + .read() + .unbind_surface_from_context(&mut swapchain.context.write()) + .expect("TODO") + .expect("TODO"); + gl.surfman_device + .read() + .present_surface(&gl.surfman_context.read(), &mut surface) + .expect("TODO"); + gl.surfman_device + .read() + .bind_surface_to_context(&mut swapchain.context.write(), surface) + .expect("TODO") + } + + #[cfg(glutin)] swapchain.context.swap_buffers().unwrap(); - #[cfg(all(feature = "wgl", not(target_arch = "wasm32")))] + + #[cfg(wgl)] swapchain.swap_buffers(); } @@ -277,12 +313,11 @@ impl CommandQueue { }; } else if self.state.num_viewports > 1 { // 16 viewports is a common limit set in drivers. - let viewports: SmallVec<[[f32; 4]; 16]> = (0 .. self.state.num_viewports) + let viewports: SmallVec<[[f32; 4]; 16]> = (0..self.state.num_viewports) .map(|_| [0.0, 0.0, 0.0, 0.0]) .collect(); - let depth_ranges: SmallVec<[[f64; 2]; 16]> = (0 .. self.state.num_viewports) - .map(|_| [0.0, 0.0]) - .collect(); + let depth_ranges: SmallVec<[[f64; 2]; 16]> = + (0..self.state.num_viewports).map(|_| [0.0, 0.0]).collect(); unsafe { gl.viewport_f32_slice(0, viewports.len() as i32, &viewports); gl.depth_range_f64_slice(0, depth_ranges.len() as i32, &depth_ranges); @@ -294,9 +329,8 @@ impl CommandQueue { unsafe { gl.scissor(0, 0, 0, 0) }; } else if self.state.num_scissors > 1 { // 16 viewports is a common limit set in drivers. - let scissors: SmallVec<[[i32; 4]; 16]> = (0 .. self.state.num_scissors) - .map(|_| [0, 0, 0, 0]) - .collect(); + let scissors: SmallVec<[[i32; 4]; 16]> = + (0..self.state.num_scissors).map(|_| [0, 0, 0, 0]).collect(); unsafe { gl.scissor_slice(0, scissors.len() as i32, scissors.as_slice()) }; } } @@ -316,7 +350,7 @@ impl CommandQueue { } => { let gl = &self.share.context; let legacy = &self.share.legacy_features; - if instances == &(0u32 .. 1) { + if instances == &(0u32..1) { unsafe { gl.draw_arrays( primitive, @@ -365,7 +399,7 @@ impl CommandQueue { let legacy = &self.share.legacy_features; let hints = &self.share.hints; - if instances == &(0u32 .. 1) { + if instances == &(0u32..1) { if base_vertex == 0 { unsafe { gl.draw_elements( @@ -887,60 +921,60 @@ impl CommandQueue { com::Command::UnbindAttribute(slot) => unsafe { self.share.context.DisableVertexAttribArray(slot as gl::types::GLuint); },*/ - com::Command::BindUniform { uniform, buffer } => { + com::Command::BindUniform { ref uniform, buffer } => { let gl = &self.share.context; unsafe { match uniform.utype { glow::FLOAT => { let data = Self::get::(data_buf, buffer)[0]; - gl.uniform_1_f32(Some(uniform.location), data); + gl.uniform_1_f32(Some((*uniform.location).clone()), data); } glow::FLOAT_VEC2 => { // TODO: Remove`mut` let mut data = Self::get::<[f32; 2]>(data_buf, buffer)[0]; - gl.uniform_2_f32_slice(Some(uniform.location), &mut data); + gl.uniform_2_f32_slice(Some((*uniform.location).clone()), &mut data); } glow::FLOAT_VEC3 => { // TODO: Remove`mut` let mut data = Self::get::<[f32; 3]>(data_buf, buffer)[0]; - gl.uniform_3_f32_slice(Some(uniform.location), &mut data); + gl.uniform_3_f32_slice(Some((*uniform.location).clone()), &mut data); } glow::FLOAT_VEC4 => { // TODO: Remove`mut` let mut data = Self::get::<[f32; 4]>(data_buf, buffer)[0]; - gl.uniform_4_f32_slice(Some(uniform.location), &mut data); + gl.uniform_4_f32_slice(Some((*uniform.location).clone()), &mut data); } glow::INT => { let data = Self::get::(data_buf, buffer)[0]; - gl.uniform_1_i32(Some(uniform.location), data); + gl.uniform_1_i32(Some((*uniform.location).clone()), data); } glow::INT_VEC2 => { // TODO: Remove`mut` let mut data = Self::get::<[i32; 2]>(data_buf, buffer)[0]; - gl.uniform_2_i32_slice(Some(uniform.location), &mut data); + gl.uniform_2_i32_slice(Some((*uniform.location).clone()), &mut data); } glow::INT_VEC3 => { // TODO: Remove`mut` let mut data = Self::get::<[i32; 3]>(data_buf, buffer)[0]; - gl.uniform_3_i32_slice(Some(uniform.location), &mut data); + gl.uniform_3_i32_slice(Some((*uniform.location).clone()), &mut data); } glow::INT_VEC4 => { // TODO: Remove`mut` let mut data = Self::get::<[i32; 4]>(data_buf, buffer)[0]; - gl.uniform_4_i32_slice(Some(uniform.location), &mut data); + gl.uniform_4_i32_slice(Some((*uniform.location).clone()), &mut data); } glow::FLOAT_MAT2 => { let data = Self::get::<[f32; 4]>(data_buf, buffer)[0]; - gl.uniform_matrix_2_f32_slice(Some(uniform.location), false, &data); + gl.uniform_matrix_2_f32_slice(Some((*uniform.location).clone()), false, &data); } glow::FLOAT_MAT3 => { let data = Self::get::<[f32; 9]>(data_buf, buffer)[0]; - gl.uniform_matrix_3_f32_slice(Some(uniform.location), false, &data); + gl.uniform_matrix_3_f32_slice(Some((*uniform.location).clone()), false, &data); } glow::FLOAT_MAT4 => { let data = Self::get::<[f32; 16]>(data_buf, buffer)[0]; - gl.uniform_matrix_4_f32_slice(Some(uniform.location), false, &data); + gl.uniform_matrix_4_f32_slice(Some((*uniform.location).clone()), false, &data); } _ => panic!("Unsupported uniform datatype!"), } @@ -1117,7 +1151,7 @@ impl hal::queue::CommandQueue for CommandQueue { assert!(buffer.commands.len() >= (cb.buf.offset + cb.buf.size) as usize); let commands = &buffer.commands - [cb.buf.offset as usize .. (cb.buf.offset + cb.buf.size) as usize]; + [cb.buf.offset as usize..(cb.buf.offset + cb.buf.size) as usize]; self.reset_state(); for com in commands { self.process(com, &buffer.data); @@ -1155,7 +1189,7 @@ impl hal::queue::CommandQueue for CommandQueue { self.present_by_copy(swapchain.borrow(), index); } - #[cfg(all(feature = "wgl", not(target_arch = "wasm32")))] + #[cfg(wgl)] self.share.instance_context.make_current(); Ok(None) @@ -1173,7 +1207,7 @@ impl hal::queue::CommandQueue for CommandQueue { .expect("No swapchain is configured!"); self.present_by_copy(swapchain, 0); - #[cfg(all(feature = "wgl", not(target_arch = "wasm32")))] + #[cfg(wgl)] self.share.instance_context.make_current(); Ok(None) diff --git a/src/backend/gl/src/window/glutin.rs b/src/backend/gl/src/window/glutin.rs index b165126bbb0..685825a84db 100644 --- a/src/backend/gl/src/window/glutin.rs +++ b/src/backend/gl/src/window/glutin.rs @@ -50,9 +50,13 @@ use crate::{conv, native, Backend as B, Device, GlContainer, PhysicalDevice, QueueFamily, Starc}; use hal::{adapter::Adapter, format as f, image, window}; +use std::ffi::c_void; +use std::os::raw::c_ulong; +use std::sync::Arc; + use arrayvec::ArrayVec; use glow::HasContext; -use glutin; +use glutin::{self, platform::unix::RawContextExt}; use std::iter; @@ -78,6 +82,128 @@ impl window::Swapchain for Swapchain { } } +#[derive(Debug)] +pub enum Instance { + Headless(Headless), + Surface(Surface), +} + +impl Instance { + pub fn create_surface_from_wayland( + &self, + display: *mut c_void, + surface: *mut c_void, + ) -> Surface { + log::trace!("Creating GL surface from wayland"); + let context = unsafe { + glutin::ContextBuilder::new() + .with_vsync(true) + .build_raw_wayland_context( + display as _, + surface, + /*TODO: do something with these dimensions*/ + 400, + 400, + ) + .expect("TODO: handle this error") + }; + let context = unsafe { context.make_current().expect("TODO: handle this error") }; + Surface::from_context(context) + } + + pub fn create_surface_from_xlib(&self, window: c_ulong, display: *mut c_void) -> Surface { + log::trace!("Creating GL surface from Xlib"); + let xconn = { + // This is taken from `glutin::platform::unix::x11::XConnection::new except with tweaks + // that allow us to create the connection with an existing display pointer + use glutin::platform::unix::x11::{ffi, XConnection}; + // opening the libraries + let xlib = ffi::Xlib::open().expect("TODO: Handle error"); + let xcursor = ffi::Xcursor::open().expect("TODO: Handle error"); + let xrandr = ffi::Xrandr_2_2_0::open().expect("TODO: Handle error"); + let xrandr_1_5 = ffi::Xrandr::open().ok(); + let xinput2 = ffi::XInput2::open().expect("TODO: Handle error"); + let xlib_xcb = ffi::Xlib_xcb::open().expect("TODO: Handle error"); + let xrender = ffi::Xrender::open().expect("TODO: Handle error"); + + unsafe { (xlib.XInitThreads)() }; + // unsafe { (xlib.XSetErrorHandler)(error_handler) }; + + // Get X11 socket file descriptor + let fd = unsafe { (xlib.XConnectionNumber)(display as *mut ffi::_XDisplay) }; + + XConnection { + xlib, + xrandr, + xrandr_1_5, + xcursor, + xinput2, + xlib_xcb, + xrender, + display: display as _, + x11_fd: fd, + latest_error: parking_lot::Mutex::new(None), + cursor_cache: Default::default(), + } + }; + let xconn = Arc::new(xconn); + + let context = unsafe { + glutin::ContextBuilder::new() + .with_vsync(true) + .build_raw_x11_context(xconn, window) + .expect("TODO: handle this error") + }; + let context = unsafe { context.make_current().expect("TODO: handle this error") }; + Surface::from_context(context) + } +} + +impl hal::Instance for Instance { + fn create(name: &str, version: u32) -> Result { + Headless::create(name, version).map(Instance::Headless) + } + + fn enumerate_adapters(&self) -> Vec> { + match self { + Instance::Headless(instance) => instance.enumerate_adapters(), + Instance::Surface(instance) => instance.enumerate_adapters(), + } + } + + unsafe fn create_surface( + &self, + has_handle: &impl raw_window_handle::HasRawWindowHandle, + ) -> Result { + use raw_window_handle::RawWindowHandle; + + match self { + Instance::Headless(instance) => instance.create_surface(has_handle), + Instance::Surface(instance) => instance.create_surface(has_handle), + } + .expect("TODO"); + + match has_handle.raw_window_handle() { + #[cfg(all(unix, not(android), not(macos)))] + RawWindowHandle::Wayland(handle) => { + Ok(self.create_surface_from_wayland(handle.display, handle.surface)) + } + #[cfg(all(unix, not(android), not(macos)))] + RawWindowHandle::Xlib(handle) => { + Ok(self.create_surface_from_xlib(handle.window, handle.display)) + } + _ => Err(hal::window::InitError::UnsupportedWindowHandle), + } + } + + unsafe fn destroy_surface(&self, surface: Surface) { + match self { + Instance::Headless(instance) => instance.destroy_surface(surface), + Instance::Surface(instance) => instance.destroy_surface(surface), + } + } +} + //TODO: if we make `Surface` a `WindowBuilder` instead of `RawContext`, // we could spawn window + GL context when a swapchain is requested // and actually respect the swapchain configuration provided by the user. @@ -193,15 +319,15 @@ impl window::Surface for Surface { present_modes: window::PresentMode::FIFO, //TODO composite_alpha_modes: window::CompositeAlphaMode::OPAQUE, //TODO image_count: if self.context.get_pixel_format().double_buffer { - 2 ..= 2 + 2..=2 } else { - 1 ..= 1 + 1..=1 }, current_extent: None, extents: window::Extent2D { width: 4, height: 4, - } ..= window::Extent2D { + }..=window::Extent2D { width: 4096, height: 4096, }, @@ -240,6 +366,7 @@ impl hal::Instance for Surface { } } +// This isn't used anymore according to the linter. Keeping it commented just in case. pub fn config_context( builder: glutin::ContextBuilder, color_format: f::Format, @@ -273,7 +400,7 @@ impl Headless { impl hal::Instance for Headless { fn create(_: &str, _: u32) -> Result { let context: glutin::Context; - #[cfg(target_os = "linux")] + #[cfg(linux)] { /// TODO: Update portability to make this more flexible use glutin::platform::unix::HeadlessContextExt; @@ -284,7 +411,7 @@ impl hal::Instance for Headless { hal::UnsupportedBackend })?; } - #[cfg(not(target_os = "linux"))] + #[cfg(not(linux))] { context = unimplemented!(); } diff --git a/src/backend/gl/src/window/mod.rs b/src/backend/gl/src/window/mod.rs index 7088e31f82e..8f7ad30bcf1 100644 --- a/src/backend/gl/src/window/mod.rs +++ b/src/backend/gl/src/window/mod.rs @@ -1,11 +1,14 @@ -#[cfg(all(feature = "glutin", not(target_arch = "wasm32")))] +#[cfg(wasm)] +pub mod web; + +#[cfg(glutin)] pub mod glutin; -#[cfg(target_arch = "wasm32")] -pub mod web; +#[cfg(surfman)] +pub mod surfman; -#[cfg(all(feature = "wgl", not(target_arch = "wasm32")))] +#[cfg(wgl)] pub mod wgl; -#[cfg(not(any(target_arch = "wasm32", feature = "glutin", feature = "wgl")))] +#[cfg(dummy)] pub mod dummy; diff --git a/src/backend/gl/src/window/surfman.rs b/src/backend/gl/src/window/surfman.rs new file mode 100644 index 00000000000..fcfc3ac0c8b --- /dev/null +++ b/src/backend/gl/src/window/surfman.rs @@ -0,0 +1,346 @@ +//! [Surfman](https://github.com/pcwalton/surfman)-based OpenGL backend for GFX-hal + +use crate::{conv, native, Backend as B, Device, GlContainer, PhysicalDevice, QueueFamily, Starc}; +use hal::{adapter::Adapter, format as f, image, window}; + +use arrayvec::ArrayVec; +use glow::HasContext; +use parking_lot::RwLock; +use surfman as sm; + +use std::cell::RefCell; +use std::fmt; +use std::iter; + +#[derive(Debug)] +pub struct Swapchain { + // Underlying window, required for presentation + pub(crate) context: Starc>, + // Extent because the window lies + pub(crate) extent: window::Extent2D, + /// + pub(crate) fbos: ArrayVec<[native::RawFrameBuffer; 3]>, +} + +impl window::Swapchain for Swapchain { + unsafe fn acquire_image( + &mut self, + _timeout_ns: u64, + _semaphore: Option<&native::Semaphore>, + _fence: Option<&native::Fence>, + ) -> Result<(window::SwapImageIndex, Option), window::AcquireError> { + // TODO: sync + Ok((0, None)) + } +} + +thread_local! { + /// The thread-local surfman connection + static SM_CONN: RefCell = + RefCell::new(sm::Connection::new().expect("TODO")); +} + +pub struct Instance { + hardware_adapter: sm::Adapter, + // TODO: We're not using these yet, but leave them here for later + #[allow(dead_code)] + low_power_adapter: sm::Adapter, + #[allow(dead_code)] + software_adapter: sm::Adapter, +} + +impl fmt::Debug for Instance { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Instance").field(&["Adapter..."; 3]).finish() + } +} + +impl Instance { + fn get_default_context_attributes() -> sm::ContextAttributes { + sm::ContextAttributes { + version: sm::GLVersion::new(3, 3), // TODO: Figure out how to determine GL version + // TODO: Skipping COMPATIBILITY_PROFILE for now, because it panics with a TODO, but + // that is probably something we want to provide later. + flags: sm::ContextAttributeFlags::ALPHA, + } + } + + pub unsafe fn create_surface_from_rwh( + &self, + raw_handle: raw_window_handle::RawWindowHandle, + ) -> Surface { + // Get context attributes + let context_attributes = Self::get_default_context_attributes(); + + // Open a device for the surface + // TODO: Assume hardware adapter + let mut device = SM_CONN + .with(|c| c.borrow().create_device(&self.hardware_adapter)) + .expect("TODO"); + + // Create context descriptor + let context_descriptor = device + .create_context_descriptor(&context_attributes) + .expect("TODO"); + + // Create context + let mut context = device.create_context(&context_descriptor).expect("TODO"); + + // Create the surface with the context + let surface = device + .create_surface( + &context, + surfman::SurfaceAccess::GPUOnly, + surfman::SurfaceType::Widget { + // Create a native widget for the raw window handle + native_widget: SM_CONN.with(|c| { + c.borrow() + .create_native_widget_from_rwh(raw_handle) + .expect("TODO") + }), + }, + ) + .expect("TODO"); + + // Bind surface to context + device + .bind_surface_to_context(&mut context, surface) + .expect("TODO"); + + device.make_context_current(&context).expect("TODO"); + + // Create a surface with the given context + Surface { + renderbuffer: None, + swapchain: None, + context: Starc::new(RwLock::new(context)), + device: Starc::new(RwLock::new(device)), + } + } +} + +impl hal::Instance for Instance { + fn create(_: &str, _: u32) -> Result { + Ok(Instance { + hardware_adapter: SM_CONN.with(|c| c.borrow().create_hardware_adapter().expect("TODO")), + low_power_adapter: SM_CONN + .with(|c| c.borrow().create_low_power_adapter().expect("TODO")), + software_adapter: SM_CONN.with(|c| c.borrow().create_software_adapter().expect("TODO")), + }) + } + + fn enumerate_adapters(&self) -> Vec> { + let mut adapters = Vec::with_capacity(3); + + let context_attributes = Self::get_default_context_attributes(); + + for surfman_adapter in &[ + &self.hardware_adapter, + &self.low_power_adapter, + &self.software_adapter, + ] { + // Create a surfman device + let mut device = + SM_CONN.with(|c| c.borrow().create_device(surfman_adapter).expect("TODO")); + + // Create context descriptor + let context_descriptor = device + .create_context_descriptor(&context_attributes) + .expect("TODO"); + + // Create context + let context = device.create_context(&context_descriptor).expect("TODO"); + // Make context current + device.make_context_current(&context).expect("TODO"); + + // Wrap in Starc> + let context = Starc::new(RwLock::new(context)); + let context_ = context.clone(); + let device = Starc::new(RwLock::new(device)); + let device_ = device.clone(); + + // Create gl container + let gl = GlContainer::from_fn_proc( + |symbol_name| { + device_ + .write() + .get_proc_address(&context_.read(), symbol_name) + as *const _ + }, + device, + context, + ); + + // Create physical device + adapters.push(PhysicalDevice::new_adapter((), gl)); + } + + adapters + } + + unsafe fn create_surface( + &self, + has_handle: &impl raw_window_handle::HasRawWindowHandle, + ) -> Result { + Ok(self.create_surface_from_rwh(has_handle.raw_window_handle())) + } + + unsafe fn destroy_surface(&self, _surface: Surface) {} +} + +#[derive(Debug)] +pub struct Surface { + pub(crate) swapchain: Option, + pub(crate) context: Starc>, + device: Starc>, + renderbuffer: Option, +} + +impl Surface { + /// Make the surface's gl context the current context + pub fn make_context_current(&self) { + self.device + .write() + .make_context_current(&self.context.read()) + .expect("TODO"); + } + + pub fn context(&self) -> Starc> { + self.context.clone() + } + + fn swapchain_formats(&self) -> Vec { + // TODO: Make sure this is correct. I believe it is. Reference: + // https://github.com/pcwalton/surfman/blob/master/surfman/src/context.rs#L34-L37 + vec![f::Format::Rgba8Srgb, f::Format::Bgra8Srgb] + } +} + +impl Drop for Surface { + fn drop(&mut self) { + // Unbind and get the underlying surface from the context + let surface = self + .device + .read() + .unbind_surface_from_context(&mut self.context.write()) + .expect("TODO"); + + if let Some(mut surface) = surface { + // Destroy the underlying surface + self.device + .read() + .destroy_surface(&mut self.context.write(), &mut surface) + .expect("TODO"); + } + + // Destroy the backing context + self.device + .read() + .destroy_context(&mut self.context.write()) + .expect("TODO"); + } +} + +impl window::PresentationSurface for Surface { + type SwapchainImage = native::ImageView; + + unsafe fn configure_swapchain( + &mut self, + device: &Device, + config: window::SwapchainConfig, + ) -> Result<(), window::CreationError> { + let gl = &device.share.context; + + if let Some(old) = self.swapchain.take() { + for fbo in old.fbos { + gl.delete_framebuffer(fbo); + } + } + + if self.renderbuffer.is_none() { + self.renderbuffer = Some(gl.create_renderbuffer().unwrap()); + } + + let desc = conv::describe_format(config.format).unwrap(); + gl.bind_renderbuffer(glow::RENDERBUFFER, self.renderbuffer); + gl.renderbuffer_storage( + glow::RENDERBUFFER, + desc.tex_internal, + config.extent.width as i32, + config.extent.height as i32, + ); + + // let fbo = surface_info.framebuffer_object; + let fbo = gl.create_framebuffer().unwrap(); + gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(fbo)); + gl.framebuffer_renderbuffer( + glow::READ_FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + glow::RENDERBUFFER, + self.renderbuffer, + ); + self.swapchain = Some(Swapchain { + context: self.context.clone(), + extent: config.extent, + fbos: iter::once(fbo).collect(), + // out_fbo: Some(surface_info.framebuffer_object), + }); + + Ok(()) + } + + unsafe fn unconfigure_swapchain(&mut self, device: &Device) { + let gl = &device.share.context; + if let Some(old) = self.swapchain.take() { + for fbo in old.fbos { + gl.delete_framebuffer(fbo); + } + } + if let Some(rbo) = self.renderbuffer.take() { + gl.delete_renderbuffer(rbo); + } + } + + unsafe fn acquire_image( + &mut self, + _timeout_ns: u64, + ) -> Result<(Self::SwapchainImage, Option), window::AcquireError> { + let image = native::ImageView::Renderbuffer(self.renderbuffer.unwrap()); + Ok((image, None)) + } +} + +impl window::Surface for Surface { + fn supports_queue_family(&self, _: &QueueFamily) -> bool { + self.make_context_current(); + true + } + + fn capabilities(&self, _physical_device: &PhysicalDevice) -> window::SurfaceCapabilities { + window::SurfaceCapabilities { + present_modes: window::PresentMode::FIFO, //TODO + composite_alpha_modes: window::CompositeAlphaMode::OPAQUE, //TODO + // TODO: Figure out how to get pixel format from surfman + // image_count: if self.context.get_pixel_format().double_buffer { + // 2..=2 + // } else { + // 1..=1 + // }, + image_count: 2..=2, + current_extent: None, + extents: window::Extent2D { + width: 4, + height: 4, + }..=window::Extent2D { + width: 4096, + height: 4096, + }, + max_image_layers: 1, + usage: image::Usage::COLOR_ATTACHMENT | image::Usage::TRANSFER_SRC, + } + } + + fn supported_formats(&self, _physical_device: &PhysicalDevice) -> Option> { + Some(self.swapchain_formats()) + } +} diff --git a/src/backend/gl/src/window/web.rs b/src/backend/gl/src/window/web.rs index f9c3be36079..7daa6d89083 100644 --- a/src/backend/gl/src/window/web.rs +++ b/src/backend/gl/src/window/web.rs @@ -14,9 +14,6 @@ use hal::{adapter::Adapter, format as f, image, window}; use std::iter; use wasm_bindgen::JsCast; -#[cfg(feature = "winit")] -use winit::{platform::web::WindowExtWebSys, window::Window}; - #[derive(Clone, Debug)] pub struct Swapchain { pub(crate) extent: window::Extent2D, diff --git a/src/warden/Cargo.toml b/src/warden/Cargo.toml index 3218bfb4e84..9f17f9c377b 100644 --- a/src/warden/Cargo.toml +++ b/src/warden/Cargo.toml @@ -24,7 +24,6 @@ dx12 = ["gfx-backend-dx12"] dx11 = ["gfx-backend-dx11"] metal = ["gfx-backend-metal"] gl = ["gfx-backend-gl"] -gl-ci = ["gfx-backend-gl"] # "glsl-to-spirv" #TODO: keep Warden backend-agnostic? @@ -61,7 +60,6 @@ optional = true [dependencies.gfx-backend-gl] path = "../../src/backend/gl" version = "0.5" -features = ["glutin"] optional = true [[example]] diff --git a/src/warden/src/bin/bench.rs b/src/warden/src/bin/bench.rs index be30daab765..bba181870ca 100644 --- a/src/warden/src/bin/bench.rs +++ b/src/warden/src/bin/bench.rs @@ -5,7 +5,6 @@ feature = "dx11", feature = "metal", feature = "gl", - feature = "gl-ci" )), allow(dead_code) )] @@ -91,7 +90,6 @@ impl Harness { Harness { base_path, suite } } - #[cfg_attr(any(feature = "gl", feature = "gl-ci"), allow(dead_code))] fn run(&self, name: &str, disabilities: Disabilities) { println!("Benching {}:", name); let instance = B::Instance::create("warden", 1).unwrap(); @@ -199,15 +197,7 @@ fn main() { } #[cfg(feature = "gl")] { - println!("Benching GL:"); - let instance = warden::init_gl_surface(); - harness.run_instance(instance, Disabilities::default()); - } - #[cfg(feature = "gl-ci")] - { - println!("Benching GL on CI:"); - let instance = warden::init_gl_on_ci(); - harness.run_instance(instance, Disabilities::default()); + harness.run::("GL", Disabilities::default()); } #[cfg(not(any( feature = "vulkan", @@ -215,7 +205,6 @@ fn main() { feature = "dx11", feature = "metal", feature = "gl", - feature = "gl-ci" )))] { println!("No backend selected!"); diff --git a/src/warden/src/bin/reftest.rs b/src/warden/src/bin/reftest.rs index 78ecbcf6adc..999ab0ada8a 100644 --- a/src/warden/src/bin/reftest.rs +++ b/src/warden/src/bin/reftest.rs @@ -5,7 +5,6 @@ feature = "dx11", feature = "metal", feature = "gl", - feature = "gl-ci" )), allow(dead_code) )] @@ -100,7 +99,6 @@ impl Harness { Harness { base_path, suite } } - #[cfg_attr(any(feature = "gl", feature = "gl-ci"), allow(dead_code))] fn run(&self, name: &str, disabilities: Disabilities) -> usize { println!("Testing {}:", name); let instance = B::Instance::create("warden", 1).unwrap(); @@ -237,15 +235,7 @@ fn main() { } #[cfg(feature = "gl")] { - println!("Testing GL:"); - let instance = warden::init_gl_surface(); - num_failures += harness.run_instance(instance, Disabilities::default()); - } - #[cfg(feature = "gl-ci")] - { - println!("Testing GL on CI:"); - let instance = warden::init_gl_on_ci(); - num_failures += harness.run_instance(instance, Disabilities::default()); + num_failures += harness.run::("GL", Disabilities::default()); } let _ = harness; num_failures += 0; // mark as mutated diff --git a/src/warden/src/lib.rs b/src/warden/src/lib.rs index 06f3f3451d1..10810257c55 100644 --- a/src/warden/src/lib.rs +++ b/src/warden/src/lib.rs @@ -9,47 +9,6 @@ extern crate serde; pub mod gpu; pub mod raw; -#[cfg(feature = "gl")] -pub fn init_gl_surface() -> gfx_backend_gl::Surface { - use gfx_backend_gl::glutin; - - let events_loop = glutin::event_loop::EventLoop::new(); - let windowed_context = glutin::ContextBuilder::new() - .with_gl_profile(glutin::GlProfile::Core) - .build_windowed(glutin::window::WindowBuilder::new(), &events_loop) - .unwrap(); - let (context, _window) = unsafe { - windowed_context - .make_current() - .expect("Unable to make window current") - .split() - }; - - gfx_backend_gl::Surface::from_context(context) -} - -#[cfg(feature = "gl-ci")] -pub fn init_gl_on_ci() -> gfx_backend_gl::Headless { - use gfx_backend_gl::glutin; - - let events_loop = glutin::event_loop::EventLoop::new(); - let context; - #[cfg(all(unix, not(target_vendor = "apple")))] - { - use gfx_backend_gl::glutin::platform::unix::HeadlessContextExt as _; - context = glutin::ContextBuilder::new().build_surfaceless(&events_loop); - } - #[cfg(any(not(unix), target_vendor = "apple"))] - { - context = glutin::ContextBuilder::new() - .build_headless(&events_loop, glutin::dpi::PhysicalSize::new(0, 0)); - } - let current_context = - unsafe { context.unwrap().make_current() }.expect("Unable to make context current"); - - gfx_backend_gl::Headless::from_context(current_context) -} - #[derive(Debug, serde::Deserialize)] pub enum Feature {}