aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/webgl2renderingcontext.rs
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2020-01-09 08:52:15 -0500
committerGitHub <noreply@github.com>2020-01-09 08:52:15 -0500
commit123d43bb16cd6807ad6de3e83316191a58505d5b (patch)
tree1bb3050695e0c2df00d9a8f111a75c30cb24e3ee /components/script/dom/webgl2renderingcontext.rs
parentff6ddb4b613b8028bd16fb2355c539dc14bec7a6 (diff)
parentda94f8d0e78546a40972596ad0ae4ded510057de (diff)
downloadservo-123d43bb16cd6807ad6de3e83316191a58505d5b.tar.gz
servo-123d43bb16cd6807ad6de3e83316191a58505d5b.zip
Auto merge of #25229 - mmatyas:webgl_fns_ubo, r=jdm
Add initial support for WebGL2 uniform buffer functions This *work-in-progress* patch adds initial support for the following WebGL2 calls: - `bindBufferBase` - `bindBufferRange` - `getUniformIndices` - `getUniformBlockIndex` - `getActiveUniforms` - `getActiveUniformBlockParameter` - `getActiveUniformBlockName` - `uniformBlockBinding` See: https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16 However, indexed uniforms and `getIndexedParameter`, which would be used by some of the functions (and transform feedback) is still missing. Also this patch depends on: - https://github.com/servo/sparkle/pull/16 - https://github.com/servo/servo/issues/25034 (required for both building and running the tests). cc @jdm @zakorgy @imiklos <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [ ] These changes fix #___ (GitHub issue number if applicable) <!-- Either: --> - [x] There are tests for these changes OR - [ ] These changes do not require tests because ___ <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
Diffstat (limited to 'components/script/dom/webgl2renderingcontext.rs')
-rw-r--r--components/script/dom/webgl2renderingcontext.rs357
1 files changed, 342 insertions, 15 deletions
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs
index 2c63b775bb1..e8993f472d9 100644
--- a/components/script/dom/webgl2renderingcontext.rs
+++ b/components/script/dom/webgl2renderingcontext.rs
@@ -45,13 +45,14 @@ use dom_struct::dom_struct;
use euclid::default::{Point2D, Rect, Size2D};
use ipc_channel::ipc;
use js::jsapi::{JSObject, Type};
-use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, UInt32Value};
+use js::jsval::{BooleanValue, DoubleValue, Int32Value, UInt32Value};
+use js::jsval::{JSVal, NullValue, ObjectValue, UndefinedValue};
use js::rust::CustomAutoRooterGuard;
-use js::typedarray::ArrayBufferView;
+use js::typedarray::{ArrayBufferView, CreateWith, Uint32Array};
use script_layout_interface::HTMLCanvasDataSource;
use std::cell::Cell;
use std::cmp;
-use std::ptr::NonNull;
+use std::ptr::{self, NonNull};
#[dom_struct]
pub struct WebGL2RenderingContext {
@@ -160,6 +161,18 @@ impl WebGL2RenderingContext {
}
}
+ pub fn buffer_usage(&self, usage: u32) -> WebGLResult<u32> {
+ match usage {
+ constants::STATIC_READ |
+ constants::DYNAMIC_READ |
+ constants::STREAM_READ |
+ constants::STATIC_COPY |
+ constants::DYNAMIC_COPY |
+ constants::STREAM_COPY => Ok(usage),
+ _ => self.base.buffer_usage(usage),
+ }
+ }
+
fn unbind_from(&self, slot: &MutNullableDom<WebGLBuffer>, buffer: &WebGLBuffer) {
if slot.get().map_or(false, |b| buffer == &*b) {
buffer.decrement_attached_counter();
@@ -411,40 +424,94 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
fn GetParameter(&self, cx: JSContext, parameter: u32) -> JSVal {
match parameter {
constants::MAX_CLIENT_WAIT_TIMEOUT_WEBGL => {
- Int32Value(self.base.limits().max_client_wait_timeout_webgl.as_nanos() as i32)
+ return Int32Value(
+ self.base.limits().max_client_wait_timeout_webgl.as_nanos() as i32
+ );
},
constants::SAMPLER_BINDING => unsafe {
let idx = (self.base.textures().active_unit_enum() - constants::TEXTURE0) as usize;
assert!(idx < self.samplers.len());
let sampler = self.samplers[idx].get();
- optional_root_object_to_js_or_null!(*cx, sampler)
+ return optional_root_object_to_js_or_null!(*cx, sampler);
},
constants::COPY_READ_BUFFER_BINDING => unsafe {
- optional_root_object_to_js_or_null!(*cx, &self.bound_copy_read_buffer.get())
+ return optional_root_object_to_js_or_null!(
+ *cx,
+ &self.bound_copy_read_buffer.get()
+ );
},
constants::COPY_WRITE_BUFFER_BINDING => unsafe {
- optional_root_object_to_js_or_null!(*cx, &self.bound_copy_write_buffer.get())
+ return optional_root_object_to_js_or_null!(
+ *cx,
+ &self.bound_copy_write_buffer.get()
+ );
},
constants::PIXEL_PACK_BUFFER_BINDING => unsafe {
- optional_root_object_to_js_or_null!(*cx, &self.bound_pixel_pack_buffer.get())
+ return optional_root_object_to_js_or_null!(
+ *cx,
+ &self.bound_pixel_pack_buffer.get()
+ );
},
constants::PIXEL_UNPACK_BUFFER_BINDING => unsafe {
- optional_root_object_to_js_or_null!(*cx, &self.bound_pixel_unpack_buffer.get())
+ return optional_root_object_to_js_or_null!(
+ *cx,
+ &self.bound_pixel_unpack_buffer.get()
+ );
},
constants::TRANSFORM_FEEDBACK_BUFFER_BINDING => unsafe {
- optional_root_object_to_js_or_null!(
+ return optional_root_object_to_js_or_null!(
*cx,
&self.bound_transform_feedback_buffer.get()
- )
+ );
},
constants::UNIFORM_BUFFER_BINDING => unsafe {
- optional_root_object_to_js_or_null!(*cx, &self.bound_uniform_buffer.get())
+ return optional_root_object_to_js_or_null!(*cx, &self.bound_uniform_buffer.get());
},
constants::TRANSFORM_FEEDBACK_BINDING => unsafe {
- optional_root_object_to_js_or_null!(*cx, self.current_transform_feedback.get())
+ return optional_root_object_to_js_or_null!(
+ *cx,
+ self.current_transform_feedback.get()
+ );
},
- _ => self.base.GetParameter(cx, parameter),
+ _ => {},
}
+
+ let limit = match parameter {
+ constants::MAX_UNIFORM_BUFFER_BINDINGS => {
+ Some(self.base.limits().max_uniform_buffer_bindings)
+ },
+ constants::MAX_UNIFORM_BLOCK_SIZE => Some(self.base.limits().max_uniform_block_size),
+ constants::MAX_COMBINED_UNIFORM_BLOCKS => {
+ Some(self.base.limits().max_combined_uniform_blocks)
+ },
+ constants::MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS => {
+ Some(self.base.limits().max_combined_vertex_uniform_components)
+ },
+ constants::MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS => {
+ Some(self.base.limits().max_combined_fragment_uniform_components)
+ },
+ constants::MAX_VERTEX_UNIFORM_BLOCKS => {
+ Some(self.base.limits().max_vertex_uniform_blocks)
+ },
+ constants::MAX_VERTEX_UNIFORM_COMPONENTS => {
+ Some(self.base.limits().max_vertex_uniform_components)
+ },
+ constants::MAX_FRAGMENT_UNIFORM_BLOCKS => {
+ Some(self.base.limits().max_fragment_uniform_blocks)
+ },
+ constants::MAX_FRAGMENT_UNIFORM_COMPONENTS => {
+ Some(self.base.limits().max_fragment_uniform_components)
+ },
+ constants::UNIFORM_BUFFER_OFFSET_ALIGNMENT => {
+ Some(self.base.limits().uniform_buffer_offset_alignment)
+ },
+ _ => None,
+ };
+ if let Some(limit) = limit {
+ return UInt32Value(limit);
+ }
+
+ self.base.GetParameter(cx, parameter)
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
@@ -571,6 +638,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn BufferData(&self, target: u32, data: Option<ArrayBufferViewOrArrayBuffer>, usage: u32) {
+ let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
let bound_buffer =
handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
self.base.buffer_data(target, data, usage, bound_buffer)
@@ -578,6 +646,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn BufferData_(&self, target: u32, size: i64, usage: u32) {
+ let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
let bound_buffer =
handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
self.base.buffer_data_(target, size, usage, bound_buffer)
@@ -593,6 +662,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
elem_offset: u32,
length: u32,
) {
+ let usage = handle_potential_webgl_error!(self.base, self.buffer_usage(usage), return);
let bound_buffer =
handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
let bound_buffer =
@@ -628,7 +698,10 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn BufferSubData(&self, target: u32, offset: i64, data: ArrayBufferViewOrArrayBuffer) {
- self.base.BufferSubData(target, offset, data)
+ let bound_buffer =
+ handle_potential_webgl_error!(self.base, self.bound_buffer(target), return);
+ self.base
+ .buffer_sub_data(target, offset, data, bound_buffer)
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.3
@@ -2304,6 +2377,260 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
DOMString::from(name),
))
}
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16
+ fn BindBufferBase(&self, target: u32, index: u32, buffer: Option<&WebGLBuffer>) {
+ let (bind_limit, slot) = match target {
+ constants::TRANSFORM_FEEDBACK_BUFFER => (
+ self.base.limits().max_transform_feedback_separate_attribs,
+ &self.bound_transform_feedback_buffer,
+ ),
+ constants::UNIFORM_BUFFER => (
+ self.base.limits().max_uniform_buffer_bindings,
+ &self.bound_uniform_buffer,
+ ),
+ _ => return self.base.webgl_error(InvalidEnum),
+ };
+ if index >= bind_limit {
+ return self.base.webgl_error(InvalidValue);
+ }
+
+ if let Some(buffer) = buffer {
+ handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
+
+ if buffer.is_marked_for_deletion() {
+ return self.base.webgl_error(InvalidOperation);
+ }
+ handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return);
+ buffer.increment_attached_counter();
+ }
+
+ self.base.send_command(WebGLCommand::BindBufferBase(
+ target,
+ index,
+ buffer.map(|b| b.id()),
+ ));
+ if let Some(old) = slot.get() {
+ old.decrement_attached_counter();
+ }
+
+ slot.set(buffer);
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16
+ fn BindBufferRange(
+ &self,
+ target: u32,
+ index: u32,
+ buffer: Option<&WebGLBuffer>,
+ offset: i64,
+ size: i64,
+ ) {
+ let (bind_limit, slot) = match target {
+ constants::TRANSFORM_FEEDBACK_BUFFER => (
+ self.base.limits().max_transform_feedback_separate_attribs,
+ &self.bound_transform_feedback_buffer,
+ ),
+ constants::UNIFORM_BUFFER => (
+ self.base.limits().max_uniform_buffer_bindings,
+ &self.bound_uniform_buffer,
+ ),
+ _ => return self.base.webgl_error(InvalidEnum),
+ };
+ if index >= bind_limit {
+ return self.base.webgl_error(InvalidValue);
+ }
+
+ if offset < 0 || size < 0 {
+ return self.base.webgl_error(InvalidValue);
+ }
+ if buffer.is_some() && size == 0 {
+ return self.base.webgl_error(InvalidValue);
+ }
+
+ match target {
+ constants::TRANSFORM_FEEDBACK_BUFFER => {
+ if size % 4 != 0 && offset % 4 != 0 {
+ return self.base.webgl_error(InvalidValue);
+ }
+ },
+ constants::UNIFORM_BUFFER => {
+ let offset_alignment = self.base.limits().uniform_buffer_offset_alignment;
+ if offset % offset_alignment as i64 != 0 {
+ return self.base.webgl_error(InvalidValue);
+ }
+ },
+ _ => unreachable!(),
+ }
+
+ if let Some(buffer) = buffer {
+ handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
+
+ if buffer.is_marked_for_deletion() {
+ return self.base.webgl_error(InvalidOperation);
+ }
+ handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return);
+ buffer.increment_attached_counter();
+ }
+
+ self.base.send_command(WebGLCommand::BindBufferRange(
+ target,
+ index,
+ buffer.map(|b| b.id()),
+ offset,
+ size,
+ ));
+ if let Some(old) = slot.get() {
+ old.decrement_attached_counter();
+ }
+
+ slot.set(buffer);
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16
+ fn GetUniformIndices(&self, program: &WebGLProgram, names: Vec<DOMString>) -> Option<Vec<u32>> {
+ handle_potential_webgl_error!(
+ self.base,
+ self.base.validate_ownership(program),
+ return None
+ );
+ let indices = handle_potential_webgl_error!(
+ self.base,
+ program.get_uniform_indices(names),
+ return None
+ );
+ Some(indices)
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16
+ #[allow(unsafe_code)]
+ fn GetActiveUniforms(
+ &self,
+ cx: JSContext,
+ program: &WebGLProgram,
+ indices: Vec<u32>,
+ pname: u32,
+ ) -> JSVal {
+ handle_potential_webgl_error!(
+ self.base,
+ self.base.validate_ownership(program),
+ return NullValue()
+ );
+ let values = handle_potential_webgl_error!(
+ self.base,
+ program.get_active_uniforms(indices, pname),
+ return NullValue()
+ );
+
+ rooted!(in(*cx) let mut rval = UndefinedValue());
+ match pname {
+ constants::UNIFORM_SIZE |
+ constants::UNIFORM_TYPE |
+ constants::UNIFORM_BLOCK_INDEX |
+ constants::UNIFORM_OFFSET |
+ constants::UNIFORM_ARRAY_STRIDE |
+ constants::UNIFORM_MATRIX_STRIDE => unsafe {
+ values.to_jsval(*cx, rval.handle_mut());
+ },
+ constants::UNIFORM_IS_ROW_MAJOR => unsafe {
+ let values = values.iter().map(|&v| v != 0).collect::<Vec<_>>();
+ values.to_jsval(*cx, rval.handle_mut());
+ },
+ _ => unreachable!(),
+ }
+ rval.get()
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16
+ fn GetUniformBlockIndex(&self, program: &WebGLProgram, block_name: DOMString) -> u32 {
+ handle_potential_webgl_error!(
+ self.base,
+ self.base.validate_ownership(program),
+ return constants::INVALID_INDEX
+ );
+ let index = handle_potential_webgl_error!(
+ self.base,
+ program.get_uniform_block_index(block_name),
+ return constants::INVALID_INDEX
+ );
+ index
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16
+ #[allow(unsafe_code)]
+ fn GetActiveUniformBlockParameter(
+ &self,
+ cx: JSContext,
+ program: &WebGLProgram,
+ block_index: u32,
+ pname: u32,
+ ) -> JSVal {
+ handle_potential_webgl_error!(
+ self.base,
+ self.base.validate_ownership(program),
+ return NullValue()
+ );
+ let values = handle_potential_webgl_error!(
+ self.base,
+ program.get_active_uniform_block_parameter(block_index, pname),
+ return NullValue()
+ );
+ match pname {
+ constants::UNIFORM_BLOCK_BINDING |
+ constants::UNIFORM_BLOCK_DATA_SIZE |
+ constants::UNIFORM_BLOCK_ACTIVE_UNIFORMS => {
+ assert!(values.len() == 1);
+ UInt32Value(values[0] as u32)
+ },
+ constants::UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES => unsafe {
+ let values = values.iter().map(|&v| v as u32).collect::<Vec<_>>();
+ rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
+ let _ = Uint32Array::create(*cx, CreateWith::Slice(&values), result.handle_mut())
+ .unwrap();
+ ObjectValue(result.get())
+ },
+ constants::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER |
+ constants::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER => {
+ assert!(values.len() == 1);
+ BooleanValue(values[0] != 0)
+ },
+ _ => unreachable!(),
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16
+ fn GetActiveUniformBlockName(
+ &self,
+ program: &WebGLProgram,
+ block_index: u32,
+ ) -> Option<DOMString> {
+ handle_potential_webgl_error!(
+ self.base,
+ self.base.validate_ownership(program),
+ return None
+ );
+ let name = handle_potential_webgl_error!(
+ self.base,
+ program.get_active_uniform_block_name(block_index),
+ return None
+ );
+ Some(DOMString::from(name))
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16
+ fn UniformBlockBinding(&self, program: &WebGLProgram, block_index: u32, block_binding: u32) {
+ handle_potential_webgl_error!(self.base, self.base.validate_ownership(program), return);
+
+ if block_binding >= self.base.limits().max_uniform_buffer_bindings {
+ return self.base.webgl_error(InvalidValue);
+ }
+
+ handle_potential_webgl_error!(
+ self.base,
+ program.bind_uniform_block(block_index, block_binding),
+ return
+ )
+ }
}
impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<WebGL2RenderingContext> {