Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/angle/context.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
//! Wrapper for EGL contexts managed by ANGLE using Direct3D 11 as a backend on Windows.

use super::surface::Surface;
use crate::angle::surface::AngleSurface;
pub use crate::base::egl::context::NativeContext;
use crate::base::egl::surface::ExternalEGLSurfaces;
use crate::context::ContextID;
use crate::egl;
use crate::egl::types::EGLContext;
use crate::surface::Framebuffer;
use crate::Gl;
use crate::{egl, Gl};
use std::thread;

/// An implementation of [`crate::Context`] for ANGLE on Windows.
pub struct AngleContext {
pub(crate) egl_context: EGLContext,
pub(crate) id: ContextID,
pub(crate) framebuffer: Framebuffer<Surface, ExternalEGLSurfaces>,
pub(crate) framebuffer: Framebuffer<AngleSurface, ExternalEGLSurfaces>,
pub(crate) context_is_owned: bool,
pub(crate) gl: Gl,
}
Expand Down
68 changes: 38 additions & 30 deletions src/angle/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::adapter::AngleAdapter;
use crate::angle::connection::Connection;
use crate::angle::context::{AngleContext, NativeContext};
use crate::angle::surface::{
Surface, SurfaceDataGuard, SurfaceTexture, Synchronization, Win32Objects,
AngleSurface, AngleSurfaceTexture, SurfaceDataGuard, Synchronization, Win32Objects,
};
use crate::base::egl::context::{self, CurrentContextGuard};
use crate::base::egl::device::EGL_FUNCTIONS;
Expand All @@ -22,7 +22,7 @@ use crate::egl::types::{
use crate::surface::Framebuffer;
use crate::{
egl, gl, Adapter, Context, ContextAttributes, ContextDescriptor, EglContextDescriptor, Error,
GLApi, Gl, SurfaceAccess, SurfaceInfo, SurfaceType,
GLApi, Gl, Surface, SurfaceAccess, SurfaceInfo, SurfaceTexture, SurfaceType,
};
use euclid::default::Size2D;
use glow::HasContext;
Expand Down Expand Up @@ -487,14 +487,15 @@ impl Device {
Ok(context) => context,
Err(error) => return Err((error, surface)),
};
let surface: AngleSurface = surface.try_into()?;
if context.id != surface.context_id {
return Err((Error::IncompatibleSurface, surface));
return Err((Error::IncompatibleSurface, surface.into()));
}

match context.framebuffer {
Framebuffer::None => {}
Framebuffer::External(_) => return Err((Error::ExternalRenderTarget, surface)),
Framebuffer::Surface(_) => return Err((Error::SurfaceAlreadyBound, surface)),
Framebuffer::External(_) => return Err((Error::ExternalRenderTarget, surface.into())),
Framebuffer::Surface(_) => return Err((Error::SurfaceAlreadyBound, surface.into())),
}

// If the surface is synchronized with GLFinish, then finish.
Expand Down Expand Up @@ -561,7 +562,7 @@ impl Device {
_ => {}
}

Ok(Some(surface))
Ok(Some(surface.into()))
}

/// Displays the contents of the currently bound surface to the screen, if
Expand Down Expand Up @@ -608,15 +609,15 @@ impl Device {
match context.framebuffer {
Framebuffer::None => Ok(None),
Framebuffer::External(_) => Err(Error::ExternalRenderTarget),
Framebuffer::Surface(ref surface) => Ok(Some(self.surface_info(surface))),
Framebuffer::Surface(ref surface) => Ok(Some(surface.info())),
}
}

/// Given a context, returns its underlying EGL context and attached surfaces.
pub fn native_context(&self, context: &Context) -> NativeContext {
let context = context.angle().expect("Passed incorrect context type");
let (egl_draw_surface, egl_read_surface) = match context.framebuffer {
Framebuffer::Surface(Surface { egl_surface, .. }) => (egl_surface, egl_surface),
Framebuffer::Surface(AngleSurface { egl_surface, .. }) => (egl_surface, egl_surface),
Framebuffer::External(ExternalEGLSurfaces { draw, read }) => (draw, read),
Framebuffer::None => (egl::NO_SURFACE, egl::NO_SURFACE),
};
Expand All @@ -639,7 +640,9 @@ impl Device {
surface_type: SurfaceType<'_>,
) -> Result<Surface, Error> {
match surface_type {
SurfaceType::Generic { ref size } => self.create_pbuffer_surface(context, size, None),
SurfaceType::Generic { ref size } => self
.create_pbuffer_surface(context, size, None)
.map(Into::into),
SurfaceType::Widget { window_handle, .. } => {
let RawWindowHandle::Win32(handle) = window_handle.as_raw() else {
return Err(Error::IncompatibleSurfaceType);
Expand All @@ -655,7 +658,7 @@ impl Device {
context: &Context,
size: &Size2D<i32>,
texture: Option<ComPtr<d3d11::ID3D11Texture2D>>,
) -> Result<Surface, Error> {
) -> Result<AngleSurface, Error> {
let context_descriptor = self.context_descriptor(context);
let context_descriptor = context_descriptor.egl()?.clone();
let egl_config = self.context_descriptor_to_egl_config(&context_descriptor);
Expand Down Expand Up @@ -730,7 +733,7 @@ impl Device {
Synchronization::None
};

Ok(Surface {
Ok(AngleSurface {
egl_surface,
size: *size,
context_id: context.id,
Expand All @@ -754,6 +757,7 @@ impl Device {
texture: ComPtr<d3d11::ID3D11Texture2D>,
) -> Result<Surface, Error> {
self.create_pbuffer_surface(context, size, Some(texture))
.map(Into::into)
}

fn create_window_surface(
Expand Down Expand Up @@ -793,13 +797,14 @@ impl Device {
assert_ne!(width, 0);
assert_ne!(height, 0);

Ok(Surface {
Ok(AngleSurface {
egl_surface,
size: Size2D::new(width, height),
context_id: context.id,
context_descriptor,
win32_objects: Win32Objects::Window,
})
}
.into())
})
}
}
Expand All @@ -820,8 +825,9 @@ impl Device {
context: &mut Context,
surface: Surface,
) -> Result<SurfaceTexture, (Error, Surface)> {
let surface: AngleSurface = surface.try_into()?;
let share_handle = match surface.win32_objects {
Win32Objects::Window => return Err((Error::WidgetAttached, surface)),
Win32Objects::Window => return Err((Error::WidgetAttached, surface.into())),
Win32Objects::Pbuffer { share_handle, .. } => share_handle,
};

Expand Down Expand Up @@ -853,7 +859,10 @@ impl Device {
);
if local_egl_surface == egl::NO_SURFACE {
let windowing_api_error = egl.GetError().to_windowing_api_error();
return Err((Error::SurfaceImportFailed(windowing_api_error), surface));
return Err((
Error::SurfaceImportFailed(windowing_api_error),
surface.into(),
));
}

let mut local_keyed_mutex: *mut IDXGIKeyedMutex = ptr::null_mut();
Expand Down Expand Up @@ -889,13 +898,13 @@ impl Device {
fn create_surface_texture_from_local_surface(
&self,
context: &Context,
surface: Surface,
surface: AngleSurface,
local_egl_surface: EGLSurface,
local_keyed_mutex: Option<ComPtr<IDXGIKeyedMutex>>,
) -> Result<SurfaceTexture, (Error, Surface)> {
let context = match context.angle() {
Ok(context) => context,
Err(error) => return Err((error, surface)),
Err(error) => return Err((error, surface.into())),
};

EGL_FUNCTIONS.with(|egl| {
Expand All @@ -913,7 +922,7 @@ impl Device {
let windowing_api_error = egl.GetError().to_windowing_api_error();
return Err((
Error::SurfaceTextureCreationFailed(windowing_api_error),
surface,
surface.into(),
));
}

Expand All @@ -926,13 +935,14 @@ impl Device {
gl.bind_texture(gl::TEXTURE_2D, None);
debug_assert_eq!(gl.get_error(), gl::NO_ERROR);

Ok(SurfaceTexture {
Ok(AngleSurfaceTexture {
surface,
local_egl_surface,
local_keyed_mutex,
gl_texture: Some(texture),
phantom: PhantomData,
})
}
.into())
}
})
}
Expand Down Expand Up @@ -968,6 +978,7 @@ impl Device {
surface: &mut Surface,
) -> Result<(), Error> {
let context = context.angle()?;
let surface: &mut AngleSurface = surface.try_into()?;
if context.id != surface.context_id {
return Err(Error::IncompatibleSurface);
}
Expand Down Expand Up @@ -1004,12 +1015,13 @@ impl Device {
pub fn destroy_surface_texture(
&self,
context: &mut Context,
mut surface_texture: SurfaceTexture,
surface_texture: SurfaceTexture,
) -> Result<Surface, (Error, SurfaceTexture)> {
let context = match context.angle() {
Ok(context) => context,
Err(error) => return Err((error, surface_texture)),
};
let mut surface_texture: AngleSurfaceTexture = surface_texture.try_into()?;

unsafe {
if let Some(texture) = surface_texture.gl_texture.take() {
Expand All @@ -1031,7 +1043,7 @@ impl Device {
})
}

Ok(surface_texture.surface)
Ok(surface_texture.surface.into())
}

/// Returns the OpenGL texture target needed to read from this surface texture.
Expand Down Expand Up @@ -1059,7 +1071,7 @@ impl Device {
/// The supplied context must match the context the surface was created with, or an
/// `IncompatibleSurface` error is returned.
pub fn present_surface(&self, _: &Context, surface: &mut Surface) -> Result<(), Error> {
surface.present(self)
surface.angle()?.present(self)
}

/// Resizes a widget surface.
Expand All @@ -1069,6 +1081,7 @@ impl Device {
surface: &mut Surface,
size: Size2D<i32>,
) -> Result<(), Error> {
let surface: &mut AngleSurface = surface.try_into()?;
surface.resize(size);
Ok(())
}
Expand All @@ -1081,12 +1094,7 @@ impl Device {
/// 0, the default framebuffer, depending on platform.
#[inline]
pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo {
SurfaceInfo {
size: surface.size,
id: surface.id(),
context_id: surface.context_id,
framebuffer_object: None,
}
surface.angle().expect("Incompatible surface type").info()
}

/// Returns the OpenGL texture object containing the contents of this surface.
Expand All @@ -1097,7 +1105,7 @@ impl Device {
&self,
surface_texture: &SurfaceTexture,
) -> Option<glow::Texture> {
surface_texture.gl_texture
surface_texture.angle().ok()?.gl_texture
}
}

Expand Down
54 changes: 20 additions & 34 deletions src/angle/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::base::egl::device::EGL_FUNCTIONS;
use crate::context::ContextID;
use crate::egl::types::EGLSurface;
use crate::egl::{self};
use crate::{EglContextDescriptor, Error, SurfaceID};
use crate::{EglContextDescriptor, Error, SurfaceID, SurfaceInfo};

use euclid::default::Size2D;
use std::fmt::{self, Debug, Formatter};
Expand All @@ -16,64 +16,41 @@ use winapi::um::d3d11;
use winapi::um::winnt::HANDLE;
use wio::com::ComPtr;

/// Represents a hardware buffer of pixels that can be rendered to via the CPU or GPU and either
/// displayed in a native widget or bound to a texture for reading.
///
/// Surfaces come in two varieties: generic and widget surfaces. Generic surfaces can be bound to a
/// texture but cannot be displayed in a widget (without using other APIs such as Core Animation,
/// DirectComposition, or XPRESENT). Widget surfaces are the opposite: they can be displayed in a
/// widget but not bound to a texture.
///
/// Surfaces are specific to a given context and cannot be rendered to from any context other than
/// the one they were created with. However, they can be *read* from any context on any thread (as
/// long as that context shares the same adapter and connection), by wrapping them in a
/// `SurfaceTexture`.
///
/// Depending on the platform, each surface may be internally double-buffered.
///
/// Surfaces must be destroyed with the `destroy_surface()` method, or a panic will occur.
pub struct Surface {
/// An implementation of [`crate::Surface`] for Angle on Windows.
pub struct AngleSurface {
pub(crate) egl_surface: EGLSurface,
pub(crate) size: Size2D<i32>,
pub(crate) context_id: ContextID,
pub(crate) context_descriptor: EglContextDescriptor,
pub(crate) win32_objects: Win32Objects,
}

/// Represents an OpenGL texture that wraps a surface.
///
/// Reading from the associated OpenGL texture reads from the surface. It is undefined behavior to
/// write to such a texture (e.g. by binding it to a framebuffer and rendering to that
/// framebuffer).
///
/// Surface textures are local to a context, but that context does not have to be the same context
/// as that associated with the underlying surface. The texture must be destroyed with the
/// `destroy_surface_texture()` method, or a panic will occur.
pub struct SurfaceTexture {
pub(crate) surface: Surface,
/// An implementation of [`crate::SurfaceTexture`] for Angle on Windows.
pub struct AngleSurfaceTexture {
pub(crate) surface: AngleSurface,
pub(crate) local_egl_surface: EGLSurface,
pub(crate) local_keyed_mutex: Option<ComPtr<IDXGIKeyedMutex>>,
pub(crate) gl_texture: Option<glow::Texture>,
pub(crate) phantom: PhantomData<*const ()>,
}

unsafe impl Send for Surface {}
unsafe impl Send for AngleSurface {}

impl Debug for Surface {
impl Debug for AngleSurface {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(f, "Surface({:x})", self.id().0)
}
}

impl Drop for Surface {
impl Drop for AngleSurface {
fn drop(&mut self) {
if self.egl_surface != egl::NO_SURFACE && !thread::panicking() {
panic!("Should have destroyed the surface first with `destroy_surface()`!")
}
}
}

impl Debug for SurfaceTexture {
impl Debug for AngleSurfaceTexture {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(f, "SurfaceTexture({:?})", self.surface)
}
Expand All @@ -95,7 +72,7 @@ pub(crate) enum Synchronization {
None,
}

impl Surface {
impl AngleSurface {
#[inline]
pub(crate) fn id(&self) -> SurfaceID {
SurfaceID(self.egl_surface as usize)
Expand Down Expand Up @@ -137,6 +114,15 @@ impl Surface {
pub(crate) fn resize(&mut self, size: Size2D<i32>) {
self.size = size;
}

pub(crate) fn info(&self) -> SurfaceInfo {
SurfaceInfo {
size: self.size,
id: self.id(),
context_id: self.context_id,
framebuffer_object: None,
}
}
}

/// Represents the CPU view of the pixel data of this surface.
Expand Down
Loading
Loading