aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/canvas/Cargo.toml2
-rw-r--r--components/canvas/webgl_limits.rs40
-rw-r--r--components/canvas/webgl_thread.rs67
-rw-r--r--components/canvas_traits/webgl.rs28
-rw-r--r--components/script/dom/bindings/trace.rs5
-rw-r--r--components/script/dom/webgl2renderingcontext.rs357
-rw-r--r--components/script/dom/webglbuffer.rs8
-rw-r--r--components/script/dom/webglprogram.rs149
-rw-r--r--components/script/dom/webglrenderingcontext.rs68
-rw-r--r--components/script/dom/webidls/WebGL2RenderingContext.webidl16
10 files changed, 688 insertions, 52 deletions
diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml
index daa07fab430..2f9495c961d 100644
--- a/components/canvas/Cargo.toml
+++ b/components/canvas/Cargo.toml
@@ -34,7 +34,7 @@ num-traits = "0.2"
raqote = {git = "https://github.com/jrmuizel/raqote", optional = true}
pixels = {path = "../pixels"}
servo_config = {path = "../config"}
-sparkle = "0.1.12"
+sparkle = "0.1.13"
webrender = {git = "https://github.com/servo/webrender"}
webrender_api = {git = "https://github.com/servo/webrender"}
webrender_traits = {path = "../webrender_traits"}
diff --git a/components/canvas/webgl_limits.rs b/components/canvas/webgl_limits.rs
index d910be71d99..1a08dfea945 100644
--- a/components/canvas/webgl_limits.rs
+++ b/components/canvas/webgl_limits.rs
@@ -65,14 +65,24 @@ impl GLLimitsDetect for GLLimits {
};
let (
+ max_uniform_block_size,
max_uniform_buffer_bindings,
min_program_texel_offset,
max_program_texel_offset,
max_transform_feedback_separate_attribs,
max_draw_buffers,
max_color_attachments,
+ max_combined_uniform_blocks,
+ max_combined_vertex_uniform_components,
+ max_combined_fragment_uniform_components,
+ max_vertex_uniform_blocks,
+ max_vertex_uniform_components,
+ max_fragment_uniform_blocks,
+ max_fragment_uniform_components,
+ uniform_buffer_offset_alignment,
);
if webgl_version == WebGLVersion::WebGL2 {
+ max_uniform_block_size = gl.get_integer(gl::MAX_UNIFORM_BLOCK_SIZE);
max_uniform_buffer_bindings = gl.get_integer(gl::MAX_UNIFORM_BUFFER_BINDINGS);
min_program_texel_offset = gl.get_integer(gl::MIN_PROGRAM_TEXEL_OFFSET);
max_program_texel_offset = gl.get_integer(gl::MAX_PROGRAM_TEXEL_OFFSET);
@@ -81,14 +91,33 @@ impl GLLimitsDetect for GLLimits {
max_color_attachments = gl.get_integer(gl::MAX_COLOR_ATTACHMENTS);
max_draw_buffers = gl
.get_integer(gl::MAX_DRAW_BUFFERS)
- .min(max_color_attachments)
+ .min(max_color_attachments);
+ max_combined_uniform_blocks = gl.get_integer(gl::MAX_COMBINED_UNIFORM_BLOCKS);
+ max_combined_vertex_uniform_components =
+ gl.get_integer(gl::MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS);
+ max_combined_fragment_uniform_components =
+ gl.get_integer(gl::MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS);
+ max_vertex_uniform_blocks = gl.get_integer(gl::MAX_VERTEX_UNIFORM_BLOCKS);
+ max_vertex_uniform_components = gl.get_integer(gl::MAX_VERTEX_UNIFORM_COMPONENTS);
+ max_fragment_uniform_blocks = gl.get_integer(gl::MAX_FRAGMENT_UNIFORM_BLOCKS);
+ max_fragment_uniform_components = gl.get_integer(gl::MAX_FRAGMENT_UNIFORM_COMPONENTS);
+ uniform_buffer_offset_alignment = gl.get_integer(gl::UNIFORM_BUFFER_OFFSET_ALIGNMENT);
} else {
+ max_uniform_block_size = 0;
max_uniform_buffer_bindings = 0;
min_program_texel_offset = 0;
max_program_texel_offset = 0;
max_transform_feedback_separate_attribs = 0;
max_color_attachments = 1;
max_draw_buffers = 1;
+ max_combined_uniform_blocks = 0;
+ max_combined_vertex_uniform_components = 0;
+ max_combined_fragment_uniform_components = 0;
+ max_vertex_uniform_blocks = 0;
+ max_vertex_uniform_components = 0;
+ max_fragment_uniform_blocks = 0;
+ max_fragment_uniform_components = 0;
+ uniform_buffer_offset_alignment = 0;
}
GLLimits {
@@ -111,6 +140,15 @@ impl GLLimitsDetect for GLLimits {
max_program_texel_offset,
max_color_attachments,
max_draw_buffers,
+ max_uniform_block_size,
+ max_combined_uniform_blocks,
+ max_combined_vertex_uniform_components,
+ max_combined_fragment_uniform_components,
+ max_vertex_uniform_blocks,
+ max_vertex_uniform_components,
+ max_fragment_uniform_blocks,
+ max_fragment_uniform_components,
+ uniform_buffer_offset_alignment,
}
}
}
diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs
index b9a4533f134..46ea56c1c4f 100644
--- a/components/canvas/webgl_thread.rs
+++ b/components/canvas/webgl_thread.rs
@@ -6,6 +6,7 @@ use crate::webgl_limits::GLLimitsDetect;
use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
use canvas_traits::webgl;
use canvas_traits::webgl::ActiveAttribInfo;
+use canvas_traits::webgl::ActiveUniformBlockInfo;
use canvas_traits::webgl::ActiveUniformInfo;
use canvas_traits::webgl::AlphaTreatment;
use canvas_traits::webgl::DOMToTextureCommand;
@@ -1744,6 +1745,40 @@ impl WebGLImpl {
}
sender.send(value).unwrap();
},
+ WebGLCommand::GetUniformBlockIndex(program_id, ref name, ref sender) => {
+ let name = to_name_in_compiled_shader(name);
+ let index = gl.get_uniform_block_index(program_id.get(), &name);
+ sender.send(index).unwrap();
+ },
+ WebGLCommand::GetUniformIndices(program_id, ref names, ref sender) => {
+ let names = names
+ .iter()
+ .map(|name| to_name_in_compiled_shader(name))
+ .collect::<Vec<_>>();
+ let name_strs = names.iter().map(|name| name.as_str()).collect::<Vec<_>>();
+ let indices = gl.get_uniform_indices(program_id.get(), &name_strs);
+ sender.send(indices).unwrap();
+ },
+ WebGLCommand::GetActiveUniforms(program_id, ref indices, pname, ref sender) => {
+ let results = gl.get_active_uniforms_iv(program_id.get(), indices, pname);
+ sender.send(results).unwrap();
+ },
+ WebGLCommand::GetActiveUniformBlockName(program_id, block_idx, ref sender) => {
+ let name = gl.get_active_uniform_block_name(program_id.get(), block_idx);
+ sender.send(name).unwrap();
+ },
+ WebGLCommand::GetActiveUniformBlockParameter(
+ program_id,
+ block_idx,
+ pname,
+ ref sender,
+ ) => {
+ let results = gl.get_active_uniform_block_iv(program_id.get(), block_idx, pname);
+ sender.send(results).unwrap();
+ },
+ WebGLCommand::UniformBlockBinding(program_id, block_idx, block_binding) => {
+ gl.uniform_block_binding(program_id.get(), block_idx, block_binding)
+ },
WebGLCommand::InitializeFramebuffer {
color,
depth,
@@ -1790,6 +1825,16 @@ impl WebGLImpl {
let value = gl.get_sampler_parameter_fv(sampler_id.get(), pname)[0];
sender.send(value).unwrap();
},
+ WebGLCommand::BindBufferBase(target, index, id) => {
+ gl.bind_buffer_base(target, index, id.map_or(0, WebGLBufferId::get))
+ },
+ 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,
+ ),
}
// If debug asertions are enabled, then check the error state.
@@ -1890,6 +1935,7 @@ impl WebGLImpl {
linked: false,
active_attribs: vec![].into(),
active_uniforms: vec![].into(),
+ active_uniform_blocks: vec![].into(),
transform_feedback_length: Default::default(),
transform_feedback_mode: Default::default(),
};
@@ -1945,6 +1991,26 @@ impl WebGLImpl {
})
.collect::<Vec<_>>()
.into();
+
+ let mut num_active_uniform_blocks = [0];
+ unsafe {
+ gl.get_program_iv(
+ program.get(),
+ gl::ACTIVE_UNIFORM_BLOCKS,
+ &mut num_active_uniform_blocks,
+ );
+ }
+ let active_uniform_blocks = (0..num_active_uniform_blocks[0] as u32)
+ .map(|i| {
+ let name = gl.get_active_uniform_block_name(program.get(), i);
+ let size =
+ gl.get_active_uniform_block_iv(program.get(), i, gl::UNIFORM_BLOCK_DATA_SIZE)
+ [0];
+ ActiveUniformBlockInfo { name, size }
+ })
+ .collect::<Vec<_>>()
+ .into();
+
let mut transform_feedback_length = [0];
unsafe {
gl.get_program_iv(
@@ -1965,6 +2031,7 @@ impl WebGLImpl {
linked: true,
active_attribs,
active_uniforms,
+ active_uniform_blocks,
transform_feedback_length: transform_feedback_length[0],
transform_feedback_mode: transform_feedback_mode[0],
}
diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs
index 63ee46c108c..c5660c24505 100644
--- a/components/canvas_traits/webgl.rs
+++ b/components/canvas_traits/webgl.rs
@@ -462,6 +462,12 @@ pub enum WebGLCommand {
GetUniformFloat4(WebGLProgramId, i32, WebGLSender<[f32; 4]>),
GetUniformFloat9(WebGLProgramId, i32, WebGLSender<[f32; 9]>),
GetUniformFloat16(WebGLProgramId, i32, WebGLSender<[f32; 16]>),
+ GetUniformBlockIndex(WebGLProgramId, String, WebGLSender<u32>),
+ GetUniformIndices(WebGLProgramId, Vec<String>, WebGLSender<Vec<u32>>),
+ GetActiveUniforms(WebGLProgramId, Vec<u32>, u32, WebGLSender<Vec<i32>>),
+ GetActiveUniformBlockName(WebGLProgramId, u32, WebGLSender<String>),
+ GetActiveUniformBlockParameter(WebGLProgramId, u32, u32, WebGLSender<Vec<i32>>),
+ UniformBlockBinding(WebGLProgramId, u32, u32),
InitializeFramebuffer {
color: bool,
depth: bool,
@@ -479,6 +485,8 @@ pub enum WebGLCommand {
SetSamplerParameterInt(WebGLSamplerId, u32, i32),
GetSamplerParameterFloat(WebGLSamplerId, u32, WebGLSender<f32>),
GetSamplerParameterInt(WebGLSamplerId, u32, WebGLSender<i32>),
+ BindBufferBase(u32, u32, Option<WebGLBufferId>),
+ BindBufferRange(u32, u32, Option<WebGLBufferId>, i64, i64),
}
macro_rules! nonzero_type {
@@ -671,6 +679,8 @@ pub struct ProgramLinkInfo {
pub active_attribs: Box<[ActiveAttribInfo]>,
/// The list of active uniforms.
pub active_uniforms: Box<[ActiveUniformInfo]>,
+ /// The list of active uniform blocks.
+ pub active_uniform_blocks: Box<[ActiveUniformBlockInfo]>,
/// The number of varying variables
pub transform_feedback_length: i32,
/// The buffer mode used when transform feedback is active
@@ -713,6 +723,15 @@ impl ActiveUniformInfo {
}
}
+/// Description of a single uniform block.
+#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
+pub struct ActiveUniformBlockInfo {
+ /// The name of the uniform block.
+ pub name: String,
+ /// The size of the uniform block.
+ pub size: i32,
+}
+
macro_rules! parameters {
($name:ident { $(
$variant:ident($kind:ident { $(
@@ -999,4 +1018,13 @@ pub struct GLLimits {
pub max_uniform_buffer_bindings: u32,
pub min_program_texel_offset: u32,
pub max_program_texel_offset: u32,
+ pub max_uniform_block_size: u32,
+ pub max_combined_uniform_blocks: u32,
+ pub max_combined_vertex_uniform_components: u32,
+ pub max_combined_fragment_uniform_components: u32,
+ pub max_vertex_uniform_blocks: u32,
+ pub max_vertex_uniform_components: u32,
+ pub max_fragment_uniform_blocks: u32,
+ pub max_fragment_uniform_components: u32,
+ pub uniform_buffer_offset_alignment: u32,
}
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 3bad24b1b1d..1d83fff920d 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -49,7 +49,9 @@ use canvas_traits::canvas::{
};
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::{
+ ActiveAttribInfo, ActiveUniformBlockInfo, ActiveUniformInfo, GlType, TexDataType, TexFormat,
+};
use canvas_traits::webgl::{GLLimits, WebGLQueryId, WebGLSamplerId};
use canvas_traits::webgl::{WebGLBufferId, WebGLChan, WebGLContextId, WebGLError};
use canvas_traits::webgl::{WebGLFramebufferId, WebGLMsgSender, WebGLPipeline, WebGLProgramId};
@@ -437,6 +439,7 @@ unsafe impl<A: JSTraceable, B: JSTraceable, C: JSTraceable> JSTraceable for (A,
unsafe_no_jsmanaged_fields!(ActiveAttribInfo);
unsafe_no_jsmanaged_fields!(ActiveUniformInfo);
+unsafe_no_jsmanaged_fields!(ActiveUniformBlockInfo);
unsafe_no_jsmanaged_fields!(bool, f32, f64, String, AtomicBool, AtomicUsize, Uuid, char);
unsafe_no_jsmanaged_fields!(usize, u8, u16, u32, u64);
unsafe_no_jsmanaged_fields!(isize, i8, i16, i32, i64);
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> {
diff --git a/components/script/dom/webglbuffer.rs b/components/script/dom/webglbuffer.rs
index 182100ae41f..6e951f3f53e 100644
--- a/components/script/dom/webglbuffer.rs
+++ b/components/script/dom/webglbuffer.rs
@@ -75,7 +75,13 @@ impl WebGLBuffer {
match usage {
WebGLRenderingContextConstants::STREAM_DRAW |
WebGLRenderingContextConstants::STATIC_DRAW |
- WebGLRenderingContextConstants::DYNAMIC_DRAW => (),
+ WebGLRenderingContextConstants::DYNAMIC_DRAW |
+ WebGL2RenderingContextConstants::STATIC_READ |
+ WebGL2RenderingContextConstants::DYNAMIC_READ |
+ WebGL2RenderingContextConstants::STREAM_READ |
+ WebGL2RenderingContextConstants::STATIC_COPY |
+ WebGL2RenderingContextConstants::DYNAMIC_COPY |
+ WebGL2RenderingContextConstants::STREAM_COPY => (),
_ => return Err(WebGLError::InvalidEnum),
}
diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs
index 3b040a170b1..556573aae2e 100644
--- a/components/script/dom/webglprogram.rs
+++ b/components/script/dom/webglprogram.rs
@@ -4,6 +4,7 @@
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
use crate::dom::bindings::cell::{DomRefCell, Ref};
+use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants2;
use crate::dom::bindings::codegen::Bindings::WebGLProgramBinding;
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use crate::dom::bindings::inheritance::Castable;
@@ -16,7 +17,9 @@ use crate::dom::webglrenderingcontext::WebGLRenderingContext;
use crate::dom::webglshader::WebGLShader;
use crate::dom::webgluniformlocation::WebGLUniformLocation;
use canvas_traits::webgl::{webgl_channel, WebGLProgramId, WebGLResult};
-use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, WebGLCommand, WebGLError};
+use canvas_traits::webgl::{
+ ActiveAttribInfo, ActiveUniformBlockInfo, ActiveUniformInfo, WebGLCommand, WebGLError,
+};
use dom_struct::dom_struct;
use fnv::FnvHashSet;
use std::cell::Cell;
@@ -34,6 +37,7 @@ pub struct WebGLProgram {
vertex_shader: MutNullableDom<WebGLShader>,
active_attribs: DomRefCell<Box<[ActiveAttribInfo]>>,
active_uniforms: DomRefCell<Box<[ActiveUniformInfo]>>,
+ active_uniform_blocks: DomRefCell<Box<[ActiveUniformBlockInfo]>>,
transform_feedback_varyings_length: Cell<i32>,
transform_feedback_mode: Cell<i32>,
}
@@ -52,6 +56,7 @@ impl WebGLProgram {
vertex_shader: Default::default(),
active_attribs: DomRefCell::new(vec![].into()),
active_uniforms: DomRefCell::new(vec![].into()),
+ active_uniform_blocks: DomRefCell::new(vec![].into()),
transform_feedback_varyings_length: Default::default(),
transform_feedback_mode: Default::default(),
}
@@ -143,6 +148,7 @@ impl WebGLProgram {
.set(self.link_generation.get().checked_add(1).unwrap());
*self.active_attribs.borrow_mut() = Box::new([]);
*self.active_uniforms.borrow_mut() = Box::new([]);
+ *self.active_uniform_blocks.borrow_mut() = Box::new([]);
match self.fragment_shader.get() {
Some(ref shader) if shader.successfully_compiled() => {},
@@ -197,6 +203,7 @@ impl WebGLProgram {
.set(link_info.transform_feedback_mode);
*self.active_attribs.borrow_mut() = link_info.active_attribs;
*self.active_uniforms.borrow_mut() = link_info.active_uniforms;
+ *self.active_uniform_blocks.borrow_mut() = link_info.active_uniform_blocks;
Ok(())
}
@@ -208,6 +215,10 @@ impl WebGLProgram {
Ref::map(self.active_uniforms.borrow(), |uniforms| &**uniforms)
}
+ pub fn active_uniform_blocks(&self) -> Ref<[ActiveUniformBlockInfo]> {
+ Ref::map(self.active_uniform_blocks.borrow(), |blocks| &**blocks)
+ }
+
/// glValidateProgram
pub fn validate(&self) -> WebGLResult<()> {
if self.is_deleted() {
@@ -413,6 +424,142 @@ impl WebGLProgram {
)))
}
+ pub fn get_uniform_block_index(&self, name: DOMString) -> WebGLResult<u32> {
+ if !self.link_called.get() || self.is_deleted() {
+ return Err(WebGLError::InvalidOperation);
+ }
+
+ if !validate_glsl_name(&name)? {
+ return Ok(constants2::INVALID_INDEX);
+ }
+
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.upcast::<WebGLObject>()
+ .context()
+ .send_command(WebGLCommand::GetUniformBlockIndex(
+ self.id,
+ name.into(),
+ sender,
+ ));
+ Ok(receiver.recv().unwrap())
+ }
+
+ pub fn get_uniform_indices(&self, names: Vec<DOMString>) -> WebGLResult<Vec<u32>> {
+ if !self.link_called.get() || self.is_deleted() {
+ return Err(WebGLError::InvalidOperation);
+ }
+
+ let validation_errors = names
+ .iter()
+ .map(|name| validate_glsl_name(&name))
+ .collect::<Vec<_>>();
+ let first_validation_error = validation_errors.iter().find(|result| result.is_err());
+ if let Some(error) = first_validation_error {
+ return Err(error.unwrap_err());
+ }
+
+ let names = names
+ .iter()
+ .map(|name| name.to_string())
+ .collect::<Vec<_>>();
+
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.upcast::<WebGLObject>()
+ .context()
+ .send_command(WebGLCommand::GetUniformIndices(self.id, names, sender));
+ Ok(receiver.recv().unwrap())
+ }
+
+ pub fn get_active_uniforms(&self, indices: Vec<u32>, pname: u32) -> WebGLResult<Vec<i32>> {
+ if !self.is_linked() || self.is_deleted() {
+ return Err(WebGLError::InvalidOperation);
+ }
+
+ match pname {
+ constants2::UNIFORM_TYPE |
+ constants2::UNIFORM_SIZE |
+ constants2::UNIFORM_BLOCK_INDEX |
+ constants2::UNIFORM_OFFSET |
+ constants2::UNIFORM_ARRAY_STRIDE |
+ constants2::UNIFORM_MATRIX_STRIDE |
+ constants2::UNIFORM_IS_ROW_MAJOR => {},
+ _ => return Err(WebGLError::InvalidEnum),
+ }
+
+ if indices.len() > self.active_uniforms.borrow().len() {
+ return Err(WebGLError::InvalidValue);
+ }
+
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.upcast::<WebGLObject>()
+ .context()
+ .send_command(WebGLCommand::GetActiveUniforms(
+ self.id, indices, pname, sender,
+ ));
+ Ok(receiver.recv().unwrap())
+ }
+
+ pub fn get_active_uniform_block_parameter(
+ &self,
+ block_index: u32,
+ pname: u32,
+ ) -> WebGLResult<Vec<i32>> {
+ if !self.link_called.get() || self.is_deleted() {
+ return Err(WebGLError::InvalidOperation);
+ }
+
+ if block_index as usize >= self.active_uniform_blocks.borrow().len() {
+ return Err(WebGLError::InvalidValue);
+ }
+
+ match pname {
+ constants2::UNIFORM_BLOCK_BINDING |
+ constants2::UNIFORM_BLOCK_DATA_SIZE |
+ constants2::UNIFORM_BLOCK_ACTIVE_UNIFORMS |
+ constants2::UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES |
+ constants2::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER |
+ constants2::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER => {},
+ _ => return Err(WebGLError::InvalidEnum),
+ }
+
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.upcast::<WebGLObject>().context().send_command(
+ WebGLCommand::GetActiveUniformBlockParameter(self.id, block_index, pname, sender),
+ );
+ Ok(receiver.recv().unwrap())
+ }
+
+ pub fn get_active_uniform_block_name(&self, block_index: u32) -> WebGLResult<String> {
+ if !self.link_called.get() || self.is_deleted() {
+ return Err(WebGLError::InvalidOperation);
+ }
+
+ if block_index as usize >= self.active_uniforms.borrow().len() {
+ return Err(WebGLError::InvalidValue);
+ }
+
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.upcast::<WebGLObject>().context().send_command(
+ WebGLCommand::GetActiveUniformBlockName(self.id, block_index, sender),
+ );
+ Ok(receiver.recv().unwrap())
+ }
+
+ pub fn bind_uniform_block(&self, block_index: u32, block_binding: u32) -> WebGLResult<()> {
+ if block_index as usize >= self.active_uniform_blocks.borrow().len() {
+ return Err(WebGLError::InvalidValue);
+ }
+
+ self.upcast::<WebGLObject>()
+ .context()
+ .send_command(WebGLCommand::UniformBlockBinding(
+ self.id,
+ block_index,
+ block_binding,
+ ));
+ Ok(())
+ }
+
/// glGetProgramInfoLog
pub fn get_info_log(&self) -> WebGLResult<String> {
if self.is_deleted() {
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 85930cd3529..68eccfa711d 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -1020,6 +1020,13 @@ impl WebGLRenderingContext {
}
}
+ pub fn buffer_usage(&self, usage: u32) -> WebGLResult<u32> {
+ match usage {
+ constants::STREAM_DRAW | constants::STATIC_DRAW | constants::DYNAMIC_DRAW => Ok(usage),
+ _ => Err(WebGLError::InvalidEnum),
+ }
+ }
+
pub fn create_vertex_array(&self) -> Option<DomRoot<WebGLVertexArrayObjectOES>> {
let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::CreateVertexArray(sender));
@@ -1146,6 +1153,40 @@ impl WebGLRenderingContext {
handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, &data, usage));
}
+ #[allow(unsafe_code)]
+ pub fn buffer_sub_data(
+ &self,
+ target: u32,
+ offset: i64,
+ data: ArrayBufferViewOrArrayBuffer,
+ bound_buffer: Option<DomRoot<WebGLBuffer>>,
+ ) {
+ let bound_buffer =
+ handle_potential_webgl_error!(self, bound_buffer.ok_or(InvalidOperation), return);
+
+ if offset < 0 {
+ return self.webgl_error(InvalidValue);
+ }
+
+ let data = unsafe {
+ // Safe because we don't do anything with JS until the end of the method.
+ match data {
+ ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref data) => data.as_slice(),
+ ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref data) => data.as_slice(),
+ }
+ };
+ if (offset as u64) + data.len() as u64 > bound_buffer.capacity() as u64 {
+ return self.webgl_error(InvalidValue);
+ }
+ let (sender, receiver) = ipc::bytes_channel().unwrap();
+ self.send_command(WebGLCommand::BufferSubData(
+ target,
+ offset as isize,
+ receiver,
+ ));
+ sender.send(data).unwrap();
+ }
+
pub fn bind_buffer_maybe(
&self,
slot: &MutNullableDom<WebGLBuffer>,
@@ -1764,12 +1805,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// 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, self.buffer_usage(usage), return);
let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
self.buffer_data(target, data, usage, bound_buffer)
}
// 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, self.buffer_usage(usage), return);
let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
self.buffer_data_(target, size, usage, bound_buffer)
}
@@ -1778,30 +1821,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
#[allow(unsafe_code)]
fn BufferSubData(&self, target: u32, offset: i64, data: ArrayBufferViewOrArrayBuffer) {
let bound_buffer = handle_potential_webgl_error!(self, self.bound_buffer(target), return);
- let bound_buffer =
- handle_potential_webgl_error!(self, bound_buffer.ok_or(InvalidOperation), return);
-
- if offset < 0 {
- return self.webgl_error(InvalidValue);
- }
-
- let data = unsafe {
- // Safe because we don't do anything with JS until the end of the method.
- match data {
- ArrayBufferViewOrArrayBuffer::ArrayBuffer(ref data) => data.as_slice(),
- ArrayBufferViewOrArrayBuffer::ArrayBufferView(ref data) => data.as_slice(),
- }
- };
- if (offset as u64) + data.len() as u64 > bound_buffer.capacity() as u64 {
- return self.webgl_error(InvalidValue);
- }
- let (sender, receiver) = ipc::bytes_channel().unwrap();
- self.send_command(WebGLCommand::BufferSubData(
- target,
- offset as isize,
- receiver,
- ));
- sender.send(data).unwrap();
+ self.buffer_sub_data(target, offset, data, bound_buffer)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl
index 71b5ab10034..1dca400b742 100644
--- a/components/script/dom/webidls/WebGL2RenderingContext.webidl
+++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl
@@ -553,15 +553,15 @@ interface mixin WebGL2RenderingContextBase
void resumeTransformFeedback();
/* Uniform Buffer Objects and Transform Feedback Buffers */
- // void bindBufferBase(GLenum target, GLuint index, WebGLBuffer? buffer);
- // void bindBufferRange(GLenum target, GLuint index, WebGLBuffer? buffer, GLintptr offset, GLsizeiptr size);
+ void bindBufferBase(GLenum target, GLuint index, WebGLBuffer? buffer);
+ void bindBufferRange(GLenum target, GLuint index, WebGLBuffer? buffer, GLintptr offset, GLsizeiptr size);
// any getIndexedParameter(GLenum target, GLuint index);
- // sequence<GLuint>? getUniformIndices(WebGLProgram program, sequence<DOMString> uniformNames);
- // any getActiveUniforms(WebGLProgram program, sequence<GLuint> uniformIndices, GLenum pname);
- // GLuint getUniformBlockIndex(WebGLProgram program, DOMString uniformBlockName);
- // any getActiveUniformBlockParameter(WebGLProgram program, GLuint uniformBlockIndex, GLenum pname);
- // DOMString? getActiveUniformBlockName(WebGLProgram program, GLuint uniformBlockIndex);
- // void uniformBlockBinding(WebGLProgram program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
+ sequence<GLuint>? getUniformIndices(WebGLProgram program, sequence<DOMString> uniformNames);
+ any getActiveUniforms(WebGLProgram program, sequence<GLuint> uniformIndices, GLenum pname);
+ GLuint getUniformBlockIndex(WebGLProgram program, DOMString uniformBlockName);
+ any getActiveUniformBlockParameter(WebGLProgram program, GLuint uniformBlockIndex, GLenum pname);
+ DOMString? getActiveUniformBlockName(WebGLProgram program, GLuint uniformBlockIndex);
+ void uniformBlockBinding(WebGLProgram program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
/* Vertex Array Objects */
/*WebGLVertexArrayObject? createVertexArray();