Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial implementation of WebGLSync #24250

Merged
merged 1 commit into from Oct 2, 2019
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Initial implementation of WebGLSync

This patch adds initial support for WebGLSync.

Note:
There is no test for the isSync, deleteSync and waitSync functions in the `conformance2/sync/sync-webgl-specific.html`.
  • Loading branch information
imiklos committed Oct 2, 2019
commit 248545ddda503e06bc59b5274c63a6c25da4b355
@@ -238,6 +238,7 @@ fn map_limits(limits: RawGLLimits) -> GLLimits {
max_varying_vectors: limits.max_varying_vectors,
max_vertex_texture_image_units: limits.max_vertex_texture_image_units,
max_vertex_uniform_vectors: limits.max_vertex_uniform_vectors,
max_client_wait_timeout_webgl: std::time::Duration::new(1, 0),
}
}

@@ -1360,6 +1360,33 @@ impl WebGLImpl {
}
sender.send(value[0] != 0).unwrap()
},
WebGLCommand::FenceSync(ref sender) => {
let value = ctx.gl().fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0);
sender
.send(unsafe { WebGLSyncId::new(value as u64) })
.unwrap();
},
WebGLCommand::IsSync(sync_id, ref sender) => {
let value = ctx.gl().is_sync(sync_id.get() as *const _);
sender.send(value).unwrap();
},
WebGLCommand::ClientWaitSync(sync_id, flags, timeout, ref sender) => {
let value =
ctx.gl()
.client_wait_sync(sync_id.get() as *const _, flags, timeout as u64);
sender.send(value).unwrap();
},
WebGLCommand::WaitSync(sync_id, flags, timeout) => {
ctx.gl()
.wait_sync(sync_id.get() as *const _, flags, timeout as u64);
},
WebGLCommand::GetSyncParameter(sync_id, param, ref sender) => {
let value = ctx.gl().get_sync_iv(sync_id.get() as *const _, param);
sender.send(value[0] as u32).unwrap();
},
WebGLCommand::DeleteSync(sync_id) => {
ctx.gl().delete_sync(sync_id.get() as *const _);
},
WebGLCommand::GetParameterBool4(param, ref sender) => {
let mut value = [0; 4];
unsafe {
@@ -9,7 +9,7 @@ use sparkle::gl;
use sparkle::gl::Gl;
use std::borrow::Cow;
use std::fmt;
use std::num::NonZeroU32;
use std::num::{NonZeroU32, NonZeroU64};
use std::ops::Deref;
use webrender_api::{DocumentId, ImageKey, PipelineId};
use webvr_traits::WebVRPoseInformation;
@@ -280,6 +280,12 @@ pub enum WebGLCommand {
StencilMaskSeparate(u32, u32),
StencilOp(u32, u32, u32),
StencilOpSeparate(u32, u32, u32, u32),
FenceSync(WebGLSender<WebGLSyncId>),
IsSync(WebGLSyncId, WebGLSender<bool>),
ClientWaitSync(WebGLSyncId, u32, u64, WebGLSender<u32>),
WaitSync(WebGLSyncId, u32, i64),
GetSyncParameter(WebGLSyncId, u32, WebGLSender<u32>),
DeleteSync(WebGLSyncId),
Hint(u32, u32),
LineWidth(f32),
PixelStorei(u32, i32),
@@ -434,20 +440,29 @@ pub enum WebGLCommand {
GetQueryState(WebGLSender<u32>, WebGLQueryId, u32),
}

macro_rules! nonzero_type {
(u32) => {
NonZeroU32
};
(u64) => {
NonZeroU64
};
}

macro_rules! define_resource_id {
($name:ident) => {
($name:ident, $type:tt) => {
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct $name(NonZeroU32);
pub struct $name(nonzero_type!($type));

impl $name {
#[allow(unsafe_code)]
#[inline]
pub unsafe fn new(id: u32) -> Self {
$name(NonZeroU32::new_unchecked(id))
pub unsafe fn new(id: $type) -> Self {
$name(<nonzero_type!($type)>::new_unchecked(id))
}

#[inline]
pub fn get(self) -> u32 {
pub fn get(self) -> $type {
self.0.get()
}
}
@@ -458,7 +473,7 @@ macro_rules! define_resource_id {
where
D: ::serde::Deserializer<'de>,
{
let id = u32::deserialize(deserializer)?;
let id = <$type>::deserialize(deserializer)?;
if id == 0 {
Err(::serde::de::Error::custom("expected a non-zero value"))
} else {
@@ -498,14 +513,15 @@ macro_rules! define_resource_id {
};
}

define_resource_id!(WebGLBufferId);
define_resource_id!(WebGLFramebufferId);
define_resource_id!(WebGLRenderbufferId);
define_resource_id!(WebGLTextureId);
define_resource_id!(WebGLProgramId);
define_resource_id!(WebGLQueryId);
define_resource_id!(WebGLShaderId);
define_resource_id!(WebGLVertexArrayId);
define_resource_id!(WebGLBufferId, u32);
define_resource_id!(WebGLFramebufferId, u32);
define_resource_id!(WebGLRenderbufferId, u32);
define_resource_id!(WebGLTextureId, u32);
define_resource_id!(WebGLProgramId, u32);
define_resource_id!(WebGLQueryId, u32);
define_resource_id!(WebGLShaderId, u32);
define_resource_id!(WebGLSyncId, u64);
define_resource_id!(WebGLVertexArrayId, u32);

#[derive(
Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize,
@@ -893,6 +909,7 @@ pub struct GLLimits {
pub max_varying_vectors: u32,
pub max_vertex_texture_image_units: u32,
pub max_vertex_uniform_vectors: u32,
pub max_client_wait_timeout_webgl: std::time::Duration,
}

#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
@@ -45,12 +45,13 @@ use canvas_traits::canvas::{
CanvasGradientStop, CanvasId, LinearGradientStyle, RadialGradientStyle,
};
use canvas_traits::canvas::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle};
use canvas_traits::webgl::WebGLVertexArrayId;
use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, GlType, TexDataType, TexFormat};
use canvas_traits::webgl::{GLFormats, GLLimits, WebGLQueryId};
use canvas_traits::webgl::{WebGLBufferId, WebGLChan, WebGLContextShareMode, WebGLError};
use canvas_traits::webgl::{WebGLFramebufferId, WebGLMsgSender, WebGLPipeline, WebGLProgramId};
use canvas_traits::webgl::{WebGLReceiver, WebGLRenderbufferId, WebGLSLVersion, WebGLSender};
use canvas_traits::webgl::{WebGLShaderId, WebGLTextureId, WebGLVersion, WebGLVertexArrayId};
use canvas_traits::webgl::{WebGLShaderId, WebGLSyncId, WebGLTextureId, WebGLVersion};
use crossbeam_channel::{Receiver, Sender};
use cssparser::RGBA;
use devtools_traits::{CSSError, TimelineMarkerType, WorkerId};
@@ -480,6 +481,7 @@ unsafe_no_jsmanaged_fields!(WebGLProgramId);
unsafe_no_jsmanaged_fields!(WebGLQueryId);
unsafe_no_jsmanaged_fields!(WebGLRenderbufferId);
unsafe_no_jsmanaged_fields!(WebGLShaderId);
unsafe_no_jsmanaged_fields!(WebGLSyncId);
unsafe_no_jsmanaged_fields!(WebGLTextureId);
unsafe_no_jsmanaged_fields!(WebGLVertexArrayId);
unsafe_no_jsmanaged_fields!(WebGLVersion);
@@ -527,6 +527,7 @@ pub mod webglrenderbuffer;
pub mod webglrenderingcontext;
pub mod webglshader;
pub mod webglshaderprecisionformat;
pub mod webglsync;
pub mod webgltexture;
pub mod webgluniformlocation;
pub mod webglvertexarrayobjectoes;
@@ -28,17 +28,18 @@ use crate::dom::webglrenderingcontext::{
};
use crate::dom::webglshader::WebGLShader;
use crate::dom::webglshaderprecisionformat::WebGLShaderPrecisionFormat;
use crate::dom::webglsync::WebGLSync;
use crate::dom::webgltexture::WebGLTexture;
use crate::dom::webgluniformlocation::WebGLUniformLocation;
use crate::dom::window::Window;
use crate::script_runtime::JSContext;
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/webgl.idl
use canvas_traits::webgl::WebGLError::*;
use canvas_traits::webgl::{GLContextAttributes, WebGLVersion};
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/webgl.idl
use canvas_traits::webgl::{webgl_channel, GLContextAttributes, WebGLCommand, WebGLVersion};
use dom_struct::dom_struct;
use euclid::default::Size2D;
use js::jsapi::JSObject;
use js::jsval::{BooleanValue, JSVal, NullValue, UInt32Value};
use js::jsval::{BooleanValue, Int32Value, JSVal, NullValue, UInt32Value};
use js::rust::CustomAutoRooterGuard;
use js::typedarray::ArrayBufferView;
use script_layout_interface::HTMLCanvasDataSource;
@@ -125,7 +126,12 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
#[allow(unsafe_code)]
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
fn GetParameter(&self, cx: JSContext, parameter: u32) -> JSVal {
self.base.GetParameter(cx, parameter)
match parameter {
constants::MAX_CLIENT_WAIT_TIMEOUT_WEBGL => {
Int32Value(self.base.limits().max_client_wait_timeout_webgl.as_nanos() as i32)
},
_ => self.base.GetParameter(cx, parameter),
}
}

/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
@@ -1197,6 +1203,124 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
},
}
}

/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14
fn FenceSync(&self, condition: u32, flags: u32) -> Option<DomRoot<WebGLSync>> {
if flags != 0 {
self.base.webgl_error(InvalidValue);
return None;
}
if condition != constants::SYNC_GPU_COMMANDS_COMPLETE {
self.base.webgl_error(InvalidEnum);
return None;
}

Some(WebGLSync::new(&self.base))
}

/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14
fn IsSync(&self, sync: Option<&WebGLSync>) -> bool {
match sync {
Some(sync) => {
if !sync.is_valid() {
return false;
}
handle_potential_webgl_error!(
self.base,
self.base.validate_ownership(sync),
return false
);
let (sender, receiver) = webgl_channel().unwrap();
self.base
.send_command(WebGLCommand::IsSync(sync.id(), sender));
receiver.recv().unwrap()
},
None => false,
}
}

/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14
fn ClientWaitSync(&self, sync: &WebGLSync, flags: u32, timeout: u64) -> u32 {
if !sync.is_valid() {
self.base.webgl_error(InvalidOperation);
return constants::WAIT_FAILED;
This conversation was marked as resolved by jdm

This comment has been minimized.

@jdm

jdm Sep 20, 2019

Member

We need to set an InvalidOperation webgl error here.

}
handle_potential_webgl_error!(
self.base,
self.base.validate_ownership(sync),
return constants::WAIT_FAILED
);
if flags != 0 && flags != constants::SYNC_FLUSH_COMMANDS_BIT {
self.base.webgl_error(InvalidValue);
return constants::WAIT_FAILED;
}
if timeout > self.base.limits().max_client_wait_timeout_webgl.as_nanos() as u64 {
self.base.webgl_error(InvalidOperation);
return constants::WAIT_FAILED;
}

match sync.client_wait_sync(&self.base, flags, timeout) {
Some(status) => status,
None => constants::WAIT_FAILED,
}
}

/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14
fn WaitSync(&self, sync: &WebGLSync, flags: u32, timeout: i64) {
if !sync.is_valid() {
self.base.webgl_error(InvalidOperation);
return;
}
handle_potential_webgl_error!(self.base, self.base.validate_ownership(sync), return);
if flags != 0 {
self.base.webgl_error(InvalidValue);
return;
}
if timeout != constants::TIMEOUT_IGNORED {
self.base.webgl_error(InvalidValue);
return;
}

self.base
.send_command(WebGLCommand::WaitSync(sync.id(), flags, timeout));
}

/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14
fn GetSyncParameter(&self, _cx: JSContext, sync: &WebGLSync, pname: u32) -> JSVal {
if !sync.is_valid() {
self.base.webgl_error(InvalidOperation);
return NullValue();
}
handle_potential_webgl_error!(
self.base,
self.base.validate_ownership(sync),
return NullValue()
);
match pname {
constants::OBJECT_TYPE | constants::SYNC_CONDITION | constants::SYNC_FLAGS => {
let (sender, receiver) = webgl_channel().unwrap();
self.base
.send_command(WebGLCommand::GetSyncParameter(sync.id(), pname, sender));
This conversation was marked as resolved by jdm

This comment has been minimized.

@jdm

jdm Sep 20, 2019

Member

We will need to do something more clever here - "Repeatedly fetching a sync object's SYNC_STATUS parameter in a loop, without returning control to the user agent, must always return the same value." We should be able to use a similar strategy to what I described in #24178.

This comment has been minimized.

@imiklos

imiklos Sep 23, 2019

Author Contributor

You are right! I will update the PR with this change.
I've just noticed that the test file (sync-webgl-specific.html) has a wrong check on the getSyncParameter return value which has to be gl.SIGNALED instead of gl.SYNC_SIGNALED, otherwise the test will always pass.

UInt32Value(receiver.recv().unwrap())
},
constants::SYNC_STATUS => match sync.get_sync_status(pname, &self.base) {
Some(status) => UInt32Value(status),
None => UInt32Value(constants::UNSIGNALED),
},
_ => {
self.base.webgl_error(InvalidEnum);
NullValue()
},
}
}

/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14
fn DeleteSync(&self, sync: Option<&WebGLSync>) {
if let Some(sync) = sync {
handle_potential_webgl_error!(self.base, self.base.validate_ownership(sync), return);
sync.delete(false);
}
}
}

impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<WebGL2RenderingContext> {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.