mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Auto merge of #21118 - servo:webgl, r=emilio
Store vertex attribs data in DOM and optimise GetVertexAttrib This is not an extremely useful change on its own but those things need to be stored on the DOM side to implement some draw checks anyway. <!-- 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/21118) <!-- Reviewable:end -->
This commit is contained in:
commit
c90737e6c8
11 changed files with 400 additions and 376 deletions
|
@ -32,7 +32,7 @@
|
|||
use app_units::Au;
|
||||
use canvas_traits::canvas::{CanvasGradientStop, CanvasId, LinearGradientStyle, RadialGradientStyle};
|
||||
use canvas_traits::canvas::{CompositionOrBlending, LineCapStyle, LineJoinStyle, RepetitionStyle};
|
||||
use canvas_traits::webgl::{WebGLBufferId, WebGLFramebufferId, WebGLProgramId, WebGLRenderbufferId};
|
||||
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};
|
||||
|
@ -342,6 +342,7 @@ unsafe impl<A: JSTraceable, B: JSTraceable, C: JSTraceable> JSTraceable for (A,
|
|||
}
|
||||
}
|
||||
|
||||
unsafe_no_jsmanaged_fields!(ActiveAttribInfo);
|
||||
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);
|
||||
|
|
|
@ -594,7 +594,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
|
|||
}
|
||||
|
||||
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
|
||||
fn LinkProgram(&self, program: Option<&WebGLProgram>) {
|
||||
fn LinkProgram(&self, program: &WebGLProgram) {
|
||||
self.base.LinkProgram(program)
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,13 @@ impl OESVertexArrayObjectMethods for OESVertexArrayObject {
|
|||
self.ctx.send_command(WebGLCommand::CreateVertexArray(sender));
|
||||
|
||||
let result = receiver.recv().unwrap();
|
||||
result.map(|vao_id| WebGLVertexArrayObjectOES::new(&self.global(), vao_id))
|
||||
result.map(|vao_id| {
|
||||
WebGLVertexArrayObjectOES::new(
|
||||
&self.global(),
|
||||
vao_id,
|
||||
self.ctx.limits().max_vertex_attribs,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/
|
||||
|
@ -69,8 +75,8 @@ impl OESVertexArrayObjectMethods for OESVertexArrayObject {
|
|||
}
|
||||
|
||||
// Remove VAO references from buffers
|
||||
for (_, &(_, ref buffer)) in vao.bound_attrib_buffers().borrow().iter() {
|
||||
if let Some(ref buffer) = *buffer {
|
||||
for attrib_data in &*vao.vertex_attribs().borrow() {
|
||||
if let Some(buffer) = attrib_data.buffer() {
|
||||
buffer.remove_vao_reference(vao.id());
|
||||
}
|
||||
}
|
||||
|
@ -94,9 +100,9 @@ impl OESVertexArrayObjectMethods for OESVertexArrayObject {
|
|||
fn BindVertexArrayOES(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
|
||||
if let Some(bound_vao) = self.bound_vao.get() {
|
||||
// Store buffers attached to attrib pointers
|
||||
bound_vao.bound_attrib_buffers().set_from(&self.ctx.bound_attrib_buffers());
|
||||
for (_, (_, ref buffer)) in bound_vao.bound_attrib_buffers().borrow().iter() {
|
||||
if let Some(ref buffer) = *buffer {
|
||||
bound_vao.vertex_attribs().clone_from(&self.ctx.vertex_attribs());
|
||||
for attrib_data in &*bound_vao.vertex_attribs().borrow() {
|
||||
if let Some(buffer) = attrib_data.buffer() {
|
||||
buffer.add_vao_reference(bound_vao.id());
|
||||
}
|
||||
}
|
||||
|
@ -119,13 +125,13 @@ impl OESVertexArrayObjectMethods for OESVertexArrayObject {
|
|||
self.bound_vao.set(Some(&vao));
|
||||
|
||||
// Restore WebGLRenderingContext current bindings
|
||||
self.ctx.bound_attrib_buffers().set_from(&vao.bound_attrib_buffers());
|
||||
self.ctx.vertex_attribs().clone_from(&vao.vertex_attribs());
|
||||
let element_array = vao.bound_buffer_element_array();
|
||||
self.ctx.set_bound_buffer_element_array(element_array.as_ref().map(|buffer| &**buffer));
|
||||
} else {
|
||||
self.ctx.send_command(WebGLCommand::BindVertexArray(None));
|
||||
self.bound_vao.set(None);
|
||||
self.ctx.bound_attrib_buffers().clear();
|
||||
self.ctx.vertex_attribs().clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
* 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::{WebGLCommand, WebGLError, WebGLMsgSender, WebGLProgramId, WebGLResult};
|
||||
use canvas_traits::webgl::webgl_channel;
|
||||
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 dom::bindings::cell::DomRefCell;
|
||||
use dom::bindings::codegen::Bindings::WebGLProgramBinding;
|
||||
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
|
||||
use dom::bindings::reflector::{DomObject, reflect_dom_object};
|
||||
|
@ -16,7 +18,7 @@ use dom::webglrenderingcontext::MAX_UNIFORM_AND_ATTRIBUTE_LEN;
|
|||
use dom::webglshader::WebGLShader;
|
||||
use dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use std::cell::Cell;
|
||||
use std::cell::{Cell, Ref};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct WebGLProgram {
|
||||
|
@ -29,46 +31,7 @@ pub struct WebGLProgram {
|
|||
vertex_shader: MutNullableDom<WebGLShader>,
|
||||
#[ignore_malloc_size_of = "Defined in ipc-channel"]
|
||||
renderer: WebGLMsgSender,
|
||||
}
|
||||
|
||||
/// ANGLE adds a `_u` prefix to variable names:
|
||||
///
|
||||
/// https://chromium.googlesource.com/angle/angle/+/855d964bd0d05f6b2cb303f625506cf53d37e94f
|
||||
///
|
||||
/// To avoid hard-coding this we would need to use the `sh::GetAttributes` and `sh::GetUniforms`
|
||||
/// API to look up the `x.name` and `x.mappedName` members,
|
||||
/// then build a data structure for bi-directional lookup (so either linear scan or two hashmaps).
|
||||
/// Even then, this would probably only support plain variable names like "foo".
|
||||
/// Strings passed to e.g. `GetUniformLocation` can be expressions like "foo[0].bar",
|
||||
/// with the mapping for that "bar" name in yet another part of ANGLE’s API.
|
||||
const ANGLE_NAME_PREFIX: &'static str = "_u";
|
||||
|
||||
fn to_name_in_compiled_shader(s: &str) -> String {
|
||||
map_dot_separated(s, |s, mapped| {
|
||||
mapped.push_str(ANGLE_NAME_PREFIX);
|
||||
mapped.push_str(s);
|
||||
})
|
||||
}
|
||||
|
||||
fn from_name_in_compiled_shader(s: &str) -> String {
|
||||
map_dot_separated(s, |s, mapped| {
|
||||
mapped.push_str(if s.starts_with(ANGLE_NAME_PREFIX) {
|
||||
&s[ANGLE_NAME_PREFIX.len()..]
|
||||
} else {
|
||||
s
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn map_dot_separated<F: Fn(&str, &mut String)>(s: &str, f: F) -> String {
|
||||
let mut iter = s.split('.');
|
||||
let mut mapped = String::new();
|
||||
f(iter.next().unwrap(), &mut mapped);
|
||||
for s in iter {
|
||||
mapped.push('.');
|
||||
f(s, &mut mapped);
|
||||
}
|
||||
mapped
|
||||
active_attribs: DomRefCell<Box<[ActiveAttribInfo]>>,
|
||||
}
|
||||
|
||||
impl WebGLProgram {
|
||||
|
@ -84,6 +47,7 @@ impl WebGLProgram {
|
|||
fragment_shader: Default::default(),
|
||||
vertex_shader: Default::default(),
|
||||
renderer: renderer,
|
||||
active_attribs: DomRefCell::new(vec![].into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,7 +106,7 @@ impl WebGLProgram {
|
|||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
self.linked.set(false);
|
||||
self.link_called.set(true);
|
||||
*self.active_attribs.borrow_mut() = vec![].into();
|
||||
|
||||
match self.fragment_shader.get() {
|
||||
Some(ref shader) if shader.successfully_compiled() => {},
|
||||
|
@ -154,22 +118,16 @@ impl WebGLProgram {
|
|||
_ => return Ok(()), // callers use gl.LINK_STATUS to check link errors
|
||||
}
|
||||
|
||||
self.linked.set(true);
|
||||
self.renderer.send(WebGLCommand::LinkProgram(self.id)).unwrap();
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.renderer.send(WebGLCommand::LinkProgram(self.id, sender)).unwrap();
|
||||
let link_info = receiver.recv().unwrap();
|
||||
self.linked.set(link_info.linked);
|
||||
*self.active_attribs.borrow_mut() = link_info.active_attribs;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// glUseProgram
|
||||
pub fn use_program(&self) -> WebGLResult<()> {
|
||||
if self.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
if !self.linked.get() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
||||
self.renderer.send(WebGLCommand::UseProgram(self.id)).unwrap();
|
||||
Ok(())
|
||||
pub fn active_attribs(&self) -> Ref<[ActiveAttribInfo]> {
|
||||
Ref::map(self.active_attribs.borrow(), |attribs| &**attribs)
|
||||
}
|
||||
|
||||
/// glValidateProgram
|
||||
|
@ -281,19 +239,18 @@ impl WebGLProgram {
|
|||
if self.is_deleted() {
|
||||
return Err(WebGLError::InvalidValue);
|
||||
}
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.renderer
|
||||
.send(WebGLCommand::GetActiveAttrib(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 attribs = self.active_attribs.borrow();
|
||||
let data = attribs.get(index as usize).ok_or(WebGLError::InvalidValue)?;
|
||||
Ok(WebGLActiveInfo::new(
|
||||
self.global().as_window(),
|
||||
data.size,
|
||||
data.type_,
|
||||
data.name.clone().into(),
|
||||
))
|
||||
}
|
||||
|
||||
/// glGetAttribLocation
|
||||
pub fn get_attrib_location(&self, name: DOMString) -> WebGLResult<Option<i32>> {
|
||||
pub fn get_attrib_location(&self, name: DOMString) -> WebGLResult<i32> {
|
||||
if !self.is_linked() || self.is_deleted() {
|
||||
return Err(WebGLError::InvalidOperation);
|
||||
}
|
||||
|
@ -303,21 +260,20 @@ impl WebGLProgram {
|
|||
|
||||
// Check if the name is reserved
|
||||
if name.starts_with("gl_") {
|
||||
return Ok(None);
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#GLSL_CONSTRUCTS
|
||||
if name.starts_with("webgl_") || name.starts_with("_webgl_") {
|
||||
return Ok(None);
|
||||
return Ok(-1);
|
||||
}
|
||||
|
||||
let name = to_name_in_compiled_shader(&name);
|
||||
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.renderer
|
||||
.send(WebGLCommand::GetAttribLocation(self.id, name, sender))
|
||||
.unwrap();
|
||||
Ok(receiver.recv().unwrap())
|
||||
let location = self.active_attribs
|
||||
.borrow()
|
||||
.iter()
|
||||
.find(|attrib| attrib.name == &*name)
|
||||
.map_or(-1, |attrib| attrib.location);
|
||||
Ok(location)
|
||||
}
|
||||
|
||||
/// glGetUniformLocation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
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::{DOMToTextureCommand, Parameter};
|
||||
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};
|
||||
|
@ -193,7 +193,7 @@ pub struct WebGLRenderingContext {
|
|||
bound_texture_unit: Cell<u32>,
|
||||
bound_buffer_array: MutNullableDom<WebGLBuffer>,
|
||||
bound_buffer_element_array: MutNullableDom<WebGLBuffer>,
|
||||
bound_attrib_buffers: BoundAttribBuffers,
|
||||
vertex_attribs: VertexAttribs,
|
||||
current_program: MutNullableDom<WebGLProgram>,
|
||||
#[ignore_malloc_size_of = "Because it's small"]
|
||||
current_vertex_attrib_0: Cell<(f32, f32, f32, f32)>,
|
||||
|
@ -234,6 +234,7 @@ impl WebGLRenderingContext {
|
|||
share_mode: ctx_data.share_mode,
|
||||
webgl_version,
|
||||
glsl_version: ctx_data.glsl_version,
|
||||
vertex_attribs: VertexAttribs::new(ctx_data.limits.max_vertex_attribs),
|
||||
limits: ctx_data.limits,
|
||||
canvas: Dom::from_ref(canvas),
|
||||
last_error: Cell::new(None),
|
||||
|
@ -244,7 +245,6 @@ impl WebGLRenderingContext {
|
|||
bound_texture_unit: Cell::new(constants::TEXTURE0),
|
||||
bound_buffer_array: MutNullableDom::new(None),
|
||||
bound_buffer_element_array: MutNullableDom::new(None),
|
||||
bound_attrib_buffers: Default::default(),
|
||||
bound_renderbuffer: MutNullableDom::new(None),
|
||||
current_program: MutNullableDom::new(None),
|
||||
current_vertex_attrib_0: Cell::new((0f32, 0f32, 0f32, 1f32)),
|
||||
|
@ -312,8 +312,8 @@ impl WebGLRenderingContext {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn bound_attrib_buffers(&self) -> &BoundAttribBuffers {
|
||||
&self.bound_attrib_buffers
|
||||
pub fn vertex_attribs(&self) -> &VertexAttribs {
|
||||
&self.vertex_attribs
|
||||
}
|
||||
|
||||
pub fn bound_buffer_element_array(&self) -> Option<DomRoot<WebGLBuffer>> {
|
||||
|
@ -2075,7 +2075,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
}
|
||||
|
||||
// Remove deleted buffer from bound attrib buffers.
|
||||
self.bound_attrib_buffers.remove_buffer(buffer);
|
||||
self.vertex_attribs.delete_buffer(buffer);
|
||||
|
||||
// Delete buffer.
|
||||
handle_object_deletion!(self, self.bound_buffer_array, buffer,
|
||||
|
@ -2202,13 +2202,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.2
|
||||
let buffers = self.bound_attrib_buffers.borrow();
|
||||
if buffers.iter().any(|(_, &(enabled, ref buffer))| enabled && buffer.is_none()) {
|
||||
return self.webgl_error(InvalidOperation);
|
||||
}
|
||||
}
|
||||
handle_potential_webgl_error!(self, self.vertex_attribs.validate_for_draw(), return);
|
||||
|
||||
if !self.validate_framebuffer_complete() {
|
||||
return;
|
||||
|
@ -2277,13 +2271,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.2
|
||||
let buffers = self.bound_attrib_buffers.borrow();
|
||||
if buffers.iter().any(|(_, &(enabled, ref buffer))| enabled && buffer.is_none()) {
|
||||
return self.webgl_error(InvalidOperation);
|
||||
}
|
||||
}
|
||||
handle_potential_webgl_error!(self, self.vertex_attribs.validate_for_draw(), return);
|
||||
|
||||
if !self.validate_framebuffer_complete() {
|
||||
return;
|
||||
|
@ -2299,7 +2287,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
return self.webgl_error(InvalidValue);
|
||||
}
|
||||
|
||||
self.bound_attrib_buffers.enabled(attrib_id, true);
|
||||
self.vertex_attribs.enabled_as_array(attrib_id, true);
|
||||
self.send_command(WebGLCommand::EnableVertexAttribArray(attrib_id));
|
||||
}
|
||||
|
||||
|
@ -2309,7 +2297,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
return self.webgl_error(InvalidValue);
|
||||
}
|
||||
|
||||
self.bound_attrib_buffers.enabled(attrib_id, false);
|
||||
self.vertex_attribs.enabled_as_array(attrib_id, false);
|
||||
self.send_command(WebGLCommand::DisableVertexAttribArray(attrib_id));
|
||||
}
|
||||
|
||||
|
@ -2326,18 +2314,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
|
||||
fn GetActiveAttrib(&self, program: &WebGLProgram, index: u32) -> Option<DomRoot<WebGLActiveInfo>> {
|
||||
match program.get_active_attrib(index) {
|
||||
Ok(ret) => Some(ret),
|
||||
Err(e) => {
|
||||
self.webgl_error(e);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
handle_potential_webgl_error!(self, program.get_active_attrib(index).map(Some), None)
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
|
||||
fn GetAttribLocation(&self, program: &WebGLProgram, name: DOMString) -> i32 {
|
||||
handle_potential_webgl_error!(self, program.get_attrib_location(name), None).unwrap_or(-1)
|
||||
handle_potential_webgl_error!(self, program.get_attrib_location(name), -1)
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
|
@ -2509,17 +2491,32 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
#[allow(unsafe_code)]
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
|
||||
unsafe fn GetProgramParameter(&self, _: *mut JSContext, program: &WebGLProgram, param: u32) -> JSVal {
|
||||
match handle_potential_webgl_error!(self, ProgramParameter::from_u32(param), return NullValue()) {
|
||||
ProgramParameter::Bool(param) => {
|
||||
// FIXME(nox): INVALID_OPERATION if program comes from a different context.
|
||||
match param {
|
||||
constants::DELETE_STATUS => BooleanValue(program.is_deleted()),
|
||||
constants::LINK_STATUS => BooleanValue(program.is_linked()),
|
||||
constants::VALIDATE_STATUS => {
|
||||
// FIXME(nox): This could be cached on the DOM side when we call validateProgram
|
||||
// but I'm not sure when the value should be reset.
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
self.send_command(WebGLCommand::GetProgramParameterBool(program.id(), param, sender));
|
||||
self.send_command(WebGLCommand::GetProgramValidateStatus(program.id(), sender));
|
||||
BooleanValue(receiver.recv().unwrap())
|
||||
}
|
||||
ProgramParameter::Int(param) => {
|
||||
constants::ATTACHED_SHADERS => {
|
||||
// FIXME(nox): This allocates a vector and roots a couple of shaders for nothing.
|
||||
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::GetProgramParameterInt(program.id(), param, sender));
|
||||
self.send_command(WebGLCommand::GetProgramActiveUniforms(program.id(), sender));
|
||||
Int32Value(receiver.recv().unwrap())
|
||||
}
|
||||
_ => {
|
||||
self.webgl_error(InvalidEnum);
|
||||
NullValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2591,43 +2588,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 {
|
||||
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();
|
||||
[x, y, z, w]
|
||||
} else {
|
||||
let (sender, receiver) = webgl_channel().unwrap();
|
||||
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());
|
||||
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()
|
||||
value.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.bound_attrib_buffers.get(index) {
|
||||
buffer.to_jsval(cx, jsval.handle_mut());
|
||||
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()
|
||||
}
|
||||
return jsval.get();
|
||||
}
|
||||
|
||||
match handle_potential_webgl_error!(self, VertexAttrib::from_u32(param), return NullValue()) {
|
||||
VertexAttrib::Bool(param) => {
|
||||
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());
|
||||
// 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()
|
||||
_ => {
|
||||
self.webgl_error(InvalidEnum);
|
||||
NullValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2638,10 +2636,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
|
||||
|
@ -2956,12 +2956,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
|
||||
fn LinkProgram(&self, program: Option<&WebGLProgram>) {
|
||||
if let Some(program) = program {
|
||||
if let Err(e) = program.link() {
|
||||
self.webgl_error(e);
|
||||
}
|
||||
}
|
||||
fn LinkProgram(&self, program: &WebGLProgram) {
|
||||
// FIXME(nox): INVALID_OPERATION if program comes from a different context.
|
||||
handle_potential_webgl_error!(self, program.link());
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
|
||||
|
@ -3245,11 +3242,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
|||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
|
||||
fn UseProgram(&self, program: Option<&WebGLProgram>) {
|
||||
if let Some(program) = program {
|
||||
match program.use_program() {
|
||||
Ok(()) => self.current_program.set(Some(program)),
|
||||
Err(e) => self.webgl_error(e),
|
||||
if program.is_deleted() || !program.is_linked() {
|
||||
return self.webgl_error(InvalidOperation);
|
||||
}
|
||||
}
|
||||
self.send_command(WebGLCommand::UseProgram(program.map(|p| p.id())));
|
||||
self.current_program.set(program);
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
|
||||
|
@ -3328,49 +3326,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.bound_attrib_buffers.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
|
||||
|
@ -3805,48 +3784,137 @@ impl UniformSetterType {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default, JSTraceable, MallocSizeOf)]
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
#[must_root]
|
||||
pub struct BoundAttribBuffers {
|
||||
elements: DomRefCell<FnvHashMap<u32, (bool, Option<Dom<WebGLBuffer>>)>>,
|
||||
pub struct VertexAttribs {
|
||||
attribs: DomRefCell<Box<[VertexAttribData]>>,
|
||||
}
|
||||
|
||||
impl BoundAttribBuffers {
|
||||
impl VertexAttribs {
|
||||
pub fn new(max: u32) -> Self {
|
||||
// High-end GPUs have 16 of those, let's just use a boxed slice.
|
||||
Self { attribs: DomRefCell::new(vec![Default::default(); max as usize].into()) }
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
self.elements.borrow_mut().clear()
|
||||
for attrib in &mut **self.attribs.borrow_mut() {
|
||||
*attrib = Default::default();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_from(&self, other: &BoundAttribBuffers) {
|
||||
*self.elements.borrow_mut() = other.elements.borrow().clone();
|
||||
pub fn clone_from(&self, other: &Self) {
|
||||
self.attribs.borrow_mut().clone_from_slice(&other.attribs.borrow());
|
||||
}
|
||||
|
||||
pub fn borrow(&self) -> Ref<FnvHashMap<u32, (bool, Option<Dom<WebGLBuffer>>)>> {
|
||||
self.elements.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(())
|
||||
}
|
||||
|
||||
fn remove_buffer(&self, buffer: &WebGLBuffer) {
|
||||
self.elements.borrow_mut().retain(|_, v| {
|
||||
v.1.as_ref().map_or(true, |b| b.id() != buffer.id())
|
||||
})
|
||||
pub fn borrow(&self) -> Ref<[VertexAttribData]> {
|
||||
Ref::map(self.attribs.borrow(), |attribs| &**attribs)
|
||||
}
|
||||
|
||||
fn get(&self, index: u32) -> Option<Ref<WebGLBuffer>> {
|
||||
ref_filter_map(self.elements.borrow(), |elements| {
|
||||
elements.get(&index).and_then(|&(_, ref buffer)| {
|
||||
buffer.as_ref().map(|b| &**b)
|
||||
})
|
||||
})
|
||||
fn delete_buffer(&self, buffer: &WebGLBuffer) {
|
||||
for attrib in &mut **self.attribs.borrow_mut() {
|
||||
if attrib.buffer().map_or(false, |b| b.id() == buffer.id()) {
|
||||
attrib.buffer = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enabled(&self, index: u32, value: bool) {
|
||||
let mut elements = self.elements.borrow_mut();
|
||||
let pair = elements.entry(index).or_insert((false, None));
|
||||
pair.0 = value;
|
||||
fn get(&self, index: u32) -> Option<Ref<VertexAttribData>> {
|
||||
ref_filter_map(self.attribs.borrow(), |attribs| attribs.get(index as usize))
|
||||
}
|
||||
|
||||
fn bind_buffer(&self, index: u32, buffer: &WebGLBuffer) {
|
||||
let mut elements = self.elements.borrow_mut();
|
||||
let pair = elements.entry(index).or_insert((false, None));
|
||||
pair.1 = Some(Dom::from_ref(buffer));
|
||||
fn enabled_as_array(&self, index: u32, value: bool) {
|
||||
self.attribs.borrow_mut()[index as usize].enabled_as_array = value;
|
||||
}
|
||||
|
||||
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()) {
|
||||
return Err(InvalidOperation);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use dom::bindings::root::{DomRoot, MutNullableDom};
|
|||
use dom::globalscope::GlobalScope;
|
||||
use dom::webglbuffer::WebGLBuffer;
|
||||
use dom::webglobject::WebGLObject;
|
||||
use dom::webglrenderingcontext::BoundAttribBuffers;
|
||||
use dom::webglrenderingcontext::VertexAttribs;
|
||||
use dom_struct::dom_struct;
|
||||
use std::cell::Cell;
|
||||
|
||||
|
@ -19,30 +19,36 @@ pub struct WebGLVertexArrayObjectOES {
|
|||
id: WebGLVertexArrayId,
|
||||
ever_bound: Cell<bool>,
|
||||
is_deleted: Cell<bool>,
|
||||
bound_attrib_buffers: BoundAttribBuffers,
|
||||
vertex_attribs: VertexAttribs,
|
||||
bound_buffer_element_array: MutNullableDom<WebGLBuffer>,
|
||||
}
|
||||
|
||||
impl WebGLVertexArrayObjectOES {
|
||||
fn new_inherited(id: WebGLVertexArrayId) -> WebGLVertexArrayObjectOES {
|
||||
fn new_inherited(id: WebGLVertexArrayId, max_vertex_attribs: u32) -> Self {
|
||||
Self {
|
||||
webgl_object_: WebGLObject::new_inherited(),
|
||||
id: id,
|
||||
ever_bound: Cell::new(false),
|
||||
is_deleted: Cell::new(false),
|
||||
bound_attrib_buffers: Default::default(),
|
||||
vertex_attribs: VertexAttribs::new(max_vertex_attribs),
|
||||
bound_buffer_element_array: MutNullableDom::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope, id: WebGLVertexArrayId) -> DomRoot<WebGLVertexArrayObjectOES> {
|
||||
reflect_dom_object(Box::new(WebGLVertexArrayObjectOES::new_inherited(id)),
|
||||
global,
|
||||
WebGLVertexArrayObjectOESBinding::Wrap)
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
id: WebGLVertexArrayId,
|
||||
max_vertex_attribs: u32,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(WebGLVertexArrayObjectOES::new_inherited(id, max_vertex_attribs)),
|
||||
global,
|
||||
WebGLVertexArrayObjectOESBinding::Wrap,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn bound_attrib_buffers(&self) -> &BoundAttribBuffers {
|
||||
&self.bound_attrib_buffers
|
||||
pub fn vertex_attribs(&self) -> &VertexAttribs {
|
||||
&self.vertex_attribs
|
||||
}
|
||||
|
||||
pub fn id(&self) -> WebGLVertexArrayId {
|
||||
|
|
|
@ -597,7 +597,7 @@ interface WebGLRenderingContextBase
|
|||
[WebGLHandlesContextLoss] GLboolean isShader(WebGLShader? shader);
|
||||
[WebGLHandlesContextLoss] GLboolean isTexture(WebGLTexture? texture);
|
||||
void lineWidth(GLfloat width);
|
||||
void linkProgram(WebGLProgram? program);
|
||||
void linkProgram(WebGLProgram program);
|
||||
void pixelStorei(GLenum pname, GLint param);
|
||||
void polygonOffset(GLfloat factor, GLfloat units);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue