Auto merge of #21184 - servo:webgl, r=jdm

Use active uniforms data to implement gl.uniform* checks

<!-- 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/21184)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-07-16 19:46:05 -04:00 committed by GitHub
commit 3003e6f897
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 592 additions and 418 deletions

View file

@ -32,10 +32,11 @@
use app_units::Au;
use canvas_traits::canvas::{CanvasGradientStop, CanvasId, LinearGradientStyle, RadialGradientStyle};
use canvas_traits::canvas::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle};
use canvas_traits::webgl::{ActiveAttribInfo, WebGLBufferId, WebGLFramebufferId, WebGLProgramId, WebGLRenderbufferId};
use canvas_traits::webgl::{WebGLChan, WebGLContextShareMode, WebGLError, WebGLPipeline, WebGLMsgSender};
use canvas_traits::webgl::{WebGLReceiver, WebGLSender, WebGLShaderId, WebGLTextureId, WebGLVertexArrayId};
use canvas_traits::webgl::{WebGLSLVersion, WebGLVersion};
use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, WebGLBufferId, WebGLChan};
use canvas_traits::webgl::{WebGLContextShareMode, WebGLError, WebGLFramebufferId, WebGLMsgSender};
use canvas_traits::webgl::{WebGLPipeline, WebGLProgramId, WebGLReceiver, WebGLRenderbufferId};
use canvas_traits::webgl::{WebGLSLVersion, WebGLSender, WebGLShaderId, WebGLTextureId};
use canvas_traits::webgl::{WebGLVersion, WebGLVertexArrayId};
use cssparser::RGBA;
use devtools_traits::{CSSError, TimelineMarkerType, WorkerId};
use dom::abstractworker::SharedRt;
@ -343,6 +344,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!(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);

View file

@ -3,9 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
use canvas_traits::webgl::{ActiveAttribInfo, WebGLCommand, WebGLError, WebGLMsgSender};
use canvas_traits::webgl::{WebGLProgramId, WebGLResult, from_name_in_compiled_shader};
use canvas_traits::webgl::{to_name_in_compiled_shader, webgl_channel};
use canvas_traits::webgl::{ActiveAttribInfo, ActiveUniformInfo, WebGLCommand, WebGLError};
use canvas_traits::webgl::{WebGLMsgSender, WebGLProgramId, WebGLResult, webgl_channel};
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::WebGLProgramBinding;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
@ -16,6 +15,7 @@ use dom::webglactiveinfo::WebGLActiveInfo;
use dom::webglobject::WebGLObject;
use dom::webglrenderingcontext::MAX_UNIFORM_AND_ATTRIBUTE_LEN;
use dom::webglshader::WebGLShader;
use dom::webgluniformlocation::WebGLUniformLocation;
use dom::window::Window;
use dom_struct::dom_struct;
use fnv::FnvHashSet;
@ -33,6 +33,7 @@ pub struct WebGLProgram {
#[ignore_malloc_size_of = "Defined in ipc-channel"]
renderer: WebGLMsgSender,
active_attribs: DomRefCell<Box<[ActiveAttribInfo]>>,
active_uniforms: DomRefCell<Box<[ActiveUniformInfo]>>,
}
impl WebGLProgram {
@ -49,6 +50,7 @@ impl WebGLProgram {
vertex_shader: Default::default(),
renderer: renderer,
active_attribs: DomRefCell::new(vec![].into()),
active_uniforms: DomRefCell::new(vec![].into()),
}
}
@ -123,20 +125,30 @@ impl WebGLProgram {
self.renderer.send(WebGLCommand::LinkProgram(self.id, sender)).unwrap();
let link_info = receiver.recv().unwrap();
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.31
let mut used_locs = FnvHashSet::default();
for active_attrib in &*link_info.active_attribs {
if active_attrib.location == -1 {
continue;
{
let mut used_locs = FnvHashSet::default();
let mut used_names = FnvHashSet::default();
for active_attrib in &*link_info.active_attribs {
if active_attrib.location == -1 {
continue;
}
let columns = match active_attrib.type_ {
constants::FLOAT_MAT2 => 2,
constants::FLOAT_MAT3 => 3,
constants::FLOAT_MAT4 => 4,
_ => 1,
};
assert!(used_names.insert(&*active_attrib.name));
for column in 0..columns {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.31
if !used_locs.insert(active_attrib.location as u32 + column) {
return Ok(());
}
}
}
let columns = match active_attrib.type_ {
constants::FLOAT_MAT2 => 2,
constants::FLOAT_MAT3 => 3,
constants::FLOAT_MAT4 => 4,
_ => 1,
};
for column in 0..columns {
if !used_locs.insert(active_attrib.location as u32 + column) {
for active_uniform in &*link_info.active_uniforms {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.41
if !used_names.insert(&*active_uniform.base_name) {
return Ok(());
}
}
@ -144,6 +156,7 @@ impl WebGLProgram {
self.linked.set(link_info.linked);
*self.active_attribs.borrow_mut() = link_info.active_attribs;
*self.active_uniforms.borrow_mut() = link_info.active_uniforms;
Ok(())
}
@ -151,6 +164,10 @@ impl WebGLProgram {
Ref::map(self.active_attribs.borrow(), |attribs| &**attribs)
}
pub fn active_uniforms(&self) -> Ref<[ActiveUniformInfo]> {
Ref::map(self.active_uniforms.borrow(), |uniforms| &**uniforms)
}
/// glValidateProgram
pub fn validate(&self) -> WebGLResult<()> {
if self.is_deleted() {
@ -232,10 +249,8 @@ impl WebGLProgram {
return Err(WebGLError::InvalidOperation);
}
let name = to_name_in_compiled_shader(&name);
self.renderer
.send(WebGLCommand::BindAttribLocation(self.id, index, name))
.send(WebGLCommand::BindAttribLocation(self.id, index, name.into()))
.unwrap();
Ok(())
}
@ -244,15 +259,14 @@ impl WebGLProgram {
if self.is_deleted() {
return Err(WebGLError::InvalidValue);
}
let (sender, receiver) = webgl_channel().unwrap();
self.renderer
.send(WebGLCommand::GetActiveUniform(self.id, index, sender))
.unwrap();
receiver.recv().unwrap().map(|(size, ty, name)| {
let name = DOMString::from(from_name_in_compiled_shader(&name));
WebGLActiveInfo::new(self.global().as_window(), size, ty, name)
})
let uniforms = self.active_uniforms.borrow();
let data = uniforms.get(index as usize).ok_or(WebGLError::InvalidValue)?;
Ok(WebGLActiveInfo::new(
self.global().as_window(),
data.size.unwrap_or(1),
data.type_,
data.name().into(),
))
}
/// glGetActiveAttrib
@ -298,7 +312,10 @@ impl WebGLProgram {
}
/// glGetUniformLocation
pub fn get_uniform_location(&self, name: DOMString) -> WebGLResult<Option<i32>> {
pub fn get_uniform_location(
&self,
name: DOMString,
) -> WebGLResult<Option<DomRoot<WebGLUniformLocation>>> {
if !self.is_linked() || self.is_deleted() {
return Err(WebGLError::InvalidOperation);
}
@ -307,17 +324,37 @@ impl WebGLProgram {
}
// Check if the name is reserved
if name.starts_with("webgl") || name.starts_with("_webgl_") {
if name.starts_with("gl_") {
return Ok(None);
}
let name = to_name_in_compiled_shader(&name);
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#GLSL_CONSTRUCTS
if name.starts_with("webgl_") || name.starts_with("_webgl_") {
return Ok(None);
}
let (size, type_) = {
let (base_name, array_index) = match parse_uniform_name(&name) {
Some((name, index)) if index.map_or(true, |i| i >= 0) => (name, index),
_ => return Ok(None),
};
let uniforms = self.active_uniforms.borrow();
match uniforms.iter().find(|attrib| &*attrib.base_name == base_name) {
Some(uniform) if array_index.is_none() || array_index < uniform.size => {
(uniform.size.map(|size| size - array_index.unwrap_or_default()), uniform.type_)
},
_ => return Ok(None),
}
};
let (sender, receiver) = webgl_channel().unwrap();
self.renderer
.send(WebGLCommand::GetUniformLocation(self.id, name, sender))
.send(WebGLCommand::GetUniformLocation(self.id, name.into(), sender))
.unwrap();
Ok(receiver.recv().unwrap())
let location = receiver.recv().unwrap();
Ok(Some(WebGLUniformLocation::new(self.global().as_window(), location, self.id, size, type_)))
}
/// glGetProgramInfoLog
@ -358,3 +395,13 @@ impl Drop for WebGLProgram {
self.delete();
}
}
fn parse_uniform_name(name: &str) -> Option<(&str, Option<i32>)> {
if !name.ends_with(']') {
return Some((name, None));
}
let bracket_pos = name[..name.len() - 1].rfind('[')?;
let index = name[(bracket_pos + 1)..(name.len() - 1)].parse::<i32>().ok()?;
Some((&name[..bracket_pos], Some(index)))
}

View file

@ -425,6 +425,21 @@ impl WebGLRenderingContext {
}
}
fn with_location<F>(&self, location: Option<&WebGLUniformLocation>, f: F)
where
F: FnOnce(&WebGLUniformLocation) -> WebGLResult<()>,
{
let location = match location {
Some(loc) => loc,
None => return,
};
match self.current_program.get() {
Some(ref program) if program.id() == location.program_id() => {}
_ => return self.webgl_error(InvalidOperation),
}
handle_potential_webgl_error!(self, f(location));
}
fn tex_parameter(&self, target: u32, name: u32, value: TexParameterValue) {
let texture = match target {
constants::TEXTURE_2D |
@ -528,38 +543,6 @@ impl WebGLRenderingContext {
}
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
// https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml
// https://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf#nameddest=section-2.10.4
fn validate_uniform_parameters<T>(&self,
uniform: Option<&WebGLUniformLocation>,
uniform_type: UniformSetterType,
data: &[T]) -> bool {
let uniform = match uniform {
Some(uniform) => uniform,
None => return false,
};
let program = self.current_program.get();
match program {
Some(ref program) if program.id() == uniform.program_id() => {},
_ => {
self.webgl_error(InvalidOperation);
return false;
},
};
// TODO(emilio): Get more complex uniform info from ANGLE, and use it to
// properly validate that the uniform setter type is compatible with the
// uniform type, and that the uniform size matches.
if data.len() % uniform_type.element_count() != 0 {
self.webgl_error(InvalidOperation);
return false;
}
true
}
// https://en.wikipedia.org/wiki/Relative_luminance
#[inline]
fn luminance(r: u8, g: u8, b: u8) -> u8 {
@ -2693,12 +2676,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
Int32Value(program.attached_shaders().map(|shaders| shaders.len() as i32).unwrap_or(0))
}
constants::ACTIVE_ATTRIBUTES => Int32Value(program.active_attribs().len() as i32),
constants::ACTIVE_UNIFORMS => {
// FIXME(nox): We'll need to cache that on the DOM side at some point.
let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetProgramActiveUniforms(program.id(), sender));
Int32Value(receiver.recv().unwrap())
}
constants::ACTIVE_UNIFORMS => Int32Value(program.active_uniforms().len() as i32),
_ => {
self.webgl_error(InvalidEnum);
NullValue()
@ -2767,9 +2745,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
program: &WebGLProgram,
name: DOMString,
) -> Option<DomRoot<WebGLUniformLocation>> {
handle_potential_webgl_error!(self, program.get_uniform_location(name), None).map(|location| {
WebGLUniformLocation::new(self.global().as_window(), location, program.id())
})
handle_potential_webgl_error!(self, program.get_uniform_location(name), None)
}
#[allow(unsafe_code)]
@ -3171,75 +3147,145 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform1f(&self,
location: Option<&WebGLUniformLocation>,
val: f32) {
if self.validate_uniform_parameters(location, UniformSetterType::Float, &[val]) {
self.send_command(WebGLCommand::Uniform1f(location.unwrap().id(), val))
}
fn Uniform1f(
&self,
location: Option<&WebGLUniformLocation>,
val: f32,
) {
self.with_location(location, |location| {
match location.type_() {
constants::BOOL | constants::FLOAT => {}
_ => return Err(InvalidOperation),
}
self.send_command(WebGLCommand::Uniform1f(location.id(), val));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform1i(&self,
location: Option<&WebGLUniformLocation>,
val: i32) {
if self.validate_uniform_parameters(location, UniformSetterType::Int, &[val]) {
self.send_command(WebGLCommand::Uniform1i(location.unwrap().id(), val))
}
fn Uniform1i(
&self,
location: Option<&WebGLUniformLocation>,
val: i32,
) {
self.with_location(location, |location| {
match location.type_() {
constants::BOOL | constants::INT => {}
constants::SAMPLER_2D | constants::SAMPLER_CUBE => {
if val < 0 || val as u32 >= self.limits.max_combined_texture_image_units {
return Err(InvalidValue);
}
}
_ => return Err(InvalidOperation),
}
self.send_command(WebGLCommand::Uniform1i(location.id(), val));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform1iv(
&self,
location: Option<&WebGLUniformLocation>,
v: Int32ArrayOrLongSequence,
val: Int32ArrayOrLongSequence,
) {
let v = match v {
Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
Int32ArrayOrLongSequence::LongSequence(v) => v,
};
if self.validate_uniform_parameters(location, UniformSetterType::Int, &v) {
self.send_command(WebGLCommand::Uniform1iv(location.unwrap().id(), v))
}
self.with_location(location, |location| {
match location.type_() {
constants::BOOL | constants::INT | constants::SAMPLER_2D | constants::SAMPLER_CUBE => {}
_ => return Err(InvalidOperation),
}
let val = match val {
Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
Int32ArrayOrLongSequence::LongSequence(v) => v,
};
if val.is_empty() {
return Err(InvalidValue);
}
if location.size().is_none() && val.len() != 1 {
return Err(InvalidOperation);
}
match location.type_() {
constants::SAMPLER_2D | constants::SAMPLER_CUBE => {
for &v in val.iter().take(cmp::min(location.size().unwrap_or(1) as usize, val.len())) {
if v < 0 || v as u32 >= self.limits.max_combined_texture_image_units {
return Err(InvalidValue);
}
}
}
_ => {}
}
self.send_command(WebGLCommand::Uniform1iv(location.id(), val));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform1fv(
&self,
location: Option<&WebGLUniformLocation>,
v: Float32ArrayOrUnrestrictedFloatSequence,
val: Float32ArrayOrUnrestrictedFloatSequence,
) {
let v = match v {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if self.validate_uniform_parameters(location, UniformSetterType::Float, &v) {
self.send_command(WebGLCommand::Uniform1fv(location.unwrap().id(), v));
}
self.with_location(location, |location| {
match location.type_() {
constants::BOOL | constants::FLOAT => {}
_ => return Err(InvalidOperation),
}
let val = match val {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if val.is_empty() {
return Err(InvalidValue);
}
if location.size().is_none() && val.len() != 1 {
return Err(InvalidOperation);
}
self.send_command(WebGLCommand::Uniform1fv(location.id(), val));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform2f(&self,
location: Option<&WebGLUniformLocation>,
x: f32, y: f32) {
if self.validate_uniform_parameters(location, UniformSetterType::FloatVec2, &[x, y]) {
self.send_command(WebGLCommand::Uniform2f(location.unwrap().id(), x, y));
}
fn Uniform2f(
&self,
location: Option<&WebGLUniformLocation>,
x: f32,
y: f32,
) {
self.with_location(location, |location| {
match location.type_() {
constants::BOOL_VEC2 | constants::FLOAT_VEC2 => {}
_ => return Err(InvalidOperation),
}
self.send_command(WebGLCommand::Uniform2f(location.id(), x, y));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform2fv(
&self,
location: Option<&WebGLUniformLocation>,
v: Float32ArrayOrUnrestrictedFloatSequence,
val: Float32ArrayOrUnrestrictedFloatSequence,
) {
let v = match v {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if self.validate_uniform_parameters(location, UniformSetterType::FloatVec2, &v) {
self.send_command(WebGLCommand::Uniform2fv(location.unwrap().id(), v));
}
self.with_location(location, |location| {
match location.type_() {
constants::BOOL_VEC2 | constants::FLOAT_VEC2 => {}
_ => return Err(InvalidOperation),
}
let val = match val {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if val.len() < 2 || val.len() % 2 != 0 {
return Err(InvalidValue);
}
if location.size().is_none() && val.len() != 2 {
return Err(InvalidOperation);
}
self.send_command(WebGLCommand::Uniform2fv(location.id(), val));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@ -3249,26 +3295,40 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
x: i32,
y: i32,
) {
if self.validate_uniform_parameters(location,
UniformSetterType::IntVec2,
&[x, y]) {
self.send_command(WebGLCommand::Uniform2i(location.unwrap().id(), x, y));
}
self.with_location(location, |location| {
match location.type_() {
constants::BOOL_VEC2 | constants::INT_VEC2 => {}
_ => return Err(InvalidOperation),
}
self.send_command(WebGLCommand::Uniform2i(location.id(), x, y));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform2iv(
&self,
location: Option<&WebGLUniformLocation>,
v: Int32ArrayOrLongSequence,
val: Int32ArrayOrLongSequence,
) {
let v = match v {
Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
Int32ArrayOrLongSequence::LongSequence(v) => v,
};
if self.validate_uniform_parameters(location, UniformSetterType::IntVec2, &v) {
self.send_command(WebGLCommand::Uniform2iv(location.unwrap().id(), v));
}
self.with_location(location, |location| {
match location.type_() {
constants::BOOL_VEC2 | constants::INT_VEC2 => {}
_ => return Err(InvalidOperation),
}
let val = match val {
Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
Int32ArrayOrLongSequence::LongSequence(v) => v,
};
if val.len() < 2 || val.len() % 2 != 0 {
return Err(InvalidValue);
}
if location.size().is_none() && val.len() != 2 {
return Err(InvalidOperation);
}
self.send_command(WebGLCommand::Uniform2iv(location.id(), val));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@ -3279,52 +3339,84 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
y: f32,
z: f32,
) {
if self.validate_uniform_parameters(location,
UniformSetterType::FloatVec3,
&[x, y, z]) {
self.send_command(WebGLCommand::Uniform3f(location.unwrap().id(), x, y, z));
}
self.with_location(location, |location| {
match location.type_() {
constants::BOOL_VEC3 | constants::FLOAT_VEC3 => {}
_ => return Err(InvalidOperation),
}
self.send_command(WebGLCommand::Uniform3f(location.id(), x, y, z));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform3fv(
&self,
location: Option<&WebGLUniformLocation>,
v: Float32ArrayOrUnrestrictedFloatSequence,
val: Float32ArrayOrUnrestrictedFloatSequence,
) {
let v = match v {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if self.validate_uniform_parameters(location, UniformSetterType::FloatVec3, &v) {
self.send_command(WebGLCommand::Uniform3fv(location.unwrap().id(), v))
}
self.with_location(location, |location| {
match location.type_() {
constants::BOOL_VEC3 | constants::FLOAT_VEC3 => {}
_ => return Err(InvalidOperation),
}
let val = match val {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if val.len() < 3 || val.len() % 3 != 0 {
return Err(InvalidValue);
}
if location.size().is_none() && val.len() != 3 {
return Err(InvalidOperation);
}
self.send_command(WebGLCommand::Uniform3fv(location.id(), val));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform3i(&self,
location: Option<&WebGLUniformLocation>,
x: i32, y: i32, z: i32) {
if self.validate_uniform_parameters(location,
UniformSetterType::IntVec3,
&[x, y, z]) {
self.send_command(WebGLCommand::Uniform3i(location.unwrap().id(), x, y, z))
}
fn Uniform3i(
&self,
location: Option<&WebGLUniformLocation>,
x: i32,
y: i32,
z: i32,
) {
self.with_location(location, |location| {
match location.type_() {
constants::BOOL_VEC3 | constants::INT_VEC3 => {}
_ => return Err(InvalidOperation),
}
self.send_command(WebGLCommand::Uniform3i(location.id(), x, y, z));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform3iv(
&self,
location: Option<&WebGLUniformLocation>,
v: Int32ArrayOrLongSequence,
val: Int32ArrayOrLongSequence,
) {
let v = match v {
Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
Int32ArrayOrLongSequence::LongSequence(v) => v,
};
if self.validate_uniform_parameters(location, UniformSetterType::IntVec3, &v) {
self.send_command(WebGLCommand::Uniform3iv(location.unwrap().id(), v))
}
self.with_location(location, |location| {
match location.type_() {
constants::BOOL_VEC3 | constants::INT_VEC3 => {}
_ => return Err(InvalidOperation),
}
let val = match val {
Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
Int32ArrayOrLongSequence::LongSequence(v) => v,
};
if val.len() < 3 || val.len() % 3 != 0 {
return Err(InvalidValue);
}
if location.size().is_none() && val.len() != 3 {
return Err(InvalidOperation);
}
self.send_command(WebGLCommand::Uniform3iv(location.id(), val));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@ -3336,11 +3428,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
z: i32,
w: i32,
) {
if self.validate_uniform_parameters(location,
UniformSetterType::IntVec4,
&[x, y, z, w]) {
self.send_command(WebGLCommand::Uniform4i(location.unwrap().id(), x, y, z, w))
}
self.with_location(location, |location| {
match location.type_() {
constants::BOOL_VEC4 | constants::INT_VEC4 => {}
_ => return Err(InvalidOperation),
}
self.send_command(WebGLCommand::Uniform4i(location.id(), x, y, z, w));
Ok(())
});
}
@ -3348,15 +3443,26 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
fn Uniform4iv(
&self,
location: Option<&WebGLUniformLocation>,
v: Int32ArrayOrLongSequence,
val: Int32ArrayOrLongSequence,
) {
let v = match v {
Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
Int32ArrayOrLongSequence::LongSequence(v) => v,
};
if self.validate_uniform_parameters(location, UniformSetterType::IntVec4, &v) {
self.send_command(WebGLCommand::Uniform4iv(location.unwrap().id(), v))
}
self.with_location(location, |location| {
match location.type_() {
constants::BOOL_VEC4 | constants::INT_VEC4 => {}
_ => return Err(InvalidOperation),
}
let val = match val {
Int32ArrayOrLongSequence::Int32Array(v) => v.to_vec(),
Int32ArrayOrLongSequence::LongSequence(v) => v,
};
if val.len() < 4 || val.len() % 4 != 0 {
return Err(InvalidValue);
}
if location.size().is_none() && val.len() != 4 {
return Err(InvalidOperation);
}
self.send_command(WebGLCommand::Uniform4iv(location.id(), val));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@ -3368,26 +3474,40 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
z: f32,
w: f32,
) {
if self.validate_uniform_parameters(location,
UniformSetterType::FloatVec4,
&[x, y, z, w]) {
self.send_command(WebGLCommand::Uniform4f(location.unwrap().id(), x, y, z, w))
}
self.with_location(location, |location| {
match location.type_() {
constants::BOOL_VEC4 | constants::FLOAT_VEC4 => {}
_ => return Err(InvalidOperation),
}
self.send_command(WebGLCommand::Uniform4f(location.id(), x, y, z, w));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn Uniform4fv(
&self,
location: Option<&WebGLUniformLocation>,
v: Float32ArrayOrUnrestrictedFloatSequence,
val: Float32ArrayOrUnrestrictedFloatSequence,
) {
let v = match v {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if self.validate_uniform_parameters(location, UniformSetterType::FloatVec4, &v) {
self.send_command(WebGLCommand::Uniform4fv(location.unwrap().id(), v))
}
self.with_location(location, |location| {
match location.type_() {
constants::BOOL_VEC4 | constants::FLOAT_VEC4 => {}
_ => return Err(InvalidOperation),
}
let val = match val {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if val.len() < 4 || val.len() % 4 != 0 {
return Err(InvalidValue);
}
if location.size().is_none() && val.len() != 4 {
return Err(InvalidOperation);
}
self.send_command(WebGLCommand::Uniform4fv(location.id(), val));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@ -3395,15 +3515,29 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
&self,
location: Option<&WebGLUniformLocation>,
transpose: bool,
v: Float32ArrayOrUnrestrictedFloatSequence,
val: Float32ArrayOrUnrestrictedFloatSequence,
) {
let v = match v {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if self.validate_uniform_parameters(location, UniformSetterType::FloatMat2, &v) {
self.send_command(WebGLCommand::UniformMatrix2fv(location.unwrap().id(), transpose, v));
}
self.with_location(location, |location| {
match location.type_() {
constants::FLOAT_MAT2 => {}
_ => return Err(InvalidOperation),
}
let val = match val {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if transpose {
return Err(InvalidValue);
}
if val.len() < 4 || val.len() % 4 != 0 {
return Err(InvalidValue);
}
if location.size().is_none() && val.len() != 4 {
return Err(InvalidOperation);
}
self.send_command(WebGLCommand::UniformMatrix2fv(location.id(), val));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@ -3411,15 +3545,29 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
&self,
location: Option<&WebGLUniformLocation>,
transpose: bool,
v: Float32ArrayOrUnrestrictedFloatSequence,
val: Float32ArrayOrUnrestrictedFloatSequence,
) {
let v = match v {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if self.validate_uniform_parameters(location, UniformSetterType::FloatMat3, &v) {
self.send_command(WebGLCommand::UniformMatrix3fv(location.unwrap().id(), transpose, v));
}
self.with_location(location, |location| {
match location.type_() {
constants::FLOAT_MAT3 => {}
_ => return Err(InvalidOperation),
}
let val = match val {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if transpose {
return Err(InvalidValue);
}
if val.len() < 9 || val.len() % 9 != 0 {
return Err(InvalidValue);
}
if location.size().is_none() && val.len() != 9 {
return Err(InvalidOperation);
}
self.send_command(WebGLCommand::UniformMatrix3fv(location.id(), val));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
@ -3427,15 +3575,29 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
&self,
location: Option<&WebGLUniformLocation>,
transpose: bool,
v: Float32ArrayOrUnrestrictedFloatSequence,
val: Float32ArrayOrUnrestrictedFloatSequence,
) {
let v = match v {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if self.validate_uniform_parameters(location, UniformSetterType::FloatMat4, &v) {
self.send_command(WebGLCommand::UniformMatrix4fv(location.unwrap().id(), transpose, v));
}
self.with_location(location, |location| {
match location.type_() {
constants::FLOAT_MAT4 => {}
_ => return Err(InvalidOperation),
}
let val = match val {
Float32ArrayOrUnrestrictedFloatSequence::Float32Array(v) => v.to_vec(),
Float32ArrayOrUnrestrictedFloatSequence::UnrestrictedFloatSequence(v) => v,
};
if transpose {
return Err(InvalidValue);
}
if val.len() < 16 || val.len() % 16 != 0 {
return Err(InvalidValue);
}
if location.size().is_none() && val.len() != 16 {
return Err(InvalidOperation);
}
self.send_command(WebGLCommand::UniformMatrix4fv(location.id(), val));
Ok(())
});
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
@ -3937,39 +4099,6 @@ impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<WebGLRenderingContex
}
}
#[derive(Debug, PartialEq)]
pub enum UniformSetterType {
Int,
IntVec2,
IntVec3,
IntVec4,
Float,
FloatVec2,
FloatVec3,
FloatVec4,
FloatMat2,
FloatMat3,
FloatMat4,
}
impl UniformSetterType {
pub fn element_count(&self) -> usize {
match *self {
UniformSetterType::Int => 1,
UniformSetterType::IntVec2 => 2,
UniformSetterType::IntVec3 => 3,
UniformSetterType::IntVec4 => 4,
UniformSetterType::Float => 1,
UniformSetterType::FloatVec2 => 2,
UniformSetterType::FloatVec3 => 3,
UniformSetterType::FloatVec4 => 4,
UniformSetterType::FloatMat2 => 4,
UniformSetterType::FloatMat3 => 9,
UniformSetterType::FloatMat4 => 16,
}
}
}
#[derive(JSTraceable, MallocSizeOf)]
#[must_root]
pub struct VertexAttribs {

View file

@ -15,26 +15,38 @@ pub struct WebGLUniformLocation {
reflector_: Reflector,
id: i32,
program_id: WebGLProgramId,
size: Option<i32>,
type_: u32,
}
impl WebGLUniformLocation {
fn new_inherited(id: i32,
program_id: WebGLProgramId)
-> WebGLUniformLocation {
WebGLUniformLocation {
fn new_inherited(
id: i32,
program_id: WebGLProgramId,
size: Option<i32>,
type_: u32,
) -> Self {
Self {
reflector_: Reflector::new(),
id: id,
program_id: program_id,
id,
program_id,
size,
type_,
}
}
pub fn new(window: &Window,
id: i32,
program_id: WebGLProgramId)
-> DomRoot<WebGLUniformLocation> {
reflect_dom_object(Box::new(WebGLUniformLocation::new_inherited(id, program_id)),
window,
WebGLUniformLocationBinding::Wrap)
pub fn new(
window: &Window,
id: i32,
program_id: WebGLProgramId,
size: Option<i32>,
type_: u32,
) -> DomRoot<Self> {
reflect_dom_object(
Box::new(Self::new_inherited(id, program_id, size, type_)),
window,
WebGLUniformLocationBinding::Wrap,
)
}
pub fn id(&self) -> i32 {
@ -44,4 +56,12 @@ impl WebGLUniformLocation {
pub fn program_id(&self) -> WebGLProgramId {
self.program_id
}
pub fn size(&self) -> Option<i32> {
self.size
}
pub fn type_(&self) -> u32 {
self.type_
}
}