mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
hal/gles: support externally initialized contexts
This commit is contained in:
134
Cargo.lock
generated
134
Cargo.lock
generated
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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::{
|
||||
|
||||
118
wgpu-hal/examples/raw-gles.rs
Normal file
118
wgpu-hal/examples/raw-gles.rs
Normal 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,
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user