mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Update surfman to 0.2 and remove glutin
This commit is contained in:
parent
9dbc6554f0
commit
8bb1732258
94 changed files with 2265 additions and 1513 deletions
|
@ -38,9 +38,10 @@ servo_config = {path = "../config"}
|
|||
sparkle = "0.1.22"
|
||||
webrender = {git = "https://github.com/servo/webrender"}
|
||||
webrender_api = {git = "https://github.com/servo/webrender"}
|
||||
webrender_surfman = {path = "../webrender_surfman"}
|
||||
webrender_traits = {path = "../webrender_traits"}
|
||||
webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]}
|
||||
# NOTE: the sm-angle feature only enables angle on windows, not other platforms!
|
||||
surfman = { version = "0.1", features = ["sm-angle", "sm-osmesa"] }
|
||||
surfman = { version = "0.2", features = ["sm-angle","sm-angle-default"] }
|
||||
surfman-chains = "0.3"
|
||||
surfman-chains-api = "0.2"
|
||||
|
|
|
@ -15,19 +15,19 @@ use std::collections::HashMap;
|
|||
use std::default::Default;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use surfman::platform::generic::universal::context::Context;
|
||||
use surfman::platform::generic::universal::device::Device;
|
||||
use surfman::platform::generic::universal::surface::SurfaceTexture;
|
||||
use surfman::Device;
|
||||
use surfman::SurfaceInfo;
|
||||
use surfman::SurfaceTexture;
|
||||
use surfman_chains::SwapChains;
|
||||
use surfman_chains_api::SwapChainAPI;
|
||||
use surfman_chains_api::SwapChainsAPI;
|
||||
use webrender_surfman::WebrenderSurfman;
|
||||
use webrender_traits::{WebrenderExternalImageApi, WebrenderExternalImageRegistry};
|
||||
use webxr_api::SwapChainId as WebXRSwapChainId;
|
||||
|
||||
pub struct WebGLComm {
|
||||
pub webgl_threads: WebGLThreads,
|
||||
pub webxr_swap_chains: SwapChains<WebXRSwapChainId>,
|
||||
pub webxr_swap_chains: SwapChains<WebXRSwapChainId, Device>,
|
||||
pub webxr_surface_providers: SurfaceProviders,
|
||||
pub image_handler: Box<dyn WebrenderExternalImageApi>,
|
||||
pub output_handler: Option<Box<dyn webrender_api::OutputImageHandler>>,
|
||||
|
@ -37,8 +37,7 @@ pub struct WebGLComm {
|
|||
impl WebGLComm {
|
||||
/// Creates a new `WebGLComm` object.
|
||||
pub fn new(
|
||||
device: Device,
|
||||
context: Context,
|
||||
surfman: WebrenderSurfman,
|
||||
webrender_gl: Rc<dyn gleam::gl::Gl>,
|
||||
webrender_api_sender: webrender_api::RenderApiSender,
|
||||
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
||||
|
@ -60,8 +59,8 @@ impl WebGLComm {
|
|||
webrender_swap_chains: webrender_swap_chains.clone(),
|
||||
webxr_swap_chains: webxr_swap_chains.clone(),
|
||||
webxr_surface_providers: webxr_surface_providers.clone(),
|
||||
connection: device.connection(),
|
||||
adapter: device.adapter(),
|
||||
connection: surfman.connection(),
|
||||
adapter: surfman.adapter(),
|
||||
api_type,
|
||||
runnable_receiver,
|
||||
};
|
||||
|
@ -72,7 +71,7 @@ impl WebGLComm {
|
|||
None
|
||||
};
|
||||
|
||||
let external = WebGLExternalImages::new(device, context, webrender_swap_chains);
|
||||
let external = WebGLExternalImages::new(surfman, webrender_swap_chains);
|
||||
|
||||
WebGLThread::run_on_own_thread(init);
|
||||
|
||||
|
@ -89,23 +88,15 @@ impl WebGLComm {
|
|||
|
||||
/// Bridge between the webrender::ExternalImage callbacks and the WebGLThreads.
|
||||
struct WebGLExternalImages {
|
||||
device: Device,
|
||||
context: Context,
|
||||
swap_chains: SwapChains<WebGLContextId>,
|
||||
surfman: WebrenderSurfman,
|
||||
swap_chains: SwapChains<WebGLContextId, Device>,
|
||||
locked_front_buffers: FnvHashMap<WebGLContextId, SurfaceTexture>,
|
||||
}
|
||||
|
||||
impl Drop for WebGLExternalImages {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.device.destroy_context(&mut self.context);
|
||||
}
|
||||
}
|
||||
|
||||
impl WebGLExternalImages {
|
||||
fn new(device: Device, context: Context, swap_chains: SwapChains<WebGLContextId>) -> Self {
|
||||
fn new(surfman: WebrenderSurfman, swap_chains: SwapChains<WebGLContextId, Device>) -> Self {
|
||||
Self {
|
||||
device,
|
||||
context,
|
||||
surfman,
|
||||
swap_chains,
|
||||
locked_front_buffers: FnvHashMap::default(),
|
||||
}
|
||||
|
@ -119,13 +110,10 @@ impl WebGLExternalImages {
|
|||
id: front_buffer_id,
|
||||
size,
|
||||
..
|
||||
} = self.device.surface_info(&front_buffer);
|
||||
} = self.surfman.surface_info(&front_buffer);
|
||||
debug!("... getting texture for surface {:?}", front_buffer_id);
|
||||
let front_buffer_texture = self
|
||||
.device
|
||||
.create_surface_texture(&mut self.context, front_buffer)
|
||||
.unwrap();
|
||||
let gl_texture = front_buffer_texture.gl_texture();
|
||||
let front_buffer_texture = self.surfman.create_surface_texture(front_buffer).unwrap();
|
||||
let gl_texture = self.surfman.surface_texture_object(&front_buffer_texture);
|
||||
|
||||
self.locked_front_buffers.insert(id, front_buffer_texture);
|
||||
|
||||
|
@ -135,8 +123,8 @@ impl WebGLExternalImages {
|
|||
fn unlock_swap_chain(&mut self, id: WebGLContextId) -> Option<()> {
|
||||
let locked_front_buffer = self.locked_front_buffers.remove(&id)?;
|
||||
let locked_front_buffer = self
|
||||
.device
|
||||
.destroy_surface_texture(&mut self.context, locked_front_buffer)
|
||||
.surfman
|
||||
.destroy_surface_texture(locked_front_buffer)
|
||||
.unwrap();
|
||||
|
||||
debug!("... unlocked chain {:?}", id);
|
||||
|
|
|
@ -47,7 +47,6 @@ use euclid::default::Size2D;
|
|||
use fnv::FnvHashMap;
|
||||
use half::f16;
|
||||
use pixels::{self, PixelFormat};
|
||||
use servo_config::opts;
|
||||
use sparkle::gl;
|
||||
use sparkle::gl::GLint;
|
||||
use sparkle::gl::GLuint;
|
||||
|
@ -59,12 +58,12 @@ use std::slice;
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use surfman;
|
||||
use surfman::platform::generic::universal::adapter::Adapter;
|
||||
use surfman::platform::generic::universal::connection::Connection;
|
||||
use surfman::platform::generic::universal::context::Context;
|
||||
use surfman::platform::generic::universal::device::Device;
|
||||
use surfman::Adapter;
|
||||
use surfman::Connection;
|
||||
use surfman::Context;
|
||||
use surfman::ContextAttributeFlags;
|
||||
use surfman::ContextAttributes;
|
||||
use surfman::Device;
|
||||
use surfman::GLVersion;
|
||||
use surfman::SurfaceAccess;
|
||||
use surfman::SurfaceInfo;
|
||||
|
@ -87,30 +86,130 @@ struct GLContextData {
|
|||
attributes: GLContextAttributes,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GLState {
|
||||
webgl_version: WebGLVersion,
|
||||
gl_version: GLVersion,
|
||||
requested_flags: ContextAttributeFlags,
|
||||
// This is the WebGL view of the color mask
|
||||
// The GL view may be different: if the GL context supports alpha
|
||||
// but the WebGL context doesn't, then color_write_mask.3 might be true
|
||||
// but the GL color write mask is false.
|
||||
color_write_mask: [bool; 4],
|
||||
clear_color: (f32, f32, f32, f32),
|
||||
scissor_test_enabled: bool,
|
||||
// The WebGL view of the stencil write mask (see comment re `color_write_mask`)
|
||||
stencil_write_mask: (u32, u32),
|
||||
stencil_test_enabled: bool,
|
||||
stencil_clear_value: i32,
|
||||
// The WebGL view of the depth write mask (see comment re `color_write_mask`)
|
||||
depth_write_mask: bool,
|
||||
depth_test_enabled: bool,
|
||||
depth_clear_value: f64,
|
||||
// True when the default framebuffer is bound to DRAW_FRAMEBUFFER
|
||||
drawing_to_default_framebuffer: bool,
|
||||
default_vao: gl::GLuint,
|
||||
}
|
||||
|
||||
impl GLState {
|
||||
// Are we faking having no alpha / depth / stencil?
|
||||
fn fake_no_alpha(&self) -> bool {
|
||||
self.drawing_to_default_framebuffer &
|
||||
!self.requested_flags.contains(ContextAttributeFlags::ALPHA)
|
||||
}
|
||||
|
||||
fn fake_no_depth(&self) -> bool {
|
||||
self.drawing_to_default_framebuffer &
|
||||
!self.requested_flags.contains(ContextAttributeFlags::DEPTH)
|
||||
}
|
||||
|
||||
fn fake_no_stencil(&self) -> bool {
|
||||
self.drawing_to_default_framebuffer &
|
||||
!self
|
||||
.requested_flags
|
||||
.contains(ContextAttributeFlags::STENCIL)
|
||||
}
|
||||
|
||||
// We maintain invariants between the GLState object and the GL state.
|
||||
fn restore_invariant(&self, gl: &Gl) {
|
||||
self.restore_clear_color_invariant(gl);
|
||||
self.restore_scissor_invariant(gl);
|
||||
self.restore_alpha_invariant(gl);
|
||||
self.restore_depth_invariant(gl);
|
||||
self.restore_stencil_invariant(gl);
|
||||
}
|
||||
|
||||
fn restore_clear_color_invariant(&self, gl: &Gl) {
|
||||
let (r, g, b, a) = self.clear_color;
|
||||
gl.clear_color(r, g, b, a);
|
||||
}
|
||||
|
||||
fn restore_scissor_invariant(&self, gl: &Gl) {
|
||||
if self.scissor_test_enabled {
|
||||
gl.enable(gl::SCISSOR_TEST);
|
||||
} else {
|
||||
gl.disable(gl::SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
fn restore_alpha_invariant(&self, gl: &Gl) {
|
||||
let [r, g, b, a] = self.color_write_mask;
|
||||
if self.fake_no_alpha() {
|
||||
gl.color_mask(r, g, b, false);
|
||||
} else {
|
||||
gl.color_mask(r, g, b, a);
|
||||
}
|
||||
}
|
||||
|
||||
fn restore_depth_invariant(&self, gl: &Gl) {
|
||||
if self.fake_no_depth() {
|
||||
gl.depth_mask(false);
|
||||
gl.disable(gl::DEPTH_TEST);
|
||||
} else {
|
||||
gl.depth_mask(self.depth_write_mask);
|
||||
if self.depth_test_enabled {
|
||||
gl.enable(gl::DEPTH_TEST);
|
||||
} else {
|
||||
gl.disable(gl::DEPTH_TEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn restore_stencil_invariant(&self, gl: &Gl) {
|
||||
if self.fake_no_stencil() {
|
||||
gl.stencil_mask(0);
|
||||
gl.disable(gl::STENCIL_TEST);
|
||||
} else {
|
||||
let (f, b) = self.stencil_write_mask;
|
||||
gl.stencil_mask_separate(gl::FRONT, f);
|
||||
gl.stencil_mask_separate(gl::BACK, b);
|
||||
if self.stencil_test_enabled {
|
||||
gl.enable(gl::STENCIL_TEST);
|
||||
} else {
|
||||
gl.disable(gl::STENCIL_TEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GLState {
|
||||
fn default() -> GLState {
|
||||
GLState {
|
||||
gl_version: GLVersion { major: 1, minor: 0 },
|
||||
webgl_version: WebGLVersion::WebGL1,
|
||||
requested_flags: ContextAttributeFlags::empty(),
|
||||
color_write_mask: [true, true, true, true],
|
||||
clear_color: (0., 0., 0., 0.),
|
||||
scissor_test_enabled: false,
|
||||
// Should these be 0xFFFF_FFFF?
|
||||
stencil_write_mask: (0, 0),
|
||||
stencil_test_enabled: false,
|
||||
stencil_clear_value: 0,
|
||||
depth_write_mask: true,
|
||||
depth_test_enabled: false,
|
||||
depth_clear_value: 1.,
|
||||
default_vao: 0,
|
||||
drawing_to_default_framebuffer: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -138,9 +237,9 @@ pub(crate) struct WebGLThread {
|
|||
/// The receiver that should be used to send WebGL messages for processing.
|
||||
sender: WebGLSender<WebGLMsg>,
|
||||
/// The swap chains used by webrender
|
||||
webrender_swap_chains: SwapChains<WebGLContextId>,
|
||||
webrender_swap_chains: SwapChains<WebGLContextId, Device>,
|
||||
/// The swap chains used by webxr
|
||||
webxr_swap_chains: SwapChains<WebXRSwapChainId>,
|
||||
webxr_swap_chains: SwapChains<WebXRSwapChainId, Device>,
|
||||
/// The set of all surface providers corresponding to WebXR sessions.
|
||||
webxr_surface_providers: SurfaceProviders,
|
||||
/// A channel to allow arbitrary threads to execute tasks that run in the WebGL thread.
|
||||
|
@ -150,9 +249,9 @@ pub(crate) struct WebGLThread {
|
|||
}
|
||||
|
||||
pub type WebGlExecutor = crossbeam_channel::Sender<WebGlRunnable>;
|
||||
pub type WebGlRunnable = Box<dyn FnOnce() + Send>;
|
||||
pub type WebGlRunnable = Box<dyn FnOnce(&Device) + Send>;
|
||||
pub type SurfaceProviders = Arc<Mutex<HashMap<SessionId, SurfaceProvider>>>;
|
||||
pub type SurfaceProvider = Box<dyn surfman_chains::SurfaceProvider + Send>;
|
||||
pub type SurfaceProvider = Box<dyn surfman_chains::SurfaceProvider<Device> + Send>;
|
||||
|
||||
/// The data required to initialize an instance of the WebGLThread type.
|
||||
pub(crate) struct WebGLThreadInit {
|
||||
|
@ -161,8 +260,8 @@ pub(crate) struct WebGLThreadInit {
|
|||
pub external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
|
||||
pub sender: WebGLSender<WebGLMsg>,
|
||||
pub receiver: WebGLReceiver<WebGLMsg>,
|
||||
pub webrender_swap_chains: SwapChains<WebGLContextId>,
|
||||
pub webxr_swap_chains: SwapChains<WebXRSwapChainId>,
|
||||
pub webrender_swap_chains: SwapChains<WebGLContextId, Device>,
|
||||
pub webxr_swap_chains: SwapChains<WebXRSwapChainId, Device>,
|
||||
pub connection: Connection,
|
||||
pub adapter: Adapter,
|
||||
pub api_type: gl::GlType,
|
||||
|
@ -190,7 +289,9 @@ impl WebGLThread {
|
|||
}: WebGLThreadInit,
|
||||
) -> Self {
|
||||
WebGLThread {
|
||||
device: Device::new(&connection, &adapter).expect("Couldn't open WebGL device!"),
|
||||
device: connection
|
||||
.create_device(&adapter)
|
||||
.expect("Couldn't open WebGL device!"),
|
||||
webrender_api: webrender_api_sender.create_api(),
|
||||
contexts: Default::default(),
|
||||
cached_context_info: Default::default(),
|
||||
|
@ -236,7 +337,7 @@ impl WebGLThread {
|
|||
}
|
||||
recv(self.runnable_receiver) -> msg => {
|
||||
if let Ok(msg) = msg {
|
||||
msg();
|
||||
msg(&self.device);
|
||||
} else {
|
||||
self.runnable_receiver = crossbeam_channel::never();
|
||||
}
|
||||
|
@ -303,7 +404,7 @@ impl WebGLThread {
|
|||
.unwrap();
|
||||
},
|
||||
WebGLMsg::ResizeContext(ctx_id, size, sender) => {
|
||||
self.resize_webgl_context(ctx_id, size, sender);
|
||||
let _ = sender.send(self.resize_webgl_context(ctx_id, size));
|
||||
},
|
||||
WebGLMsg::RemoveContext(ctx_id) => {
|
||||
self.remove_webgl_context(ctx_id);
|
||||
|
@ -394,21 +495,35 @@ impl WebGLThread {
|
|||
requested_size: Size2D<u32>,
|
||||
attributes: GLContextAttributes,
|
||||
) -> Result<(WebGLContextId, webgl::GLLimits), String> {
|
||||
debug!("WebGLThread::create_webgl_context({:?})", requested_size);
|
||||
debug!(
|
||||
"WebGLThread::create_webgl_context({:?}, {:?}, {:?})",
|
||||
webgl_version, requested_size, attributes
|
||||
);
|
||||
|
||||
// Creating a new GLContext may make the current bound context_id dirty.
|
||||
// Clear it to ensure that make_current() is called in subsequent commands.
|
||||
self.bound_context_id = None;
|
||||
|
||||
let requested_flags =
|
||||
attributes.to_surfman_context_attribute_flags(webgl_version, self.api_type);
|
||||
// Some GL implementations seem to only allow famebuffers
|
||||
// to have alpha, depth and stencil if their creating context does.
|
||||
// WebGL requires all contexts to be able to create framebuffers with
|
||||
// alpha, depth and stencil. So we always create a context with them,
|
||||
// and fake not having them if requested.
|
||||
let flags = requested_flags |
|
||||
ContextAttributeFlags::ALPHA |
|
||||
ContextAttributeFlags::DEPTH |
|
||||
ContextAttributeFlags::STENCIL;
|
||||
let context_attributes = &ContextAttributes {
|
||||
version: webgl_version.to_surfman_version(),
|
||||
flags: attributes.to_surfman_context_attribute_flags(webgl_version),
|
||||
version: webgl_version.to_surfman_version(self.api_type),
|
||||
flags: flags,
|
||||
};
|
||||
|
||||
let context_descriptor = self
|
||||
.device
|
||||
.create_context_descriptor(&context_attributes)
|
||||
.unwrap();
|
||||
.map_err(|err| format!("Failed to create context descriptor: {:?}", err))?;
|
||||
|
||||
let safe_size = Size2D::new(
|
||||
requested_size.width.min(SAFE_VIEWPORT_DIMS[0]).max(1),
|
||||
|
@ -423,30 +538,30 @@ impl WebGLThread {
|
|||
let mut ctx = self
|
||||
.device
|
||||
.create_context(&context_descriptor)
|
||||
.expect("Failed to create the GL context!");
|
||||
.map_err(|err| format!("Failed to create the GL context: {:?}", err))?;
|
||||
let surface = self
|
||||
.device
|
||||
.create_surface(&ctx, surface_access, &surface_type)
|
||||
.expect("Failed to create the initial surface!");
|
||||
.create_surface(&ctx, surface_access, surface_type)
|
||||
.map_err(|err| format!("Failed to create the initial surface: {:?}", err))?;
|
||||
self.device
|
||||
.bind_surface_to_context(&mut ctx, surface)
|
||||
.unwrap();
|
||||
.map_err(|err| format!("Failed to bind initial surface: {:?}", err))?;
|
||||
// https://github.com/pcwalton/surfman/issues/7
|
||||
self.device
|
||||
.make_context_current(&ctx)
|
||||
.expect("failed to make new context current");
|
||||
.map_err(|err| format!("Failed to make new context current: {:?}", err))?;
|
||||
|
||||
let id = WebGLContextId(
|
||||
self.external_images
|
||||
.lock()
|
||||
.unwrap()
|
||||
.expect("Lock poisoned?")
|
||||
.next_id(WebrenderImageHandlerType::WebGL)
|
||||
.0,
|
||||
);
|
||||
|
||||
self.webrender_swap_chains
|
||||
.create_attached_swap_chain(id, &mut self.device, &mut ctx, surface_provider)
|
||||
.expect("Failed to create the swap chain");
|
||||
.map_err(|err| format!("Failed to create swap chain: {:?}", err))?;
|
||||
|
||||
let swap_chain = self
|
||||
.webrender_swap_chains
|
||||
|
@ -456,7 +571,7 @@ impl WebGLThread {
|
|||
debug!(
|
||||
"Created webgl context {:?}/{:?}",
|
||||
id,
|
||||
self.device.context_id(&ctx)
|
||||
self.device.context_id(&ctx),
|
||||
);
|
||||
|
||||
let gl = match self.api_type {
|
||||
|
@ -475,34 +590,33 @@ impl WebGLThread {
|
|||
debug!("Resizing swap chain from {} to {}", safe_size, size);
|
||||
swap_chain
|
||||
.resize(&mut self.device, &mut ctx, size.to_i32())
|
||||
.expect("Failed to resize swap chain");
|
||||
.map_err(|err| format!("Failed to resize swap chain: {:?}", err))?;
|
||||
}
|
||||
|
||||
let descriptor = self.device.context_descriptor(&ctx);
|
||||
let descriptor_attributes = self.device.context_descriptor_attributes(&descriptor);
|
||||
let gl_version = descriptor_attributes.version;
|
||||
let has_alpha = requested_flags.contains(ContextAttributeFlags::ALPHA);
|
||||
let texture_target = current_wr_texture_target(&self.device);
|
||||
|
||||
self.device.make_context_current(&ctx).unwrap();
|
||||
let framebuffer = self
|
||||
.device
|
||||
.context_surface_info(&ctx)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.map_err(|err| format!("Failed to get context surface info: {:?}", err))?
|
||||
.ok_or_else(|| format!("Failed to get context surface info"))?
|
||||
.framebuffer_object;
|
||||
|
||||
gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer);
|
||||
gl.viewport(0, 0, size.width as i32, size.height as i32);
|
||||
gl.scissor(0, 0, size.width as i32, size.height as i32);
|
||||
gl.clear_color(0., 0., 0., 0.);
|
||||
gl.clear_color(0., 0., 0., !has_alpha as u32 as f32);
|
||||
gl.clear_depth(1.);
|
||||
gl.clear_stencil(0);
|
||||
gl.clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
|
||||
gl.clear_color(0., 0., 0., 0.);
|
||||
debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
|
||||
|
||||
let descriptor = self.device.context_descriptor(&ctx);
|
||||
let descriptor_attributes = self.device.context_descriptor_attributes(&descriptor);
|
||||
|
||||
let gl_version = descriptor_attributes.version;
|
||||
let has_alpha = descriptor_attributes
|
||||
.flags
|
||||
.contains(ContextAttributeFlags::ALPHA);
|
||||
let texture_target = current_wr_texture_target(&self.device);
|
||||
|
||||
let use_apple_vertex_array = WebGLImpl::needs_apple_vertex_arrays(gl_version);
|
||||
let default_vao = if let Some(vao) =
|
||||
WebGLImpl::create_vertex_array(&gl, use_apple_vertex_array, webgl_version)
|
||||
|
@ -517,9 +631,15 @@ impl WebGLThread {
|
|||
let state = GLState {
|
||||
gl_version,
|
||||
webgl_version,
|
||||
requested_flags,
|
||||
default_vao,
|
||||
..Default::default()
|
||||
};
|
||||
debug!("Created state {:?}", state);
|
||||
|
||||
state.restore_invariant(&*gl);
|
||||
debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
|
||||
|
||||
self.contexts.insert(
|
||||
id,
|
||||
GLContextData {
|
||||
|
@ -549,8 +669,7 @@ impl WebGLThread {
|
|||
&mut self,
|
||||
context_id: WebGLContextId,
|
||||
requested_size: Size2D<u32>,
|
||||
sender: WebGLSender<Result<(), String>>,
|
||||
) {
|
||||
) -> Result<(), String> {
|
||||
let data = Self::make_current_if_needed_mut(
|
||||
&self.device,
|
||||
context_id,
|
||||
|
@ -568,16 +687,17 @@ impl WebGLThread {
|
|||
|
||||
// Resize the swap chains
|
||||
if let Some(swap_chain) = self.webrender_swap_chains.get(context_id) {
|
||||
let alpha = data
|
||||
.state
|
||||
.requested_flags
|
||||
.contains(ContextAttributeFlags::ALPHA);
|
||||
let clear_color = [0.0, 0.0, 0.0, !alpha as i32 as f32];
|
||||
swap_chain
|
||||
.resize(&mut self.device, &mut data.ctx, size.to_i32())
|
||||
.expect("Failed to resize swap chain");
|
||||
// temporary, till https://github.com/pcwalton/surfman/issues/35 is fixed
|
||||
self.device
|
||||
.make_context_current(&data.ctx)
|
||||
.expect("Failed to make context current again");
|
||||
.map_err(|err| format!("Failed to resize swap chain: {:?}", err))?;
|
||||
swap_chain
|
||||
.clear_surface(&mut self.device, &mut data.ctx, &*data.gl)
|
||||
.expect("Failed to clear resized swap chain");
|
||||
.clear_surface(&mut self.device, &mut data.ctx, &*data.gl, clear_color)
|
||||
.map_err(|err| format!("Failed to clear resized swap chain: {:?}", err))?;
|
||||
} else {
|
||||
error!("Failed to find swap chain");
|
||||
}
|
||||
|
@ -587,11 +707,9 @@ impl WebGLThread {
|
|||
|
||||
// Update WR image if needed.
|
||||
let info = self.cached_context_info.get_mut(&context_id).unwrap();
|
||||
let context_descriptor = self.device.context_descriptor(&data.ctx);
|
||||
let has_alpha = self
|
||||
.device
|
||||
.context_descriptor_attributes(&context_descriptor)
|
||||
.flags
|
||||
let has_alpha = data
|
||||
.state
|
||||
.requested_flags
|
||||
.contains(ContextAttributeFlags::ALPHA);
|
||||
let texture_target = current_wr_texture_target(&self.device);
|
||||
Self::update_wr_external_image(
|
||||
|
@ -605,7 +723,7 @@ impl WebGLThread {
|
|||
|
||||
debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR);
|
||||
|
||||
sender.send(Ok(())).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes a WebGLContext and releases attached resources.
|
||||
|
@ -697,8 +815,13 @@ impl WebGLThread {
|
|||
// TODO: if preserveDrawingBuffer is true, then blit the front buffer to the back buffer
|
||||
// https://github.com/servo/servo/issues/24604
|
||||
debug!("Clearing {:?}", swap_id);
|
||||
let alpha = data
|
||||
.state
|
||||
.requested_flags
|
||||
.contains(ContextAttributeFlags::ALPHA);
|
||||
let clear_color = [0.0, 0.0, 0.0, !alpha as i32 as f32];
|
||||
swap_chain
|
||||
.clear_surface(&mut self.device, &mut data.ctx, &*data.gl)
|
||||
.clear_surface(&mut self.device, &mut data.ctx, &*data.gl, clear_color)
|
||||
.unwrap();
|
||||
debug_assert_eq!(data.gl.get_error(), gl::NO_ERROR);
|
||||
|
||||
|
@ -1084,7 +1207,10 @@ impl WebGLImpl {
|
|||
state.stencil_clear_value = stencil;
|
||||
gl.clear_stencil(stencil);
|
||||
},
|
||||
WebGLCommand::ColorMask(r, g, b, a) => gl.color_mask(r, g, b, a),
|
||||
WebGLCommand::ColorMask(r, g, b, a) => {
|
||||
state.color_write_mask = [r, g, b, a];
|
||||
state.restore_alpha_invariant(gl);
|
||||
},
|
||||
WebGLCommand::CopyTexImage2D(
|
||||
target,
|
||||
level,
|
||||
|
@ -1109,22 +1235,40 @@ impl WebGLImpl {
|
|||
WebGLCommand::DepthFunc(func) => gl.depth_func(func),
|
||||
WebGLCommand::DepthMask(flag) => {
|
||||
state.depth_write_mask = flag;
|
||||
gl.depth_mask(flag);
|
||||
state.restore_depth_invariant(gl);
|
||||
},
|
||||
WebGLCommand::DepthRange(near, far) => {
|
||||
gl.depth_range(near.max(0.).min(1.) as f64, far.max(0.).min(1.) as f64)
|
||||
},
|
||||
WebGLCommand::Disable(cap) => {
|
||||
if cap == gl::SCISSOR_TEST {
|
||||
WebGLCommand::Disable(cap) => match cap {
|
||||
gl::SCISSOR_TEST => {
|
||||
state.scissor_test_enabled = false;
|
||||
}
|
||||
gl.disable(cap);
|
||||
state.restore_scissor_invariant(gl);
|
||||
},
|
||||
gl::DEPTH_TEST => {
|
||||
state.depth_test_enabled = false;
|
||||
state.restore_depth_invariant(gl);
|
||||
},
|
||||
gl::STENCIL_TEST => {
|
||||
state.stencil_test_enabled = false;
|
||||
state.restore_stencil_invariant(gl);
|
||||
},
|
||||
_ => gl.disable(cap),
|
||||
},
|
||||
WebGLCommand::Enable(cap) => {
|
||||
if cap == gl::SCISSOR_TEST {
|
||||
WebGLCommand::Enable(cap) => match cap {
|
||||
gl::SCISSOR_TEST => {
|
||||
state.scissor_test_enabled = true;
|
||||
}
|
||||
gl.enable(cap);
|
||||
state.restore_scissor_invariant(gl);
|
||||
},
|
||||
gl::DEPTH_TEST => {
|
||||
state.depth_test_enabled = true;
|
||||
state.restore_depth_invariant(gl);
|
||||
},
|
||||
gl::STENCIL_TEST => {
|
||||
state.stencil_test_enabled = true;
|
||||
state.restore_stencil_invariant(gl);
|
||||
},
|
||||
_ => gl.enable(cap),
|
||||
},
|
||||
WebGLCommand::FramebufferRenderbuffer(target, attachment, renderbuffertarget, rb) => {
|
||||
let attach = |attachment| {
|
||||
|
@ -1221,7 +1365,7 @@ impl WebGLImpl {
|
|||
},
|
||||
WebGLCommand::StencilMask(mask) => {
|
||||
state.stencil_write_mask = (mask, mask);
|
||||
gl.stencil_mask(mask);
|
||||
state.restore_stencil_invariant(gl);
|
||||
},
|
||||
WebGLCommand::StencilMaskSeparate(face, mask) => {
|
||||
if face == gl::FRONT {
|
||||
|
@ -1229,7 +1373,7 @@ impl WebGLImpl {
|
|||
} else {
|
||||
state.stencil_write_mask.1 = mask;
|
||||
}
|
||||
gl.stencil_mask_separate(face, mask);
|
||||
state.restore_stencil_invariant(gl);
|
||||
},
|
||||
WebGLCommand::StencilOp(fail, zfail, zpass) => gl.stencil_op(fail, zfail, zpass),
|
||||
WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass) => {
|
||||
|
@ -1321,7 +1465,7 @@ impl WebGLImpl {
|
|||
gl.bind_buffer(target, id.map_or(0, WebGLBufferId::get))
|
||||
},
|
||||
WebGLCommand::BindFramebuffer(target, request) => {
|
||||
Self::bind_framebuffer(gl, target, request, ctx, device)
|
||||
Self::bind_framebuffer(gl, target, request, ctx, device, state)
|
||||
},
|
||||
WebGLCommand::BindRenderbuffer(target, id) => {
|
||||
gl.bind_renderbuffer(target, id.map_or(0, WebGLRenderbufferId::get))
|
||||
|
@ -1557,11 +1701,15 @@ impl WebGLImpl {
|
|||
Self::bind_vertex_array(gl, id, use_apple_vertex_array, state.webgl_version);
|
||||
},
|
||||
WebGLCommand::GetParameterBool(param, ref sender) => {
|
||||
let mut value = [0];
|
||||
unsafe {
|
||||
gl.get_boolean_v(param as u32, &mut value);
|
||||
}
|
||||
sender.send(value[0] != 0).unwrap()
|
||||
let value = match param {
|
||||
webgl::ParameterBool::DepthWritemask => state.depth_write_mask,
|
||||
_ => unsafe {
|
||||
let mut value = [0];
|
||||
gl.get_boolean_v(param as u32, &mut value);
|
||||
value[0] != 0
|
||||
},
|
||||
};
|
||||
sender.send(value).unwrap()
|
||||
},
|
||||
WebGLCommand::FenceSync(ref sender) => {
|
||||
let value = gl.fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
|
@ -1588,19 +1736,25 @@ impl WebGLImpl {
|
|||
gl.delete_sync(sync_id.get() as *const _);
|
||||
},
|
||||
WebGLCommand::GetParameterBool4(param, ref sender) => {
|
||||
let mut value = [0; 4];
|
||||
unsafe {
|
||||
gl.get_boolean_v(param as u32, &mut value);
|
||||
}
|
||||
let value = [value[0] != 0, value[1] != 0, value[2] != 0, value[3] != 0];
|
||||
let value = match param {
|
||||
webgl::ParameterBool4::ColorWritemask => state.color_write_mask,
|
||||
};
|
||||
sender.send(value).unwrap()
|
||||
},
|
||||
WebGLCommand::GetParameterInt(param, ref sender) => {
|
||||
let mut value = [0];
|
||||
unsafe {
|
||||
gl.get_integer_v(param as u32, &mut value);
|
||||
}
|
||||
sender.send(value[0]).unwrap()
|
||||
let value = match param {
|
||||
webgl::ParameterInt::AlphaBits if state.fake_no_alpha() => 0,
|
||||
webgl::ParameterInt::DepthBits if state.fake_no_depth() => 0,
|
||||
webgl::ParameterInt::StencilBits if state.fake_no_stencil() => 0,
|
||||
webgl::ParameterInt::StencilWritemask => state.stencil_write_mask.0 as i32,
|
||||
webgl::ParameterInt::StencilBackWritemask => state.stencil_write_mask.1 as i32,
|
||||
_ => unsafe {
|
||||
let mut value = [0];
|
||||
gl.get_integer_v(param as u32, &mut value);
|
||||
value[0]
|
||||
},
|
||||
};
|
||||
sender.send(value).unwrap()
|
||||
},
|
||||
WebGLCommand::GetParameterInt2(param, ref sender) => {
|
||||
let mut value = [0; 2];
|
||||
|
@ -1978,15 +2132,25 @@ impl WebGLImpl {
|
|||
sender.send(value).unwrap();
|
||||
},
|
||||
WebGLCommand::BindBufferBase(target, index, id) => {
|
||||
gl.bind_buffer_base(target, index, id.map_or(0, WebGLBufferId::get))
|
||||
// https://searchfox.org/mozilla-central/rev/13b081a62d3f3e3e3120f95564529257b0bf451c/dom/canvas/WebGLContextBuffers.cpp#208-210
|
||||
// BindBufferBase/Range will fail (on some drivers) if the buffer name has
|
||||
// never been bound. (GenBuffers makes a name, but BindBuffer initializes
|
||||
// that name as a real buffer object)
|
||||
let id = id.map_or(0, WebGLBufferId::get);
|
||||
gl.bind_buffer(target, id);
|
||||
gl.bind_buffer(target, 0);
|
||||
gl.bind_buffer_base(target, index, id);
|
||||
},
|
||||
WebGLCommand::BindBufferRange(target, index, id, offset, size) => {
|
||||
// https://searchfox.org/mozilla-central/rev/13b081a62d3f3e3e3120f95564529257b0bf451c/dom/canvas/WebGLContextBuffers.cpp#208-210
|
||||
// BindBufferBase/Range will fail (on some drivers) if the buffer name has
|
||||
// never been bound. (GenBuffers makes a name, but BindBuffer initializes
|
||||
// that name as a real buffer object)
|
||||
let id = id.map_or(0, WebGLBufferId::get);
|
||||
gl.bind_buffer(target, id);
|
||||
gl.bind_buffer(target, 0);
|
||||
gl.bind_buffer_range(target, index, id, offset as isize, size as isize);
|
||||
},
|
||||
WebGLCommand::BindBufferRange(target, index, id, offset, size) => gl.bind_buffer_range(
|
||||
target,
|
||||
index,
|
||||
id.map_or(0, WebGLBufferId::get),
|
||||
offset as isize,
|
||||
size as isize,
|
||||
),
|
||||
WebGLCommand::ClearBufferfv(buffer, draw_buffer, ref value) => {
|
||||
gl.clear_buffer_fv(buffer, draw_buffer, value)
|
||||
},
|
||||
|
@ -2065,47 +2229,17 @@ impl WebGLImpl {
|
|||
bits | if enabled { bit } else { 0 }
|
||||
});
|
||||
|
||||
if state.scissor_test_enabled {
|
||||
gl.disable(gl::SCISSOR_TEST);
|
||||
}
|
||||
|
||||
if color {
|
||||
gl.clear_color(0., 0., 0., 0.);
|
||||
}
|
||||
|
||||
if depth {
|
||||
gl.depth_mask(true);
|
||||
gl.clear_depth(1.);
|
||||
}
|
||||
|
||||
if stencil {
|
||||
gl.stencil_mask_separate(gl::FRONT, 0xFFFFFFFF);
|
||||
gl.stencil_mask_separate(gl::BACK, 0xFFFFFFFF);
|
||||
gl.clear_stencil(0);
|
||||
}
|
||||
|
||||
gl.disable(gl::SCISSOR_TEST);
|
||||
gl.color_mask(true, true, true, true);
|
||||
gl.clear_color(0., 0., 0., 0.);
|
||||
gl.depth_mask(true);
|
||||
gl.clear_depth(1.);
|
||||
gl.stencil_mask_separate(gl::FRONT, 0xFFFFFFFF);
|
||||
gl.stencil_mask_separate(gl::BACK, 0xFFFFFFFF);
|
||||
gl.clear_stencil(0);
|
||||
gl.clear(bits);
|
||||
|
||||
if state.scissor_test_enabled {
|
||||
gl.enable(gl::SCISSOR_TEST);
|
||||
}
|
||||
|
||||
if color {
|
||||
let (r, g, b, a) = state.clear_color;
|
||||
gl.clear_color(r, g, b, a);
|
||||
}
|
||||
|
||||
if depth {
|
||||
gl.depth_mask(state.depth_write_mask);
|
||||
gl.clear_depth(state.depth_clear_value);
|
||||
}
|
||||
|
||||
if stencil {
|
||||
let (front, back) = state.stencil_write_mask;
|
||||
gl.stencil_mask_separate(gl::FRONT, front);
|
||||
gl.stencil_mask_separate(gl::BACK, back);
|
||||
gl.clear_stencil(state.stencil_clear_value);
|
||||
}
|
||||
state.restore_invariant(gl);
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
|
@ -2213,6 +2347,7 @@ impl WebGLImpl {
|
|||
&mut transform_feedback_mode,
|
||||
);
|
||||
}
|
||||
|
||||
ProgramLinkInfo {
|
||||
linked: true,
|
||||
active_attribs,
|
||||
|
@ -2243,7 +2378,7 @@ impl WebGLImpl {
|
|||
// array object functions, but support a set of APPLE extension functions that
|
||||
// provide VAO support instead.
|
||||
fn needs_apple_vertex_arrays(gl_version: GLVersion) -> bool {
|
||||
cfg!(target_os = "macos") && !opts::get().headless && gl_version.major < 3
|
||||
cfg!(target_os = "macos") && gl_version.major < 3
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
|
@ -2427,8 +2562,8 @@ impl WebGLImpl {
|
|||
/// Updates the swap buffers if the context surface needs to be changed
|
||||
fn attach_surface(
|
||||
context_id: WebGLContextId,
|
||||
webrender_swap_chains: &SwapChains<WebGLContextId>,
|
||||
webxr_swap_chains: &SwapChains<WebXRSwapChainId>,
|
||||
webrender_swap_chains: &SwapChains<WebGLContextId, Device>,
|
||||
webxr_swap_chains: &SwapChains<WebXRSwapChainId, Device>,
|
||||
request: WebGLFramebufferBindingRequest,
|
||||
ctx: &mut Context,
|
||||
device: &mut Device,
|
||||
|
@ -2479,6 +2614,7 @@ impl WebGLImpl {
|
|||
request: WebGLFramebufferBindingRequest,
|
||||
ctx: &Context,
|
||||
device: &Device,
|
||||
state: &mut GLState,
|
||||
) {
|
||||
let id = match request {
|
||||
WebGLFramebufferBindingRequest::Explicit(WebGLFramebufferId::Transparent(id)) => {
|
||||
|
@ -2496,6 +2632,12 @@ impl WebGLImpl {
|
|||
|
||||
debug!("WebGLImpl::bind_framebuffer: {:?}", id);
|
||||
gl.bind_framebuffer(target, id);
|
||||
|
||||
if (target == gl::FRAMEBUFFER) || (target == gl::DRAW_FRAMEBUFFER) {
|
||||
state.drawing_to_default_framebuffer =
|
||||
request == WebGLFramebufferBindingRequest::Default;
|
||||
state.restore_invariant(gl);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -2885,27 +3027,41 @@ fn flip_pixels_y(
|
|||
|
||||
// Clamp a size to the current GL context's max viewport
|
||||
fn clamp_viewport(gl: &Gl, size: Size2D<u32>) -> Size2D<u32> {
|
||||
let mut max_size = [i32::max_value(), i32::max_value()];
|
||||
let mut max_viewport = [i32::max_value(), i32::max_value()];
|
||||
let mut max_renderbuffer = [i32::max_value()];
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
gl.get_integer_v(gl::MAX_VIEWPORT_DIMS, &mut max_size);
|
||||
gl.get_integer_v(gl::MAX_VIEWPORT_DIMS, &mut max_viewport);
|
||||
gl.get_integer_v(gl::MAX_RENDERBUFFER_SIZE, &mut max_renderbuffer);
|
||||
debug_assert_eq!(gl.get_error(), gl::NO_ERROR);
|
||||
}
|
||||
Size2D::new(
|
||||
size.width.min(max_size[0] as u32).max(1),
|
||||
size.height.min(max_size[1] as u32).max(1),
|
||||
size.width
|
||||
.min(max_viewport[0] as u32)
|
||||
.min(max_renderbuffer[0] as u32)
|
||||
.max(1),
|
||||
size.height
|
||||
.min(max_viewport[1] as u32)
|
||||
.min(max_renderbuffer[0] as u32)
|
||||
.max(1),
|
||||
)
|
||||
}
|
||||
|
||||
trait ToSurfmanVersion {
|
||||
fn to_surfman_version(self) -> GLVersion;
|
||||
fn to_surfman_version(self, api_type: gl::GlType) -> GLVersion;
|
||||
}
|
||||
|
||||
impl ToSurfmanVersion for WebGLVersion {
|
||||
fn to_surfman_version(self) -> GLVersion {
|
||||
fn to_surfman_version(self, api_type: gl::GlType) -> GLVersion {
|
||||
if api_type == gl::GlType::Gles {
|
||||
return GLVersion::new(3, 0);
|
||||
}
|
||||
match self {
|
||||
WebGLVersion::WebGL1 => GLVersion::new(2, 0),
|
||||
WebGLVersion::WebGL2 => GLVersion::new(3, 0),
|
||||
// We make use of GL_PACK_PIXEL_BUFFER, which needs at least GL2.1
|
||||
// We make use of compatibility mode, which needs at most GL3.0
|
||||
WebGLVersion::WebGL1 => GLVersion::new(2, 1),
|
||||
// The WebGL2 conformance tests use std140 layout, which needs at GL3.1
|
||||
WebGLVersion::WebGL2 => GLVersion::new(3, 2),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2914,6 +3070,7 @@ trait SurfmanContextAttributeFlagsConvert {
|
|||
fn to_surfman_context_attribute_flags(
|
||||
&self,
|
||||
webgl_version: WebGLVersion,
|
||||
api_type: gl::GlType,
|
||||
) -> ContextAttributeFlags;
|
||||
}
|
||||
|
||||
|
@ -2921,12 +3078,13 @@ impl SurfmanContextAttributeFlagsConvert for GLContextAttributes {
|
|||
fn to_surfman_context_attribute_flags(
|
||||
&self,
|
||||
webgl_version: WebGLVersion,
|
||||
api_type: gl::GlType,
|
||||
) -> ContextAttributeFlags {
|
||||
let mut flags = ContextAttributeFlags::empty();
|
||||
flags.set(ContextAttributeFlags::ALPHA, self.alpha);
|
||||
flags.set(ContextAttributeFlags::DEPTH, self.depth);
|
||||
flags.set(ContextAttributeFlags::STENCIL, self.stencil);
|
||||
if webgl_version == WebGLVersion::WebGL1 {
|
||||
if (webgl_version == WebGLVersion::WebGL1) && (api_type == gl::GlType::Gl) {
|
||||
flags.set(ContextAttributeFlags::COMPATIBILITY_PROFILE, true);
|
||||
}
|
||||
flags
|
||||
|
|
|
@ -667,7 +667,7 @@ pub enum WebGLFramebufferId {
|
|||
Opaque(WebGLOpaqueFramebufferId),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub enum WebGLFramebufferBindingRequest {
|
||||
Explicit(WebGLFramebufferId),
|
||||
Default,
|
||||
|
|
|
@ -40,6 +40,7 @@ style_traits = {path = "../style_traits"}
|
|||
time = "0.1.17"
|
||||
webrender = {git = "https://github.com/servo/webrender", features = ["capture"]}
|
||||
webrender_api = {git = "https://github.com/servo/webrender"}
|
||||
webrender_surfman = {path = "../webrender_surfman"}
|
||||
webxr = {git = "https://github.com/servo/webxr"}
|
||||
|
||||
[build-dependencies]
|
||||
|
|
|
@ -19,6 +19,7 @@ use gfx_traits::Epoch;
|
|||
use image::{DynamicImage, ImageFormat};
|
||||
use ipc_channel::ipc;
|
||||
use libc::c_void;
|
||||
use log::warn;
|
||||
use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId};
|
||||
use net_traits::image::base::Image;
|
||||
use net_traits::image_cache::CorsStatus;
|
||||
|
@ -46,6 +47,7 @@ use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor};
|
|||
use time::{now, precise_time_ns, precise_time_s};
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntSize, DevicePoint, LayoutVector2D};
|
||||
use webrender_api::{self, HitTestFlags, HitTestResult, ScrollLocation};
|
||||
use webrender_surfman::WebrenderSurfman;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum UnableToComposite {
|
||||
|
@ -178,6 +180,12 @@ pub struct IOCompositor<Window: WindowMethods + ?Sized> {
|
|||
/// The webrender interface, if enabled.
|
||||
webrender_api: webrender_api::RenderApi,
|
||||
|
||||
/// The surfman instance that webrender targets
|
||||
webrender_surfman: WebrenderSurfman,
|
||||
|
||||
/// The GL bindings for webrender
|
||||
webrender_gl: Rc<dyn gleam::gl::Gl>,
|
||||
|
||||
/// Some XR devices want to run on the main thread.
|
||||
pub webxr_main_thread: webxr::MainThreadRegistry,
|
||||
|
||||
|
@ -316,6 +324,8 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
webrender: state.webrender,
|
||||
webrender_document: state.webrender_document,
|
||||
webrender_api: state.webrender_api,
|
||||
webrender_surfman: state.webrender_surfman,
|
||||
webrender_gl: state.webrender_gl,
|
||||
webxr_main_thread: state.webxr_main_thread,
|
||||
pending_paint_metrics: HashMap::new(),
|
||||
cursor: Cursor::None,
|
||||
|
@ -345,6 +355,9 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
convert_mouse_to_touch,
|
||||
);
|
||||
|
||||
// Make sure the GL state is OK
|
||||
compositor.assert_gl_framebuffer_complete();
|
||||
|
||||
// Set the size of the root layer.
|
||||
compositor.update_zoom_transform();
|
||||
|
||||
|
@ -352,7 +365,9 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
}
|
||||
|
||||
pub fn deinit(self) {
|
||||
self.window.make_gl_context_current();
|
||||
if let Err(err) = self.webrender_surfman.make_gl_context_current() {
|
||||
warn!("Failed to make GL context current: {:?}", err);
|
||||
}
|
||||
self.webrender.deinit();
|
||||
}
|
||||
|
||||
|
@ -1238,7 +1253,22 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
) -> Result<Option<Image>, UnableToComposite> {
|
||||
let size = self.embedder_coordinates.framebuffer.to_u32();
|
||||
|
||||
self.window.make_gl_context_current();
|
||||
if let Err(err) = self.webrender_surfman.make_gl_context_current() {
|
||||
warn!("Failed to make GL context current: {:?}", err);
|
||||
}
|
||||
self.assert_no_gl_error();
|
||||
|
||||
// Bind the webrender framebuffer
|
||||
let framebuffer_object = self
|
||||
.webrender_surfman
|
||||
.context_surface_info()
|
||||
.unwrap_or(None)
|
||||
.map(|info| info.framebuffer_object)
|
||||
.unwrap_or(0);
|
||||
self.webrender_gl
|
||||
.bind_framebuffer(gleam::gl::FRAMEBUFFER, framebuffer_object);
|
||||
self.assert_gl_framebuffer_complete();
|
||||
|
||||
self.webrender.update();
|
||||
|
||||
let wait_for_stable_image = match target {
|
||||
|
@ -1266,7 +1296,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
CompositeTarget::Window => gl::RenderTargetInfo::default(),
|
||||
#[cfg(feature = "gl")]
|
||||
CompositeTarget::WindowAndPng | CompositeTarget::PngFile => gl::initialize_png(
|
||||
&*self.window.gl(),
|
||||
&*self.webrender_gl,
|
||||
FramebufferUintLength::new(size.width),
|
||||
FramebufferUintLength::new(size.height),
|
||||
),
|
||||
|
@ -1347,7 +1377,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
#[cfg(feature = "gl")]
|
||||
CompositeTarget::WindowAndPng => {
|
||||
let img = gl::draw_img(
|
||||
&*self.window.gl(),
|
||||
&*self.webrender_gl,
|
||||
rt_info,
|
||||
x,
|
||||
y,
|
||||
|
@ -1365,7 +1395,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
},
|
||||
#[cfg(feature = "gl")]
|
||||
CompositeTarget::PngFile => {
|
||||
let gl = &*self.window.gl();
|
||||
let gl = &*self.webrender_gl;
|
||||
profile(
|
||||
ProfilerCategory::ImageSaving,
|
||||
None,
|
||||
|
@ -1399,7 +1429,9 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
};
|
||||
|
||||
// Perform the page flip. This will likely block for a while.
|
||||
self.window.present();
|
||||
if let Err(err) = self.webrender_surfman.present() {
|
||||
warn!("Failed to present surface: {:?}", err);
|
||||
}
|
||||
|
||||
self.last_composite_time = precise_time_ns();
|
||||
|
||||
|
@ -1426,11 +1458,13 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
}
|
||||
|
||||
fn clear_background(&self) {
|
||||
let gl = self.window.gl();
|
||||
let gl = &self.webrender_gl;
|
||||
self.assert_gl_framebuffer_complete();
|
||||
|
||||
// Make framebuffer fully transparent.
|
||||
gl.clear_color(0.0, 0.0, 0.0, 0.0);
|
||||
gl.clear(gleam::gl::COLOR_BUFFER_BIT);
|
||||
self.assert_gl_framebuffer_complete();
|
||||
|
||||
// Make the viewport white.
|
||||
let viewport = self.embedder_coordinates.get_flipped_viewport();
|
||||
|
@ -1444,6 +1478,24 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
gl.enable(gleam::gl::SCISSOR_TEST);
|
||||
gl.clear(gleam::gl::COLOR_BUFFER_BIT);
|
||||
gl.disable(gleam::gl::SCISSOR_TEST);
|
||||
self.assert_gl_framebuffer_complete();
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_no_gl_error(&self) {
|
||||
debug_assert_eq!(self.webrender_gl.get_error(), gleam::gl::NO_ERROR);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_gl_framebuffer_complete(&self) {
|
||||
debug_assert_eq!(
|
||||
(
|
||||
self.webrender_gl.get_error(),
|
||||
self.webrender_gl
|
||||
.check_frame_buffer_status(gleam::gl::FRAMEBUFFER)
|
||||
),
|
||||
(gleam::gl::NO_ERROR, gleam::gl::FRAMEBUFFER_COMPLETE)
|
||||
);
|
||||
}
|
||||
|
||||
fn get_root_pipeline_id(&self) -> Option<PipelineId> {
|
||||
|
|
|
@ -17,12 +17,14 @@ use profile_traits::mem;
|
|||
use profile_traits::time;
|
||||
use script_traits::{AnimationState, EventResult, MouseButton, MouseEventType};
|
||||
use std::fmt::{Debug, Error, Formatter};
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
use style_traits::viewport::ViewportConstraints;
|
||||
use style_traits::CSSPixel;
|
||||
use webrender_api;
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntSize};
|
||||
use webrender_surfman::WebrenderSurfman;
|
||||
|
||||
/// Sends messages to the compositor.
|
||||
pub struct CompositorProxy {
|
||||
|
@ -166,6 +168,8 @@ pub struct InitialCompositorState {
|
|||
pub webrender: webrender::Renderer,
|
||||
pub webrender_document: webrender_api::DocumentId,
|
||||
pub webrender_api: webrender_api::RenderApi,
|
||||
pub webrender_surfman: WebrenderSurfman,
|
||||
pub webrender_gl: Rc<dyn gleam::gl::Gl>,
|
||||
pub webxr_main_thread: webxr::MainThreadRegistry,
|
||||
pub pending_wr_frame: Arc<AtomicBool>,
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![feature(track_caller)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
use canvas::{SurfaceProviders, WebGlExecutor};
|
||||
use embedder_traits::{EmbedderProxy, EventLoopWaker};
|
||||
use euclid::Scale;
|
||||
#[cfg(feature = "gl")]
|
||||
use gleam::gl;
|
||||
use keyboard_types::KeyboardEvent;
|
||||
use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId, TraversalDirection};
|
||||
use script_traits::{MediaSessionActionType, MouseButton, TouchEventType, TouchId, WheelDelta};
|
||||
|
@ -16,14 +14,13 @@ use servo_geometry::DeviceIndependentPixel;
|
|||
use servo_media::player::context::{GlApi, GlContext, NativeDisplay};
|
||||
use servo_url::ServoUrl;
|
||||
use std::fmt::{Debug, Error, Formatter};
|
||||
#[cfg(feature = "gl")]
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
use style_traits::DevicePixel;
|
||||
|
||||
use webrender_api::units::DevicePoint;
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
|
||||
use webrender_api::ScrollLocation;
|
||||
use webrender_surfman::WebrenderSurfman;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum MouseWindowEvent {
|
||||
|
@ -148,14 +145,10 @@ pub enum AnimationState {
|
|||
Animating,
|
||||
}
|
||||
|
||||
// TODO: this trait assumes that the window is responsible
|
||||
// for creating the GL context, making it current, buffer
|
||||
// swapping, etc. Really that should all be done by surfman.
|
||||
pub trait WindowMethods {
|
||||
/// Presents the window to the screen (perhaps by page flipping).
|
||||
fn present(&self);
|
||||
/// Make the OpenGL context current.
|
||||
fn make_gl_context_current(&self);
|
||||
/// Return the GL function pointer trait.
|
||||
#[cfg(feature = "gl")]
|
||||
fn gl(&self) -> Rc<dyn gl::Gl>;
|
||||
/// Get the coordinates of the native window, the screen and the framebuffer.
|
||||
fn get_coordinates(&self) -> EmbedderCoordinates;
|
||||
/// Set whether the application is currently animating.
|
||||
|
@ -163,12 +156,14 @@ pub trait WindowMethods {
|
|||
/// will want to avoid blocking on UI events, and just
|
||||
/// run the event loop at the vsync interval.
|
||||
fn set_animation_state(&self, _state: AnimationState);
|
||||
/// Get the GL context
|
||||
/// Get the media GL context
|
||||
fn get_gl_context(&self) -> GlContext;
|
||||
/// Get the native display
|
||||
/// Get the media native display
|
||||
fn get_native_display(&self) -> NativeDisplay;
|
||||
/// Get the GL api
|
||||
fn get_gl_api(&self) -> GlApi;
|
||||
/// Get the webrender surfman instance
|
||||
fn webrender_surfman(&self) -> WebrenderSurfman;
|
||||
}
|
||||
|
||||
pub trait EmbedderMethods {
|
||||
|
|
|
@ -321,7 +321,11 @@ mod gen {
|
|||
subpixel_text_antialiasing: {
|
||||
#[serde(rename = "gfx.subpixel-text-antialiasing.enabled")]
|
||||
enabled: bool,
|
||||
}
|
||||
},
|
||||
texture_swizzling: {
|
||||
#[serde(rename = "gfx.texture-swizzling.enabled")]
|
||||
enabled: bool,
|
||||
},
|
||||
},
|
||||
js: {
|
||||
asmjs: {
|
||||
|
|
|
@ -52,12 +52,24 @@ const DEFAULT_DISABLED_GET_PARAMETER_NAMES_WEBGL1: [GLenum; 3] = [
|
|||
OESVertexArrayObjectConstants::VERTEX_ARRAY_BINDING_OES,
|
||||
];
|
||||
|
||||
// Param names that are implemented for glGetParameter in a WebGL 2.0 context
|
||||
// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
|
||||
// Example: https://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/
|
||||
const DEFAULT_DISABLED_GET_PARAMETER_NAMES_WEBGL2: [GLenum; 1] =
|
||||
[EXTTextureFilterAnisotropicConstants::MAX_TEXTURE_MAX_ANISOTROPY_EXT];
|
||||
|
||||
// Param names that are implemented for glGetTexParameter in a WebGL 1.0 context
|
||||
// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
|
||||
// Example: https://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/
|
||||
const DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL1: [GLenum; 1] =
|
||||
[EXTTextureFilterAnisotropicConstants::TEXTURE_MAX_ANISOTROPY_EXT];
|
||||
|
||||
// Param names that are implemented for glGetTexParameter in a WebGL 2.0 context
|
||||
// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
|
||||
// Example: https://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/
|
||||
const DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL2: [GLenum; 1] =
|
||||
[EXTTextureFilterAnisotropicConstants::TEXTURE_MAX_ANISOTROPY_EXT];
|
||||
|
||||
// Param names that are implemented for glGetVertexAttrib in a WebGL 1.0 context
|
||||
// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
|
||||
// Example: https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
|
||||
|
@ -116,8 +128,14 @@ impl WebGLExtensionFeatures {
|
|||
),
|
||||
WebGLVersion::WebGL2 => (
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
DEFAULT_DISABLED_GET_PARAMETER_NAMES_WEBGL2
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
DEFAULT_DISABLED_GET_TEX_PARAMETER_NAMES_WEBGL2
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
Default::default(),
|
||||
true,
|
||||
true,
|
||||
|
|
|
@ -233,7 +233,7 @@ impl WebGLRenderbuffer {
|
|||
),
|
||||
);
|
||||
let samples = receiver.recv().unwrap();
|
||||
if sample_count < 0 || sample_count as usize > samples.len() {
|
||||
if sample_count < 0 || sample_count > samples.get(0).cloned().unwrap_or(0) {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -277,8 +277,49 @@ impl WebGLShader {
|
|||
},
|
||||
};
|
||||
|
||||
match validator.compile_and_translate(&[&source]) {
|
||||
Ok(translated_source) => {
|
||||
// Replicating
|
||||
// https://searchfox.org/mozilla-central/rev/c621276fbdd9591f52009042d959b9e19b66d49f/dom/canvas/WebGLShaderValidator.cpp#32
|
||||
let options = mozangle::shaders::ffi::SH_VARIABLES |
|
||||
mozangle::shaders::ffi::SH_ENFORCE_PACKING_RESTRICTIONS |
|
||||
mozangle::shaders::ffi::SH_OBJECT_CODE |
|
||||
mozangle::shaders::ffi::SH_INIT_GL_POSITION |
|
||||
mozangle::shaders::ffi::SH_INITIALIZE_UNINITIALIZED_LOCALS |
|
||||
mozangle::shaders::ffi::SH_INIT_OUTPUT_VARIABLES |
|
||||
mozangle::shaders::ffi::SH_LIMIT_EXPRESSION_COMPLEXITY |
|
||||
mozangle::shaders::ffi::SH_LIMIT_CALL_STACK_DEPTH |
|
||||
if cfg!(target_os = "macos") {
|
||||
// Work around https://bugs.webkit.org/show_bug.cgi?id=124684,
|
||||
// https://chromium.googlesource.com/angle/angle/+/5e70cf9d0b1bb
|
||||
mozangle::shaders::ffi::SH_UNFOLD_SHORT_CIRCUIT |
|
||||
// Work around that Mac drivers handle struct scopes incorrectly.
|
||||
mozangle::shaders::ffi::SH_REGENERATE_STRUCT_NAMES |
|
||||
// Work around that Intel drivers on Mac OSX handle for-loop incorrectly.
|
||||
mozangle::shaders::ffi::SH_ADD_AND_TRUE_TO_LOOP_CONDITION
|
||||
} else {
|
||||
// We want to do this everywhere, but to do this on Mac, we need
|
||||
// to do it only on Mac OSX > 10.6 as this causes the shader
|
||||
// compiler in 10.6 to crash
|
||||
mozangle::shaders::ffi::SH_CLAMP_INDIRECT_ARRAY_BOUNDS
|
||||
};
|
||||
|
||||
// Replicating
|
||||
// https://github.com/servo/mozangle/blob/706a9baaf8026c1a3cb6c67ba63aa5f4734264d0/src/shaders/mod.rs#L226
|
||||
let options = options |
|
||||
mozangle::shaders::ffi::SH_VALIDATE |
|
||||
mozangle::shaders::ffi::SH_OBJECT_CODE |
|
||||
mozangle::shaders::ffi::SH_VARIABLES | // For uniform_name_map()
|
||||
mozangle::shaders::ffi::SH_EMULATE_ABS_INT_FUNCTION | // To workaround drivers
|
||||
mozangle::shaders::ffi::SH_EMULATE_ISNAN_FLOAT_FUNCTION | // To workaround drivers
|
||||
mozangle::shaders::ffi::SH_EMULATE_ATAN2_FLOAT_FUNCTION | // To workaround drivers
|
||||
mozangle::shaders::ffi::SH_CLAMP_INDIRECT_ARRAY_BOUNDS |
|
||||
mozangle::shaders::ffi::SH_INIT_GL_POSITION |
|
||||
mozangle::shaders::ffi::SH_ENFORCE_PACKING_RESTRICTIONS |
|
||||
mozangle::shaders::ffi::SH_LIMIT_EXPRESSION_COMPLEXITY |
|
||||
mozangle::shaders::ffi::SH_LIMIT_CALL_STACK_DEPTH;
|
||||
|
||||
match validator.compile(&[&source], options) {
|
||||
Ok(()) => {
|
||||
let translated_source = validator.object_code();
|
||||
debug!("Shader translated: {}", translated_source);
|
||||
// NOTE: At this point we should be pretty sure that the compilation in the paint thread
|
||||
// will succeed.
|
||||
|
|
|
@ -81,11 +81,12 @@ style_traits = {path = "../style_traits", features = ["servo"]}
|
|||
webgpu = {path = "../webgpu"}
|
||||
webrender = {git = "https://github.com/servo/webrender"}
|
||||
webrender_api = {git = "https://github.com/servo/webrender"}
|
||||
webrender_surfman = {path = "../webrender_surfman"}
|
||||
webrender_traits = {path = "../webrender_traits"}
|
||||
webdriver_server = {path = "../webdriver_server", optional = true}
|
||||
webxr-api = {git = "https://github.com/servo/webxr"}
|
||||
webxr = {git = "https://github.com/servo/webxr"}
|
||||
surfman = { version = "0.1", features = ["sm-osmesa"] }
|
||||
surfman = "0.2"
|
||||
gstreamer = { version = "0.15", optional = true }
|
||||
|
||||
[target.'cfg(all(not(target_os = "windows"), not(target_os = "ios"), not(target_os="android"), not(target_arch="arm"), not(target_arch="aarch64")))'.dependencies]
|
||||
|
|
|
@ -51,6 +51,7 @@ pub use style;
|
|||
pub use style_traits;
|
||||
pub use webgpu;
|
||||
pub use webrender_api;
|
||||
pub use webrender_surfman;
|
||||
pub use webrender_traits;
|
||||
|
||||
#[cfg(feature = "webdriver")]
|
||||
|
@ -116,14 +117,9 @@ use std::path::PathBuf;
|
|||
use std::rc::Rc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, Mutex};
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
use surfman::platform::default::device::Device as HWDevice;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
use surfman::platform::generic::osmesa::device::Device as SWDevice;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
use surfman::platform::generic::universal::context::Context;
|
||||
use surfman::platform::generic::universal::device::Device;
|
||||
use surfman::GLApi;
|
||||
use webrender::{RendererKind, ShaderPrecacheFlags};
|
||||
use webrender_surfman::WebrenderSurfman;
|
||||
use webrender_traits::WebrenderImageHandlerType;
|
||||
use webrender_traits::{WebrenderExternalImageHandlers, WebrenderExternalImageRegistry};
|
||||
|
||||
|
@ -353,8 +349,28 @@ where
|
|||
.unwrap_or(default_user_agent_string_for(DEFAULT_USER_AGENT).into()),
|
||||
};
|
||||
|
||||
// Initialize surfman
|
||||
let webrender_surfman = window.webrender_surfman();
|
||||
|
||||
// Get GL bindings
|
||||
let webrender_gl = match webrender_surfman.connection().gl_api() {
|
||||
GLApi::GL => unsafe { gl::GlFns::load_with(|s| webrender_surfman.get_proc_address(s)) },
|
||||
GLApi::GLES => unsafe {
|
||||
gl::GlesFns::load_with(|s| webrender_surfman.get_proc_address(s))
|
||||
},
|
||||
};
|
||||
|
||||
// Make sure the gl context is made current.
|
||||
window.make_gl_context_current();
|
||||
webrender_surfman.make_gl_context_current().unwrap();
|
||||
debug_assert_eq!(webrender_gl.get_error(), gleam::gl::NO_ERROR,);
|
||||
|
||||
// Bind the webrender framebuffer
|
||||
let framebuffer_object = webrender_surfman
|
||||
.context_surface_info()
|
||||
.unwrap_or(None)
|
||||
.map(|info| info.framebuffer_object)
|
||||
.unwrap_or(0);
|
||||
webrender_gl.bind_framebuffer(gleam::gl::FRAMEBUFFER, framebuffer_object);
|
||||
|
||||
// Reserving a namespace to create TopLevelBrowserContextId.
|
||||
PipelineNamespace::install(PipelineNamespaceId(0));
|
||||
|
@ -407,7 +423,7 @@ where
|
|||
let window_size = Size2D::from_untyped(viewport_size.to_i32().to_untyped());
|
||||
|
||||
webrender::Renderer::new(
|
||||
window.gl(),
|
||||
webrender_gl.clone(),
|
||||
render_notifier,
|
||||
webrender::RendererOptions {
|
||||
device_pixel_ratio,
|
||||
|
@ -422,6 +438,7 @@ where
|
|||
},
|
||||
renderer_kind: renderer_kind,
|
||||
enable_subpixel_aa: opts.enable_subpixel_text_antialiasing,
|
||||
allow_texture_swizzling: pref!(gfx.texture_swizzling.enabled),
|
||||
clear_color: None,
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -451,7 +468,8 @@ where
|
|||
.expect("Failed to create WebXR device registry");
|
||||
|
||||
let (webgl_threads, webgl_extras) = create_webgl_threads(
|
||||
&*window,
|
||||
webrender_surfman.clone(),
|
||||
webrender_gl.clone(),
|
||||
&mut webrender,
|
||||
webrender_api_sender.clone(),
|
||||
&mut webxr_main_thread,
|
||||
|
@ -542,6 +560,8 @@ where
|
|||
webrender,
|
||||
webrender_document,
|
||||
webrender_api,
|
||||
webrender_surfman,
|
||||
webrender_gl,
|
||||
webxr_main_thread,
|
||||
pending_wr_frame,
|
||||
},
|
||||
|
@ -806,6 +826,10 @@ where
|
|||
log::set_max_level(filter);
|
||||
}
|
||||
|
||||
pub fn window(&self) -> &Window {
|
||||
&self.compositor.window
|
||||
}
|
||||
|
||||
pub fn deinit(self) {
|
||||
self.compositor.deinit();
|
||||
}
|
||||
|
@ -1030,8 +1054,9 @@ fn create_sandbox() {
|
|||
}
|
||||
|
||||
// Initializes the WebGL thread.
|
||||
fn create_webgl_threads<W>(
|
||||
window: &W,
|
||||
fn create_webgl_threads(
|
||||
webrender_surfman: WebrenderSurfman,
|
||||
webrender_gl: Rc<dyn gl::Gl>,
|
||||
webrender: &mut webrender::Renderer,
|
||||
webrender_api_sender: webrender_api::RenderApiSender,
|
||||
webxr_main_thread: &mut webxr::MainThreadRegistry,
|
||||
|
@ -1040,45 +1065,8 @@ fn create_webgl_threads<W>(
|
|||
) -> (
|
||||
Option<WebGLThreads>,
|
||||
Option<(SurfaceProviders, WebGlExecutor)>,
|
||||
)
|
||||
where
|
||||
W: WindowMethods + 'static + ?Sized,
|
||||
{
|
||||
// Create a `surfman` device and context.
|
||||
window.make_gl_context_current();
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let (device, context) = unsafe {
|
||||
if opts::get().headless {
|
||||
let (device, context) = match SWDevice::from_current_context() {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
warn!("Failed to create software graphics context: {:?}", e);
|
||||
return (None, None);
|
||||
},
|
||||
};
|
||||
(Device::Software(device), Context::Software(context))
|
||||
} else {
|
||||
let (device, context) = match HWDevice::from_current_context() {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
warn!("Failed to create hardware graphics context: {:?}", e);
|
||||
return (None, None);
|
||||
},
|
||||
};
|
||||
(Device::Hardware(device), Context::Hardware(context))
|
||||
}
|
||||
};
|
||||
#[cfg(target_os = "windows")]
|
||||
let (device, context) = match unsafe { Device::from_current_context() } {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
warn!("Failed to create graphics context: {:?}", e);
|
||||
return (None, None);
|
||||
},
|
||||
};
|
||||
|
||||
let gl_type = match window.gl().get_type() {
|
||||
) {
|
||||
let gl_type = match webrender_gl.get_type() {
|
||||
gleam::gl::GlType::Gl => sparkle::gl::GlType::Gl,
|
||||
gleam::gl::GlType::Gles => sparkle::gl::GlType::Gles,
|
||||
};
|
||||
|
@ -1091,9 +1079,8 @@ where
|
|||
output_handler,
|
||||
webgl_executor,
|
||||
} = WebGLComm::new(
|
||||
device,
|
||||
context,
|
||||
window.gl(),
|
||||
webrender_surfman,
|
||||
webrender_gl,
|
||||
webrender_api_sender,
|
||||
external_images,
|
||||
gl_type,
|
||||
|
|
17
components/webrender_surfman/Cargo.toml
Normal file
17
components/webrender_surfman/Cargo.toml
Normal file
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "webrender_surfman"
|
||||
version = "0.0.1"
|
||||
authors = ["The Servo Project Developers"]
|
||||
license = "MPL-2.0"
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "webrender_surfman"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
euclid = "0.20"
|
||||
surfman = "0.2"
|
||||
surfman-chains = "0.3"
|
||||
|
213
components/webrender_surfman/lib.rs
Normal file
213
components/webrender_surfman/lib.rs
Normal file
|
@ -0,0 +1,213 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
use euclid::default::Size2D;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::c_void;
|
||||
use std::rc::Rc;
|
||||
use surfman::Adapter;
|
||||
use surfman::Connection;
|
||||
use surfman::Context;
|
||||
use surfman::ContextAttributeFlags;
|
||||
use surfman::ContextAttributes;
|
||||
use surfman::Device;
|
||||
use surfman::Error;
|
||||
use surfman::GLApi;
|
||||
use surfman::GLVersion;
|
||||
use surfman::NativeContext;
|
||||
use surfman::NativeDevice;
|
||||
use surfman::NativeWidget;
|
||||
use surfman::Surface;
|
||||
use surfman::SurfaceAccess;
|
||||
use surfman::SurfaceInfo;
|
||||
use surfman::SurfaceTexture;
|
||||
use surfman::SurfaceType;
|
||||
use surfman_chains::SurfmanProvider;
|
||||
use surfman_chains::SwapChain;
|
||||
|
||||
/// A bridge between webrender and surfman
|
||||
// TODO: move this into a different crate so that script doesn't depend on surfman
|
||||
#[derive(Clone)]
|
||||
pub struct WebrenderSurfman(Rc<WebrenderSurfmanData>);
|
||||
|
||||
struct WebrenderSurfmanData {
|
||||
device: RefCell<Device>,
|
||||
context: RefCell<Context>,
|
||||
// We either render to a swap buffer or to a native widget
|
||||
swap_chain: Option<SwapChain<Device>>,
|
||||
}
|
||||
|
||||
impl Drop for WebrenderSurfmanData {
|
||||
fn drop(&mut self) {
|
||||
let ref mut device = self.device.borrow_mut();
|
||||
let ref mut context = self.context.borrow_mut();
|
||||
if let Some(ref swap_chain) = self.swap_chain {
|
||||
let _ = swap_chain.destroy(device, context);
|
||||
}
|
||||
let _ = device.destroy_context(context);
|
||||
}
|
||||
}
|
||||
|
||||
impl WebrenderSurfman {
|
||||
pub fn create(
|
||||
connection: &Connection,
|
||||
adapter: &Adapter,
|
||||
surface_type: SurfaceType<NativeWidget>,
|
||||
) -> Result<Self, Error> {
|
||||
let mut device = connection.create_device(&adapter)?;
|
||||
let flags = ContextAttributeFlags::ALPHA |
|
||||
ContextAttributeFlags::DEPTH |
|
||||
ContextAttributeFlags::STENCIL;
|
||||
let version = match connection.gl_api() {
|
||||
GLApi::GLES => GLVersion { major: 3, minor: 0 },
|
||||
GLApi::GL => GLVersion { major: 3, minor: 2 },
|
||||
};
|
||||
let context_attributes = ContextAttributes { flags, version };
|
||||
let context_descriptor = device.create_context_descriptor(&context_attributes)?;
|
||||
let mut context = device.create_context(&context_descriptor)?;
|
||||
let surface_access = SurfaceAccess::GPUOnly;
|
||||
let headless = match surface_type {
|
||||
SurfaceType::Widget { .. } => false,
|
||||
SurfaceType::Generic { .. } => true,
|
||||
};
|
||||
let surface = device.create_surface(&context, surface_access, surface_type)?;
|
||||
device
|
||||
.bind_surface_to_context(&mut context, surface)
|
||||
.map_err(|(err, mut surface)| {
|
||||
let _ = device.destroy_surface(&mut context, &mut surface);
|
||||
err
|
||||
})?;
|
||||
let swap_chain = if headless {
|
||||
let surface_provider = Box::new(SurfmanProvider::new(surface_access));
|
||||
Some(SwapChain::create_attached(
|
||||
&mut device,
|
||||
&mut context,
|
||||
surface_provider,
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let device = RefCell::new(device);
|
||||
let context = RefCell::new(context);
|
||||
let data = WebrenderSurfmanData {
|
||||
device,
|
||||
context,
|
||||
swap_chain,
|
||||
};
|
||||
Ok(WebrenderSurfman(Rc::new(data)))
|
||||
}
|
||||
|
||||
pub fn create_surface_texture(
|
||||
&self,
|
||||
surface: Surface,
|
||||
) -> Result<SurfaceTexture, (Error, Surface)> {
|
||||
let ref device = self.0.device.borrow();
|
||||
let ref mut context = self.0.context.borrow_mut();
|
||||
device.create_surface_texture(context, surface)
|
||||
}
|
||||
|
||||
pub fn destroy_surface_texture(
|
||||
&self,
|
||||
surface_texture: SurfaceTexture,
|
||||
) -> Result<Surface, (Error, SurfaceTexture)> {
|
||||
let ref device = self.0.device.borrow();
|
||||
let ref mut context = self.0.context.borrow_mut();
|
||||
device.destroy_surface_texture(context, surface_texture)
|
||||
}
|
||||
|
||||
pub fn make_gl_context_current(&self) -> Result<(), Error> {
|
||||
let ref device = self.0.device.borrow();
|
||||
let ref context = self.0.context.borrow();
|
||||
device.make_context_current(context)
|
||||
}
|
||||
|
||||
pub fn swap_chain(&self) -> Result<&SwapChain<Device>, Error> {
|
||||
self.0.swap_chain.as_ref().ok_or(Error::WidgetAttached)
|
||||
}
|
||||
|
||||
pub fn resize(&self, size: Size2D<i32>) -> Result<(), Error> {
|
||||
let ref mut device = self.0.device.borrow_mut();
|
||||
let ref mut context = self.0.context.borrow_mut();
|
||||
if let Some(swap_chain) = self.0.swap_chain.as_ref() {
|
||||
return swap_chain.resize(device, context, size);
|
||||
}
|
||||
let mut surface = device.unbind_surface_from_context(context)?.unwrap();
|
||||
device.resize_surface(context, &mut surface, size)?;
|
||||
device
|
||||
.bind_surface_to_context(context, surface)
|
||||
.map_err(|(err, mut surface)| {
|
||||
let _ = device.destroy_surface(context, &mut surface);
|
||||
err
|
||||
})
|
||||
}
|
||||
|
||||
pub fn present(&self) -> Result<(), Error> {
|
||||
let ref mut device = self.0.device.borrow_mut();
|
||||
let ref mut context = self.0.context.borrow_mut();
|
||||
if let Some(ref swap_chain) = self.0.swap_chain {
|
||||
return swap_chain.swap_buffers(device, context);
|
||||
}
|
||||
let mut surface = device.unbind_surface_from_context(context)?.unwrap();
|
||||
device.present_surface(context, &mut surface)?;
|
||||
device
|
||||
.bind_surface_to_context(context, surface)
|
||||
.map_err(|(err, mut surface)| {
|
||||
let _ = device.destroy_surface(context, &mut surface);
|
||||
err
|
||||
})
|
||||
}
|
||||
|
||||
pub fn connection(&self) -> Connection {
|
||||
let ref device = self.0.device.borrow();
|
||||
device.connection()
|
||||
}
|
||||
|
||||
pub fn adapter(&self) -> Adapter {
|
||||
let ref device = self.0.device.borrow();
|
||||
device.adapter()
|
||||
}
|
||||
|
||||
pub fn native_context(&self) -> NativeContext {
|
||||
let ref device = self.0.device.borrow();
|
||||
let ref context = self.0.context.borrow();
|
||||
device.native_context(context)
|
||||
}
|
||||
|
||||
pub fn native_device(&self) -> NativeDevice {
|
||||
let ref device = self.0.device.borrow();
|
||||
device.native_device()
|
||||
}
|
||||
|
||||
pub fn context_attributes(&self) -> ContextAttributes {
|
||||
let ref device = self.0.device.borrow();
|
||||
let ref context = self.0.context.borrow();
|
||||
let ref descriptor = device.context_descriptor(context);
|
||||
device.context_descriptor_attributes(descriptor)
|
||||
}
|
||||
|
||||
pub fn context_surface_info(&self) -> Result<Option<SurfaceInfo>, Error> {
|
||||
let ref device = self.0.device.borrow();
|
||||
let ref context = self.0.context.borrow();
|
||||
device.context_surface_info(context)
|
||||
}
|
||||
|
||||
pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo {
|
||||
let ref device = self.0.device.borrow();
|
||||
device.surface_info(surface)
|
||||
}
|
||||
|
||||
pub fn surface_texture_object(&self, surface: &SurfaceTexture) -> u32 {
|
||||
let ref device = self.0.device.borrow();
|
||||
device.surface_texture_object(surface)
|
||||
}
|
||||
|
||||
pub fn get_proc_address(&self, name: &str) -> *const c_void {
|
||||
let ref device = self.0.device.borrow();
|
||||
let ref context = self.0.context.borrow();
|
||||
device.get_proc_address(context, name)
|
||||
}
|
||||
}
|
|
@ -12,5 +12,6 @@ path = "lib.rs"
|
|||
|
||||
[dependencies]
|
||||
euclid = "0.20"
|
||||
servo_geometry = {path = "../geometry"}
|
||||
webrender_api = {git = "https://github.com/servo/webrender"}
|
||||
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
#![deny(unsafe_code)]
|
||||
|
||||
use euclid::default::Size2D;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use webrender_api::units::TexelRect;
|
||||
|
||||
/// This trait is used as a bridge between the different GL clients
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue