Auto merge of #20525 - servo:webgl2, r=emilio

More WebGL improvements

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20525)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-04-04 07:19:26 -04:00 committed by GitHub
commit e06f0d32d0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 128 additions and 114 deletions

View file

@ -614,3 +614,18 @@ macro_rules! impl_performance_entry_struct(
} }
); );
); );
macro_rules! handle_potential_webgl_error {
($context:expr, $call:expr, $return_on_error:expr) => {
match $call {
Ok(ret) => ret,
Err(error) => {
$context.webgl_error(error);
$return_on_error
}
}
};
($context:expr, $call:expr) => {
handle_potential_webgl_error!($context, $call, ());
};
}

View file

@ -241,7 +241,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
} }
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn BufferSubData(&self, target: u32, offset: i64, data: Option<ArrayBufferViewOrArrayBuffer>) { fn BufferSubData(&self, target: u32, offset: i64, data: ArrayBufferViewOrArrayBuffer) {
self.base.BufferSubData(target, offset, data) self.base.BufferSubData(target, offset, data)
} }

View file

@ -7,6 +7,7 @@ use canvas_traits::webgl::{WebGLBufferId, WebGLCommand, WebGLError, WebGLMsgSend
use canvas_traits::webgl::webgl_channel; use canvas_traits::webgl::webgl_channel;
use dom::bindings::cell::DomRefCell; use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::WebGLBufferBinding; use dom::bindings::codegen::Bindings::WebGLBufferBinding;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants;
use dom::bindings::reflector::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::root::DomRoot; use dom::bindings::root::DomRoot;
use dom::webglobject::WebGLObject; use dom::webglobject::WebGLObject;
@ -86,18 +87,25 @@ impl WebGLBuffer {
Ok(()) Ok(())
} }
pub fn buffer_data(&self, target: u32, data: &[u8], usage: u32) -> WebGLResult<()> { pub fn buffer_data<T>(&self, target: u32, data: T, usage: u32) -> WebGLResult<()>
where
T: Into<Vec<u8>>,
{
match usage {
WebGLRenderingContextConstants::STREAM_DRAW |
WebGLRenderingContextConstants::STATIC_DRAW |
WebGLRenderingContextConstants::DYNAMIC_DRAW => (),
_ => return Err(WebGLError::InvalidEnum),
}
if let Some(previous_target) = self.target.get() { if let Some(previous_target) = self.target.get() {
if target != previous_target { if target != previous_target {
return Err(WebGLError::InvalidOperation); return Err(WebGLError::InvalidOperation);
} }
} }
let data = data.into();
self.capacity.set(data.len()); self.capacity.set(data.len());
self.renderer.send(WebGLCommand::BufferData( self.renderer.send(WebGLCommand::BufferData(target, data.into(), usage)).unwrap();
target,
data.to_vec().into(),
usage,
)).unwrap();
Ok(()) Ok(())
} }

View file

@ -4,8 +4,9 @@
use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
use canvas_traits::canvas::{byte_swap, multiply_u8_pixel}; use canvas_traits::canvas::{byte_swap, multiply_u8_pixel};
use canvas_traits::webgl::{WebGLContextShareMode, WebGLCommand, WebGLError, WebGLVersion, WebGLSLVersion}; use canvas_traits::webgl::{WebGLCommand, WebGLContextShareMode, WebGLError};
use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender, WebGLParameter, WebVRCommand}; use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender};
use canvas_traits::webgl::{WebGLParameter, WebGLResult, WebGLSLVersion, WebGLVersion, WebVRCommand};
use canvas_traits::webgl::DOMToTextureCommand; use canvas_traits::webgl::DOMToTextureCommand;
use canvas_traits::webgl::WebGLError::*; use canvas_traits::webgl::WebGLError::*;
use canvas_traits::webgl::webgl_channel; use canvas_traits::webgl::webgl_channel;
@ -67,21 +68,6 @@ use webrender_api;
type ImagePixelResult = Result<(Vec<u8>, Size2D<i32>, bool), ()>; type ImagePixelResult = Result<(Vec<u8>, Size2D<i32>, bool), ()>;
pub const MAX_UNIFORM_AND_ATTRIBUTE_LEN: usize = 256; pub const MAX_UNIFORM_AND_ATTRIBUTE_LEN: usize = 256;
macro_rules! handle_potential_webgl_error {
($context:ident, $call:expr, $return_on_error:expr) => {
match $call {
Ok(ret) => ret,
Err(error) => {
$context.webgl_error(error);
$return_on_error
}
}
};
($context:ident, $call:expr) => {
handle_potential_webgl_error!($context, $call, ());
};
}
// From the GLES 2.0.25 spec, page 85: // From the GLES 2.0.25 spec, page 85:
// //
// "If a texture that is currently bound to one of the targets // "If a texture that is currently bound to one of the targets
@ -1195,6 +1181,14 @@ impl WebGLRenderingContext {
)); ));
Some(receiver.recv().unwrap().into()) Some(receiver.recv().unwrap().into())
} }
pub fn bound_buffer(&self, target: u32) -> WebGLResult<Option<DomRoot<WebGLBuffer>>> {
match target {
constants::ARRAY_BUFFER => Ok(self.bound_buffer_array.get()),
constants::ELEMENT_ARRAY_BUFFER => Ok(self.bound_buffer_element_array.get()),
_ => Err(WebGLError::InvalidEnum),
}
}
} }
impl Drop for WebGLRenderingContext { impl Drop for WebGLRenderingContext {
@ -1256,14 +1250,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
target: u32, target: u32,
parameter: u32, parameter: u32,
) -> JSVal { ) -> JSVal {
let buffer = match target { let buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return NullValue());
constants::ARRAY_BUFFER => self.bound_buffer_array.get(),
constants::ELEMENT_ARRAY_BUFFER => self.bound_buffer_element_array.get(),
_ => {
self.webgl_error(InvalidEnum);
return NullValue();
}
};
match parameter { match parameter {
constants::BUFFER_SIZE | constants::BUFFER_USAGE => {}, constants::BUFFER_SIZE | constants::BUFFER_USAGE => {},
_ => { _ => {
@ -1693,77 +1681,44 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
Err(_) => fallible_array_buffer_view_to_vec(cx, data)?, Err(_) => fallible_array_buffer_view_to_vec(cx, data)?,
}; };
let bound_buffer = match target { let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return Ok(()));
constants::ARRAY_BUFFER => self.bound_buffer_array.get(),
constants::ELEMENT_ARRAY_BUFFER => self.bound_buffer_element_array.get(),
_ => return Ok(self.webgl_error(InvalidEnum)),
};
let bound_buffer = match bound_buffer { let bound_buffer = match bound_buffer {
Some(bound_buffer) => bound_buffer, Some(bound_buffer) => bound_buffer,
None => return Ok(self.webgl_error(InvalidValue)), None => return Ok(self.webgl_error(InvalidOperation)),
}; };
match usage { handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, data_vec, usage));
constants::STREAM_DRAW |
constants::STATIC_DRAW |
constants::DYNAMIC_DRAW => (),
_ => return Ok(self.webgl_error(InvalidEnum)),
}
handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, &data_vec, usage));
Ok(()) Ok(())
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn BufferData_(&self, target: u32, size: i64, usage: u32) -> ErrorResult { fn BufferData_(&self, target: u32, size: i64, usage: u32) -> ErrorResult {
let bound_buffer = match target { let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return Ok(()));
constants::ARRAY_BUFFER => self.bound_buffer_array.get(),
constants::ELEMENT_ARRAY_BUFFER => self.bound_buffer_element_array.get(),
_ => return Ok(self.webgl_error(InvalidEnum)),
};
let bound_buffer = match bound_buffer { let bound_buffer = match bound_buffer {
Some(bound_buffer) => bound_buffer, Some(bound_buffer) => bound_buffer,
None => return Ok(self.webgl_error(InvalidValue)), None => return Ok(self.webgl_error(InvalidOperation)),
}; };
if size < 0 { if size < 0 {
return Ok(self.webgl_error(InvalidValue)); return Ok(self.webgl_error(InvalidValue));
} }
match usage {
constants::STREAM_DRAW |
constants::STATIC_DRAW |
constants::DYNAMIC_DRAW => (),
_ => return Ok(self.webgl_error(InvalidEnum)),
}
// FIXME: Allocating a buffer based on user-requested size is // FIXME: Allocating a buffer based on user-requested size is
// not great, but we don't have a fallible allocation to try. // not great, but we don't have a fallible allocation to try.
let data = vec![0u8; size as usize]; let data = vec![0u8; size as usize];
handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, &data, usage)); handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, data, usage));
Ok(()) Ok(())
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn BufferSubData(&self, target: u32, offset: i64, data: Option<ArrayBufferViewOrArrayBuffer>) { fn BufferSubData(&self, target: u32, offset: i64, data: ArrayBufferViewOrArrayBuffer) {
let data_vec = match data { let data_vec = match data {
// Typed array is rooted, so we can safely temporarily retrieve its slice // Typed array is rooted, so we can safely temporarily retrieve its slice
Some(ArrayBufferViewOrArrayBuffer::ArrayBuffer(mut inner)) => inner.to_vec(), ArrayBufferViewOrArrayBuffer::ArrayBuffer(mut inner) => inner.to_vec(),
Some(ArrayBufferViewOrArrayBuffer::ArrayBufferView(mut inner)) => inner.to_vec(), ArrayBufferViewOrArrayBuffer::ArrayBufferView(mut inner) => inner.to_vec(),
// Spec: If data is null then an INVALID_VALUE error is generated.
None => return self.webgl_error(InvalidValue),
};
let bound_buffer = match target {
constants::ARRAY_BUFFER => self.bound_buffer_array.get(),
constants::ELEMENT_ARRAY_BUFFER => self.bound_buffer_element_array.get(),
_ => return self.webgl_error(InvalidEnum),
}; };
let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
let bound_buffer = match bound_buffer { let bound_buffer = match bound_buffer {
Some(bound_buffer) => bound_buffer, Some(bound_buffer) => bound_buffer,
None => return self.webgl_error(InvalidOperation), None => return self.webgl_error(InvalidOperation),

View file

@ -179,6 +179,7 @@ interface WebGL2RenderingContextBase
const GLenum FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE = 0x8216; const GLenum FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE = 0x8216;
const GLenum FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE = 0x8217; const GLenum FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE = 0x8217;
const GLenum FRAMEBUFFER_DEFAULT = 0x8218; const GLenum FRAMEBUFFER_DEFAULT = 0x8218;
// BUG: https://github.com/KhronosGroup/WebGL/issues/2216
// const GLenum DEPTH_STENCIL_ATTACHMENT = 0x821A; // const GLenum DEPTH_STENCIL_ATTACHMENT = 0x821A;
// const GLenum DEPTH_STENCIL = 0x84F9; // const GLenum DEPTH_STENCIL = 0x84F9;
const GLenum UNSIGNED_INT_24_8 = 0x84FA; const GLenum UNSIGNED_INT_24_8 = 0x84FA;
@ -303,9 +304,13 @@ interface WebGL2RenderingContextBase
/* Buffer objects */ /* Buffer objects */
// WebGL1: // WebGL1:
// void bufferData(GLenum target, GLsizeiptr size, GLenum usage); // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
// void bufferData(GLenum target, [AllowShared] BufferSource? srcData, GLenum usage); // FIXME(xanewok): https://github.com/servo/servo/issues/20513
// void bufferSubData(GLenum target, GLintptr dstByteOffset, [AllowShared] BufferSource srcData); [Throws]
void bufferData(GLenum target, object? data, GLenum usage);
[Throws]
void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
void bufferSubData(GLenum target, GLintptr dstByteOffset, /*[AllowShared]*/ BufferSource srcData);
// WebGL2: // WebGL2:
// void bufferData(GLenum target, [AllowShared] ArrayBufferView srcData, GLenum usage, GLuint srcOffset, // void bufferData(GLenum target, [AllowShared] ArrayBufferView srcData, GLenum usage, GLuint srcOffset,
// optional GLuint length = 0); // optional GLuint length = 0);
@ -342,17 +347,23 @@ interface WebGL2RenderingContextBase
// GLsizei height, GLsizei depth); // GLsizei height, GLsizei depth);
// WebGL1 legacy entrypoints: // WebGL1 legacy entrypoints:
// void texImage2D(GLenum target, GLint level, GLint internalformat, // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
// GLsizei width, GLsizei height, GLint border, GLenum format, [Throws]
// GLenum type, [AllowShared] ArrayBufferView? pixels); void texImage2D(GLenum target, GLint level, GLenum internalformat,
// void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format,
// GLenum format, GLenum type, TexImageSource source); // May throw DOMException GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
[Throws]
void texImage2D(GLenum target, GLint level, GLenum internalformat,
GLenum format, GLenum type, TexImageSource source); // May throw DOMException
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
// GLsizei width, GLsizei height, [Throws]
// GLenum format, GLenum type, [AllowShared] ArrayBufferView? pixels); void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
// void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
// GLenum format, GLenum type, TexImageSource source); // May throw DOMException GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
[Throws]
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLenum format, GLenum type, TexImageSource source); // May throw DOMException
// WebGL2 entrypoints: // WebGL2 entrypoints:
// void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, // void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
@ -498,8 +509,9 @@ interface WebGL2RenderingContextBase
/* Reading back pixels */ /* Reading back pixels */
// WebGL1: // WebGL1:
// void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
// [AllowShared] ArrayBufferView? dstData); void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
/*[AllowShared]*/ ArrayBufferView? dstData);
// WebGL2: // WebGL2:
// void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, // void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
// GLintptr offset); // GLintptr offset);

View file

@ -491,12 +491,10 @@ interface WebGLRenderingContextBase
void blendFuncSeparate(GLenum srcRGB, GLenum dstRGB, void blendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
GLenum srcAlpha, GLenum dstAlpha); GLenum srcAlpha, GLenum dstAlpha);
// FIXME(xanewok): https://github.com/servo/servo/issues/20513 // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
[Throws] // void bufferData(GLenum target, object? data, GLenum usage);
void bufferData(GLenum target, object? data, GLenum usage); // void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
[Throws] // void bufferSubData(GLenum target, GLintptr offset, /*[AllowShared]*/ BufferSource data);
void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
void bufferSubData(GLenum target, GLintptr offset, /*[AllowShared]*/ BufferSource? data);
[WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target); [WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target);
void clear(GLbitfield mask); void clear(GLbitfield mask);
@ -604,8 +602,9 @@ interface WebGLRenderingContextBase
void pixelStorei(GLenum pname, GLint param); void pixelStorei(GLenum pname, GLint param);
void polygonOffset(GLfloat factor, GLfloat units); void polygonOffset(GLfloat factor, GLfloat units);
void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels); // void readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
// GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
void renderbufferStorage(GLenum target, GLenum internalformat, void renderbufferStorage(GLenum target, GLenum internalformat,
GLsizei width, GLsizei height); GLsizei width, GLsizei height);
@ -621,14 +620,12 @@ interface WebGLRenderingContextBase
void stencilOp(GLenum fail, GLenum zfail, GLenum zpass); void stencilOp(GLenum fail, GLenum zfail, GLenum zpass);
void stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); void stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
// FIXME: https://github.com/servo/servo/issues/20516 // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
[Throws] // void texImage2D(GLenum target, GLint level, GLenum internalformat,
void texImage2D(GLenum target, GLint level, GLenum internalformat, // GLsizei width, GLsizei height, GLint border, GLenum format,
GLsizei width, GLsizei height, GLint border, GLenum format, // GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels); // void texImage2D(GLenum target, GLint level, GLenum internalformat,
[Throws] // GLenum format, GLenum type, TexImageSource source); // May throw DOMException
void texImage2D(GLenum target, GLint level, GLenum internalformat,
GLenum format, GLenum type, TexImageSource source); // May throw DOMException
[Throws, Pref="dom.webgl.dom_to_texture.enabled"] [Throws, Pref="dom.webgl.dom_to_texture.enabled"]
void texImageDOM(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, void texImageDOM(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
GLenum format, GLenum type, HTMLIFrameElement source); // May throw DOMException GLenum format, GLenum type, HTMLIFrameElement source); // May throw DOMException
@ -636,14 +633,12 @@ interface WebGLRenderingContextBase
void texParameterf(GLenum target, GLenum pname, GLfloat param); void texParameterf(GLenum target, GLenum pname, GLfloat param);
void texParameteri(GLenum target, GLenum pname, GLint param); void texParameteri(GLenum target, GLenum pname, GLint param);
// FIXME: https://github.com/servo/servo/issues/20516 // BUG: https://github.com/KhronosGroup/WebGL/issues/2216
[Throws] // void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, // GLsizei width, GLsizei height,
GLsizei width, GLsizei height, // GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels); // void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
[Throws] // GLenum format, GLenum type, TexImageSource source); // May throw DOMException
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLenum format, GLenum type, TexImageSource source); // May throw DOMException
void uniform1f(WebGLUniformLocation? location, GLfloat x); void uniform1f(WebGLUniformLocation? location, GLfloat x);
void uniform2f(WebGLUniformLocation? location, GLfloat x, GLfloat y); void uniform2f(WebGLUniformLocation? location, GLfloat x, GLfloat y);
@ -691,5 +686,34 @@ interface WebGLRenderingContextBase
[Exposed=Window] [Exposed=Window]
interface WebGLRenderingContext interface WebGLRenderingContext
{ {
// BUG: https://github.com/KhronosGroup/WebGL/issues/2216
// FIXME(xanewok): https://github.com/servo/servo/issues/20513
[Throws]
void bufferData(GLenum target, object? data, GLenum usage);
[Throws]
void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
void bufferSubData(GLenum target, GLintptr offset, /*[AllowShared]*/ BufferSource data);
// FIXME: https://github.com/servo/servo/issues/20516
[Throws]
void texImage2D(GLenum target, GLint level, GLenum internalformat,
GLsizei width, GLsizei height, GLint border, GLenum format,
GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
[Throws]
void texImage2D(GLenum target, GLint level, GLenum internalformat,
GLenum format, GLenum type, TexImageSource source); // May throw DOMException
// FIXME: https://github.com/servo/servo/issues/20516
[Throws]
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height,
GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
[Throws]
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLenum format, GLenum type, TexImageSource source); // May throw DOMException
void readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type, /*[AllowShared]*/ ArrayBufferView? pixels);
}; };
WebGLRenderingContext implements WebGLRenderingContextBase; WebGLRenderingContext implements WebGLRenderingContextBase;