hal/gles: support externally initialized contexts

This commit is contained in:
Dzmitry Malyshau
2022-01-03 00:54:43 -05:00
parent 43f09fdb21
commit 75b885b0ca
9 changed files with 502 additions and 178 deletions

134
Cargo.lock generated
View File

@@ -23,6 +23,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "android_glue"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407"
[[package]]
name = "approx"
version = "0.4.0"
@@ -202,6 +208,15 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "cgl"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff"
dependencies = [
"libc",
]
[[package]]
name = "cgmath"
version = "0.18.0"
@@ -598,6 +613,17 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "gl_generator"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
dependencies = [
"khronos_api",
"log",
"xml-rs",
]
[[package]]
name = "glow"
version = "0.11.1"
@@ -610,6 +636,78 @@ dependencies = [
"web-sys",
]
[[package]]
name = "glutin"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00ea9dbe544bc8a657c4c4a798c2d16cd01b549820e47657297549d28371f6d2"
dependencies = [
"android_glue",
"cgl",
"cocoa",
"core-foundation 0.9.1",
"glutin_egl_sys",
"glutin_emscripten_sys",
"glutin_gles2_sys",
"glutin_glx_sys",
"glutin_wgl_sys",
"lazy_static",
"libloading",
"log",
"objc",
"osmesa-sys",
"parking_lot",
"wayland-client",
"wayland-egl",
"winapi",
"winit",
]
[[package]]
name = "glutin_egl_sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2abb6aa55523480c4adc5a56bbaa249992e2dddb2fc63dc96e04a3355364c211"
dependencies = [
"gl_generator",
"winapi",
]
[[package]]
name = "glutin_emscripten_sys"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80de4146df76e8a6c32b03007bc764ff3249dcaeb4f675d68a06caf1bac363f1"
[[package]]
name = "glutin_gles2_sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8094e708b730a7c8a1954f4f8a31880af00eb8a1c5b5bf85d28a0a3c6d69103"
dependencies = [
"gl_generator",
"objc",
]
[[package]]
name = "glutin_glx_sys"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e393c8fc02b807459410429150e9c4faffdb312d59b8c038566173c81991351"
dependencies = [
"gl_generator",
"x11-dl",
]
[[package]]
name = "glutin_wgl_sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3da5951a1569dbab865c6f2a863efafff193a93caf05538d193e9e3816d21696"
dependencies = [
"gl_generator",
]
[[package]]
name = "gpu-alloc"
version = "0.5.2"
@@ -745,6 +843,12 @@ dependencies = [
"libloading",
]
[[package]]
name = "khronos_api"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]]
name = "lazy_static"
version = "1.4.0"
@@ -1049,6 +1153,15 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "osmesa-sys"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b"
dependencies = [
"shared_library",
]
[[package]]
name = "parking"
version = "2.0.0"
@@ -1335,6 +1448,16 @@ dependencies = [
"syn",
]
[[package]]
name = "shared_library"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11"
dependencies = [
"lazy_static",
"libc",
]
[[package]]
name = "slab"
version = "0.4.4"
@@ -1575,6 +1698,16 @@ dependencies = [
"xcursor",
]
[[package]]
name = "wayland-egl"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accf27d1e5e1f64ba30b683fd926c2c916cc1014bea3376fb258e80abf622e40"
dependencies = [
"wayland-client",
"wayland-sys",
]
[[package]]
name = "wayland-protocols"
version = "0.29.1"
@@ -1691,6 +1824,7 @@ dependencies = [
"foreign-types",
"fxhash",
"glow",
"glutin",
"gpu-alloc",
"gpu-descriptor",
"inplace_it",

View File

@@ -19,6 +19,13 @@ gles = ["naga/glsl-out", "glow", "egl", "libloading"]
dx12 = ["naga/hlsl-out", "native", "bit-set", "range-alloc", "winapi/d3d12", "winapi/d3d12shader", "winapi/d3d12sdklayers", "winapi/dxgi1_6"]
renderdoc = ["libloading", "renderdoc-sys"]
[[example]]
name = "halmark"
[[example]]
name = "raw-gles"
required-features = ["gles"]
[dependencies]
bitflags = "1.0"
parking_lot = "0.11"
@@ -86,4 +93,5 @@ features = ["wgsl-in"]
[dev-dependencies]
env_logger = "0.8"
winit = "0.26"
winit = "0.26" # for "halmark" example
glutin = "0.28" # for "gles" example

View File

@@ -1,3 +1,5 @@
//! This example shows basic usage of wgpu-hal by rendering
//! a ton of moving sprites, each with a separate texture and draw call.
extern crate wgpu_hal as hal;
use hal::{

View File

@@ -0,0 +1,118 @@
//! This example shows interop with raw GLES contexts -
//! the ability to hook up wgpu-hal to an existing context and draw into it.
extern crate wgpu_hal as hal;
use hal::{Adapter as _, CommandEncoder as _, Device as _, Queue as _};
fn main() {
env_logger::init();
println!("Initializing external GL context");
let event_loop = glutin::event_loop::EventLoop::new();
let window_builder = glutin::window::WindowBuilder::new();
let gl_context = unsafe {
glutin::ContextBuilder::new()
.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGlEs, (3, 0)))
.build_windowed(window_builder, &event_loop)
.unwrap()
.make_current()
.unwrap()
};
let inner_size = gl_context.window().inner_size();
println!("Hooking up to wgpu-hal");
let exposed = unsafe {
<hal::api::Gles as hal::Api>::Adapter::new_external(|name| {
gl_context.get_proc_address(name)
})
}
.expect("GL adapter can't be initialized");
let mut od = unsafe {
exposed
.adapter
.open(wgt::Features::empty(), &wgt::Limits::downlevel_defaults())
}
.unwrap();
let format = wgt::TextureFormat::Rgba8UnormSrgb;
let texture = <hal::api::Gles as hal::Api>::Texture::default_framebuffer(format);
let view = unsafe {
od.device
.create_texture_view(
&texture,
&hal::TextureViewDescriptor {
label: None,
format,
dimension: wgt::TextureViewDimension::D2,
usage: hal::TextureUses::COLOR_TARGET,
range: wgt::ImageSubresourceRange::default(),
},
)
.unwrap()
};
println!("Filling the screen");
let mut encoder = unsafe {
od.device
.create_command_encoder(&hal::CommandEncoderDescriptor {
label: None,
queue: &od.queue,
})
.unwrap()
};
let rp_desc = hal::RenderPassDescriptor {
label: None,
extent: wgt::Extent3d {
width: inner_size.width,
height: inner_size.height,
depth_or_array_layers: 1,
},
sample_count: 1,
color_attachments: &[hal::ColorAttachment {
target: hal::Attachment {
view: &view,
usage: hal::TextureUses::COLOR_TARGET,
},
resolve_target: None,
ops: hal::AttachmentOps::STORE,
clear_value: wgt::Color::BLUE,
}],
depth_stencil_attachment: None,
multiview: None,
};
unsafe {
encoder.begin_encoding(None).unwrap();
encoder.begin_render_pass(&rp_desc);
encoder.end_render_pass();
let cmd_buf = encoder.end_encoding().unwrap();
od.queue.submit(&[&cmd_buf], None).unwrap();
}
println!("Showing the window");
gl_context.swap_buffers().unwrap();
event_loop.run(move |event, _, control_flow| {
use glutin::{
event::{Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::ControlFlow,
};
*control_flow = ControlFlow::Wait;
match event {
Event::LoopDestroyed => return,
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested
| WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Escape),
..
},
..
} => *control_flow = ControlFlow::Exit,
_ => (),
},
_ => (),
}
});
}

View File

@@ -386,54 +386,72 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
self.state.has_pass_label = true;
}
// set the framebuffer
self.cmd_buffer.commands.push(C::ResetFramebuffer);
for (i, cat) in desc.color_attachments.iter().enumerate() {
let attachment = glow::COLOR_ATTACHMENT0 + i as u32;
self.cmd_buffer.commands.push(C::BindAttachment {
attachment,
view: cat.target.view.clone(),
});
if let Some(ref rat) = cat.resolve_target {
self.state
.resolve_attachments
.push((attachment, rat.view.clone()));
match desc
.color_attachments
.first()
.map(|at| &at.target.view.inner)
{
// default framebuffer (provided externally)
Some(&super::TextureInner::DefaultRenderbuffer) => {
self.cmd_buffer
.commands
.push(C::ResetFramebuffer { is_default: true });
}
if !cat.ops.contains(crate::AttachmentOps::STORE) {
self.state.invalidate_attachments.push(attachment);
}
}
if let Some(ref dsat) = desc.depth_stencil_attachment {
let aspects = dsat.target.view.aspects;
let attachment = match aspects {
crate::FormatAspects::DEPTH => glow::DEPTH_ATTACHMENT,
crate::FormatAspects::STENCIL => glow::STENCIL_ATTACHMENT,
_ => glow::DEPTH_STENCIL_ATTACHMENT,
};
self.cmd_buffer.commands.push(C::BindAttachment {
attachment,
view: dsat.target.view.clone(),
});
if aspects.contains(crate::FormatAspects::DEPTH)
&& !dsat.depth_ops.contains(crate::AttachmentOps::STORE)
{
self.state
.invalidate_attachments
.push(glow::DEPTH_ATTACHMENT);
}
if aspects.contains(crate::FormatAspects::STENCIL)
&& !dsat.stencil_ops.contains(crate::AttachmentOps::STORE)
{
self.state
.invalidate_attachments
.push(glow::STENCIL_ATTACHMENT);
_ => {
// set the framebuffer
self.cmd_buffer
.commands
.push(C::ResetFramebuffer { is_default: false });
for (i, cat) in desc.color_attachments.iter().enumerate() {
let attachment = glow::COLOR_ATTACHMENT0 + i as u32;
self.cmd_buffer.commands.push(C::BindAttachment {
attachment,
view: cat.target.view.clone(),
});
if let Some(ref rat) = cat.resolve_target {
self.state
.resolve_attachments
.push((attachment, rat.view.clone()));
}
if !cat.ops.contains(crate::AttachmentOps::STORE) {
self.state.invalidate_attachments.push(attachment);
}
}
if let Some(ref dsat) = desc.depth_stencil_attachment {
let aspects = dsat.target.view.aspects;
let attachment = match aspects {
crate::FormatAspects::DEPTH => glow::DEPTH_ATTACHMENT,
crate::FormatAspects::STENCIL => glow::STENCIL_ATTACHMENT,
_ => glow::DEPTH_STENCIL_ATTACHMENT,
};
self.cmd_buffer.commands.push(C::BindAttachment {
attachment,
view: dsat.target.view.clone(),
});
if aspects.contains(crate::FormatAspects::DEPTH)
&& !dsat.depth_ops.contains(crate::AttachmentOps::STORE)
{
self.state
.invalidate_attachments
.push(glow::DEPTH_ATTACHMENT);
}
if aspects.contains(crate::FormatAspects::STENCIL)
&& !dsat.stencil_ops.contains(crate::AttachmentOps::STORE)
{
self.state
.invalidate_attachments
.push(glow::STENCIL_ATTACHMENT);
}
}
// set the draw buffers and states
self.cmd_buffer
.commands
.push(C::SetDrawColorBuffers(desc.color_attachments.len() as u8));
}
}
// set the draw buffers and states
self.cmd_buffer
.commands
.push(C::SetDrawColorBuffers(desc.color_attachments.len() as u8));
let rect = crate::Rect {
x: 0,
y: 0,

View File

@@ -656,6 +656,7 @@ impl crate::Device<super::Api> for super::Device {
super::TextureInner::Renderbuffer { raw, .. } => {
gl.delete_renderbuffer(raw);
}
super::TextureInner::DefaultRenderbuffer => {}
super::TextureInner::Texture { raw, .. } => {
gl.delete_texture(raw);
}
@@ -889,14 +890,8 @@ impl crate::Device<super::Api> for super::Device {
log::error!("Unable to create a sampled texture binding for non-zero mipmap level or array layer.\n{}",
"This is an implementation problem of wgpu-hal/gles backend.")
}
match view.inner {
super::TextureInner::Renderbuffer { .. } => {
panic!("Unable to use a renderbuffer in a group")
}
super::TextureInner::Texture { raw, target } => {
super::RawBinding::Texture { raw, target }
}
}
let (raw, target) = view.inner.as_native();
super::RawBinding::Texture { raw, target }
}
wgt::BindingType::StorageTexture {
access,
@@ -905,24 +900,18 @@ impl crate::Device<super::Api> for super::Device {
} => {
let view = desc.textures[entry.resource_index as usize].view;
let format_desc = self.shared.describe_texture_format(format);
match view.inner {
super::TextureInner::Renderbuffer { .. } => {
panic!("Unable to use a renderbuffer in a group")
}
super::TextureInner::Texture { raw, .. } => {
super::RawBinding::Image(super::ImageBinding {
raw,
mip_level: view.mip_levels.start,
array_layer: match view_dimension {
wgt::TextureViewDimension::D2Array
| wgt::TextureViewDimension::CubeArray => None,
_ => Some(view.array_layers.start),
},
access: conv::map_storage_access(access),
format: format_desc.internal,
})
}
}
let (raw, _target) = view.inner.as_native();
super::RawBinding::Image(super::ImageBinding {
raw,
mip_level: view.mip_levels.start,
array_layer: match view_dimension {
wgt::TextureViewDimension::D2Array
| wgt::TextureViewDimension::CubeArray => None,
_ => Some(view.array_layers.start),
},
access: conv::map_storage_access(access),
format: format_desc.internal,
})
}
};
contents.push(binding);
@@ -1133,11 +1122,10 @@ impl crate::Device<super::Api> for super::Device {
unsafe fn start_capture(&self) -> bool {
#[cfg(feature = "renderdoc")]
{
self.render_doc
.start_frame_capture(self.shared.context.egl_context.as_ptr(), ptr::null_mut())
}
#[cfg(not(feature = "renderdoc"))]
return self
.render_doc
.start_frame_capture(self.shared.context.raw_context(), ptr::null_mut());
#[allow(unreachable_code)]
false
}
unsafe fn stop_capture(&self) {

View File

@@ -2,7 +2,7 @@ use glow::HasContext;
use parking_lot::{Mutex, MutexGuard};
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
use std::{ffi::CStr, os::raw, ptr, sync::Arc, time::Duration};
use std::{ffi, os::raw, ptr, sync::Arc, time::Duration};
/// The amount of time to wait while trying to obtain a lock to the adapter context
const CONTEXT_LOCK_TIMEOUT_SECS: u64 = 1;
@@ -88,11 +88,11 @@ unsafe extern "system" fn egl_debug_proc(
EGL_DEBUG_MSG_INFO_KHR => log::Level::Info,
_ => log::Level::Debug,
};
let command = CStr::from_ptr(command_raw).to_string_lossy();
let command = ffi::CStr::from_ptr(command_raw).to_string_lossy();
let message = if message_raw.is_null() {
"".into()
} else {
CStr::from_ptr(message_raw).to_string_lossy()
ffi::CStr::from_ptr(message_raw).to_string_lossy()
};
log::log!(
@@ -261,40 +261,73 @@ fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, m
}
}
#[derive(Clone, Debug)]
struct EglContext {
instance: Arc<egl::DynamicInstance<egl::EGL1_4>>,
display: egl::Display,
raw: egl::Context,
pbuffer: Option<egl::Surface>,
}
impl EglContext {
fn make_current(&self) {
self.instance
.make_current(self.display, self.pbuffer, self.pbuffer, Some(self.raw))
.unwrap();
}
fn unmake_current(&self) {
self.instance
.make_current(self.display, None, None, None)
.unwrap();
}
}
/// A wrapper around a [`glow::Context`] and the required EGL context that uses locking to guarantee
/// exclusive access when shared with multiple threads.
pub struct AdapterContext {
glow_context: Mutex<glow::Context>,
egl: Arc<egl::DynamicInstance<egl::EGL1_4>>,
egl_display: egl::Display,
pub(super) egl_context: egl::Context,
egl_pbuffer: Option<egl::Surface>,
glow: Mutex<glow::Context>,
egl: Option<EglContext>,
}
unsafe impl Sync for AdapterContext {}
unsafe impl Send for AdapterContext {}
impl AdapterContext {
#[cfg(feature = "renderdoc")]
pub fn raw_context(&self) -> *mut raw::c_void {
match self.egl {
Some(ref egl) => egl.raw.as_ptr(),
None => ptr::null_mut(),
}
}
}
struct EglContextLock<'a> {
instance: &'a Arc<egl::DynamicInstance<egl::EGL1_4>>,
display: egl::Display,
}
/// A guard containing a lock to an [`AdapterContext`]
pub struct AdapterContextLock<'a> {
glow_context: MutexGuard<'a, glow::Context>,
egl: &'a Arc<egl::DynamicInstance<egl::EGL1_4>>,
egl_display: egl::Display,
glow: MutexGuard<'a, glow::Context>,
egl: Option<EglContextLock<'a>>,
}
impl<'a> std::ops::Deref for AdapterContextLock<'a> {
type Target = glow::Context;
fn deref(&self) -> &Self::Target {
&self.glow_context
&self.glow
}
}
impl<'a> Drop for AdapterContextLock<'a> {
fn drop(&mut self) {
// Make the EGL context *not* current on this thread
self.egl
.make_current(self.egl_display, None, None, None)
.expect("Cannot make EGL context not current");
if let Some(egl) = self.egl.take() {
egl.instance
.make_current(egl.display, None, None, None)
.unwrap();
}
}
}
@@ -311,7 +344,7 @@ impl AdapterContext {
/// > **Note:** Calling this function **will** still lock the [`glow::Context`] which adds an
/// > extra safe-guard against accidental concurrent access to the context.
pub unsafe fn get_without_egl_lock(&self) -> MutexGuard<glow::Context> {
self.glow_context
self.glow
.try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))
.expect("Could not lock adapter context. This is most-likely a deadlcok.")
}
@@ -320,43 +353,34 @@ impl AdapterContext {
/// do rendering.
#[track_caller]
pub fn lock<'a>(&'a self) -> AdapterContextLock<'a> {
let glow_context = self
.glow_context
let glow = self
.glow
// Don't lock forever. If it takes longer than 1 second to get the lock we've got a
// deadlock and should panic to show where we got stuck
.try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))
.expect("Could not lock adapter context. This is most-likely a deadlcok.");
// Make the EGL context current on this thread
self.egl
.make_current(
self.egl_display,
self.egl_pbuffer,
self.egl_pbuffer,
Some(self.egl_context),
)
.expect("Cannot make EGL context current");
let egl = self.egl.as_ref().map(|egl| {
egl.make_current();
EglContextLock {
instance: &egl.instance,
display: egl.display,
}
});
AdapterContextLock {
glow_context,
egl: &self.egl,
egl_display: self.egl_display,
}
AdapterContextLock { glow, egl }
}
}
#[derive(Debug)]
struct Inner {
egl: Arc<egl::DynamicInstance<egl::EGL1_4>>,
/// Note: the context contains a dummy pbuffer (1x1).
/// Required for `eglMakeCurrent` on platforms that doesn't supports `EGL_KHR_surfaceless_context`.
egl: EglContext,
#[allow(unused)]
version: (i32, i32),
supports_native_window: bool,
display: egl::Display,
config: egl::Config,
context: egl::Context,
/// Dummy pbuffer (1x1).
/// Required for `eglMakeCurrent` on platforms that doesn't supports `EGL_KHR_surfaceless_context`.
pbuffer: Option<egl::Surface>,
wl_display: Option<*mut raw::c_void>,
/// Method by which the framebuffer should support srgb
srgb_kind: SrgbFrameBufferKind,
@@ -481,13 +505,15 @@ impl Inner {
};
Ok(Self {
egl,
display,
egl: EglContext {
instance: egl,
display,
raw: context,
pbuffer,
},
version,
supports_native_window,
config,
context,
pbuffer,
wl_display: None,
srgb_kind,
})
@@ -496,10 +522,14 @@ impl Inner {
impl Drop for Inner {
fn drop(&mut self) {
if let Err(e) = self.egl.destroy_context(self.display, self.context) {
if let Err(e) = self
.egl
.instance
.destroy_context(self.egl.display, self.egl.raw)
{
log::warn!("Error in destroy_context: {:?}", e);
}
if let Err(e) = self.egl.terminate(self.display) {
if let Err(e) = self.egl.instance.terminate(self.egl.display) {
log::warn!("Error in terminate: {:?}", e);
}
}
@@ -676,7 +706,8 @@ impl crate::Instance<super::Api> for Instance {
Rwh::AndroidNdk(handle) => {
let format = inner
.egl
.get_config_attrib(inner.display, inner.config, egl::NATIVE_VISUAL_ID)
.instance
.get_config_attrib(inner.egl.display, inner.config, egl::NATIVE_VISUAL_ID)
.unwrap();
let ret = ANativeWindow_setBuffersGeometry(handle.a_native_window, 0, 0, format);
@@ -703,6 +734,7 @@ impl crate::Instance<super::Api> for Instance {
let display_attributes = [egl::ATTRIB_NONE];
let display = inner
.egl
.instance
.upcast::<egl::EGL1_5>()
.unwrap()
.get_platform_display(
@@ -712,8 +744,9 @@ impl crate::Instance<super::Api> for Instance {
)
.unwrap();
let new_inner = Inner::create(self.flags, inner.egl.clone(), display)
.map_err(|_| crate::InstanceError)?;
let new_inner =
Inner::create(self.flags, Arc::clone(&inner.egl.instance), display)
.map_err(|_| crate::InstanceError)?;
let old_inner = std::mem::replace(inner.deref_mut(), new_inner);
inner.wl_display = Some(handle.display);
@@ -726,19 +759,13 @@ impl crate::Instance<super::Api> for Instance {
}
};
inner
.egl
.make_current(inner.display, None, None, None)
.unwrap();
inner.egl.unmake_current();
Ok(Surface {
egl: Arc::clone(&inner.egl),
egl: inner.egl.clone(),
wsi: self.wsi.clone(),
config: inner.config,
display: inner.display,
context: inner.context,
presentable: inner.supports_native_window,
pbuffer: inner.pbuffer,
raw_window_handle,
swapchain: None,
srgb_kind: inner.srgb_kind,
@@ -748,19 +775,12 @@ impl crate::Instance<super::Api> for Instance {
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
let inner = self.inner.lock();
inner
.egl
.make_current(
inner.display,
inner.pbuffer,
inner.pbuffer,
Some(inner.context),
)
.unwrap();
inner.egl.make_current();
let gl = glow::Context::from_loader_function(|name| {
inner
.egl
.instance
.get_proc_address(name)
.map_or(ptr::null(), |p| p as *const _)
});
@@ -778,23 +798,28 @@ impl crate::Instance<super::Api> for Instance {
gl.debug_message_callback(gl_debug_message_callback);
}
inner
.egl
.make_current(inner.display, None, None, None)
.unwrap();
inner.egl.unmake_current();
super::Adapter::expose(AdapterContext {
glow_context: Mutex::new(gl),
egl: inner.egl.clone(),
egl_display: inner.display,
egl_context: inner.context,
egl_pbuffer: inner.pbuffer,
glow: Mutex::new(gl),
egl: Some(inner.egl.clone()),
})
.into_iter()
.collect()
}
}
impl super::Adapter {
pub unsafe fn new_external(
fun: impl FnMut(&str) -> *const ffi::c_void,
) -> Option<crate::ExposedAdapter<super::Api>> {
Self::expose(AdapterContext {
glow: Mutex::new(glow::Context::from_loader_function(fun)),
egl: None,
})
}
}
#[derive(Debug)]
pub struct Swapchain {
surface: egl::Surface,
@@ -811,13 +836,9 @@ pub struct Swapchain {
#[derive(Debug)]
pub struct Surface {
egl: Arc<egl::DynamicInstance<egl::EGL1_4>>,
egl: EglContext,
wsi: WindowSystemInterface,
config: egl::Config,
display: egl::Display,
context: egl::Context,
#[allow(unused)]
pbuffer: Option<egl::Surface>,
pub(super) presentable: bool,
raw_window_handle: RawWindowHandle,
swapchain: Option<Swapchain>,
@@ -836,11 +857,12 @@ impl Surface {
let sc = self.swapchain.as_ref().unwrap();
self.egl
.instance
.make_current(
self.display,
self.egl.display,
Some(sc.surface),
Some(sc.surface),
Some(self.context),
Some(self.egl.raw),
)
.map_err(|e| {
log::error!("make_current(surface) failed: {}", e);
@@ -870,13 +892,15 @@ impl Surface {
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);
self.egl
.swap_buffers(self.display, sc.surface)
.instance
.swap_buffers(self.egl.display, sc.surface)
.map_err(|e| {
log::error!("swap_buffers failed: {}", e);
crate::SurfaceError::Lost
})?;
self.egl
.make_current(self.display, None, None, None)
.instance
.make_current(self.egl.display, None, None, None)
.map_err(|e| {
log::error!("make_current(null) failed: {}", e);
crate::SurfaceError::Lost
@@ -987,21 +1011,21 @@ impl crate::Surface<super::Api> for Surface {
attributes.push(egl::ATTRIB_NONE as i32);
// Careful, we can still be in 1.4 version even if `upcast` succeeds
let raw_result = match self.egl.upcast::<egl::EGL1_5>() {
let raw_result = match self.egl.instance.upcast::<egl::EGL1_5>() {
Some(egl) if self.wsi.kind != WindowKind::Unknown => {
let attributes_usize = attributes
.into_iter()
.map(|v| v as usize)
.collect::<Vec<_>>();
egl.create_platform_window_surface(
self.display,
self.egl.display,
self.config,
native_window_ptr,
&attributes_usize,
)
}
_ => self.egl.create_window_surface(
self.display,
_ => self.egl.instance.create_window_surface(
self.egl.display,
self.config,
native_window_ptr,
Some(&attributes),
@@ -1068,7 +1092,10 @@ impl crate::Surface<super::Api> for Surface {
unsafe fn unconfigure(&mut self, device: &super::Device) {
if let Some((surface, wl_window)) = self.unconfigure_impl(device) {
self.egl.destroy_surface(self.display, surface).unwrap();
self.egl
.instance
.destroy_surface(self.egl.display, surface)
.unwrap();
if let Some(window) = wl_window {
let wl_egl_window_destroy: libloading::Symbol<WlEglWindowDestroyFun> = self
.wsi

View File

@@ -230,6 +230,7 @@ enum TextureInner {
Renderbuffer {
raw: glow::Renderbuffer,
},
DefaultRenderbuffer,
Texture {
raw: glow::Texture,
target: BindTarget,
@@ -239,7 +240,7 @@ enum TextureInner {
impl TextureInner {
fn as_native(&self) -> (glow::Texture, BindTarget) {
match *self {
Self::Renderbuffer { .. } => {
Self::Renderbuffer { .. } | Self::DefaultRenderbuffer => {
panic!("Unexpected renderbuffer");
}
Self::Texture { raw, target } => (raw, target),
@@ -258,6 +259,27 @@ pub struct Texture {
copy_size: crate::CopyExtent,
}
impl Texture {
pub fn default_framebuffer(format: wgt::TextureFormat) -> Self {
Self {
inner: TextureInner::DefaultRenderbuffer,
mip_level_count: 1,
array_layer_count: 1,
format,
format_desc: TextureFormatDesc {
internal: 0,
external: 0,
data_type: 0,
},
copy_size: crate::CopyExtent {
width: 0,
height: 0,
depth: 0,
},
}
}
}
#[derive(Clone, Debug)]
pub struct TextureView {
inner: TextureInner,
@@ -612,7 +634,9 @@ enum Command {
dst_target: BindTarget,
dst_offset: wgt::BufferAddress,
},
ResetFramebuffer,
ResetFramebuffer {
is_default: bool,
},
BindAttachment {
attachment: u32,
view: TextureView,

View File

@@ -82,6 +82,7 @@ impl super::Queue {
super::TextureInner::Renderbuffer { raw } => {
gl.framebuffer_renderbuffer(fbo_target, attachment, glow::RENDERBUFFER, Some(raw));
}
super::TextureInner::DefaultRenderbuffer => panic!("Unexpected default RBO"),
super::TextureInner::Texture { raw, target } => {
if is_layered_target(target) {
gl.framebuffer_texture_layer(
@@ -636,24 +637,28 @@ impl super::Queue {
}
}
}
C::ResetFramebuffer => {
gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo));
gl.framebuffer_texture_2d(
glow::DRAW_FRAMEBUFFER,
glow::DEPTH_STENCIL_ATTACHMENT,
glow::TEXTURE_2D,
None,
0,
);
for i in 0..crate::MAX_COLOR_TARGETS {
let target = glow::COLOR_ATTACHMENT0 + i as u32;
C::ResetFramebuffer { is_default } => {
if is_default {
gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None);
} else {
gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo));
gl.framebuffer_texture_2d(
glow::DRAW_FRAMEBUFFER,
target,
glow::DEPTH_STENCIL_ATTACHMENT,
glow::TEXTURE_2D,
None,
0,
);
for i in 0..crate::MAX_COLOR_TARGETS {
let target = glow::COLOR_ATTACHMENT0 + i as u32;
gl.framebuffer_texture_2d(
glow::DRAW_FRAMEBUFFER,
target,
glow::TEXTURE_2D,
None,
0,
);
}
}
gl.color_mask(true, true, true, true);
gl.depth_mask(true);