Store vertex attribs data in DOM and optimise GetVertexAttrib

This commit is contained in:
Anthony Ramine 2018-07-03 15:22:40 +02:00
parent 0814bd6699
commit cde6023ed4
3 changed files with 143 additions and 168 deletions

View file

@ -746,8 +746,6 @@ impl WebGLImpl {
Self::get_renderbuffer_parameter(ctx.gl(), target, pname, chan),
WebGLCommand::GetFramebufferAttachmentParameter(target, attachment, pname, ref chan) =>
Self::get_framebuffer_attachment_parameter(ctx.gl(), target, attachment, pname, chan),
WebGLCommand::GetVertexAttribOffset(index, pname, ref chan) =>
Self::vertex_attrib_offset(ctx.gl(), index, pname, chan),
WebGLCommand::GetShaderPrecisionFormat(shader_type, precision_type, ref chan) =>
Self::shader_precision_format(ctx.gl(), shader_type, precision_type, chan),
WebGLCommand::GetExtensions(ref chan) =>
@ -949,56 +947,12 @@ impl WebGLImpl {
}
sender.send(value[0]).unwrap()
}
WebGLCommand::GetVertexAttribBool(index, param, ref sender) => {
// FIXME(nox): https://github.com/servo/servo/issues/20608
let mut max = [0];
unsafe {
ctx.gl().get_integer_v(gl::MAX_VERTEX_ATTRIBS, &mut max);
}
let result = if index >= max[0] as u32 {
Err(WebGLError::InvalidValue)
} else {
let mut value = [0];
unsafe {
ctx.gl().get_vertex_attrib_iv(index, param as u32, &mut value);
}
Ok(value[0] != 0)
};
sender.send(result).unwrap();
}
WebGLCommand::GetVertexAttribInt(index, param, ref sender) => {
// FIXME(nox): https://github.com/servo/servo/issues/20608
let mut max = [0];
unsafe {
ctx.gl().get_integer_v(gl::MAX_VERTEX_ATTRIBS, &mut max);
}
let result = if index >= max[0] as u32 {
Err(WebGLError::InvalidValue)
} else {
let mut value = [0];
unsafe {
ctx.gl().get_vertex_attrib_iv(index, param as u32, &mut value);
}
Ok(value[0])
};
sender.send(result).unwrap();
}
WebGLCommand::GetVertexAttribFloat4(index, param, ref sender) => {
// FIXME(nox): https://github.com/servo/servo/issues/20608
let mut max = [0];
unsafe {
ctx.gl().get_integer_v(gl::MAX_VERTEX_ATTRIBS, &mut max);
}
let result = if index >= max[0] as u32 {
Err(WebGLError::InvalidValue)
} else {
WebGLCommand::GetCurrentVertexAttrib(index, ref sender) => {
let mut value = [0.; 4];
unsafe {
ctx.gl().get_vertex_attrib_fv(index, param as u32, &mut value);
ctx.gl().get_vertex_attrib_fv(index, gl::CURRENT_VERTEX_ATTRIB, &mut value);
}
Ok(value)
};
sender.send(result).unwrap();
sender.send(value).unwrap();
}
WebGLCommand::GetTexParameterFloat(target, param, ref sender) => {
sender.send(ctx.gl().get_tex_parameter_fv(target, param as u32)).unwrap();
@ -1092,14 +1046,6 @@ impl WebGLImpl {
chan.send(()).unwrap();
}
fn vertex_attrib_offset(gl: &gl::Gl,
index: u32,
pname: u32,
chan: &WebGLSender<isize>) {
let result = gl.get_vertex_attrib_pointer_v(index, pname);
chan.send(result).unwrap();
}
fn shader_precision_format(gl: &gl::Gl,
shader_type: u32,
precision_type: u32,

View file

@ -211,7 +211,6 @@ pub enum WebGLCommand {
GetActiveUniform(WebGLProgramId, u32, WebGLSender<WebGLResult<(i32, u32, String)>>),
GetAttribLocation(WebGLProgramId, String, WebGLSender<Option<i32>>),
GetUniformLocation(WebGLProgramId, String, WebGLSender<Option<i32>>),
GetVertexAttribOffset(u32, u32, WebGLSender<isize>),
GetShaderInfoLog(WebGLShaderId, WebGLSender<String>),
GetProgramInfoLog(WebGLProgramId, WebGLSender<String>),
GetFramebufferAttachmentParameter(u32, u32, u32, WebGLSender<i32>),
@ -278,9 +277,7 @@ pub enum WebGLCommand {
GetProgramParameterInt(WebGLProgramId, ProgramParameterInt, WebGLSender<i32>),
GetShaderParameterBool(WebGLShaderId, ShaderParameterBool, WebGLSender<bool>),
GetShaderParameterInt(WebGLShaderId, ShaderParameterInt, WebGLSender<i32>),
GetVertexAttribBool(u32, VertexAttribBool, WebGLSender<WebGLResult<bool>>),
GetVertexAttribInt(u32, VertexAttribInt, WebGLSender<WebGLResult<i32>>),
GetVertexAttribFloat4(u32, VertexAttribFloat4, WebGLSender<WebGLResult<[f32; 4]>>),
GetCurrentVertexAttrib(u32, WebGLSender<[f32; 4]>),
GetTexParameterFloat(u32, TexParameterFloat, WebGLSender<f32>),
GetTexParameterInt(u32, TexParameterInt, WebGLSender<i32>),
TexParameteri(u32, TexParameterInt, i32),
@ -568,20 +565,3 @@ parameters! {
}),
}
}
parameters! {
VertexAttrib {
Bool(VertexAttribBool {
VertexAttribArrayEnabled = gl::VERTEX_ATTRIB_ARRAY_ENABLED,
VertexAttribArrayNormalized = gl::VERTEX_ATTRIB_ARRAY_NORMALIZED,
}),
Int(VertexAttribInt {
VertexAttribArraySize = gl::VERTEX_ATTRIB_ARRAY_SIZE,
VertexAttribArrayStride = gl::VERTEX_ATTRIB_ARRAY_STRIDE,
VertexAttribArrayType = gl::VERTEX_ATTRIB_ARRAY_TYPE,
}),
Float4(VertexAttribFloat4 {
CurrentVertexAttrib = gl::CURRENT_VERTEX_ATTRIB,
}),
}
}

View file

@ -5,7 +5,7 @@
use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
use canvas_traits::canvas::{byte_swap, multiply_u8_pixel};
use canvas_traits::webgl::{DOMToTextureCommand, Parameter, ProgramParameter};
use canvas_traits::webgl::{ShaderParameter, TexParameter, VertexAttrib, WebGLCommand};
use canvas_traits::webgl::{ShaderParameter, TexParameter, WebGLCommand};
use canvas_traits::webgl::{WebGLContextShareMode, WebGLError};
use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender};
use canvas_traits::webgl::{WebGLResult, WebGLSLVersion, WebGLVersion};
@ -2579,43 +2579,44 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
#[allow(unsafe_code)]
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
unsafe fn GetVertexAttrib(&self, cx: *mut JSContext, index: u32, param: u32) -> JSVal {
if index == 0 && param == constants::CURRENT_VERTEX_ATTRIB {
rooted!(in(cx) let mut result = UndefinedValue());
let data = handle_potential_webgl_error!(
self,
self.vertex_attribs.get(index).ok_or(InvalidValue),
return NullValue()
);
if param == constants::CURRENT_VERTEX_ATTRIB {
let value = if index == 0 {
let (x, y, z, w) = self.current_vertex_attrib_0.get();
let attrib = vec![x, y, z, w];
attrib.to_jsval(cx, result.handle_mut());
return result.get()
}
if param == constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING {
rooted!(in(cx) let mut jsval = NullValue());
if let Some(buffer) = self.vertex_attribs.get(index) {
buffer.to_jsval(cx, jsval.handle_mut());
}
return jsval.get();
}
match handle_potential_webgl_error!(self, VertexAttrib::from_u32(param), return NullValue()) {
VertexAttrib::Bool(param) => {
[x, y, z, w]
} else {
let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetVertexAttribBool(index, param, sender));
let value = handle_potential_webgl_error!(self, receiver.recv().unwrap(), return NullValue());
BooleanValue(value)
}
VertexAttrib::Int(param) => {
let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetVertexAttribInt(index, param, sender));
let value = handle_potential_webgl_error!(self, receiver.recv().unwrap(), return NullValue());
Int32Value(value)
}
VertexAttrib::Float4(param) => {
let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetVertexAttribFloat4(index, param, sender));
let value = handle_potential_webgl_error!(self, receiver.recv().unwrap(), return NullValue());
self.send_command(WebGLCommand::GetCurrentVertexAttrib(index, sender));
receiver.recv().unwrap()
};
// FIXME(nox): https://github.com/servo/servo/issues/20655
rooted!(in(cx) let mut result = UndefinedValue());
value.to_jsval(cx, result.handle_mut());
result.get()
return result.get();
}
match param {
constants::VERTEX_ATTRIB_ARRAY_ENABLED => BooleanValue(data.enabled_as_array),
constants::VERTEX_ATTRIB_ARRAY_SIZE => Int32Value(data.size as i32),
constants::VERTEX_ATTRIB_ARRAY_TYPE => Int32Value(data.type_ as i32),
constants::VERTEX_ATTRIB_ARRAY_NORMALIZED => BooleanValue(data.normalized),
constants::VERTEX_ATTRIB_ARRAY_STRIDE => Int32Value(data.stride as i32),
constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING => {
rooted!(in(cx) let mut jsval = NullValue());
if let Some(data) = self.vertex_attribs.get(index) {
if let Some(buffer) = data.buffer() {
buffer.to_jsval(cx, jsval.handle_mut());
}
}
jsval.get()
}
_ => {
self.webgl_error(InvalidEnum);
NullValue()
}
}
}
@ -2626,10 +2627,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
self.webgl_error(InvalidEnum);
return 0;
}
let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetVertexAttribOffset(index, pname, sender));
receiver.recv().unwrap() as i64
let data = handle_potential_webgl_error!(
self,
self.vertex_attribs.get(index).ok_or(InvalidValue),
return 0
);
data.offset as i64
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
@ -3316,49 +3319,30 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn VertexAttribPointer(&self, attrib_id: u32, size: i32, data_type: u32,
normalized: bool, stride: i32, offset: i64) {
if attrib_id >= self.limits.max_vertex_attribs {
return self.webgl_error(InvalidValue);
}
fn VertexAttribPointer(
&self,
index: u32,
size: i32,
type_: u32,
normalized: bool,
stride: i32,
offset: i64,
) {
handle_potential_webgl_error!(
self,
self.vertex_attribs.set_pointer(
index,
size,
type_,
normalized,
stride,
offset,
self.bound_buffer_array.get().as_ref().map(|buffer| &**buffer),
),
return
);
// GLES spec: If offset or stride is negative, an INVALID_VALUE error will be generated
// WebGL spec: the maximum supported stride is 255
if stride < 0 || stride > 255 || offset < 0 {
return self.webgl_error(InvalidValue);
}
if size < 1 || size > 4 {
return self.webgl_error(InvalidValue);
}
let buffer_array = match self.bound_buffer_array.get() {
Some(buffer) => buffer,
None => {
return self.webgl_error(InvalidOperation);
}
};
// stride and offset must be multiple of data_type
match data_type {
constants::BYTE | constants::UNSIGNED_BYTE => {},
constants::SHORT | constants::UNSIGNED_SHORT => {
if offset % 2 > 0 || stride % 2 > 0 {
return self.webgl_error(InvalidOperation);
}
},
constants::FLOAT => {
if offset % 4 > 0 || stride % 4 > 0 {
return self.webgl_error(InvalidOperation);
}
},
_ => return self.webgl_error(InvalidEnum),
}
self.vertex_attribs.bind_buffer(attrib_id, &buffer_array);
let msg = WebGLCommand::VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset as u32);
self.send_command(msg);
self.send_command(WebGLCommand::VertexAttribPointer(index, size, type_, normalized, stride, offset as u32));
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4
@ -3815,6 +3799,57 @@ impl VertexAttribs {
self.attribs.borrow_mut().clone_from_slice(&other.attribs.borrow());
}
pub fn set_pointer(
&self,
index: u32,
size: i32,
type_: u32,
normalized: bool,
stride: i32,
offset: i64,
buffer: Option<&WebGLBuffer>,
) -> WebGLResult<()> {
let mut attribs = self.attribs.borrow_mut();
let data = attribs.get_mut(index as usize).ok_or(InvalidValue)?;
if size < 1 || size > 4 {
return Err(InvalidValue);
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#BUFFER_OFFSET_AND_STRIDE
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#VERTEX_STRIDE
if stride < 0 || stride > 255 || offset < 0 {
return Err(InvalidValue);
}
match type_ {
constants::BYTE | constants::UNSIGNED_BYTE => {},
constants::SHORT | constants::UNSIGNED_SHORT => {
if offset % 2 > 0 || stride % 2 > 0 {
return Err(InvalidOperation);
}
},
constants::FLOAT => {
if offset % 4 > 0 || stride % 4 > 0 {
return Err(InvalidOperation);
}
},
_ => return Err(InvalidEnum),
}
let buffer = buffer.ok_or(InvalidOperation)?;
*data = VertexAttribData {
enabled_as_array: data.enabled_as_array,
size: size as u8,
type_,
normalized,
stride: stride as u8,
offset: offset as u32,
buffer: Some(Dom::from_ref(buffer)),
};
Ok(())
}
pub fn borrow(&self) -> Ref<[VertexAttribData]> {
Ref::map(self.attribs.borrow(), |attribs| &**attribs)
}
@ -3827,20 +3862,14 @@ impl VertexAttribs {
}
}
fn get(&self, index: u32) -> Option<Ref<WebGLBuffer>> {
ref_filter_map(self.attribs.borrow(), |attribs| {
attribs[index as usize].buffer.as_ref().map(|buffer| &**buffer)
})
fn get(&self, index: u32) -> Option<Ref<VertexAttribData>> {
ref_filter_map(self.attribs.borrow(), |attribs| attribs.get(index as usize))
}
fn enabled_as_array(&self, index: u32, value: bool) {
self.attribs.borrow_mut()[index as usize].enabled_as_array = value;
}
fn bind_buffer(&self, index: u32, buffer: &WebGLBuffer) {
self.attribs.borrow_mut()[index as usize].buffer = Some(Dom::from_ref(buffer));
}
fn validate_for_draw(&self) -> WebGLResult<()> {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.2
if self.borrow().iter().any(|data| data.enabled_as_array && data.buffer.is_none()) {
@ -3850,13 +3879,33 @@ impl VertexAttribs {
}
}
#[derive(Clone, Default, JSTraceable, MallocSizeOf)]
#[derive(Clone, JSTraceable, MallocSizeOf)]
#[must_root]
pub struct VertexAttribData {
enabled_as_array: bool,
size: u8,
type_: u32,
normalized: bool,
stride: u8,
offset: u32,
buffer: Option<Dom<WebGLBuffer>>,
}
impl Default for VertexAttribData {
#[allow(unrooted_must_root)]
fn default() -> Self {
Self {
enabled_as_array: false,
size: 4,
type_: constants::FLOAT,
normalized: false,
stride: 0,
offset: 0,
buffer: None,
}
}
}
impl VertexAttribData {
pub fn buffer(&self) -> Option<&WebGLBuffer> {
self.buffer.as_ref().map(|b| &**b)