mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
hal/gl: start the backend, port the Instance
This commit is contained in:
committed by
Dzmitry Malyshau
parent
81214b21ec
commit
41bc9d0625
33
Cargo.lock
generated
33
Cargo.lock
generated
@@ -687,6 +687,18 @@ dependencies = [
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glow"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "945be163fdb893227410c8b44c2412dade922585b262d1daa6a7e96135217d4c"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"slotmap",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpu-alloc"
|
||||
version = "0.4.7"
|
||||
@@ -846,6 +858,16 @@ dependencies = [
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "khronos-egl"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libloading 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@@ -1586,6 +1608,15 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
|
||||
|
||||
[[package]]
|
||||
name = "slotmap"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "585cd5dffe4e9e06f6dfdf66708b70aca3f781bed561f4f667b2d9c0d4559e36"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.6.1"
|
||||
@@ -1957,9 +1988,11 @@ dependencies = [
|
||||
"env_logger",
|
||||
"foreign-types",
|
||||
"fxhash",
|
||||
"glow",
|
||||
"gpu-alloc",
|
||||
"gpu-descriptor",
|
||||
"inplace_it",
|
||||
"khronos-egl",
|
||||
"libloading 0.7.0",
|
||||
"log",
|
||||
"metal",
|
||||
|
||||
@@ -15,6 +15,7 @@ license = "MIT OR Apache-2.0"
|
||||
default = []
|
||||
metal = ["naga/msl-out", "block", "foreign-types"]
|
||||
vulkan = ["naga/spv-out", "ash", "gpu-alloc", "gpu-descriptor", "libloading", "inplace_it", "renderdoc-sys"]
|
||||
gles = ["naga/glsl-out", "glow", "egl", "libloading"]
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
@@ -26,7 +27,6 @@ wgt = { package = "wgpu-types", path = "../wgpu-types" }
|
||||
# backends common
|
||||
arrayvec = "0.5"
|
||||
fxhash = "0.2.1"
|
||||
libloading = { version = "0.7", optional = true }
|
||||
log = "0.4"
|
||||
# backend: Metal
|
||||
block = { version = "0.1", optional = true }
|
||||
@@ -37,6 +37,12 @@ gpu-alloc = { version = "0.4", optional = true }
|
||||
gpu-descriptor = { version = "0.1", optional = true }
|
||||
inplace_it = { version ="0.3.3", optional = true }
|
||||
renderdoc-sys = { version = "0.7.1", optional = true }
|
||||
# backend: Gles
|
||||
glow = { version = "0.10", optional = true }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], optional = true }
|
||||
libloading = { version = "0.7", optional = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3", features = ["libloaderapi", "windef", "winuser"] }
|
||||
|
||||
@@ -681,7 +681,9 @@ impl<A: hal::Api> Example<A> {
|
||||
type Api = hal::api::Metal;
|
||||
#[cfg(all(feature = "vulkan", not(feature = "metal")))]
|
||||
type Api = hal::api::Vulkan;
|
||||
#[cfg(all(not(feature = "vulkan"), not(feature = "metal")))]
|
||||
#[cfg(all(feature = "gles", not(feature = "metal"), not(feature = "vulkan")))]
|
||||
type Api = hal::api::Gles;
|
||||
#[cfg(not(any(feature = "metal", feature = "vulkan", feature = "gles")))]
|
||||
type Api = hal::api::Empty;
|
||||
|
||||
fn main() {
|
||||
|
||||
556
wgpu-hal/src/gles/egl.rs
Normal file
556
wgpu-hal/src/gles/egl.rs
Normal file
@@ -0,0 +1,556 @@
|
||||
use glow::HasContext;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use std::{os::raw, ptr, sync::Arc};
|
||||
|
||||
const EGL_PLATFORM_WAYLAND_KHR: u32 = 0x31D8;
|
||||
const EGL_PLATFORM_X11_KHR: u32 = 0x31D5;
|
||||
|
||||
type XOpenDisplayFun =
|
||||
unsafe extern "system" fn(display_name: *const raw::c_char) -> *mut raw::c_void;
|
||||
|
||||
type WlDisplayConnectFun =
|
||||
unsafe extern "system" fn(display_name: *const raw::c_char) -> *mut raw::c_void;
|
||||
|
||||
type WlDisplayDisconnectFun = unsafe extern "system" fn(display: *const raw::c_void);
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "macos")))]
|
||||
type WlEglWindowCreateFun = unsafe extern "system" fn(
|
||||
surface: *const raw::c_void,
|
||||
width: raw::c_int,
|
||||
height: raw::c_int,
|
||||
) -> *mut raw::c_void;
|
||||
|
||||
type WlEglWindowResizeFun = unsafe extern "system" fn(
|
||||
window: *const raw::c_void,
|
||||
width: raw::c_int,
|
||||
height: raw::c_int,
|
||||
dx: raw::c_int,
|
||||
dy: raw::c_int,
|
||||
);
|
||||
|
||||
type WlEglWindowDestroyFun = unsafe extern "system" fn(window: *const raw::c_void);
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
extern "C" {
|
||||
pub fn ANativeWindow_setBuffersGeometry(
|
||||
window: *mut raw::c_void,
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: i32,
|
||||
) -> i32;
|
||||
}
|
||||
|
||||
fn open_x_display() -> Option<(ptr::NonNull<raw::c_void>, libloading::Library)> {
|
||||
log::info!("Loading X11 library to get the current display");
|
||||
unsafe {
|
||||
let library = libloading::Library::new("libX11.so").ok()?;
|
||||
let func: libloading::Symbol<XOpenDisplayFun> = library.get(b"XOpenDisplay").unwrap();
|
||||
let result = func(ptr::null());
|
||||
ptr::NonNull::new(result).map(|ptr| (ptr, library))
|
||||
}
|
||||
}
|
||||
|
||||
fn test_wayland_display() -> Option<libloading::Library> {
|
||||
/* We try to connect and disconnect here to simply ensure there
|
||||
* is an active wayland display available.
|
||||
*/
|
||||
log::info!("Loading Wayland library to get the current display");
|
||||
let library = unsafe {
|
||||
let client_library = libloading::Library::new("libwayland-client.so").ok()?;
|
||||
let wl_display_connect: libloading::Symbol<WlDisplayConnectFun> =
|
||||
client_library.get(b"wl_display_connect").unwrap();
|
||||
let wl_display_disconnect: libloading::Symbol<WlDisplayDisconnectFun> =
|
||||
client_library.get(b"wl_display_disconnect").unwrap();
|
||||
let display = ptr::NonNull::new(wl_display_connect(ptr::null()))?;
|
||||
wl_display_disconnect(display.as_ptr());
|
||||
libloading::Library::new("libwayland-egl.so").ok()?
|
||||
};
|
||||
Some(library)
|
||||
}
|
||||
|
||||
/// Choose GLES framebuffer configuration.
|
||||
fn choose_config(
|
||||
egl: &egl::DynamicInstance<egl::EGL1_4>,
|
||||
display: egl::Display,
|
||||
) -> Result<(egl::Config, bool), crate::InstanceError> {
|
||||
//TODO: EGL_SLOW_CONFIG
|
||||
let tiers = [
|
||||
(
|
||||
"off-screen",
|
||||
&[egl::RENDERABLE_TYPE, egl::OPENGL_ES2_BIT][..],
|
||||
),
|
||||
("presentation", &[egl::SURFACE_TYPE, egl::WINDOW_BIT]),
|
||||
#[cfg(not(target_os = "android"))]
|
||||
("native-render", &[egl::NATIVE_RENDERABLE, egl::TRUE as _]),
|
||||
];
|
||||
|
||||
let mut attributes = Vec::with_capacity(7);
|
||||
for tier_max in (0..tiers.len()).rev() {
|
||||
let name = tiers[tier_max].0;
|
||||
log::info!("Trying {}", name);
|
||||
|
||||
attributes.clear();
|
||||
for &(_, tier_attr) in tiers[..=tier_max].iter() {
|
||||
attributes.extend_from_slice(tier_attr);
|
||||
}
|
||||
attributes.push(egl::NONE);
|
||||
|
||||
match egl.choose_first_config(display, &attributes) {
|
||||
Ok(Some(config)) => {
|
||||
return Ok((config, tier_max >= 1));
|
||||
}
|
||||
Ok(None) => {
|
||||
log::warn!("No config found!");
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("error in choose_first_config: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(crate::InstanceError)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Inner {
|
||||
egl: Arc<egl::DynamicInstance<egl::EGL1_4>>,
|
||||
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>,
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
fn create(
|
||||
flags: crate::InstanceFlag,
|
||||
egl: Arc<egl::DynamicInstance<egl::EGL1_4>>,
|
||||
display: egl::Display,
|
||||
wsi_library: Option<&libloading::Library>,
|
||||
) -> Result<Self, crate::InstanceError> {
|
||||
let version = egl.initialize(display).map_err(|_| crate::InstanceError)?;
|
||||
let vendor = egl.query_string(Some(display), egl::VENDOR).unwrap();
|
||||
let display_extensions = egl
|
||||
.query_string(Some(display), egl::EXTENSIONS)
|
||||
.unwrap()
|
||||
.to_string_lossy();
|
||||
log::info!(
|
||||
"Display vendor {:?}, version {:?}, extensions: {:?}",
|
||||
vendor,
|
||||
version,
|
||||
display_extensions
|
||||
);
|
||||
|
||||
if log::max_level() >= log::LevelFilter::Trace {
|
||||
log::trace!("Configurations:");
|
||||
let config_count = egl.get_config_count(display).unwrap();
|
||||
let mut configurations = Vec::with_capacity(config_count);
|
||||
egl.get_configs(display, &mut configurations).unwrap();
|
||||
for &config in configurations.iter() {
|
||||
log::trace!("\tCONFORMANT=0x{:X}, RENDERABLE=0x{:X}, NATIVE_RENDERABLE=0x{:X}, SURFACE_TYPE=0x{:X}",
|
||||
egl.get_config_attrib(display, config, egl::CONFORMANT).unwrap(),
|
||||
egl.get_config_attrib(display, config, egl::RENDERABLE_TYPE).unwrap(),
|
||||
egl.get_config_attrib(display, config, egl::NATIVE_RENDERABLE).unwrap(),
|
||||
egl.get_config_attrib(display, config, egl::SURFACE_TYPE).unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let (config, supports_native_window) = choose_config(&egl, display)?;
|
||||
egl.bind_api(egl::OPENGL_ES_API).unwrap();
|
||||
|
||||
//TODO: make it so `Device` == EGL Context
|
||||
let mut context_attributes = vec![
|
||||
egl::CONTEXT_CLIENT_VERSION,
|
||||
3, // Request GLES 3.0 or higher
|
||||
];
|
||||
if flags.contains(crate::InstanceFlag::VALIDATION)
|
||||
&& wsi_library.is_none()
|
||||
&& !cfg!(target_os = "android")
|
||||
{
|
||||
//TODO: figure out why this is needed
|
||||
context_attributes.push(egl::CONTEXT_OPENGL_DEBUG);
|
||||
context_attributes.push(egl::TRUE as _);
|
||||
}
|
||||
context_attributes.push(egl::NONE);
|
||||
let context = match egl.create_context(display, config, None, &context_attributes) {
|
||||
Ok(context) => context,
|
||||
Err(e) => {
|
||||
log::warn!("unable to create GLES 3.x context: {:?}", e);
|
||||
return Err(crate::InstanceError);
|
||||
}
|
||||
};
|
||||
|
||||
// Testing if context can be binded without surface
|
||||
// and creating dummy pbuffer surface if not.
|
||||
let pbuffer = if version < (1, 5)
|
||||
|| !display_extensions.contains("EGL_KHR_surfaceless_context")
|
||||
{
|
||||
let attributes = [egl::WIDTH, 1, egl::HEIGHT, 1, egl::NONE];
|
||||
egl.create_pbuffer_surface(display, config, &attributes)
|
||||
.map(Some)
|
||||
.map_err(|e| {
|
||||
log::warn!("Error in create_pbuffer_surface: {:?}", e);
|
||||
crate::InstanceError
|
||||
})?
|
||||
} else {
|
||||
log::info!("EGL_KHR_surfaceless_context is present. No need to create a dummy pbuffer");
|
||||
None
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
egl,
|
||||
display,
|
||||
version,
|
||||
supports_native_window,
|
||||
config,
|
||||
context,
|
||||
pbuffer,
|
||||
wl_display: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Inner {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self.egl.destroy_context(self.display, self.context) {
|
||||
log::warn!("Error in destroy_context: {:?}", e);
|
||||
}
|
||||
if let Err(e) = self.egl.terminate(self.display) {
|
||||
log::warn!("Error in terminate: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Instance {
|
||||
wsi_library: Option<libloading::Library>,
|
||||
flags: crate::InstanceFlag,
|
||||
inner: Mutex<Inner>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Instance {}
|
||||
unsafe impl Sync for Instance {}
|
||||
|
||||
impl crate::Instance<super::Api> for Instance {
|
||||
unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
|
||||
let egl = match unsafe { egl::DynamicInstance::<egl::EGL1_4>::load_required() } {
|
||||
Ok(egl) => Arc::new(egl),
|
||||
Err(e) => {
|
||||
log::warn!("Unable to open libEGL.so: {:?}", e);
|
||||
return Err(crate::InstanceError);
|
||||
}
|
||||
};
|
||||
|
||||
let client_extensions = egl.query_string(None, egl::EXTENSIONS);
|
||||
|
||||
let client_ext_str = match client_extensions {
|
||||
Ok(ext) => ext.to_string_lossy().into_owned(),
|
||||
Err(_) => String::new(),
|
||||
};
|
||||
log::info!("Client extensions: {:?}", client_ext_str);
|
||||
|
||||
let mut wsi_library = None;
|
||||
|
||||
let wayland_library = if client_ext_str.contains(&"EGL_EXT_platform_wayland") {
|
||||
test_wayland_display()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let x11_display_library = if client_ext_str.contains(&"EGL_EXT_platform_x11") {
|
||||
open_x_display()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let display = if let (Some(library), Some(egl)) =
|
||||
(wayland_library, egl.upcast::<egl::EGL1_5>())
|
||||
{
|
||||
log::info!("Using Wayland platform");
|
||||
let display_attributes = [egl::ATTRIB_NONE];
|
||||
wsi_library = Some(library);
|
||||
egl.get_platform_display(
|
||||
EGL_PLATFORM_WAYLAND_KHR,
|
||||
egl::DEFAULT_DISPLAY,
|
||||
&display_attributes,
|
||||
)
|
||||
.unwrap()
|
||||
} else if let (Some((display, library)), Some(egl)) =
|
||||
(x11_display_library, egl.upcast::<egl::EGL1_5>())
|
||||
{
|
||||
log::info!("Using X11 platform");
|
||||
let display_attributes = [egl::ATTRIB_NONE];
|
||||
wsi_library = Some(library);
|
||||
egl.get_platform_display(EGL_PLATFORM_X11_KHR, display.as_ptr(), &display_attributes)
|
||||
.unwrap()
|
||||
} else {
|
||||
log::info!("Using default platform");
|
||||
egl.get_display(egl::DEFAULT_DISPLAY).unwrap()
|
||||
};
|
||||
|
||||
let inner = Inner::create(desc.flags, egl, display, wsi_library.as_ref())?;
|
||||
|
||||
Ok(Instance {
|
||||
wsi_library,
|
||||
flags: desc.flags,
|
||||
inner: Mutex::new(inner),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "macos", allow(unused, unused_mut, unreachable_code))]
|
||||
unsafe fn create_surface(
|
||||
&self,
|
||||
has_handle: &impl raw_window_handle::HasRawWindowHandle,
|
||||
) -> Result<Surface, crate::InstanceError> {
|
||||
use raw_window_handle::RawWindowHandle as Rwh;
|
||||
|
||||
let mut inner = self.inner.lock();
|
||||
let mut wl_window = None;
|
||||
#[cfg(not(any(target_os = "android", target_os = "macos")))]
|
||||
let (mut temp_xlib_handle, mut temp_xcb_handle);
|
||||
|
||||
let native_window_ptr = match has_handle.raw_window_handle() {
|
||||
#[cfg(not(any(target_os = "android", target_os = "macos")))]
|
||||
Rwh::Xlib(handle) => {
|
||||
temp_xlib_handle = handle.window;
|
||||
&mut temp_xlib_handle as *mut _ as *mut std::ffi::c_void
|
||||
}
|
||||
#[cfg(not(any(target_os = "android", target_os = "macos")))]
|
||||
Rwh::Xcb(handle) => {
|
||||
temp_xcb_handle = handle.window;
|
||||
&mut temp_xcb_handle as *mut _ as *mut std::ffi::c_void
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
Rwh::Android(handle) => handle.a_native_window as *mut _ as *mut std::ffi::c_void,
|
||||
#[cfg(not(any(target_os = "android", target_os = "macos")))]
|
||||
Rwh::Wayland(handle) => {
|
||||
/* Wayland displays are not sharable between surfaces so if the
|
||||
* surface we receive from this handle is from a different
|
||||
* display, we must re-initialize the context.
|
||||
*
|
||||
* See gfx-rs/gfx#3545
|
||||
*/
|
||||
if inner
|
||||
.wl_display
|
||||
.map(|ptr| ptr != handle.display)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
use std::ops::DerefMut;
|
||||
let display_attributes = [egl::ATTRIB_NONE];
|
||||
let display = inner
|
||||
.egl
|
||||
.upcast::<egl::EGL1_5>()
|
||||
.unwrap()
|
||||
.get_platform_display(
|
||||
EGL_PLATFORM_WAYLAND_KHR,
|
||||
handle.display,
|
||||
&display_attributes,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let new_inner =
|
||||
Inner::create(inner.egl.clone(), display, self.wsi_library.as_ref())
|
||||
.map_err(|_| w::InitError::UnsupportedWindowHandle)?;
|
||||
|
||||
let old_inner = std::mem::replace(inner.deref_mut(), new_inner);
|
||||
inner.wl_display = Some(handle.display);
|
||||
drop(old_inner);
|
||||
}
|
||||
|
||||
let wl_egl_window_create: libloading::Symbol<WlEglWindowCreateFun> = self
|
||||
.wsi_library
|
||||
.as_ref()
|
||||
.expect("unsupported window")
|
||||
.get(b"wl_egl_window_create")
|
||||
.unwrap();
|
||||
let result = wl_egl_window_create(handle.surface, 640, 480) as *mut _
|
||||
as *mut std::ffi::c_void;
|
||||
wl_window = Some(result);
|
||||
result
|
||||
}
|
||||
other => {
|
||||
log::error!("Unsupported window: {:?}", other);
|
||||
return Err(crate::InstanceError);
|
||||
}
|
||||
};
|
||||
|
||||
let mut attributes = vec![
|
||||
egl::RENDER_BUFFER as usize,
|
||||
if cfg!(target_os = "android") {
|
||||
egl::BACK_BUFFER as usize
|
||||
} else {
|
||||
egl::SINGLE_BUFFER as usize
|
||||
},
|
||||
];
|
||||
if inner.version >= (1, 5) {
|
||||
// Always enable sRGB in EGL 1.5
|
||||
attributes.push(egl::GL_COLORSPACE as usize);
|
||||
attributes.push(egl::GL_COLORSPACE_SRGB as usize);
|
||||
}
|
||||
attributes.push(egl::ATTRIB_NONE);
|
||||
|
||||
let raw = if let Some(egl) = inner.egl.upcast::<egl::EGL1_5>() {
|
||||
egl.create_platform_window_surface(
|
||||
inner.display,
|
||||
inner.config,
|
||||
native_window_ptr,
|
||||
&attributes,
|
||||
)
|
||||
.map_err(|e| {
|
||||
log::warn!("Error in create_platform_window_surface: {:?}", e);
|
||||
crate::InstanceError
|
||||
})
|
||||
} else {
|
||||
let attributes_i32: Vec<i32> = attributes.iter().map(|a| (*a as i32).into()).collect();
|
||||
inner
|
||||
.egl
|
||||
.create_window_surface(
|
||||
inner.display,
|
||||
inner.config,
|
||||
native_window_ptr,
|
||||
Some(&attributes_i32),
|
||||
)
|
||||
.map_err(|e| {
|
||||
log::warn!("Error in create_platform_window_surface: {:?}", e);
|
||||
crate::InstanceError
|
||||
})
|
||||
}?;
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
let format = inner
|
||||
.egl
|
||||
.get_config_attrib(inner.display, inner.config, egl::NATIVE_VISUAL_ID)
|
||||
.unwrap();
|
||||
|
||||
let ret = ANativeWindow_setBuffersGeometry(native_window_ptr, 0, 0, format);
|
||||
|
||||
if ret != 0 {
|
||||
log::error!("Error returned from ANativeWindow_setBuffersGeometry");
|
||||
return Err(w::InitError::UnsupportedWindowHandle);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Surface {
|
||||
egl: Arc::clone(&inner.egl),
|
||||
raw,
|
||||
display: inner.display,
|
||||
context: inner.context,
|
||||
presentable: inner.supports_native_window,
|
||||
pbuffer: inner.pbuffer,
|
||||
wl_window,
|
||||
swapchain: None,
|
||||
})
|
||||
}
|
||||
unsafe fn destroy_surface(&self, surface: Surface) {}
|
||||
|
||||
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Swapchain {
|
||||
framebuffer: glow::Framebuffer,
|
||||
renderbuffer: glow::Renderbuffer,
|
||||
/// Extent because the window lies
|
||||
extent: wgt::Extent3d,
|
||||
format: super::TextureFormat,
|
||||
sample_type: wgt::TextureSampleType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Surface {
|
||||
egl: Arc<egl::DynamicInstance<egl::EGL1_4>>,
|
||||
raw: egl::Surface,
|
||||
display: egl::Display,
|
||||
context: egl::Context,
|
||||
pbuffer: Option<egl::Surface>,
|
||||
presentable: bool,
|
||||
wl_window: Option<*mut raw::c_void>,
|
||||
swapchain: Option<Swapchain>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Surface {}
|
||||
unsafe impl Sync for Surface {}
|
||||
|
||||
impl crate::Surface<super::Api> for Surface {
|
||||
unsafe fn configure(
|
||||
&mut self,
|
||||
device: &super::Context,
|
||||
config: &crate::SurfaceConfiguration,
|
||||
) -> Result<(), crate::SurfaceError> {
|
||||
self.unconfigure(device);
|
||||
|
||||
if let Some(window) = self.wl_window {
|
||||
let library = libloading::Library::new("libwayland-egl.so").unwrap();
|
||||
let wl_egl_window_resize: libloading::Symbol<WlEglWindowResizeFun> =
|
||||
library.get(b"wl_egl_window_resize").unwrap();
|
||||
wl_egl_window_resize(
|
||||
window,
|
||||
config.extent.width as i32,
|
||||
config.extent.height as i32,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
//let desc = conv::describe_format(config.format).unwrap();
|
||||
let desc: super::FormatDescription = unimplemented!();
|
||||
|
||||
let gl: glow::Context = unimplemented!(); //&device.share.context;
|
||||
let renderbuffer = gl.create_renderbuffer().unwrap();
|
||||
gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer));
|
||||
gl.renderbuffer_storage(
|
||||
glow::RENDERBUFFER,
|
||||
desc.tex_internal,
|
||||
config.extent.width as _,
|
||||
config.extent.height as _,
|
||||
);
|
||||
let framebuffer = gl.create_framebuffer().unwrap();
|
||||
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer));
|
||||
gl.framebuffer_renderbuffer(
|
||||
glow::READ_FRAMEBUFFER,
|
||||
glow::COLOR_ATTACHMENT0,
|
||||
glow::RENDERBUFFER,
|
||||
Some(renderbuffer),
|
||||
);
|
||||
gl.bind_renderbuffer(glow::RENDERBUFFER, None);
|
||||
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);
|
||||
|
||||
self.swapchain = Some(Swapchain {
|
||||
renderbuffer,
|
||||
framebuffer,
|
||||
extent: config.extent,
|
||||
format: desc.tex_internal,
|
||||
sample_type: wgt::TextureSampleType::Float { filterable: false },
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn unconfigure(&mut self, device: &super::Context) {
|
||||
/*
|
||||
let gl = &device.share.context;
|
||||
if let Some(sc) = self.swapchain.take() {
|
||||
gl.delete_renderbuffer(sc.renderbuffer);
|
||||
gl.delete_framebuffer(sc.framebuffer);
|
||||
}*/
|
||||
}
|
||||
|
||||
unsafe fn acquire_texture(
|
||||
&mut self,
|
||||
timeout_ms: u32,
|
||||
) -> Result<Option<crate::AcquiredSurfaceTexture<super::Api>>, crate::SurfaceError> {
|
||||
let sc = self.swapchain.as_ref().unwrap();
|
||||
//let sc_image =
|
||||
// native::SwapchainImage::new(sc.renderbuffer, sc.format, sc.extent, sc.channel);
|
||||
Ok(None)
|
||||
}
|
||||
unsafe fn discard_texture(&mut self, texture: super::Resource) {}
|
||||
}
|
||||
390
wgpu-hal/src/gles/mod.rs
Normal file
390
wgpu-hal/src/gles/mod.rs
Normal file
@@ -0,0 +1,390 @@
|
||||
#![allow(unused_variables)]
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod egl;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use self::egl::{Instance, Surface};
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Api;
|
||||
pub struct Context;
|
||||
pub struct Encoder;
|
||||
#[derive(Debug)]
|
||||
pub struct Resource;
|
||||
|
||||
type DeviceResult<T> = Result<T, crate::DeviceError>;
|
||||
|
||||
impl crate::Api for Api {
|
||||
type Instance = Instance;
|
||||
type Surface = Surface;
|
||||
type Adapter = Context;
|
||||
type Device = Context;
|
||||
|
||||
type Queue = Context;
|
||||
type CommandEncoder = Encoder;
|
||||
type CommandBuffer = Resource;
|
||||
|
||||
type Buffer = Resource;
|
||||
type Texture = Resource;
|
||||
type SurfaceTexture = Resource;
|
||||
type TextureView = Resource;
|
||||
type Sampler = Resource;
|
||||
type QuerySet = Resource;
|
||||
type Fence = Resource;
|
||||
|
||||
type BindGroupLayout = Resource;
|
||||
type BindGroup = Resource;
|
||||
type PipelineLayout = Resource;
|
||||
type ShaderModule = Resource;
|
||||
type RenderPipeline = Resource;
|
||||
type ComputePipeline = Resource;
|
||||
}
|
||||
|
||||
type TextureFormat = u32;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum VertexAttribKind {
|
||||
Float, // glVertexAttribPointer
|
||||
Integer, // glVertexAttribIPointer
|
||||
Double, // glVertexAttribLPointer
|
||||
}
|
||||
|
||||
struct FormatDescription {
|
||||
tex_internal: u32,
|
||||
tex_external: u32,
|
||||
data_type: u32,
|
||||
num_components: u8,
|
||||
va_kind: VertexAttribKind,
|
||||
}
|
||||
|
||||
impl FormatDescription {
|
||||
fn new(
|
||||
tex_internal: u32,
|
||||
tex_external: u32,
|
||||
data_type: u32,
|
||||
num_components: u8,
|
||||
va_kind: VertexAttribKind,
|
||||
) -> Self {
|
||||
FormatDescription {
|
||||
tex_internal,
|
||||
tex_external,
|
||||
data_type,
|
||||
num_components,
|
||||
va_kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Adapter<Api> for Context {
|
||||
unsafe fn open(&self, features: wgt::Features) -> DeviceResult<crate::OpenDevice<Api>> {
|
||||
Err(crate::DeviceError::Lost)
|
||||
}
|
||||
unsafe fn texture_format_capabilities(
|
||||
&self,
|
||||
format: wgt::TextureFormat,
|
||||
) -> crate::TextureFormatCapability {
|
||||
crate::TextureFormatCapability::empty()
|
||||
}
|
||||
unsafe fn surface_capabilities(&self, surface: &Surface) -> Option<crate::SurfaceCapabilities> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Queue<Api> for Context {
|
||||
unsafe fn submit(
|
||||
&mut self,
|
||||
command_buffers: &[&Resource],
|
||||
signal_fence: Option<(&mut Resource, crate::FenceValue)>,
|
||||
) -> DeviceResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
unsafe fn present(
|
||||
&mut self,
|
||||
surface: &mut Surface,
|
||||
texture: Resource,
|
||||
) -> Result<(), crate::SurfaceError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Device<Api> for Context {
|
||||
unsafe fn exit(self) {}
|
||||
unsafe fn create_buffer(&self, desc: &crate::BufferDescriptor) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_buffer(&self, buffer: Resource) {}
|
||||
unsafe fn map_buffer(
|
||||
&self,
|
||||
buffer: &Resource,
|
||||
range: crate::MemoryRange,
|
||||
) -> DeviceResult<crate::BufferMapping> {
|
||||
Err(crate::DeviceError::Lost)
|
||||
}
|
||||
unsafe fn unmap_buffer(&self, buffer: &Resource) -> DeviceResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
unsafe fn flush_mapped_ranges<I>(&self, buffer: &Resource, ranges: I) {}
|
||||
unsafe fn invalidate_mapped_ranges<I>(&self, buffer: &Resource, ranges: I) {}
|
||||
|
||||
unsafe fn create_texture(&self, desc: &crate::TextureDescriptor) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_texture(&self, texture: Resource) {}
|
||||
unsafe fn create_texture_view(
|
||||
&self,
|
||||
texture: &Resource,
|
||||
desc: &crate::TextureViewDescriptor,
|
||||
) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_texture_view(&self, view: Resource) {}
|
||||
unsafe fn create_sampler(&self, desc: &crate::SamplerDescriptor) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_sampler(&self, sampler: Resource) {}
|
||||
|
||||
unsafe fn create_command_encoder(
|
||||
&self,
|
||||
desc: &crate::CommandEncoderDescriptor<Api>,
|
||||
) -> DeviceResult<Encoder> {
|
||||
Ok(Encoder)
|
||||
}
|
||||
unsafe fn destroy_command_encoder(&self, encoder: Encoder) {}
|
||||
|
||||
unsafe fn create_bind_group_layout(
|
||||
&self,
|
||||
desc: &crate::BindGroupLayoutDescriptor,
|
||||
) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_bind_group_layout(&self, bg_layout: Resource) {}
|
||||
unsafe fn create_pipeline_layout(
|
||||
&self,
|
||||
desc: &crate::PipelineLayoutDescriptor<Api>,
|
||||
) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_pipeline_layout(&self, pipeline_layout: Resource) {}
|
||||
unsafe fn create_bind_group(
|
||||
&self,
|
||||
desc: &crate::BindGroupDescriptor<Api>,
|
||||
) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_bind_group(&self, group: Resource) {}
|
||||
|
||||
unsafe fn create_shader_module(
|
||||
&self,
|
||||
desc: &crate::ShaderModuleDescriptor,
|
||||
shader: crate::NagaShader,
|
||||
) -> Result<Resource, crate::ShaderError> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_shader_module(&self, module: Resource) {}
|
||||
unsafe fn create_render_pipeline(
|
||||
&self,
|
||||
desc: &crate::RenderPipelineDescriptor<Api>,
|
||||
) -> Result<Resource, crate::PipelineError> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_render_pipeline(&self, pipeline: Resource) {}
|
||||
unsafe fn create_compute_pipeline(
|
||||
&self,
|
||||
desc: &crate::ComputePipelineDescriptor<Api>,
|
||||
) -> Result<Resource, crate::PipelineError> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_compute_pipeline(&self, pipeline: Resource) {}
|
||||
|
||||
unsafe fn create_query_set(
|
||||
&self,
|
||||
desc: &wgt::QuerySetDescriptor<crate::Label>,
|
||||
) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_query_set(&self, set: Resource) {}
|
||||
unsafe fn create_fence(&self) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn destroy_fence(&self, fence: Resource) {}
|
||||
unsafe fn get_fence_value(&self, fence: &Resource) -> DeviceResult<crate::FenceValue> {
|
||||
Ok(0)
|
||||
}
|
||||
unsafe fn wait(
|
||||
&self,
|
||||
fence: &Resource,
|
||||
value: crate::FenceValue,
|
||||
timeout_ms: u32,
|
||||
) -> DeviceResult<bool> {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
unsafe fn start_capture(&self) -> bool {
|
||||
false
|
||||
}
|
||||
unsafe fn stop_capture(&self) {}
|
||||
}
|
||||
|
||||
impl crate::CommandEncoder<Api> for Encoder {
|
||||
unsafe fn begin_encoding(&mut self, label: crate::Label) -> DeviceResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
unsafe fn discard_encoding(&mut self) {}
|
||||
unsafe fn end_encoding(&mut self) -> DeviceResult<Resource> {
|
||||
Ok(Resource)
|
||||
}
|
||||
unsafe fn reset_all<I>(&mut self, command_buffers: I) {}
|
||||
|
||||
unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
|
||||
where
|
||||
T: Iterator<Item = crate::BufferBarrier<'a, Api>>,
|
||||
{
|
||||
}
|
||||
|
||||
unsafe fn transition_textures<'a, T>(&mut self, barriers: T)
|
||||
where
|
||||
T: Iterator<Item = crate::TextureBarrier<'a, Api>>,
|
||||
{
|
||||
}
|
||||
|
||||
unsafe fn fill_buffer(&mut self, buffer: &Resource, range: crate::MemoryRange, value: u8) {}
|
||||
|
||||
unsafe fn copy_buffer_to_buffer<T>(&mut self, src: &Resource, dst: &Resource, regions: T) {}
|
||||
|
||||
unsafe fn copy_texture_to_texture<T>(
|
||||
&mut self,
|
||||
src: &Resource,
|
||||
src_usage: crate::TextureUse,
|
||||
dst: &Resource,
|
||||
regions: T,
|
||||
) {
|
||||
}
|
||||
|
||||
unsafe fn copy_buffer_to_texture<T>(&mut self, src: &Resource, dst: &Resource, regions: T) {}
|
||||
|
||||
unsafe fn copy_texture_to_buffer<T>(
|
||||
&mut self,
|
||||
src: &Resource,
|
||||
src_usage: crate::TextureUse,
|
||||
dst: &Resource,
|
||||
regions: T,
|
||||
) {
|
||||
}
|
||||
|
||||
unsafe fn begin_query(&mut self, set: &Resource, index: u32) {}
|
||||
unsafe fn end_query(&mut self, set: &Resource, index: u32) {}
|
||||
unsafe fn write_timestamp(&mut self, set: &Resource, index: u32) {}
|
||||
unsafe fn reset_queries(&mut self, set: &Resource, range: Range<u32>) {}
|
||||
unsafe fn copy_query_results(
|
||||
&mut self,
|
||||
set: &Resource,
|
||||
range: Range<u32>,
|
||||
buffer: &Resource,
|
||||
offset: wgt::BufferAddress,
|
||||
) {
|
||||
}
|
||||
|
||||
// render
|
||||
|
||||
unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor<Api>) {}
|
||||
unsafe fn end_render_pass(&mut self) {}
|
||||
|
||||
unsafe fn set_bind_group(
|
||||
&mut self,
|
||||
layout: &Resource,
|
||||
index: u32,
|
||||
group: &Resource,
|
||||
dynamic_offsets: &[wgt::DynamicOffset],
|
||||
) {
|
||||
}
|
||||
unsafe fn set_push_constants(
|
||||
&mut self,
|
||||
layout: &Resource,
|
||||
stages: wgt::ShaderStage,
|
||||
offset: u32,
|
||||
data: &[u32],
|
||||
) {
|
||||
}
|
||||
|
||||
unsafe fn insert_debug_marker(&mut self, label: &str) {}
|
||||
unsafe fn begin_debug_marker(&mut self, group_label: &str) {}
|
||||
unsafe fn end_debug_marker(&mut self) {}
|
||||
|
||||
unsafe fn set_render_pipeline(&mut self, pipeline: &Resource) {}
|
||||
|
||||
unsafe fn set_index_buffer<'a>(
|
||||
&mut self,
|
||||
binding: crate::BufferBinding<'a, Api>,
|
||||
format: wgt::IndexFormat,
|
||||
) {
|
||||
}
|
||||
unsafe fn set_vertex_buffer<'a>(&mut self, index: u32, binding: crate::BufferBinding<'a, Api>) {
|
||||
}
|
||||
unsafe fn set_viewport(&mut self, rect: &crate::Rect<f32>, depth_range: Range<f32>) {}
|
||||
unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect<u32>) {}
|
||||
unsafe fn set_stencil_reference(&mut self, value: u32) {}
|
||||
unsafe fn set_blend_constants(&mut self, color: &wgt::Color) {}
|
||||
|
||||
unsafe fn draw(
|
||||
&mut self,
|
||||
start_vertex: u32,
|
||||
vertex_count: u32,
|
||||
start_instance: u32,
|
||||
instance_count: u32,
|
||||
) {
|
||||
}
|
||||
unsafe fn draw_indexed(
|
||||
&mut self,
|
||||
start_index: u32,
|
||||
index_count: u32,
|
||||
base_vertex: i32,
|
||||
start_instance: u32,
|
||||
instance_count: u32,
|
||||
) {
|
||||
}
|
||||
unsafe fn draw_indirect(
|
||||
&mut self,
|
||||
buffer: &Resource,
|
||||
offset: wgt::BufferAddress,
|
||||
draw_count: u32,
|
||||
) {
|
||||
}
|
||||
unsafe fn draw_indexed_indirect(
|
||||
&mut self,
|
||||
buffer: &Resource,
|
||||
offset: wgt::BufferAddress,
|
||||
draw_count: u32,
|
||||
) {
|
||||
}
|
||||
unsafe fn draw_indirect_count(
|
||||
&mut self,
|
||||
buffer: &Resource,
|
||||
offset: wgt::BufferAddress,
|
||||
count_buffer: &Resource,
|
||||
count_offset: wgt::BufferAddress,
|
||||
max_count: u32,
|
||||
) {
|
||||
}
|
||||
unsafe fn draw_indexed_indirect_count(
|
||||
&mut self,
|
||||
buffer: &Resource,
|
||||
offset: wgt::BufferAddress,
|
||||
count_buffer: &Resource,
|
||||
count_offset: wgt::BufferAddress,
|
||||
max_count: u32,
|
||||
) {
|
||||
}
|
||||
|
||||
// compute
|
||||
|
||||
unsafe fn begin_compute_pass(&mut self, desc: &crate::ComputePassDescriptor) {}
|
||||
unsafe fn end_compute_pass(&mut self) {}
|
||||
|
||||
unsafe fn set_compute_pipeline(&mut self, pipeline: &Resource) {}
|
||||
|
||||
unsafe fn dispatch(&mut self, count: [u32; 3]) {}
|
||||
unsafe fn dispatch_indirect(&mut self, buffer: &Resource, offset: wgt::BufferAddress) {}
|
||||
}
|
||||
@@ -48,11 +48,14 @@ mod empty;
|
||||
#[cfg(all(feature = "metal", any(target_os = "macos", target_os = "ios")))]
|
||||
mod metal;
|
||||
#[cfg(feature = "vulkan")]
|
||||
mod vulkan;
|
||||
mod vulkan;#[cfg(feature = "gles")]
|
||||
mod gles;
|
||||
|
||||
pub mod util;
|
||||
pub mod api {
|
||||
pub use super::empty::Api as Empty;
|
||||
#[cfg(feature = "gles")]
|
||||
pub use super::gles::Api as Gles;
|
||||
#[cfg(feature = "metal")]
|
||||
pub use super::metal::Api as Metal;
|
||||
#[cfg(feature = "vulkan")]
|
||||
|
||||
Reference in New Issue
Block a user