surfman/platform/unix/generic/surface.rs
1//! surfman/surfman/src/platform/unix/generic/surface.rs
2//!
3//! Wrapper for EGL surfaces on Mesa.
4
5use super::context::Context;
6use super::device::Device;
7use crate::gl;
8use crate::platform::generic::egl::surface::{EGLBackedSurface, EGLSurfaceTexture};
9use crate::{Error, SurfaceAccess, SurfaceInfo, SurfaceType};
10
11use euclid::default::Size2D;
12use glow::Texture;
13use std::marker::PhantomData;
14
15// FIXME(pcwalton): Is this right, or should it be `TEXTURE_EXTERNAL_OES`?
16const SURFACE_GL_TEXTURE_TARGET: u32 = gl::TEXTURE_2D;
17
18/// Represents a hardware buffer of pixels that can be rendered to via the CPU or GPU and either
19/// displayed in a native widget or bound to a texture for reading.
20///
21/// Surfaces come in two varieties: generic and widget surfaces. Generic surfaces can be bound to a
22/// texture but cannot be displayed in a widget (without using other APIs such as Core Animation,
23/// DirectComposition, or XPRESENT). Widget surfaces are the opposite: they can be displayed in a
24/// widget but not bound to a texture.
25///
26/// Surfaces are specific to a given context and cannot be rendered to from any context other than
27/// the one they were created with. However, they can be *read* from any context on any thread (as
28/// long as that context shares the same adapter and connection), by wrapping them in a
29/// `SurfaceTexture`.
30///
31/// Depending on the platform, each surface may be internally double-buffered.
32///
33/// Surfaces must be destroyed with the `destroy_surface()` method, or a panic will occur.
34#[derive(Debug)]
35pub struct Surface(pub(crate) EGLBackedSurface);
36
37/// Represents an OpenGL texture that wraps a surface.
38///
39/// Reading from the associated OpenGL texture reads from the surface. It is undefined behavior to
40/// write to such a texture (e.g. by binding it to a framebuffer and rendering to that
41/// framebuffer).
42///
43/// Surface textures are local to a context, but that context does not have to be the same context
44/// as that associated with the underlying surface. The texture must be destroyed with the
45/// `destroy_surface_texture()` method, or a panic will occur.
46#[derive(Debug)]
47pub struct SurfaceTexture(pub(crate) EGLSurfaceTexture);
48
49/// A placeholder wrapper for a native widget.
50#[derive(Clone)]
51pub struct NativeWidget;
52
53unsafe impl Send for Surface {}
54
55impl Device {
56 /// Creates either a generic or a widget surface, depending on the supplied surface type.
57 ///
58 /// Only the given context may ever render to the surface, but generic surfaces can be wrapped
59 /// up in a `SurfaceTexture` for reading by other contexts.
60 pub fn create_surface(
61 &mut self,
62 context: &Context,
63 _: SurfaceAccess,
64 surface_type: SurfaceType<NativeWidget>,
65 ) -> Result<Surface, Error> {
66 match surface_type {
67 SurfaceType::Generic { size } => self.create_generic_surface(context, &size),
68 SurfaceType::Widget { .. } => Err(Error::UnsupportedOnThisPlatform),
69 }
70 }
71
72 fn create_generic_surface(
73 &mut self,
74 context: &Context,
75 size: &Size2D<i32>,
76 ) -> Result<Surface, Error> {
77 let _guard = self.temporarily_make_context_current(context)?;
78 let context_descriptor = self.context_descriptor(context);
79 let context_attributes = self.context_descriptor_attributes(&context_descriptor);
80
81 Ok(Surface(EGLBackedSurface::new_generic(
82 &context.1,
83 self.native_connection.egl_display,
84 context.0.egl_context,
85 context.0.id,
86 &context_attributes,
87 size,
88 )))
89 }
90
91 /// Creates a surface texture from an existing generic surface for use with the given context.
92 ///
93 /// The surface texture is local to the supplied context and takes ownership of the surface.
94 /// Destroying the surface texture allows you to retrieve the surface again.
95 ///
96 /// *The supplied context does not have to be the same context that the surface is associated
97 /// with.* This allows you to render to a surface in one context and sample from that surface
98 /// in another context.
99 ///
100 /// Calling this method on a widget surface returns a `WidgetAttached` error.
101 pub fn create_surface_texture(
102 &self,
103 context: &mut Context,
104 surface: Surface,
105 ) -> Result<SurfaceTexture, (Error, Surface)> {
106 let _guard = match self.temporarily_make_context_current(context) {
107 Ok(guard) => guard,
108 Err(err) => return Err((err, surface)),
109 };
110
111 match surface.0.to_surface_texture(&context.1) {
112 Ok(surface_texture) => Ok(SurfaceTexture(surface_texture)),
113 Err((err, surface)) => Err((err, Surface(surface))),
114 }
115 }
116
117 /// Destroys a surface.
118 ///
119 /// The supplied context must be the context the surface is associated with, or this returns
120 /// an `IncompatibleSurface` error.
121 ///
122 /// You must explicitly call this method to dispose of a surface. Otherwise, a panic occurs in
123 /// the `drop` method.
124 pub fn destroy_surface(
125 &self,
126 context: &mut Context,
127 surface: &mut Surface,
128 ) -> Result<(), Error> {
129 let egl_display = self.native_connection.egl_display;
130 let window = surface.0.destroy(&context.1, egl_display, context.0.id)?;
131 debug_assert!(window.is_none());
132 Ok(())
133 }
134
135 /// Destroys a surface texture and returns the underlying surface.
136 ///
137 /// The supplied context must be the same context the surface texture was created with, or an
138 /// `IncompatibleSurfaceTexture` error is returned.
139 ///
140 /// All surface textures must be explicitly destroyed with this function, or a panic will
141 /// occur.
142 pub fn destroy_surface_texture(
143 &self,
144 context: &mut Context,
145 surface_texture: SurfaceTexture,
146 ) -> Result<Surface, (Error, SurfaceTexture)> {
147 match self.temporarily_make_context_current(context) {
148 Ok(_guard) => Ok(Surface(surface_texture.0.destroy(&context.1))),
149 Err(err) => Err((err, surface_texture)),
150 }
151 }
152
153 /// Displays the contents of a widget surface on screen.
154 ///
155 /// Widget surfaces are internally double-buffered, so changes to them don't show up in their
156 /// associated widgets until this method is called.
157 ///
158 /// The supplied context must match the context the surface was created with, or an
159 /// `IncompatibleSurface` error is returned.
160 pub fn present_surface(&self, context: &Context, surface: &mut Surface) -> Result<(), Error> {
161 surface
162 .0
163 .present(self.native_connection.egl_display, context.0.egl_context)
164 }
165
166 /// Resizes a widget surface.
167 pub fn resize_surface(
168 &self,
169 _context: &Context,
170 surface: &mut Surface,
171 size: Size2D<i32>,
172 ) -> Result<(), Error> {
173 surface.0.size = size;
174 Ok(())
175 }
176
177 /// Returns a pointer to the underlying surface data for reading or writing by the CPU.
178 #[inline]
179 pub fn lock_surface_data<'s>(&self, _: &'s mut Surface) -> Result<SurfaceDataGuard<'s>, Error> {
180 Err(Error::Unimplemented)
181 }
182
183 /// Returns the OpenGL texture target needed to read from this surface texture.
184 ///
185 /// This will be `GL_TEXTURE_2D` or `GL_TEXTURE_RECTANGLE`, depending on platform.
186 #[inline]
187 pub fn surface_gl_texture_target(&self) -> u32 {
188 SURFACE_GL_TEXTURE_TARGET
189 }
190
191 /// Returns various information about the surface, including the framebuffer object needed to
192 /// render to this surface.
193 ///
194 /// Before rendering to a surface attached to a context, you must call `glBindFramebuffer()`
195 /// on the framebuffer object returned by this function. This framebuffer object may or not be
196 /// 0, the default framebuffer, depending on platform.
197 pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo {
198 surface.0.info()
199 }
200
201 /// Returns the OpenGL texture object containing the contents of this surface.
202 ///
203 /// It is only legal to read from, not write to, this texture object.
204 #[inline]
205 pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option<Texture> {
206 surface_texture.0.texture_object
207 }
208}
209
210/// Represents the CPU view of the pixel data of this surface.
211pub struct SurfaceDataGuard<'a> {
212 phantom: PhantomData<&'a ()>,
213}