Merge pull request #336 from Smithay/fixes/backend
This commit is contained in:
commit
a5fca7b4ff
|
@ -99,7 +99,7 @@ where
|
|||
B: Buffer,
|
||||
U: 'static,
|
||||
{
|
||||
/// Create a new swapchain with the desired allocator and dimensions and pixel format for the created buffers.
|
||||
/// Create a new swapchain with the desired allocator, dimensions and pixel format for the created buffers.
|
||||
pub fn new(
|
||||
allocator: A,
|
||||
width: u32,
|
||||
|
|
|
@ -213,8 +213,6 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
|
|||
/// - [`crtcs`](drm::control::crtc) represent scanout engines of the device pointing to one framebuffer. \
|
||||
/// Their responsibility is to read the data of the framebuffer and export it into an "Encoder". \
|
||||
/// The number of crtc's represent the number of independant output devices the hardware may handle.
|
||||
/// - [`planes`](drm::control::plane) represent a single plane on a crtc, which is composite together with
|
||||
/// other planes on the same crtc to present the final image.
|
||||
/// - [`mode`](drm::control::Mode) describes the resolution and rate of images produced by the crtc and \
|
||||
/// has to be compatible with the provided `connectors`.
|
||||
/// - [`connectors`](drm::control::connector) - List of connectors driven by the crtc. At least one(!) connector needs to be \
|
||||
|
|
|
@ -28,8 +28,8 @@ pub enum Error {
|
|||
/// Mode is not compatible with all given connectors
|
||||
#[error("Mode `{0:?}` is not compatible with all given connectors")]
|
||||
ModeNotSuitable(Mode),
|
||||
/// The given crtc is already in use by another backend
|
||||
#[error("Crtc `{0:?}` is already in use by another backend")]
|
||||
/// The given crtc is already in use by another surface
|
||||
#[error("Crtc `{0:?}` is already in use by another surface")]
|
||||
CrtcAlreadyInUse(crtc::Handle),
|
||||
/// This operation would result in a surface without connectors.
|
||||
#[error("Surface of crtc `{0:?}` would have no connectors, which is not accepted")]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//!
|
||||
//! ## DrmDevice
|
||||
//!
|
||||
//! A device exposes certain properties, which are directly derived
|
||||
//! A device exposes certain properties, which are directly derived
|
||||
//! from the *device* as perceived by the direct rendering manager api (drm). These resources consists
|
||||
//! out of connectors, encoders, framebuffers, planes and crtcs.
|
||||
//!
|
||||
|
@ -20,13 +20,13 @@
|
|||
//!
|
||||
//! A [`connector`](drm::control::connector) represents a port on your computer, possibly with a connected monitor, TV, capture card, etc.
|
||||
//!
|
||||
//! A [`framebuffer`](drm::control::framebuffer) represents a buffer you may be rendering to, see `Surface` below.
|
||||
//! A [`framebuffer`](drm::control::framebuffer) represents a buffer you may be rendering to, see `DrmSurface` below.
|
||||
//!
|
||||
//! A [`plane`](drm::control::plane) adds another layer on top of the crtcs, which allow us to layer multiple images on top of each other more efficiently
|
||||
//! then by combining the rendered images in the rendering phase, e.g. via OpenGL. Planes can be explicitly used by the user.
|
||||
//! then by combining the rendered images in the rendering phase, e.g. via OpenGL. Planes have to be explicitly used by the user to be useful.
|
||||
//! Every device has at least one primary plane used to display an image to the whole crtc. Additionally cursor and overlay planes may be present.
|
||||
//! Cursor planes are usually very restricted in size and meant to be used for hardware cursors, while overlay planes may
|
||||
//! be used for performance reasons to display any overlay on top of the image, e.g. top-most windows.
|
||||
//! be used for performance reasons to display any overlay on top of the image, e.g. the top-most windows.
|
||||
//!
|
||||
//! The main functionality of a `Device` in smithay is to give access to all these properties for the user to
|
||||
//! choose an appropriate rendering configuration. What that means is defined by the requirements and constraints documented
|
||||
|
|
|
@ -16,13 +16,7 @@ use crate::backend::SwapBuffersError;
|
|||
|
||||
use slog::{debug, error, o, trace, warn};
|
||||
|
||||
/// Simplified by limited abstraction to link single [`DrmSurface`]s to renderers.
|
||||
///
|
||||
/// # Use-case
|
||||
///
|
||||
/// In some scenarios it might be enough to use of a drm-surface as the one and only target
|
||||
/// of a single renderer. In these cases `DrmRenderSurface` provides a way to quickly
|
||||
/// get up and running without manually handling and binding buffers.
|
||||
/// Simplified abstraction of a swapchain for gbm-buffers displayed on a [`DrmSurface`].
|
||||
pub struct GbmBufferedSurface<D: AsRawFd + 'static> {
|
||||
buffers: Buffers<D>,
|
||||
swapchain: Swapchain<GbmDevice<D>, BufferObject<()>, (Dmabuf, FbHandle<D>)>,
|
||||
|
@ -43,15 +37,12 @@ impl<D> GbmBufferedSurface<D>
|
|||
where
|
||||
D: AsRawFd + 'static,
|
||||
{
|
||||
/// Create a new `DrmRendererSurface` from a given compatible combination
|
||||
/// of a surface, an allocator and a renderer.
|
||||
/// Create a new `GbmBufferedSurface` from a given compatible combination
|
||||
/// of a surface, an allocator and renderer formats.
|
||||
///
|
||||
/// To sucessfully call this function, you need to have a renderer,
|
||||
/// which can render into a Dmabuf, and an allocator, which can create
|
||||
/// a buffer type, which can be converted into a Dmabuf.
|
||||
///
|
||||
/// The function will futhermore check for compatibility by enumerating
|
||||
/// supported pixel formats and choosing an appropriate one.
|
||||
/// which can render into a Dmabuf, and a gbm allocator that can produce
|
||||
/// buffers of a supported format for rendering.
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn new<L>(
|
||||
drm: DrmSurface<D>,
|
||||
|
|
|
@ -63,7 +63,7 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
|
|||
self.primary
|
||||
}
|
||||
|
||||
/// Currently used [`connector`](drm::control::connector)s of this `Surface`
|
||||
/// Currently used [`connector`](drm::control::connector)s of this surface
|
||||
pub fn current_connectors(&self) -> impl IntoIterator<Item = connector::Handle> {
|
||||
match &*self.internal {
|
||||
DrmSurfaceInternal::Atomic(surf) => surf.current_connectors(),
|
||||
|
@ -72,7 +72,7 @@ impl<A: AsRawFd + 'static> DrmSurface<A> {
|
|||
}
|
||||
|
||||
/// Returns the pending [`connector`](drm::control::connector)s
|
||||
/// used after the next [`commit`](DrmSurface::commit) of this [`DrmSurface`]
|
||||
/// used after the next [`commit`](DrmSurface::commit) of this surface
|
||||
pub fn pending_connectors(&self) -> impl IntoIterator<Item = connector::Handle> {
|
||||
match &*self.internal {
|
||||
DrmSurfaceInternal::Atomic(surf) => surf.pending_connectors(),
|
||||
|
|
|
@ -171,7 +171,7 @@ impl EGLContext {
|
|||
/// # Safety
|
||||
///
|
||||
/// This function is marked unsafe, because the context cannot be made current
|
||||
/// on multiple threads.
|
||||
/// on multiple threads without being unbound again (see `unbind`).
|
||||
pub unsafe fn make_current_with_surface(&self, surface: &EGLSurface) -> Result<(), MakeCurrentError> {
|
||||
let surface_ptr = surface.surface.load(Ordering::SeqCst);
|
||||
wrap_egl_call(|| {
|
||||
|
@ -186,7 +186,7 @@ impl EGLContext {
|
|||
/// # Safety
|
||||
///
|
||||
/// This function is marked unsafe, because the context cannot be made current
|
||||
/// on multiple threads without being unbound again (see `unbind`)
|
||||
/// on multiple threads without being unbound again (see `unbind`).
|
||||
pub unsafe fn make_current(&self) -> Result<(), MakeCurrentError> {
|
||||
wrap_egl_call(|| {
|
||||
ffi::egl::MakeCurrent(
|
||||
|
@ -217,7 +217,7 @@ impl EGLContext {
|
|||
|
||||
/// Unbinds this context from the current thread, if set.
|
||||
///
|
||||
/// This does nothing if this context is not the current context
|
||||
/// This does nothing if this context is not the current context.
|
||||
pub fn unbind(&self) -> Result<(), MakeCurrentError> {
|
||||
if self.is_current() {
|
||||
wrap_egl_call(|| unsafe {
|
||||
|
@ -232,12 +232,12 @@ impl EGLContext {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns a list of formats for dmabufs that can be rendered to
|
||||
/// Returns a list of formats for dmabufs that can be rendered to.
|
||||
pub fn dmabuf_render_formats(&self) -> &HashSet<DrmFormat> {
|
||||
&self.display.dmabuf_render_formats
|
||||
}
|
||||
|
||||
/// Returns a list of formats for dmabufs that can be used as textures
|
||||
/// Returns a list of formats for dmabufs that can be used as textures.
|
||||
pub fn dmabuf_texture_formats(&self) -> &HashSet<DrmFormat> {
|
||||
&self.display.dmabuf_import_formats
|
||||
}
|
||||
|
@ -262,7 +262,7 @@ pub struct GlAttributes {
|
|||
/// `(3, 0)` will request a OpenGL ES 3.0 context for example.
|
||||
/// `(2, 0)` is the minimum.
|
||||
pub version: (u8, u8),
|
||||
/// OpenGL profile to use
|
||||
/// OpenGL profile to use.
|
||||
pub profile: Option<GlProfile>,
|
||||
/// Whether to enable the debug flag of the context.
|
||||
///
|
||||
|
@ -276,7 +276,7 @@ pub struct GlAttributes {
|
|||
/// Describes the requested OpenGL context profiles.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum GlProfile {
|
||||
/// Include all the immediate more functions and definitions.
|
||||
/// Include all the immediate functions and definitions.
|
||||
Compatibility,
|
||||
/// Include all the future-compatible functions and definitions.
|
||||
Core,
|
||||
|
|
|
@ -389,7 +389,7 @@ impl EGLDisplay {
|
|||
Ok((desc, config_id))
|
||||
}
|
||||
|
||||
/// Get a handle to the underlying native EGLDisplay
|
||||
/// Get a handle to the underlying raw EGLDisplay handle
|
||||
pub fn get_display_handle(&self) -> Arc<EGLDisplayHandle> {
|
||||
self.display.clone()
|
||||
}
|
||||
|
@ -404,7 +404,7 @@ impl EGLDisplay {
|
|||
self.extensions.clone()
|
||||
}
|
||||
|
||||
/// Imports a dmabuf as an eglimage
|
||||
/// Imports a [`Dmabuf`] as an [`EGLImage`]
|
||||
pub fn create_image_from_dmabuf(&self, dmabuf: &Dmabuf) -> Result<EGLImage, Error> {
|
||||
if !self.extensions.iter().any(|s| s == "EGL_KHR_image_base")
|
||||
&& !self
|
||||
|
|
|
@ -39,11 +39,11 @@ pub enum Error {
|
|||
/// No EGLDisplay is currently bound to this `WlDisplay`
|
||||
#[error("No EGLDisplay is currently bound to this `WlDisplay`")]
|
||||
NoEGLDisplayBound,
|
||||
/// Index of plane is out of bounds for `EGLImages`
|
||||
#[error("Index of plane is out of bounds for `EGLImages`")]
|
||||
/// Index of plane is out of bounds for `EGLBuffer`
|
||||
#[error("Index of plane is out of bounds for `EGLBuffer`")]
|
||||
PlaneIndexOutOfBounds,
|
||||
/// Failed to create `EGLImages` from the buffer
|
||||
#[error("Failed to create `EGLImages` from the buffer")]
|
||||
/// Failed to create `EGLBuffer` from the buffer
|
||||
#[error("Failed to create `EGLBuffer` from the buffer")]
|
||||
EGLImageCreationFailed,
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,8 @@ impl EGLError {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn wrap_egl_call<R, F: FnOnce() -> R>(call: F) -> Result<R, EGLError> {
|
||||
/// Wraps a raw egl call and returns error codes from `eglGetError`, if it fails.
|
||||
pub fn wrap_egl_call<R, F: FnOnce() -> R>(call: F) -> Result<R, EGLError> {
|
||||
let res = call();
|
||||
EGLError::from_last_call().map(|()| res)
|
||||
}
|
||||
|
|
|
@ -41,6 +41,8 @@ extern "system" fn egl_debug_log(
|
|||
});
|
||||
}
|
||||
|
||||
/// Loads libEGL symbols, if not loaded already.
|
||||
/// This normally happens automatically during [`EGLDisplay`] initialization.
|
||||
pub fn make_sure_egl_is_loaded() -> Result<Vec<String>, Error> {
|
||||
use std::{
|
||||
ffi::{CStr, CString},
|
||||
|
@ -107,6 +109,7 @@ pub fn make_sure_egl_is_loaded() -> Result<Vec<String>, Error> {
|
|||
Ok(extensions)
|
||||
}
|
||||
|
||||
/// Module containing raw egl function bindings
|
||||
#[allow(clippy::all, missing_debug_implementations)]
|
||||
pub mod egl {
|
||||
use super::*;
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
//! Common traits and types for egl rendering
|
||||
//!
|
||||
//! Large parts of this module are taken from
|
||||
//! [glutin src/api/egl](https://github.com/tomaka/glutin/tree/044e651edf67a2029eecc650dd42546af1501414/src/api/egl/)
|
||||
//! This module has multiple responsibilities related to functionality provided by libEGL:
|
||||
//! Initializing EGL objects to:
|
||||
//! - initialize usage of EGL based [`WlBuffer`](wayland_server::protocol::wl_buffer::WlBuffer)s via `wl_drm`.
|
||||
//! - initialize OpenGL contexts from.
|
||||
//! - Import/Export external resources to/from OpenGL
|
||||
//!
|
||||
//! It therefore falls under
|
||||
//! [glutin's Apache 2.0 license](https://github.com/tomaka/glutin/tree/044e651edf67a2029eecc650dd42546af1501414/LICENSE)
|
||||
//! To use this module, you first need to create a [`EGLDisplay`] through a supported EGL platform
|
||||
//! as inidicated by an implementation of the `native::EGLNativeDisplay` trait.
|
||||
//!
|
||||
//! Wayland specific EGL functionality - EGL based [`WlBuffer`](wayland_server::protocol::wl_buffer::WlBuffer)s.
|
||||
//! You may bind the [`EGLDisplay`], that shall be used by clients for rendering (so pick one initialized by a fast platform)
|
||||
//! to the [`wayland_server::Display`] of your compositor. Note only one backend may be bound to any [`Display`](wayland_server::Display) at any time.
|
||||
//!
|
||||
//! The types of this module can be used to initialize hardware acceleration rendering
|
||||
//! based on EGL for clients as it may enabled usage of `EGLImage` based [`WlBuffer`](wayland_server::protocol::wl_buffer::WlBuffer)s.
|
||||
//!
|
||||
//! To use it bind the [`EGLDisplay`] trait, that shall do the
|
||||
//! rendering (so pick a fast one), to the [`wayland_server::Display`] of your compositor.
|
||||
//! Note only one backend may be bound to any [`Display`](wayland_server::Display) at any time.
|
||||
//!
|
||||
//! You may then use the resulting [`EGLDisplay`] to receive [`EGLBuffer`]
|
||||
//! You may then use the resulting [`display::EGLBufferReader`] to receive [`EGLBuffer`]
|
||||
//! of an EGL-based [`WlBuffer`](wayland_server::protocol::wl_buffer::WlBuffer) for rendering.
|
||||
//! Renderers implementing the [`ImportEGL`](crate::backend::renderer::ImportEGL)-trait can manage the buffer reader for you.
|
||||
//!
|
||||
//! To create OpenGL contexts you may create [`EGLContext`]s from the display and if the context is initialized with a config
|
||||
//! it may also be used to initialize an [`EGLSurface`], which can be [bound](crate::backend::renderer::Bind) to some renderers.
|
||||
//!
|
||||
//! Alternatively you may import [`dmabuf`](crate::backend::allocator::dmabuf)s using the display, which result
|
||||
//! in an [`EGLImage`], which can be rendered into by OpenGL. This is perferrable to using surfaces as the dmabuf can be
|
||||
//! passed around freely making resource-management and more complex use-cases like Multi-GPU rendering easier to manage.
|
||||
//! Renderers based on EGL may support doing this for you by allowing you to [`Bind`](crate::backend::renderer::Bind) a dmabuf directly.
|
||||
//!
|
||||
|
||||
/*
|
||||
#[cfg(feature = "renderer_gl")]
|
||||
use crate::backend::graphics::{
|
||||
gl::{ffi as gl_ffi, GLGraphicsBackend},
|
||||
SwapBuffersError as GraphicsSwapBuffersError,
|
||||
};
|
||||
*/
|
||||
use std::fmt;
|
||||
|
||||
pub mod context;
|
||||
|
@ -92,7 +92,7 @@ pub enum BufferAccessError {
|
|||
/// This buffer is not managed by the EGL buffer
|
||||
#[error("This buffer is not managed by EGL. Err: {0:}")]
|
||||
NotManaged(#[source] EGLError),
|
||||
/// Failed to create `EGLImages` from the buffer
|
||||
/// Failed to create `EGLBuffer` from the buffer
|
||||
#[error("Failed to create EGLImages from the buffer. Err: {0:}")]
|
||||
EGLImageCreationFailed(#[source] EGLError),
|
||||
/// The required EGL extension is not supported by the underlying EGL implementation
|
||||
|
@ -186,35 +186,6 @@ impl From<MakeCurrentError> for GraphicsSwapBuffersError {
|
|||
}
|
||||
}
|
||||
|
||||
/// Error that might happen when binding an `EGLImage` to a GL texture
|
||||
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
|
||||
pub enum TextureCreationError {
|
||||
/// The given plane index is out of bounds
|
||||
#[error("This buffer is not managed by EGL")]
|
||||
PlaneIndexOutOfBounds,
|
||||
/// The OpenGL context has been lost and needs to be recreated.
|
||||
///
|
||||
/// All the objects associated to it (textures, buffers, programs, etc.)
|
||||
/// need to be recreated from scratch.
|
||||
///
|
||||
/// Operations will have no effect. Functions that read textures, buffers, etc.
|
||||
/// from OpenGL will return uninitialized data instead.
|
||||
///
|
||||
/// A context loss usually happens on mobile devices when the user puts the
|
||||
/// application on sleep and wakes it up later. However any OpenGL implementation
|
||||
/// can theoretically lose the context at any time.
|
||||
#[error("The context has been lost, it needs to be recreated")]
|
||||
ContextLost,
|
||||
/// Required OpenGL Extension for texture creation is missing
|
||||
#[error("Required OpenGL Extension for texture creation is missing: {0}")]
|
||||
GLExtensionNotSupported(&'static str),
|
||||
/// Failed to bind the `EGLImage` to the given texture
|
||||
///
|
||||
/// The given argument is the GL error code
|
||||
#[error("Failed to create EGLImages from the buffer (GL error code {0:x}")]
|
||||
TextureBindingFailed(u32),
|
||||
}
|
||||
|
||||
/// Texture format types
|
||||
#[repr(i32)]
|
||||
#[allow(non_camel_case_types)]
|
||||
|
@ -261,7 +232,7 @@ pub struct EGLBuffer {
|
|||
|
||||
#[cfg(feature = "wayland_frontend")]
|
||||
impl EGLBuffer {
|
||||
/// Amount of planes of these `EGLImages`
|
||||
/// Amount of planes of this EGLBuffer
|
||||
pub fn num_planes(&self) -> usize {
|
||||
self.format.num_planes()
|
||||
}
|
||||
|
|
|
@ -172,7 +172,6 @@ impl EGLNativeDisplay for WinitWindow {
|
|||
/// The returned [`NativeWindowType`](ffi::NativeWindowType) must be valid for EGL
|
||||
/// and there is no way to test that.
|
||||
pub unsafe trait EGLNativeSurface: Send + Sync {
|
||||
/// Error type thrown by the surface creation in case of failure.
|
||||
/// Create an EGLSurface from the internal native type.
|
||||
///
|
||||
/// Must be able to deal with re-creation of existing resources,
|
||||
|
|
|
@ -46,10 +46,10 @@ impl EGLSurface {
|
|||
/// Create a new `EGLSurface`.
|
||||
///
|
||||
/// Requires:
|
||||
/// - A EGLDisplay supported by the corresponding plattform matching the surface type
|
||||
/// - A EGLDisplay supported by the corresponding platform matching the surface type
|
||||
/// - A pixel format
|
||||
/// - An (optional) preference for double_buffering
|
||||
/// - A valid `EGLConfig` (see `EGLContext::config_id()`)
|
||||
/// - A native type backing the surface matching the used platform
|
||||
/// - An (optional) Logger
|
||||
pub fn new<N, L>(
|
||||
display: &EGLDisplay,
|
||||
|
|
|
@ -407,7 +407,7 @@ impl Gles2Renderer {
|
|||
/// # Implementation details
|
||||
///
|
||||
/// - Texture handles created by the resulting renderer are valid for every rendered created with an
|
||||
/// `EGLContext` shared with the given one (see `EGLContext::new_shared`) and can be used and destroyed on
|
||||
/// `EGLContext` shared with the given one (see `EGLContext::new_shared`) and can be used on
|
||||
/// any of these renderers.
|
||||
/// - This renderer has no default framebuffer, use `Bind::bind` before rendering.
|
||||
/// - Binding a new target, while another one is already bound, will replace the current target.
|
||||
|
|
Loading…
Reference in New Issue