From 6e969af16915c86648f7bcb317dd74dc6c7c462c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 18 Nov 2015 22:45:21 +0100 Subject: [PATCH 01/14] [WIP] Preliminary work for WebGL on WebRender --- src/gl_context.rs | 45 ++++++++++------ src/lib.rs | 2 +- src/platform/mod.rs | 24 ++++++--- src/platform/with_glx/mod.rs | 2 +- src/platform/with_glx/native_gl_context.rs | 62 +++++++++++++++++----- src/platform/with_glx/utils.rs | 6 +-- 6 files changed, 100 insertions(+), 41 deletions(-) diff --git a/src/gl_context.rs b/src/gl_context.rs index ddf84c7..64bd66d 100644 --- a/src/gl_context.rs +++ b/src/gl_context.rs @@ -9,6 +9,7 @@ use GLFormats; use DrawBuffer; use ColorAttachmentType; use NativeGLContext; +use platform::NativeGLContextHandle; #[cfg(feature="texture_surface")] use layers::platform::surface::NativeDisplay; @@ -29,16 +30,9 @@ pub struct GLContext { } impl GLContext { - #[inline(always)] - pub fn get_proc_address(addr: &str) -> *const () { - NativeGLContext::get_proc_address(addr) - } - - pub fn create_headless() -> Result { - let native_context = try!(NativeGLContext::create_headless()); - + pub fn create(shared_with: Option<&NativeGLContextHandle>) -> Result { + let native_context = try!(NativeGLContext::create_shared(shared_with)); try!(native_context.make_current()); - let attributes = GLContextAttributes::any(); let formats = GLFormats::detect(&attributes); @@ -51,15 +45,25 @@ impl GLContext { }) } - /// This allows to choose a color attachment type - /// create_offscreen() chooses the default one - pub fn create_offscreen_with_color_attachment(size: Size2D, - attributes: GLContextAttributes, - color_attachment_type: ColorAttachmentType) + + #[inline(always)] + pub fn get_proc_address(addr: &str) -> *const () { + NativeGLContext::get_proc_address(addr) + } + + #[inline(always)] + pub fn current_handle() -> Option { + NativeGLContext::current_handle() + } + + pub fn new(size: Size2D, + attributes: GLContextAttributes, + color_attachment_type: ColorAttachmentType, + shared_with: Option<&NativeGLContextHandle>) -> Result { // We create a headless context with a dummy size, we're painting to the // draw_buffer's framebuffer anyways. - let mut context = try!(GLContext::create_headless()); + let mut context = try!(GLContext::create(shared_with)); context.formats = GLFormats::detect(&attributes); context.attributes = attributes; @@ -70,9 +74,11 @@ impl GLContext { } #[inline(always)] - pub fn create_offscreen(size: Size2D, attributes: GLContextAttributes) + pub fn with_default_color_attachment(size: Size2D, + attributes: GLContextAttributes, + shared_with: Option<&NativeGLContextHandle>) -> Result { - GLContext::create_offscreen_with_color_attachment(size, attributes, ColorAttachmentType::default()) + GLContext::new(size, attributes, ColorAttachmentType::default(), shared_with) } #[inline(always)] @@ -80,6 +86,11 @@ impl GLContext { self.native_context.make_current() } + #[inline(always)] + pub fn unbind(&self) -> Result<(), &'static str> { + self.native_context.unbind() + } + #[inline(always)] pub fn is_current(&self) -> bool { self.native_context.is_current() diff --git a/src/lib.rs b/src/lib.rs index 0a2c0bc..a561e04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ extern crate core_foundation; extern crate glutin; mod platform; -pub use platform::{NativeGLContext, NativeGLContextMethods}; +pub use platform::{NativeGLContext, NativeGLContextMethods, NativeGLContextHandle}; mod gl_context; pub use gl_context::GLContext; diff --git a/src/platform/mod.rs b/src/platform/mod.rs index ef3ba22..e22e856 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -2,9 +2,21 @@ use layers::platform::surface::NativeDisplay; pub trait NativeGLContextMethods: Sized { + type Handle; + fn get_proc_address(&str) -> *const (); - fn create_headless() -> Result; + // These are convenient methods to manage handles + fn current() -> Option; + fn current_handle() -> Option; + + fn create_shared(with: Option<&Self::Handle>) -> Result; + + fn create_headless() -> Result { + Self::create_shared(None) + } + + fn handle(&self) -> Self::Handle; fn is_current(&self) -> bool; fn make_current(&self) -> Result<(), &'static str>; fn unbind(&self) -> Result<(), &'static str>; @@ -17,28 +29,28 @@ pub trait NativeGLContextMethods: Sized { pub mod with_glx; #[cfg(target_os="linux")] -pub use self::with_glx::NativeGLContext; +pub use self::with_glx::{NativeGLContext, NativeGLContextHandle}; #[cfg(target_os="macos")] pub mod with_cgl; #[cfg(target_os="macos")] -pub use self::with_cgl::NativeGLContext; +pub use self::with_cgl::{NativeGLContext, NativeGLContextHandle}; #[cfg(target_os="android")] pub mod with_egl; #[cfg(target_os="android")] -pub use self::with_egl::NativeGLContext; +pub use self::with_egl::{NativeGLContext, NativeGLContextHandle}; #[cfg(target_os="windows")] pub mod with_glutin; #[cfg(target_os="windows")] -pub use self::with_glutin::NativeGLContext; +pub use self::with_glutin::{NativeGLContext, NativeGLContextHandle}; #[cfg(not(any(target_os="linux", target_os="macos", target_os="android", target_os="windows")))] pub mod not_implemented; #[cfg(not(any(target_os="linux", target_os="macos", target_os="android", target_os="windows")))] -pub use self::not_implemented::NativeGLContext; +pub use self::not_implemented::{NativeGLContext, NativeGLContextHandle}; diff --git a/src/platform/with_glx/mod.rs b/src/platform/with_glx/mod.rs index f0cce82..a7d0673 100644 --- a/src/platform/with_glx/mod.rs +++ b/src/platform/with_glx/mod.rs @@ -1,3 +1,3 @@ mod utils; mod native_gl_context; -pub use self::native_gl_context::NativeGLContext; +pub use self::native_gl_context::{NativeGLContext, NativeGLContextHandle}; diff --git a/src/platform/with_glx/native_gl_context.rs b/src/platform/with_glx/native_gl_context.rs index 3dc9edc..b4f4aee 100644 --- a/src/platform/with_glx/native_gl_context.rs +++ b/src/platform/with_glx/native_gl_context.rs @@ -12,27 +12,32 @@ use platform::NativeGLContextMethods; #[cfg(feature="texture_surface")] use layers::platform::surface::NativeDisplay; +pub struct NativeGLContextHandle(pub GLXContext); + +unsafe impl Send for NativeGLContextHandle {} + pub struct NativeGLContext { native_context: GLXContext, native_display: *mut glx::types::Display, native_drawable: GLXDrawable, + weak: bool, } impl NativeGLContext { - pub fn new(share_context: Option<&NativeGLContext>, + pub fn new(share_context: Option<&GLXContext>, display: *mut glx::types::Display, drawable: GLXDrawable, framebuffer_config: GLXFBConfig) -> Result { let shared = match share_context { - Some(ctx) => ctx.as_native_glx_context(), - None => 0 as GLXContext + Some(ctx) => *ctx, + None => 0 as GLXContext, }; let native = unsafe { glx::CreateNewContext(display, framebuffer_config, glx::RGBA_TYPE as c_int, shared, 1 as glx::types::Bool) }; - if native == (0 as *const c_void) { + if native.is_null() { unsafe { glx::DestroyPixmap(display, drawable as GLXPixmap) }; return Err("Error creating native glx context"); } @@ -41,6 +46,7 @@ impl NativeGLContext { native_context: native, native_display: display, native_drawable: drawable, + weak: false, }) } @@ -53,15 +59,19 @@ impl Drop for NativeGLContext { fn drop(&mut self) { // Unbind the current context to free the resources // inmediately - let _ = self.unbind(); // We don't want to panic - unsafe { - glx::DestroyContext(self.native_display, self.native_context); - glx::DestroyPixmap(self.native_display, self.native_drawable as GLXPixmap); + if !self.weak { + let _ = self.unbind(); // We don't want to panic + unsafe { + glx::DestroyContext(self.native_display, self.native_context); + glx::DestroyPixmap(self.native_display, self.native_drawable as GLXPixmap); + } } } } impl NativeGLContextMethods for NativeGLContext { + type Handle = NativeGLContextHandle; + fn get_proc_address(addr: &str) -> *const () { let addr = CString::new(addr.as_bytes()).unwrap(); let addr = addr.as_ptr(); @@ -70,10 +80,33 @@ impl NativeGLContextMethods for NativeGLContext { } } - fn create_headless() -> Result { - // We create a context with a dummy size since in other platforms - // a default framebuffer is not bound - create_offscreen_pixmap_backed_context(Size2D::new(16, 16)) + fn current_handle() -> Option { + let current = unsafe { glx::GetCurrentContext() }; + + if current.is_null() { + None + } else { + Some(NativeGLContextHandle(current)) + } + } + + fn current() -> Option { + if let Some(handle) = Self::current_handle() { + unsafe { + Some(NativeGLContext { + native_context: handle.0, + native_display: glx::GetCurrentDisplay(), + native_drawable: glx::GetCurrentDrawable(), + weak: true, + }) + } + } else { + None + } + } + + fn create_shared(with: Option<&Self::Handle>) -> Result { + create_offscreen_pixmap_backed_context(Size2D::new(16, 16), with.map(|handle| &handle.0)) } #[inline(always)] @@ -83,6 +116,10 @@ impl NativeGLContextMethods for NativeGLContext { } } + fn handle(&self) -> NativeGLContextHandle { + NativeGLContextHandle(self.native_context) + } + fn make_current(&self) -> Result<(), &'static str> { unsafe { if !self.is_current() && @@ -114,4 +151,3 @@ impl NativeGLContextMethods for NativeGLContext { NativeDisplay::new(self.native_display as *mut Display) } } - diff --git a/src/platform/with_glx/utils.rs b/src/platform/with_glx/utils.rs index dd9da1b..c6e725b 100644 --- a/src/platform/with_glx/utils.rs +++ b/src/platform/with_glx/utils.rs @@ -1,6 +1,6 @@ use glx; use x11::xlib::*; -use glx::types::{GLXDrawable}; +use glx::types::{GLXDrawable, GLXContext}; use std::os::raw::*; use euclid::Size2D; @@ -48,7 +48,7 @@ unsafe fn get_visual_and_depth(s: *mut Screen, id: VisualID) -> Result<(*mut Vis // Almost directly ported from // https://dxr.mozilla.org/mozilla-central/source/gfx/gl/GLContextProviderGLX.cpp -pub fn create_offscreen_pixmap_backed_context(size: Size2D) -> Result { +pub fn create_offscreen_pixmap_backed_context(size: Size2D, shared_with: Option<&GLXContext>) -> Result { let dpy = unsafe { XOpenDisplay(0 as *mut c_char) }; if dpy.is_null() { @@ -139,6 +139,6 @@ pub fn create_offscreen_pixmap_backed_context(size: Size2D) -> Result Date: Mon, 30 Nov 2015 19:16:14 +0100 Subject: [PATCH 02/14] Add dpy to glx's NativeGLContextHandle This was causing sharing problems with my Mesa drivers, since if contexts are shared without using the same display the driver either aborts or displays garbage... --- src/platform/with_glx/native_gl_context.rs | 11 +++--- src/platform/with_glx/utils.rs | 43 +++++++++++++--------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/platform/with_glx/native_gl_context.rs b/src/platform/with_glx/native_gl_context.rs index b4f4aee..bb64aab 100644 --- a/src/platform/with_glx/native_gl_context.rs +++ b/src/platform/with_glx/native_gl_context.rs @@ -12,7 +12,7 @@ use platform::NativeGLContextMethods; #[cfg(feature="texture_surface")] use layers::platform::surface::NativeDisplay; -pub struct NativeGLContextHandle(pub GLXContext); +pub struct NativeGLContextHandle(pub GLXContext, pub *mut glx::types::Display); unsafe impl Send for NativeGLContextHandle {} @@ -82,11 +82,12 @@ impl NativeGLContextMethods for NativeGLContext { fn current_handle() -> Option { let current = unsafe { glx::GetCurrentContext() }; + let dpy = unsafe { glx::GetCurrentDisplay() }; - if current.is_null() { + if current.is_null() || dpy.is_null() { None } else { - Some(NativeGLContextHandle(current)) + Some(NativeGLContextHandle(current, dpy)) } } @@ -106,7 +107,7 @@ impl NativeGLContextMethods for NativeGLContext { } fn create_shared(with: Option<&Self::Handle>) -> Result { - create_offscreen_pixmap_backed_context(Size2D::new(16, 16), with.map(|handle| &handle.0)) + create_offscreen_pixmap_backed_context(Size2D::new(16, 16), with) } #[inline(always)] @@ -117,7 +118,7 @@ impl NativeGLContextMethods for NativeGLContext { } fn handle(&self) -> NativeGLContextHandle { - NativeGLContextHandle(self.native_context) + NativeGLContextHandle(self.native_context, self.native_display) } fn make_current(&self) -> Result<(), &'static str> { diff --git a/src/platform/with_glx/utils.rs b/src/platform/with_glx/utils.rs index c6e725b..df7610f 100644 --- a/src/platform/with_glx/utils.rs +++ b/src/platform/with_glx/utils.rs @@ -5,21 +5,22 @@ use std::os::raw::*; use euclid::Size2D; use NativeGLContext; +use NativeGLContextHandle; -struct ScopedXFree { +pub struct ScopedXFree { ptr: *mut T } impl ScopedXFree { #[inline(always)] - fn new(ptr: *mut T) -> ScopedXFree { + pub fn new(ptr: *mut T) -> ScopedXFree { ScopedXFree { ptr: ptr } } #[inline(always)] - fn as_ptr(&self) -> *mut T { + pub fn as_ptr(&self) -> *mut T { self.ptr } } @@ -48,12 +49,20 @@ unsafe fn get_visual_and_depth(s: *mut Screen, id: VisualID) -> Result<(*mut Vis // Almost directly ported from // https://dxr.mozilla.org/mozilla-central/source/gfx/gl/GLContextProviderGLX.cpp -pub fn create_offscreen_pixmap_backed_context(size: Size2D, shared_with: Option<&GLXContext>) -> Result { - let dpy = unsafe { XOpenDisplay(0 as *mut c_char) }; +pub fn create_offscreen_pixmap_backed_context(size: Size2D, shared_with: Option<&NativeGLContextHandle>) -> Result { + let (shared_with, dpy) = match shared_with { + Some(handle) => (Some(&handle.0), handle.1), + None => { + let dpy = unsafe { XOpenDisplay(0 as *mut c_char) as *mut glx::types::Display }; + + if dpy.is_null() { + return Err("glx::XOpenDisplay"); + } + + (None, dpy) + } + }; - if dpy.is_null() { - return Err("glx::XOpenDisplay"); - } // We try to get possible framebuffer configurations which // can be pixmap-backed and renderable @@ -66,8 +75,8 @@ pub fn create_offscreen_pixmap_backed_context(size: Size2D, shared_with: Op let mut config_count : c_int = 0; let configs = ScopedXFree::new(unsafe { - glx::ChooseFBConfig(dpy as *mut glx::types::Display, - XDefaultScreen(dpy), + glx::ChooseFBConfig(dpy, + XDefaultScreen(dpy as *mut Display), attributes.as_mut_ptr(), &mut config_count) }); @@ -93,12 +102,12 @@ pub fn create_offscreen_pixmap_backed_context(size: Size2D, shared_with: Op // // It's in Gecko's code, so may there be an implementation which returns bad // configurations? - if glx::GetFBConfigAttrib(dpy as *mut glx::types::Display, config, glx::DRAWABLE_TYPE as c_int, &mut drawable_type) != 0 + if glx::GetFBConfigAttrib(dpy, config, glx::DRAWABLE_TYPE as c_int, &mut drawable_type) != 0 || (drawable_type & (glx::PIXMAP_BIT as c_int) == 0) { continue; } - if glx::GetFBConfigAttrib(dpy as *mut glx::types::Display, config, glx::VISUAL_ID as c_int, &mut visual_id) != 0 + if glx::GetFBConfigAttrib(dpy, config, glx::VISUAL_ID as c_int, &mut visual_id) != 0 || visual_id == 0 { continue; } @@ -113,11 +122,11 @@ pub fn create_offscreen_pixmap_backed_context(size: Size2D, shared_with: Op } unsafe { - let screen = XDefaultScreenOfDisplay(dpy); + let screen = XDefaultScreenOfDisplay(dpy as *mut _); let (_, depth) = try!(get_visual_and_depth(screen, visual_id as VisualID)); - let pixmap = XCreatePixmap(dpy, + let pixmap = XCreatePixmap(dpy as *mut _, XRootWindowOfScreen(screen), size.width as c_uint, size.height as c_uint, @@ -127,18 +136,18 @@ pub fn create_offscreen_pixmap_backed_context(size: Size2D, shared_with: Op return Err("XCreatePixMap"); } - let glx_pixmap = glx::CreatePixmap(dpy as *mut glx::types::Display, + let glx_pixmap = glx::CreatePixmap(dpy, *configs.as_ptr().offset(config_index), pixmap, 0 as *const c_int); if glx_pixmap == 0 { - XFreePixmap(dpy, pixmap); + XFreePixmap(dpy as *mut _, pixmap); return Err("glx::createPixmap"); } let chosen_config = *configs.as_ptr().offset(config_index); - NativeGLContext::new(shared_with, dpy as *mut glx::types::Display, glx_pixmap as GLXDrawable, chosen_config) + NativeGLContext::new(shared_with, dpy, glx_pixmap as GLXDrawable, chosen_config) } } From e97cc7f8b2730e08c1c88f1b164ef62ca988740d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 30 Nov 2015 21:34:14 +0100 Subject: [PATCH 03/14] Remove `layers` integration. --- Cargo.toml | 7 +- src/draw_buffer.rs | 74 ---------------------- src/gl_context.rs | 5 -- src/lib.rs | 7 -- src/platform/mod.rs | 6 -- src/platform/with_egl/native_gl_context.rs | 8 --- src/platform/with_glx/native_gl_context.rs | 8 --- 7 files changed, 2 insertions(+), 113 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c551101..ab3f436 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,8 @@ gl_generator = "0.4" khronos_api = "1.0" [features] -texture_surface = ["layers"] +# TODO: remove me! +texture_surface = [] [dependencies] log = "0.3.3" @@ -21,10 +22,6 @@ euclid = "0.4" serde = "0.6.1" serde_macros = "0.6.1" -[dependencies.layers] -git = "https://github.com/servo/rust-layers" -optional = true - [target.x86_64-apple-darwin.dependencies] core-foundation = "0.2.0" cgl = "0.1" diff --git a/src/draw_buffer.rs b/src/draw_buffer.rs index df3e195..62782b7 100644 --- a/src/draw_buffer.rs +++ b/src/draw_buffer.rs @@ -6,19 +6,9 @@ use GLContext; use std::ptr; -#[cfg(feature="texture_surface")] -use LayersSurfaceWrapper; -#[cfg(feature="texture_surface")] -use layers::texturegl::Texture; -#[cfg(feature="texture_surface")] -use layers::platform::surface::NativeSurface; - pub enum ColorAttachmentType { Texture, Renderbuffer, - - #[cfg(feature="texture_surface")] - TextureWithSurface, } impl ColorAttachmentType { @@ -35,9 +25,6 @@ impl ColorAttachmentType { pub enum ColorAttachment { Renderbuffer(GLuint), Texture(GLuint), - - #[cfg(feature="texture_surface")] - TextureWithSurface(LayersSurfaceWrapper, Texture), } impl ColorAttachment { @@ -45,8 +32,6 @@ impl ColorAttachment { match *self { ColorAttachment::Renderbuffer(_) => ColorAttachmentType::Renderbuffer, ColorAttachment::Texture(_) => ColorAttachmentType::Texture, - #[cfg(feature="texture_surface")] - ColorAttachment::TextureWithSurface(_, _) => ColorAttachmentType::TextureWithSurface, } } } @@ -57,10 +42,6 @@ impl Drop for ColorAttachment { match *self { ColorAttachment::Renderbuffer(mut id) => gl::DeleteRenderbuffers(1, &mut id), ColorAttachment::Texture(mut tex_id) => gl::DeleteTextures(1, &mut tex_id), - - #[cfg(feature="texture_surface")] - // Their destructors do everything - ColorAttachment::TextureWithSurface(_, _) => {}, } } } @@ -159,38 +140,6 @@ impl DrawBuffer { match self.color_attachment.as_ref().unwrap() { &ColorAttachment::Renderbuffer(_) => None, &ColorAttachment::Texture(id) => Some(id), - #[cfg(feature="texture_surface")] - &ColorAttachment::TextureWithSurface(_, ref tex) => Some(tex.native_texture()), - } - } - - #[inline(always)] - #[cfg(feature="texture_surface")] - pub fn get_bound_surface_id(&self) -> Option { - match self.color_attachment.as_ref().unwrap() { - &ColorAttachment::TextureWithSurface(ref surf_wrapper, _) - => Some(surf_wrapper.get_surface_id()), - _ => None - } - } - - #[inline(always)] - #[cfg(feature="texture_surface")] - pub fn borrow_bound_layers_texture(&self) -> Option<&Texture> { - match self.color_attachment.as_ref().unwrap() { - &ColorAttachment::TextureWithSurface(_, ref tex) - => Some(tex), - _ => None - } - } - - #[inline(always)] - #[cfg(feature="texture_surface")] - pub fn borrow_bound_surface(&self) -> Option<&NativeSurface> { - match self.color_attachment.as_ref().unwrap() { - &ColorAttachment::TextureWithSurface(ref surf_wrapper, _) - => Some(surf_wrapper.borrow_surface()), - _ => None } } } @@ -259,22 +208,6 @@ impl DrawBufferHelpers for DrawBuffer { Some(ColorAttachment::Texture(texture)) } }, - #[cfg(feature="texture_surface")] - ColorAttachmentType::TextureWithSurface => { - // TODO(ecoal95): check if this is correct - let (flip, target) = Texture::texture_flip_and_target(false); - let mut texture = Texture::new(target, Size2D::new(self.size.width as usize, self.size.height as usize)); - texture.flip = flip; - - let surface_wrapper = LayersSurfaceWrapper::new(context.get_display(), self.size); - surface_wrapper.bind_to_texture(&texture); - - unsafe { - debug_assert!(gl::GetError() == gl::NO_ERROR); - } - - Some(ColorAttachment::TextureWithSurface(surface_wrapper, texture)) - } }; // After this we check if we need stencil and depth buffers @@ -317,13 +250,6 @@ impl DrawBufferHelpers for DrawBuffer { gl::TEXTURE_2D, texture_id, 0); }, - #[cfg(feature="texture_surface")] - &ColorAttachment::TextureWithSurface(_, ref texture) => { - gl::FramebufferTexture2D(gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - texture.target.as_gl_target(), - texture.native_texture(), 0); - } } if self.depth_renderbuffer != 0 { diff --git a/src/gl_context.rs b/src/gl_context.rs index 64bd66d..575aa9a 100644 --- a/src/gl_context.rs +++ b/src/gl_context.rs @@ -139,11 +139,6 @@ impl GLContext { Err("No DrawBuffer found") } } - - #[cfg(feature="texture_surface")] - pub fn get_display(&self) -> NativeDisplay { - self.native_context.get_display() - } } diff --git a/src/lib.rs b/src/lib.rs index a561e04..ef5ad9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,12 +62,5 @@ mod egl { include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs")); } -#[cfg(feature="texture_surface")] -extern crate layers; -#[cfg(feature="texture_surface")] -mod layers_surface_wrapper; -#[cfg(feature="texture_surface")] -pub use layers_surface_wrapper::LayersSurfaceWrapper; - #[cfg(test)] mod tests; diff --git a/src/platform/mod.rs b/src/platform/mod.rs index e22e856..7815bb7 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -1,6 +1,3 @@ -#[cfg(feature="texture_surface")] -use layers::platform::surface::NativeDisplay; - pub trait NativeGLContextMethods: Sized { type Handle; @@ -20,9 +17,6 @@ pub trait NativeGLContextMethods: Sized { fn is_current(&self) -> bool; fn make_current(&self) -> Result<(), &'static str>; fn unbind(&self) -> Result<(), &'static str>; - - #[cfg(feature="texture_surface")] - fn get_display(&self) -> NativeDisplay; } #[cfg(target_os="linux")] diff --git a/src/platform/with_egl/native_gl_context.rs b/src/platform/with_egl/native_gl_context.rs index a3f8d52..c178174 100644 --- a/src/platform/with_egl/native_gl_context.rs +++ b/src/platform/with_egl/native_gl_context.rs @@ -117,12 +117,4 @@ impl NativeGLContextMethods for NativeGLContext { } } } - - #[cfg(feature="texture_surface")] - fn get_display(&self) -> NativeDisplay { - unsafe { - // FIXME: https://github.com/servo/servo/pull/6423#issuecomment-113282933 - NativeDisplay::new_with_display(mem::transmute(self.native_display)) - } - } } diff --git a/src/platform/with_glx/native_gl_context.rs b/src/platform/with_glx/native_gl_context.rs index bb64aab..ebd3103 100644 --- a/src/platform/with_glx/native_gl_context.rs +++ b/src/platform/with_glx/native_gl_context.rs @@ -9,9 +9,6 @@ use super::utils::{create_offscreen_pixmap_backed_context}; use platform::NativeGLContextMethods; -#[cfg(feature="texture_surface")] -use layers::platform::surface::NativeDisplay; - pub struct NativeGLContextHandle(pub GLXContext, pub *mut glx::types::Display); unsafe impl Send for NativeGLContextHandle {} @@ -146,9 +143,4 @@ impl NativeGLContextMethods for NativeGLContext { } } } - - #[cfg(feature="texture_surface")] - fn get_display(&self) -> NativeDisplay { - NativeDisplay::new(self.native_display as *mut Display) - } } From fb7a0290bf39a6adcb4c39a40c0fceec5c38dd27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 30 Nov 2015 21:35:30 +0100 Subject: [PATCH 04/14] platform: Port to egl and generate egl bindings also in linux This will help the task of splitting the backend from glx to egl, I think someone is doing that :P --- build.rs | 2 +- src/lib.rs | 2 +- src/platform/mod.rs | 24 +++----- src/platform/with_egl/mod.rs | 1 + src/platform/with_egl/native_gl_context.rs | 72 ++++++++++++++++------ src/platform/with_egl/utils.rs | 26 ++++++-- src/platform/with_glx/native_gl_context.rs | 2 +- 7 files changed, 85 insertions(+), 44 deletions(-) diff --git a/build.rs b/build.rs index 5f8aacf..595045c 100644 --- a/build.rs +++ b/build.rs @@ -18,7 +18,7 @@ fn main() { "1.4", "core", &mut file).unwrap(); } - if target.contains("android") { + if target.contains("android") || target.contains("linux") { let mut file = File::create(&dest.join("egl_bindings.rs")).unwrap(); gl_generator::generate_bindings(gl_generator::StaticGenerator, gl_generator::registry::Ns::Egl, diff --git a/src/lib.rs b/src/lib.rs index ef5ad9d..984b7e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,7 +45,7 @@ mod glx { include!(concat!(env!("OUT_DIR"), "/glx_bindings.rs")); } -#[cfg(target_os="android")] +#[cfg(any(target_os="linux", target_os="android"))] #[allow(non_camel_case_types)] mod egl { use std::os::raw::{c_long, c_void}; diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 7815bb7..06c6d0a 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -21,30 +21,20 @@ pub trait NativeGLContextMethods: Sized { #[cfg(target_os="linux")] pub mod with_glx; - #[cfg(target_os="linux")] pub use self::with_glx::{NativeGLContext, NativeGLContextHandle}; -#[cfg(target_os="macos")] -pub mod with_cgl; - -#[cfg(target_os="macos")] -pub use self::with_cgl::{NativeGLContext, NativeGLContextHandle}; - -#[cfg(target_os="android")] +#[cfg(any(target_os="android", target_os="linux"))] pub mod with_egl; - #[cfg(target_os="android")] pub use self::with_egl::{NativeGLContext, NativeGLContextHandle}; -#[cfg(target_os="windows")] -pub mod with_glutin; - -#[cfg(target_os="windows")] -pub use self::with_glutin::{NativeGLContext, NativeGLContextHandle}; +#[cfg(target_os="macos")] +pub mod with_cgl; +#[cfg(target_os="macos")] +pub use self::with_cgl::{NativeGLContext, NativeGLContextHandle}; -#[cfg(not(any(target_os="linux", target_os="macos", target_os="android", target_os="windows")))] +#[cfg(not(any(target_os="linux", target_os="macos", target_os="android")))] pub mod not_implemented; - -#[cfg(not(any(target_os="linux", target_os="macos", target_os="android", target_os="windows")))] +#[cfg(not(any(target_os="linux", target_os="macos", target_os="android")))] pub use self::not_implemented::{NativeGLContext, NativeGLContextHandle}; diff --git a/src/platform/with_egl/mod.rs b/src/platform/with_egl/mod.rs index fac4744..4fcaa64 100644 --- a/src/platform/with_egl/mod.rs +++ b/src/platform/with_egl/mod.rs @@ -1,6 +1,7 @@ mod native_gl_context; mod utils; pub use self::native_gl_context::NativeGLContext; +pub use self::native_gl_context::NativeGLContextHandle; // NB: The last three zeros in egl attributes after the egl::EGL_NONE // are a workaround for workaround buggy implementations. diff --git a/src/platform/with_egl/native_gl_context.rs b/src/platform/with_egl/native_gl_context.rs index c178174..698ed5c 100644 --- a/src/platform/with_egl/native_gl_context.rs +++ b/src/platform/with_egl/native_gl_context.rs @@ -5,26 +5,25 @@ use std::ffi::CString; use egl; use egl::types::{EGLint, EGLBoolean, EGLDisplay, EGLSurface, EGLConfig, EGLContext}; -#[cfg(feature="texture_surface")] -use layers::platform::surface::NativeDisplay; -#[cfg(feature="texture_surface")] -use std::mem; +pub struct NativeGLContextHandle(pub EGLDisplay, pub EGLSurface); +unsafe impl Send for NativeGLContextHandle {} pub struct NativeGLContext { native_display: EGLDisplay, native_surface: EGLSurface, native_context: EGLContext, + weak: bool, } impl NativeGLContext { - pub fn new(share_context: Option<&NativeGLContext>, + pub fn new(share_context: Option<&EGLContext>, display: EGLDisplay, surface: EGLSurface, config: EGLConfig) -> Result { let shared = match share_context { - Some(ctx) => ctx.as_native_egl_context(), + Some(ctx) => *ctx, None => egl::NO_CONTEXT as EGLContext, }; @@ -46,30 +45,30 @@ impl NativeGLContext { native_display: display, native_surface: surface, native_context: ctx, + weak: false, }) } - - #[inline(always)] - pub fn as_native_egl_context(&self) -> EGLContext { - self.native_context - } } impl Drop for NativeGLContext { fn drop(&mut self) { let _ = self.unbind(); - unsafe { - if egl::DestroySurface(self.native_display, self.native_surface) == 0 { - debug!("egl::DestroySurface failed"); - } - if egl::DestroyContext(self.native_display, self.native_context) == 0 { - debug!("egl::DestroyContext failed"); + if !self.weak { + unsafe { + if egl::DestroySurface(self.native_display, self.native_surface) == 0 { + debug!("egl::DestroySurface failed"); + } + if egl::DestroyContext(self.native_display, self.native_context) == 0 { + debug!("egl::DestroyContext failed"); + } } } } } impl NativeGLContextMethods for NativeGLContext { + type Handle = NativeGLContextHandle; + fn get_proc_address(addr: &str) -> *const () { unsafe { let addr = CString::new(addr.as_bytes()).unwrap().as_ptr(); @@ -80,7 +79,40 @@ impl NativeGLContextMethods for NativeGLContext { fn create_headless() -> Result { // We create a context with a dummy size, we can't rely on a // default framebuffer - create_pixel_buffer_backed_offscreen_context(Size2D::new(16, 16)) + create_pixel_buffer_backed_offscreen_context(Size2D::new(16, 16), None) + } + + fn create_shared(with: Option<&Self::Handle>) -> Result { + create_pixel_buffer_backed_offscreen_context(Size2D::new(16, 16), with) + } + + fn current_handle() -> Option { + let native_context = unsafe { egl::GetCurrentContext() }; + let native_display = unsafe { egl::GetCurrentDisplay() }; + + if native_context != egl::NO_CONTEXT && native_display != egl::NO_DISPLAY { + Some(NativeGLContextHandle(native_context, native_display)) + } else { + None + } + } + + + fn current() -> Option { + if let Some(handle) = Self::current_handle() { + let surface = unsafe { egl::GetCurrentSurface(egl::DRAW as EGLint) }; + + debug_assert!(surface != egl::NO_SURFACE); + + Some(NativeGLContext { + native_context: handle.0, + native_display: handle.1, + native_surface: surface, + weak: true, + }) + } else { + None + } } #[inline(always)] @@ -104,6 +136,10 @@ impl NativeGLContextMethods for NativeGLContext { } } + fn handle(&self) -> Self::Handle { + NativeGLContextHandle(self.native_context, self.native_display) + } + fn unbind(&self) -> Result<(), &'static str> { unsafe { if self.is_current() && diff --git a/src/platform/with_egl/utils.rs b/src/platform/with_egl/utils.rs index 55ac7c5..7c3a14e 100644 --- a/src/platform/with_egl/utils.rs +++ b/src/platform/with_egl/utils.rs @@ -1,6 +1,6 @@ use std::mem; use euclid::Size2D; -use super::NativeGLContext; +use super::{NativeGLContext, NativeGLContextHandle}; use egl; use egl::types::{EGLNativeDisplayType, EGLDisplay, EGLConfig, EGLSurface, EGLint}; @@ -21,7 +21,9 @@ fn create_pbuffer_surface(display: EGLDisplay, config: EGLConfig, size: Size2D) -> Result { +pub fn create_pixel_buffer_backed_offscreen_context(size: Size2D, + shared_with: Option<&NativeGLContextHandle>) + -> Result { let attributes = [ egl::SURFACE_TYPE as EGLint, egl::PBUFFER_BIT as EGLint, egl::RENDERABLE_TYPE as EGLint, egl::OPENGL_ES2_BIT as EGLint, @@ -32,14 +34,26 @@ pub fn create_pixel_buffer_backed_offscreen_context(size: Size2D) -> Result egl::NONE as EGLint, 0, 0, 0, // see mod.rs ]; - // TODO: Check if we should use `egl::GetCurrentDisplay` instead - let display = unsafe { egl::GetDisplay(egl::DEFAULT_DISPLAY as EGLNativeDisplayType) }; + let (shared_with, display) = match shared_with { + Some(handle) => (Some(&handle.0), handle.1), + None => { + let display = unsafe { + egl::GetDisplay(egl::DEFAULT_DISPLAY as EGLNativeDisplayType) + }; + + if display == (egl::NO_DISPLAY as EGLDisplay) { + return Err("egl::GetDisplay"); + } + + (None, display) + } + }; + if display == (egl::NO_DISPLAY as EGLDisplay) { return Err("egl::GetDisplay"); } - let mut config : EGLConfig = unsafe { mem::uninitialized() }; let mut found_configs : EGLint = 0; @@ -55,5 +69,5 @@ pub fn create_pixel_buffer_backed_offscreen_context(size: Size2D) -> Result let surface = try!(create_pbuffer_surface(display, config, size)); - NativeGLContext::new(None, display, surface, config) + NativeGLContext::new(shared_with, display, surface, config) } diff --git a/src/platform/with_glx/native_gl_context.rs b/src/platform/with_glx/native_gl_context.rs index ebd3103..a9507aa 100644 --- a/src/platform/with_glx/native_gl_context.rs +++ b/src/platform/with_glx/native_gl_context.rs @@ -93,7 +93,7 @@ impl NativeGLContextMethods for NativeGLContext { unsafe { Some(NativeGLContext { native_context: handle.0, - native_display: glx::GetCurrentDisplay(), + native_display: handle.1, native_drawable: glx::GetCurrentDrawable(), weak: true, }) From 412f3805536827a5ca5596bdfefcedf662339828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 30 Nov 2015 21:36:56 +0100 Subject: [PATCH 05/14] Make `GLContext` backend-agnostic. --- src/draw_buffer.rs | 17 +++++++++++++---- src/gl_context.rs | 35 +++++++++++++++-------------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/draw_buffer.rs b/src/draw_buffer.rs index 62782b7..39af68e 100644 --- a/src/draw_buffer.rs +++ b/src/draw_buffer.rs @@ -3,6 +3,7 @@ use gleam::gl; use gleam::gl::types::{GLuint, GLenum, GLint}; use GLContext; +use NativeGLContextMethods; use std::ptr; @@ -64,7 +65,8 @@ pub struct DrawBuffer { /// Helper function to create a render buffer /// TODO(ecoal95): We'll need to switch between `glRenderbufferStorage` and /// `glRenderbufferStorageMultisample` when we support antialising -fn create_renderbuffer(format: GLenum, size: &Size2D) -> GLuint { +fn create_renderbuffer(format: GLenum, + size: &Size2D) -> GLuint { let mut ret: GLuint = 0; unsafe { @@ -77,7 +79,9 @@ fn create_renderbuffer(format: GLenum, size: &Size2D) -> GLuint { } impl DrawBuffer { - pub fn new(context: &GLContext, size: Size2D, color_attachment_type: ColorAttachmentType) + pub fn new(context: &GLContext, + size: Size2D, + color_attachment_type: ColorAttachmentType) -> Result { let attrs = context.borrow_attributes(); @@ -166,14 +170,19 @@ impl Drop for DrawBuffer { } trait DrawBufferHelpers { - fn init(&mut self, &GLContext, color_attachment_type: ColorAttachmentType) + fn init(&mut self, + &GLContext, + color_attachment_type: ColorAttachmentType) -> Result<(), &'static str>; fn attach_to_framebuffer(&mut self) -> Result<(), &'static str>; } impl DrawBufferHelpers for DrawBuffer { - fn init(&mut self, context: &GLContext, color_attachment_type: ColorAttachmentType) -> Result<(), &'static str> { + fn init(&mut self, + context: &GLContext, + color_attachment_type: ColorAttachmentType) + -> Result<(), &'static str> { let attrs = context.borrow_attributes(); let formats = context.borrow_formats(); diff --git a/src/gl_context.rs b/src/gl_context.rs index 575aa9a..5325dd8 100644 --- a/src/gl_context.rs +++ b/src/gl_context.rs @@ -8,16 +8,10 @@ use GLContextCapabilities; use GLFormats; use DrawBuffer; use ColorAttachmentType; -use NativeGLContext; -use platform::NativeGLContextHandle; - -#[cfg(feature="texture_surface")] -use layers::platform::surface::NativeDisplay; - /// This is a wrapper over a native headless GL context -pub struct GLContext { - native_context: NativeGLContext, +pub struct GLContext { + native_context: Native, /// This an abstraction over a custom framebuffer /// with attachments according to WebGLContextAttributes // TODO(ecoal95): Ideally we may want a read and a draw @@ -29,9 +23,10 @@ pub struct GLContext { formats: GLFormats, } -impl GLContext { - pub fn create(shared_with: Option<&NativeGLContextHandle>) -> Result { - let native_context = try!(NativeGLContext::create_shared(shared_with)); +impl GLContext + where Native: NativeGLContextMethods { + pub fn create(shared_with: Option<&Native::Handle>) -> Result, &'static str> { + let native_context = try!(Native::create_shared(shared_with)); try!(native_context.make_current()); let attributes = GLContextAttributes::any(); let formats = GLFormats::detect(&attributes); @@ -48,22 +43,22 @@ impl GLContext { #[inline(always)] pub fn get_proc_address(addr: &str) -> *const () { - NativeGLContext::get_proc_address(addr) + Native::get_proc_address(addr) } #[inline(always)] - pub fn current_handle() -> Option { - NativeGLContext::current_handle() + pub fn current_handle() -> Option { + Native::current_handle() } pub fn new(size: Size2D, attributes: GLContextAttributes, color_attachment_type: ColorAttachmentType, - shared_with: Option<&NativeGLContextHandle>) - -> Result { + shared_with: Option<&Native::Handle>) + -> Result, &'static str> { // We create a headless context with a dummy size, we're painting to the // draw_buffer's framebuffer anyways. - let mut context = try!(GLContext::create(shared_with)); + let mut context = try!(Self::create(shared_with)); context.formats = GLFormats::detect(&attributes); context.attributes = attributes; @@ -76,8 +71,8 @@ impl GLContext { #[inline(always)] pub fn with_default_color_attachment(size: Size2D, attributes: GLContextAttributes, - shared_with: Option<&NativeGLContextHandle>) - -> Result { + shared_with: Option<&Native::Handle>) + -> Result, &'static str> { GLContext::new(size, attributes, ColorAttachmentType::default(), shared_with) } @@ -147,7 +142,7 @@ trait GLContextPrivateMethods { fn create_draw_buffer(&mut self, Size2D, ColorAttachmentType) -> Result<(), &'static str>; } -impl GLContextPrivateMethods for GLContext { +impl GLContextPrivateMethods for GLContext { fn init_offscreen(&mut self, size: Size2D, color_attachment_type: ColorAttachmentType) -> Result<(), &'static str> { try!(self.create_draw_buffer(size, color_attachment_type)); From 62f16ad51ed2115f02a9c9896a3c1d843bf125ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 30 Nov 2015 21:56:35 +0100 Subject: [PATCH 06/14] [wip] Add mac port I'm almost sure it won't compile, I've probably made a typo. --- src/platform/with_cgl/mod.rs | 1 + src/platform/with_cgl/native_gl_context.rs | 74 ++++++++++++++-------- 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/src/platform/with_cgl/mod.rs b/src/platform/with_cgl/mod.rs index ea59b4e..86ac835 100644 --- a/src/platform/with_cgl/mod.rs +++ b/src/platform/with_cgl/mod.rs @@ -1,2 +1,3 @@ mod native_gl_context; pub use self::native_gl_context::NativeGLContext; +pub use self::native_gl_context::NativeGLContextHandle; diff --git a/src/platform/with_cgl/native_gl_context.rs b/src/platform/with_cgl/native_gl_context.rs index fe2ab7a..8ca9208 100644 --- a/src/platform/with_cgl/native_gl_context.rs +++ b/src/platform/with_cgl/native_gl_context.rs @@ -8,21 +8,22 @@ use std::str::FromStr; use platform::NativeGLContextMethods; -#[cfg(feature="texture_surface")] -use layers::platform::surface::NativeDisplay; +pub struct NativeGLContextHandle(CGLContextObj); + +unsafe impl Send for NativeGLContextHandle {} pub struct NativeGLContext { native_context: CGLContextObj, - pixel_format: CGLPixelFormatObj, + weak: bool, } impl NativeGLContext { - pub fn new(share_context: Option, - pixel_format: CGLPixelFormatObj) + pub fn new(share_context: Option<&CGLContextObj>, + pixel_format: &CGLPixelFormatObj) -> Result { let shared = match share_context { - Some(ctx) => ctx.as_native_cgl_context(), + Some(ctx) => *ctx, None => 0 as CGLContextObj }; @@ -38,30 +39,27 @@ impl NativeGLContext { Ok(NativeGLContext { native_context: native, - pixel_format: pixel_format, + weak: false, }) } - - pub fn as_native_cgl_context(&self) -> CGLContextObj { - self.native_context - } } impl Drop for NativeGLContext { fn drop(&mut self) { let _ = self.unbind(); - unsafe { - if CGLDestroyContext(self.native_context) != 0 { - debug!("CGLDestroyContext returned an error"); - } - if CGLDestroyPixelFormat(self.pixel_format) != 0 { - debug!("CGLDestroyPixelformat errored"); + if !self.weak { + unsafe { + if CGLDestroyContext(self.native_context) != 0 { + debug!("CGLDestroyContext returned an error"); + } } } } } impl NativeGLContextMethods for NativeGLContext { + type Handle = NativeGLContextHandle; + fn get_proc_address(addr: &str) -> *const () { let symbol_name: CFString = FromStr::from_str(addr).unwrap(); let framework_name: CFString = FromStr::from_str("com.apple.opengl").unwrap(); @@ -74,7 +72,28 @@ impl NativeGLContextMethods for NativeGLContext { symbol as *const () } - fn create_headless() -> Result { + fn current() -> Option { + if let Some(handle) = Self::current_handle() { + Some(NativeGLContext { + native_context: handle.0, + weak: true, + }) + } else { + None + } + + } + + fn current_handle() -> Option { + let current = unsafe { CGLGetCurrentContext() }; + if current != 0 as CGLContextObj { + Some(NativeGLContextHandle(current)) + } else { + None + } + } + + fn create_shared(with: Option<&Self::Handle>) -> Result { let mut attributes = [ 0 ]; @@ -92,7 +111,17 @@ impl NativeGLContextMethods for NativeGLContext { } } - NativeGLContext::new(None, pixel_format) + let result = NativeGLContext::new(with.map(|handle| handle.0), pixel_format); + + if CGLDestroyPixelFormat(pixel_format) != 0 { + debug!("CGLDestroyPixelformat errored"); + } + + result + } + + fn handle(&self) -> Self::Handle { + NativeGLContextHandle(self.native_context) } #[inline(always)] @@ -123,11 +152,4 @@ impl NativeGLContextMethods for NativeGLContext { } } } - - #[cfg(feature="texture_surface")] - fn get_display(&self) -> NativeDisplay { - NativeDisplay { - pixel_format: self.pixel_format, - } - } } From cfb2dfc2e8ce8e5a11be61ed8e686e87f9da8d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 30 Nov 2015 21:59:02 +0100 Subject: [PATCH 07/14] platform/glx: Remove unused import --- src/platform/with_glx/utils.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/with_glx/utils.rs b/src/platform/with_glx/utils.rs index df7610f..de61dcd 100644 --- a/src/platform/with_glx/utils.rs +++ b/src/platform/with_glx/utils.rs @@ -1,7 +1,7 @@ use glx; use x11::xlib::*; -use glx::types::{GLXDrawable, GLXContext}; -use std::os::raw::*; +use glx::types::GLXDrawable; +use libc::*; use euclid::Size2D; use NativeGLContext; From 7d8ee2bf1c8ab2b17af9c4a531be64d53c0b6631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Tue, 1 Dec 2015 14:58:33 +0100 Subject: [PATCH 08/14] Update not_implemented platform and use it for now on osx --- src/platform/mod.rs | 6 ++++-- src/platform/not_implemented/mod.rs | 2 +- .../not_implemented/native_gl_context.rs | 19 +++++++++++++------ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 06c6d0a..b9199e3 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -29,12 +29,14 @@ pub mod with_egl; #[cfg(target_os="android")] pub use self::with_egl::{NativeGLContext, NativeGLContextHandle}; +/* #[cfg(target_os="macos")] pub mod with_cgl; #[cfg(target_os="macos")] pub use self::with_cgl::{NativeGLContext, NativeGLContextHandle}; +*/ -#[cfg(not(any(target_os="linux", target_os="macos", target_os="android")))] +#[cfg(not(any(target_os="linux", target_os="android")))] pub mod not_implemented; -#[cfg(not(any(target_os="linux", target_os="macos", target_os="android")))] +#[cfg(not(any(target_os="linux", target_os="android")))] pub use self::not_implemented::{NativeGLContext, NativeGLContextHandle}; diff --git a/src/platform/not_implemented/mod.rs b/src/platform/not_implemented/mod.rs index ea59b4e..fe3ce9a 100644 --- a/src/platform/not_implemented/mod.rs +++ b/src/platform/not_implemented/mod.rs @@ -1,2 +1,2 @@ mod native_gl_context; -pub use self::native_gl_context::NativeGLContext; +pub use self::native_gl_context::{NativeGLContext, NativeGLContextHandle}; diff --git a/src/platform/not_implemented/native_gl_context.rs b/src/platform/not_implemented/native_gl_context.rs index 23c08f2..e82dc7f 100644 --- a/src/platform/not_implemented/native_gl_context.rs +++ b/src/platform/not_implemented/native_gl_context.rs @@ -1,16 +1,16 @@ use NativeGLContextMethods; pub struct NativeGLContext; - -#[cfg(feature="texture_surface")] -use layers::platform::surface::NativeDisplay; +pub struct NativeGLContextHandle; impl NativeGLContextMethods for NativeGLContext { + type Handle = NativeGLContextHandle; + fn get_proc_address(_addr: &str) -> *const () { 0 as *const () } - fn create_headless() -> Result { + fn create_shared(_with: Option<&Self::Handle>) -> Result { Err("Not implemented (yet)") } @@ -18,6 +18,14 @@ impl NativeGLContextMethods for NativeGLContext { false } + fn current() -> Option { + None + } + + fn current_handle() -> Option { + None + } + fn make_current(&self) -> Result<(), &'static str> { Err("Not implemented (yet)") } @@ -26,8 +34,7 @@ impl NativeGLContextMethods for NativeGLContext { unimplemented!() } - #[cfg(feature="texture_surface")] - fn get_display(&self) -> NativeDisplay { + fn handle(&self) -> Self::Handle { unimplemented!() } } From 7e65a335f117d2aec86e7da0753edd1a7757c3b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Tue, 1 Dec 2015 17:14:25 +0100 Subject: [PATCH 09/14] Update gl_generator and remove texture_surface feature --- Cargo.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ab3f436..6338a93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,6 @@ build = "build.rs" gl_generator = "0.4" khronos_api = "1.0" -[features] -# TODO: remove me! -texture_surface = [] - [dependencies] log = "0.3.3" gleam = "0.2" From 4c0ec39ce7b22e606a4248bdec246a582edc10b1 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Mon, 7 Dec 2015 02:21:55 +1000 Subject: [PATCH 10/14] Fix up libc usage --- src/platform/with_glx/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/with_glx/utils.rs b/src/platform/with_glx/utils.rs index de61dcd..8f32a8e 100644 --- a/src/platform/with_glx/utils.rs +++ b/src/platform/with_glx/utils.rs @@ -1,7 +1,7 @@ use glx; use x11::xlib::*; use glx::types::GLXDrawable; -use libc::*; +use std::os::raw::*; use euclid::Size2D; use NativeGLContext; From b0b7c0ab80fd27e18460e498e171828e63f400ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 9 Dec 2015 16:18:22 +0100 Subject: [PATCH 11/14] platform/cgl: Restore OSX support & add new (and consistent) tests --- src/gl_context.rs | 6 ++ src/platform/mod.rs | 6 +- src/platform/with_cgl/native_gl_context.rs | 12 ++- src/tests.rs | 105 ++++++++++++--------- 4 files changed, 76 insertions(+), 53 deletions(-) diff --git a/src/gl_context.rs b/src/gl_context.rs index 5325dd8..672159b 100644 --- a/src/gl_context.rs +++ b/src/gl_context.rs @@ -91,6 +91,12 @@ impl GLContext self.native_context.is_current() } + #[inline(always)] + pub fn handle(&self) -> Native::Handle { + self.native_context.handle() + } + + // Allow borrowing these unmutably pub fn borrow_attributes(&self) -> &GLContextAttributes { &self.attributes diff --git a/src/platform/mod.rs b/src/platform/mod.rs index b9199e3..de78496 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -29,14 +29,12 @@ pub mod with_egl; #[cfg(target_os="android")] pub use self::with_egl::{NativeGLContext, NativeGLContextHandle}; -/* #[cfg(target_os="macos")] pub mod with_cgl; #[cfg(target_os="macos")] pub use self::with_cgl::{NativeGLContext, NativeGLContextHandle}; -*/ -#[cfg(not(any(target_os="linux", target_os="android")))] +#[cfg(not(any(target_os="linux", target_os="android", target_os="macos")))] pub mod not_implemented; -#[cfg(not(any(target_os="linux", target_os="android")))] +#[cfg(not(any(target_os="linux", target_os="android", target_os="macos")))] pub use self::not_implemented::{NativeGLContext, NativeGLContextHandle}; diff --git a/src/platform/with_cgl/native_gl_context.rs b/src/platform/with_cgl/native_gl_context.rs index 8ca9208..5809272 100644 --- a/src/platform/with_cgl/native_gl_context.rs +++ b/src/platform/with_cgl/native_gl_context.rs @@ -27,10 +27,10 @@ impl NativeGLContext { None => 0 as CGLContextObj }; - let mut native = unsafe { mem::uninitialized() }; + let mut native: CGLContextObj = unsafe { mem::uninitialized() }; unsafe { - if CGLCreateContext(pixel_format, shared, &mut native) != 0 { + if CGLCreateContext(*pixel_format, shared, &mut native) != 0 { return Err("CGLCreateContext"); } } @@ -111,10 +111,12 @@ impl NativeGLContextMethods for NativeGLContext { } } - let result = NativeGLContext::new(with.map(|handle| handle.0), pixel_format); + let result = NativeGLContext::new(with.map(|handle| &handle.0), &pixel_format); - if CGLDestroyPixelFormat(pixel_format) != 0 { - debug!("CGLDestroyPixelformat errored"); + unsafe { + if CGLDestroyPixelFormat(pixel_format) != 0 { + debug!("CGLDestroyPixelformat errored"); + } } result diff --git a/src/tests.rs b/src/tests.rs index 87e2166..723b1c5 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,13 +1,14 @@ use gleam::gl; +use gleam::gl::types::GLint; use euclid::Size2D; +use std::sync::{Once, ONCE_INIT}; use GLContext; +use NativeGLContext; +use NativeGLContextMethods; use GLContextAttributes; use ColorAttachmentType; -#[cfg(feature="texture_surface")] -use layers::texturegl::Texture; - #[cfg(target_os="macos")] #[link(name="OpenGL", kind="framework")] extern {} @@ -16,21 +17,16 @@ extern {} #[link(name="GL")] extern {} -// This is probably a time bomb -static mut GL_LOADED : bool = false; +static LOAD_GL: Once = ONCE_INIT; -fn load_gl() { - unsafe { - if GL_LOADED { - return; - } - gl::load_with(|s| GLContext::get_proc_address(s) as *const _); - GL_LOADED = true; - } +fn load_gl() { + LOAD_GL.call_once(|| { + gl::load_with(|s| GLContext::::get_proc_address(s) as *const _); + }); } -fn test_gl_context(context: &GLContext) { +fn test_gl_context(context: &GLContext) { context.make_current().unwrap(); gl::clear_color(1.0, 0.0, 0.0, 1.0); @@ -57,57 +53,78 @@ fn test_pixels(pixels: &[u8]) { } #[test] -fn test_default_color_attachment() { +fn test_renderbuffer_color_attachment() { load_gl(); - test_gl_context(&GLContext::create_offscreen(Size2D::new(256, 256), GLContextAttributes::default()).unwrap()); + test_gl_context(&GLContext::::new(Size2D::new(256, 256), + GLContextAttributes::default(), + ColorAttachmentType::Renderbuffer, + None).unwrap()); } #[test] fn test_texture_color_attachment() { load_gl(); - test_gl_context(&GLContext::create_offscreen_with_color_attachment(Size2D::new(256, 256), GLContextAttributes::default(), ColorAttachmentType::Texture).unwrap()) -} + let size = Size2D::new(256, 256); + let context = GLContext::::new(size, + GLContextAttributes::default(), + ColorAttachmentType::Texture, + None).unwrap(); + test_gl_context(&context); -#[test] -#[cfg(feature="texture_surface")] -fn test_texture_surface_color_attachment() { - load_gl(); - let size : Size2D = Size2D::new(256, 256); - let ctx = GLContext::create_offscreen_with_color_attachment(size, GLContextAttributes::default(), ColorAttachmentType::TextureWithSurface).unwrap(); - - test_gl_context(&ctx); // Get the bound texture and check we're painting on it - let texture = ctx.borrow_draw_buffer().unwrap().borrow_bound_layers_texture().unwrap(); - - // Bind the texture, get its pixels in rgba format and test - // if it has the surface contents - let _bound = texture.bind(); + let texture_id = context.borrow_draw_buffer().unwrap().get_bound_texture_id().unwrap(); + assert!(texture_id != 0); let mut vec = vec![0u8; (size.width * size.height * 4) as usize]; - unsafe { - gl::GetTexImage(texture.target.as_gl_target(), 0, gl::RGBA as u32, gl::UNSIGNED_BYTE, vec.as_mut_ptr() as *mut _); - assert!(gl::GetError() == gl::NO_ERROR); + gl::GetTexImage(gl::TEXTURE_2D, 0, gl::RGBA as u32, gl::UNSIGNED_BYTE, vec.as_mut_ptr() as *mut _); } + assert!(gl::get_error() == gl::NO_ERROR); test_pixels(&vec); +} + +#[test] +fn test_sharing() { + load_gl(); + + let size = Size2D::new(256, 256); + let primary = GLContext::::new(size, + GLContextAttributes::default(), + ColorAttachmentType::Texture, + None).unwrap(); + + let primary_texture_id = primary.borrow_draw_buffer().unwrap().get_bound_texture_id().unwrap(); + assert!(primary_texture_id != 0); - // Pick up the (in theory) painted surface - // And bind it to a new Texture, to check if we actually painted on it - let surface = ctx.borrow_draw_buffer().unwrap().borrow_bound_surface().unwrap(); - let (flip, target) = Texture::texture_flip_and_target(false); - let mut texture = Texture::new(target, Size2D::new(size.width as usize, size.height as usize)); - texture.flip = flip; - surface.bind_to_texture(&ctx.get_display(), &texture); + let secondary = GLContext::::new(size, + GLContextAttributes::default(), + ColorAttachmentType::Texture, + Some(&primary.handle())).unwrap(); - let _bound = texture.bind(); + // Paint the second context red + test_gl_context(&secondary); + + // Now the secondary context is bound, get the texture id, switch contexts, and check the + // texture is there. + let secondary_texture_id = secondary.borrow_draw_buffer().unwrap().get_bound_texture_id().unwrap(); + assert!(secondary_texture_id != 0); + + primary.make_current().unwrap(); + assert!(unsafe { gl::IsTexture(secondary_texture_id) != 0 }); let mut vec = vec![0u8; (size.width * size.height * 4) as usize]; + + // Ensure the old texture is bound, and bind the new one + assert!(gl::get_integer_v(gl::TEXTURE_BINDING_2D) == primary_texture_id as GLint); + + gl::bind_texture(gl::TEXTURE_2D, secondary_texture_id); unsafe { - gl::GetTexImage(texture.target.as_gl_target(), 0, gl::RGBA as u32, gl::UNSIGNED_BYTE, vec.as_mut_ptr() as *mut _); - assert!(gl::GetError() == gl::NO_ERROR); + gl::GetTexImage(gl::TEXTURE_2D, 0, gl::RGBA as u32, gl::UNSIGNED_BYTE, vec.as_mut_ptr() as *mut _); } + assert!(gl::get_error() == gl::NO_ERROR); + test_pixels(&vec); } From 1bca3d134a6e807ed099a22c4ecb7b4109f868a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 9 Dec 2015 16:19:58 +0100 Subject: [PATCH 12/14] Remove old unused dependencies and code --- Cargo.toml | 3 -- src/layers_surface_wrapper.rs | 44 -------------------------- src/lib.rs | 2 -- src/platform/with_glutin/mod.rs | 56 --------------------------------- 4 files changed, 105 deletions(-) delete mode 100644 src/layers_surface_wrapper.rs delete mode 100644 src/platform/with_glutin/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 6338a93..7480c67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,3 @@ features = ["xlib"] [target.aarch64-unknown-linux-gnu.dependencies.x11] version = "2.3.0" features = ["xlib"] - -[target.x86_64-pc-windows-gnu.dependencies] -servo-glutin = "0.4" diff --git a/src/layers_surface_wrapper.rs b/src/layers_surface_wrapper.rs deleted file mode 100644 index f586b91..0000000 --- a/src/layers_surface_wrapper.rs +++ /dev/null @@ -1,44 +0,0 @@ -use layers::platform::surface::{NativeSurface, NativeDisplay}; -use layers::texturegl::Texture; -use euclid::Size2D; - -/// A surface wrapper that owns the surface, -/// and thus destroys it on drop. We need a display -/// to create the surface and to bind it to a texture. -/// -/// Note that the GraphicsContext/CompositingContext -/// structs are not really GL context, just metadata -pub struct LayersSurfaceWrapper { - display: NativeDisplay, - surface: NativeSurface, -} - -impl LayersSurfaceWrapper { - pub fn new(display: NativeDisplay, size: Size2D) -> LayersSurfaceWrapper { - let mut surf = NativeSurface::new(&display, size); - surf.mark_will_leak(); - - LayersSurfaceWrapper { - display: display, - surface: surf, - } - } - - pub fn bind_to_texture(&self, texture: &Texture) { - self.surface.bind_to_texture(&self.display, texture) - } - - pub fn borrow_surface(&self) -> &NativeSurface { - &self.surface - } - - pub fn get_surface_id(&self) -> isize { - self.surface.get_id() - } -} - -impl Drop for LayersSurfaceWrapper { - fn drop(&mut self) { - self.surface.destroy(&self.display); - } -} diff --git a/src/lib.rs b/src/lib.rs index 984b7e6..9ab7904 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,8 +12,6 @@ extern crate x11; extern crate cgl; #[cfg(target_os="macos")] extern crate core_foundation; -#[cfg(target_os="windows")] -extern crate glutin; mod platform; pub use platform::{NativeGLContext, NativeGLContextMethods, NativeGLContextHandle}; diff --git a/src/platform/with_glutin/mod.rs b/src/platform/with_glutin/mod.rs deleted file mode 100644 index a90c04a..0000000 --- a/src/platform/with_glutin/mod.rs +++ /dev/null @@ -1,56 +0,0 @@ -use platform::NativeGLContextMethods; -use glutin::{HeadlessContext, HeadlessRendererBuilder}; - -#[cfg(feature="texture_surface")] -use layers::platform::surface::NativeDisplay; - -#[cfg(not(feature="texture_surface"))] -struct NativeDisplay; - -#[cfg(not(feature="texture_surface"))] -impl NativeDisplay { - fn new() -> NativeDisplay { - NativeDisplay - } -} - - -pub struct NativeGLContext { - context: HeadlessContext, - display: NativeDisplay, -} - -impl NativeGLContextMethods for NativeGLContext { - fn get_proc_address(_addr: &str) -> *const () { - 0 as *const () - } - - fn create_headless() -> Result { - let builder = HeadlessRendererBuilder::new(128, 128); - let glutin_context = try!(builder.build().or(Err("Glutin Headless context creation error"))); - - Ok(NativeGLContext { - context: glutin_context, - display: NativeDisplay::new(), - }) - } - - fn is_current(&self) -> bool { - self.context.is_current() - } - - fn make_current(&self) -> Result<(), &'static str> { - unsafe { - self.context.make_current().or(Err("MakeCurrent failed")) - } - } - - fn unbind(&self) -> Result<(), &'static str> { - Ok(()) - } - - #[cfg(feature="texture_surface")] - fn get_display(&self) -> NativeDisplay { - self.display - } -} From 758d36c924201d60212be3dc711e92fc37eb8b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 9 Dec 2015 16:20:56 +0100 Subject: [PATCH 13/14] ci: Try to reenable CI --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index a66ab24..e6bd4dc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ addons: - g++-4.8 - libxxf86vm-dev - libosmesa6-dev + - libgles2-mesa-dev before_install: - if [ "$TRAVIS_OS_NAME" = "linux" ]; then export CXX=g++-4.8; fi @@ -21,7 +22,4 @@ os: script: - cargo build --verbose - - cargo build --features texture_surface --verbose - # FIXME(ecoal95): Travis' ubuntu doesn't have the neccessary graphics stack and it fails - if [ "$TRAVIS_OS_NAME" != "linux" ]; then cargo test --verbose; fi - - if [ "$TRAVIS_OS_NAME" != "linux" ]; then cargo test --features texture_surface --verbose; fi From 9430a1a77ebe8c3ab9a0de3408f5b6923d9eafc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 9 Dec 2015 22:23:03 +0100 Subject: [PATCH 14/14] platform/egl: Improve EGL implementation --- src/draw_buffer.rs | 4 +++- src/gl_formats.rs | 7 +++++-- src/platform/with_egl/utils.rs | 30 +++++++++++++++++++++--------- src/tests.rs | 15 ++++++++++++++- 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/draw_buffer.rs b/src/draw_buffer.rs index 39af68e..567376b 100644 --- a/src/draw_buffer.rs +++ b/src/draw_buffer.rs @@ -110,7 +110,7 @@ impl DrawBuffer { unsafe { debug_assert!(gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE); - debug_assert!(gl::GetError() == gl::NO_ERROR); + debug_assert!(gl::get_error() == gl::NO_ERROR); } Ok(draw_buffer) @@ -207,6 +207,7 @@ impl DrawBufferHelpers for DrawBuffer { gl::BindTexture(gl::TEXTURE_2D, texture); gl::TexImage2D(gl::TEXTURE_2D, 0, formats.texture_internal as GLint, self.size.width, self.size.height, 0, formats.texture, formats.texture_type, ptr::null_mut()); + // Low filtering to allow rendering gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint); @@ -214,6 +215,7 @@ impl DrawBufferHelpers for DrawBuffer { // TODO(ecoal95): Check if these two are neccessary, probably not gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint); + Some(ColorAttachment::Texture(texture)) } }, diff --git a/src/gl_formats.rs b/src/gl_formats.rs index 6b3c8ff..87d19b0 100644 --- a/src/gl_formats.rs +++ b/src/gl_formats.rs @@ -15,13 +15,16 @@ pub struct GLFormats { impl GLFormats { // In the future we may use extension detection et-al to improve this, for now - // platform depending + // platform dependent. + // + // FIXME: In linux with GLES2 texture attachments create INVALID_ENUM errors. + // I suspect that it's because of texture formats, but I need time to debugit. #[cfg(not(target_os="android"))] pub fn detect(attrs: &GLContextAttributes) -> GLFormats { if attrs.alpha { GLFormats { color_renderbuffer: gl::RGBA8, - texture_internal: gl::RGBA8, + texture_internal: gl::RGBA, texture: gl::RGBA, texture_type: gl::UNSIGNED_BYTE, depth: gl::DEPTH_COMPONENT24, diff --git a/src/platform/with_egl/utils.rs b/src/platform/with_egl/utils.rs index 7c3a14e..851ce35 100644 --- a/src/platform/with_egl/utils.rs +++ b/src/platform/with_egl/utils.rs @@ -37,15 +37,23 @@ pub fn create_pixel_buffer_backed_offscreen_context(size: Size2D, let (shared_with, display) = match shared_with { Some(handle) => (Some(&handle.0), handle.1), None => { - let display = unsafe { - egl::GetDisplay(egl::DEFAULT_DISPLAY as EGLNativeDisplayType) - }; - - if display == (egl::NO_DISPLAY as EGLDisplay) { - return Err("egl::GetDisplay"); + unsafe { + let display = egl::GetDisplay(egl::DEFAULT_DISPLAY as EGLNativeDisplayType); + + if display == (egl::NO_DISPLAY as EGLDisplay) { + return Err("egl::GetDisplay"); + } + + // TODO: Ensure this is correct. It seems it's refcounted, but not atomically, so + // we can't `Terminate` it on drop. + // + // It's the default display anyways so it is not a big problem. + if egl::Initialize(display, 0 as *mut _, 0 as *mut _) == 0 { + return Err("egl::Initialize"); + } + + (None, display) } - - (None, display) } }; @@ -58,7 +66,11 @@ pub fn create_pixel_buffer_backed_offscreen_context(size: Size2D, let mut found_configs : EGLint = 0; unsafe { - if egl::ChooseConfig(display, attributes.as_ptr(), &mut config, 1, &mut found_configs) == 0 { + if egl::ChooseConfig(display, + attributes.as_ptr(), + &mut config, + 1, + &mut found_configs) == egl::FALSE as u32 { return Err("egl::ChooseConfig"); } } diff --git a/src/tests.rs b/src/tests.rs index 723b1c5..f135bb8 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -19,7 +19,6 @@ extern {} static LOAD_GL: Once = ONCE_INIT; - fn load_gl() { LOAD_GL.call_once(|| { gl::load_with(|s| GLContext::::get_proc_address(s) as *const _); @@ -52,6 +51,20 @@ fn test_pixels(pixels: &[u8]) { } } + +#[test] +fn test_unbinding() { + let ctx = GLContext::::new(Size2D::new(256, 256), + GLContextAttributes::default(), + ColorAttachmentType::Renderbuffer, + None).unwrap(); + + assert!(NativeGLContext::current_handle().is_some()); + + ctx.unbind().unwrap(); + assert!(NativeGLContext::current_handle().is_none()); +} + #[test] fn test_renderbuffer_color_attachment() { load_gl();