mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00: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
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue