From 375d769f56476275a2b6c4e62f0fd4ed1545cecf Mon Sep 17 00:00:00 2001 From: Diego Marcos Date: Sat, 2 May 2015 21:22:28 -0500 Subject: [PATCH] servo: Merge #5820 - Implements enough WebGL spec to draw a triangle (from dmarcos:firstTriangle); r=jdm This is WIP. still have to clean up the code a little bit but I wanted to show the progress. I got really excited when I saw my first triangle on screen ```./mach run tests/ref/webgl-context/triangle.html``` ![firsttriangle](https://cloud.githubusercontent.com/assets/39342/7313736/e3fdb41e-ea11-11e4-8c63-78523cd9dcc7.png) Source-Repo: https://github.com/servo/servo Source-Revision: b43a2ed80714131db4c92a51c0046245aa43da11 --- servo/components/canvas/canvas_msg.rs | 19 ++ servo/components/canvas/webgl_paint_task.rs | 125 +++++++++- servo/components/script/dom/mod.rs | 5 + servo/components/script/dom/webglbuffer.rs | 38 +++ servo/components/script/dom/webglobject.rs | 26 +++ servo/components/script/dom/webglprogram.rs | 38 +++ .../script/dom/webglrenderingcontext.rs | 217 +++++++++++++++++- servo/components/script/dom/webglshader.rs | 39 ++++ .../script/dom/webgluniformlocation.rs | 38 +++ .../script/dom/webidls/WebGLBuffer.webidl | 7 + .../script/dom/webidls/WebGLObject.webidl | 7 + .../script/dom/webidls/WebGLProgram.webidl | 7 + .../dom/webidls/WebGLRenderingContext.webidl | 118 +++++----- .../script/dom/webidls/WebGLShader.webidl | 7 + .../dom/webidls/WebGLUniformLocation.webidl | 7 + servo/tests/html/test_webgl_triangle.html | 108 +++++++++ 16 files changed, 736 insertions(+), 70 deletions(-) create mode 100644 servo/components/script/dom/webglbuffer.rs create mode 100644 servo/components/script/dom/webglobject.rs create mode 100644 servo/components/script/dom/webglprogram.rs create mode 100644 servo/components/script/dom/webglshader.rs create mode 100644 servo/components/script/dom/webgluniformlocation.rs create mode 100644 servo/components/script/dom/webidls/WebGLBuffer.webidl create mode 100644 servo/components/script/dom/webidls/WebGLObject.webidl create mode 100644 servo/components/script/dom/webidls/WebGLProgram.webidl create mode 100644 servo/components/script/dom/webidls/WebGLShader.webidl create mode 100644 servo/components/script/dom/webidls/WebGLUniformLocation.webidl create mode 100644 servo/tests/html/test_webgl_triangle.html diff --git a/servo/components/canvas/canvas_msg.rs b/servo/components/canvas/canvas_msg.rs index 6399302161b8..aa0df80eb226 100644 --- a/servo/components/canvas/canvas_msg.rs +++ b/servo/components/canvas/canvas_msg.rs @@ -52,8 +52,27 @@ pub enum Canvas2dMsg { #[derive(Clone)] pub enum CanvasWebGLMsg { + AttachShader(u32, u32), + BindBuffer(u32, u32), + BufferData(u32, Vec, u32), Clear(u32), ClearColor(f32, f32, f32, f32), + CompileShader(u32), + CreateBuffer(Sender), + CreateProgram(Sender), + CreateShader(u32, Sender), + DrawArrays(u32, i32, i32), + EnableVertexAttribArray(u32), + GetAttribLocation(u32, String, Sender), + GetShaderInfoLog(u32, Sender), + GetShaderParameter(u32, u32, Sender), + GetUniformLocation(u32, String, Sender), + LinkProgram(u32), + ShaderSource(u32, Vec), + Uniform4fv(u32, Vec), + UseProgram(u32), + VertexAttribPointer2f(u32, i32, bool, i32, i64), + Viewport(i32, i32, i32, i32), } #[derive(Clone)] diff --git a/servo/components/canvas/webgl_paint_task.rs b/servo/components/canvas/webgl_paint_task.rs index 97e711b67188..bfb97c9e0762 100644 --- a/servo/components/canvas/webgl_paint_task.rs +++ b/servo/components/canvas/webgl_paint_task.rs @@ -11,6 +11,7 @@ use gleam::gl::types::{GLsizei}; use util::task::spawn_named; use std::borrow::ToOwned; +use std::slice::bytes::copy_memory; use std::sync::mpsc::{channel, Sender}; use util::vec::byte_swap; use offscreen_gl_context::{GLContext, GLContextAttributes}; @@ -74,8 +75,29 @@ impl WebGLPaintTask { match port.recv().unwrap() { CanvasMsg::WebGL(message) => { match message { + CanvasWebGLMsg::AttachShader(program_id, shader_id) => painter.attach_shader(program_id, shader_id), + CanvasWebGLMsg::BindBuffer(buffer_type, buffer_id) => painter.bind_buffer(buffer_type, buffer_id), + CanvasWebGLMsg::BufferData(buffer_type, data, usage) => painter.buffer_data(buffer_type, data, usage), CanvasWebGLMsg::Clear(mask) => painter.clear(mask), CanvasWebGLMsg::ClearColor(r, g, b, a) => painter.clear_color(r, g, b, a), + CanvasWebGLMsg::CreateBuffer(chan) => painter.create_buffer(chan), + CanvasWebGLMsg::DrawArrays(mode, first, count) => painter.draw_arrays(mode, first, count), + CanvasWebGLMsg::EnableVertexAttribArray(attrib_id) => painter.enable_vertex_attrib_array(attrib_id), + CanvasWebGLMsg::GetAttribLocation(program_id, name, chan) => painter.get_attrib_location(program_id, name, chan), + CanvasWebGLMsg::GetShaderInfoLog(shader_id, chan) => painter.get_shader_info_log(shader_id, chan), + CanvasWebGLMsg::GetShaderParameter(shader_id, param_id, chan) => painter.get_shader_parameter(shader_id, param_id, chan), + CanvasWebGLMsg::GetUniformLocation(program_id, name, chan) => painter.get_uniform_location(program_id, name, chan), + CanvasWebGLMsg::CompileShader(shader_id) => painter.compile_shader(shader_id), + CanvasWebGLMsg::CreateProgram(chan) => painter.create_program(chan), + CanvasWebGLMsg::CreateShader(shader_type, chan) => painter.create_shader(shader_type, chan), + CanvasWebGLMsg::LinkProgram(program_id) => painter.link_program(program_id), + CanvasWebGLMsg::ShaderSource(shader_id, source) => painter.shader_source(shader_id, source), + CanvasWebGLMsg::Uniform4fv(uniform_id, data) => painter.uniform_4fv(uniform_id, data), + CanvasWebGLMsg::UseProgram(program_id) => painter.use_program(program_id), + CanvasWebGLMsg::VertexAttribPointer2f(attrib_id, size, normalized, stride, offset) => { + painter.vertex_attrib_pointer_f32(attrib_id, size, normalized, stride, offset); + }, + CanvasWebGLMsg::Viewport(x, y, width, height) => painter.viewport(x, y, width, height), } }, CanvasMsg::Common(message) => { @@ -93,6 +115,18 @@ impl WebGLPaintTask { Ok(chan) } + fn attach_shader(&self, program_id: u32, shader_id: u32) { + gl::attach_shader(program_id, shader_id); + } + + fn bind_buffer(&self, buffer_type: u32, buffer_id: u32) { + gl::bind_buffer(buffer_type, buffer_id); + } + + fn buffer_data(&self, buffer_type: u32, data: Vec, usage: u32) { + gl::buffer_data(buffer_type, &data, usage); + } + fn clear(&self, mask: u32) { gl::clear(mask); } @@ -101,19 +135,104 @@ impl WebGLPaintTask { gl::clear_color(r, g, b, a); } + fn create_buffer(&self, chan: Sender) { + let buffers = gl::gen_buffers(1); + chan.send(buffers[0]).unwrap(); + } + + fn compile_shader(&self, shader_id: u32) { + gl::compile_shader(shader_id); + } + + fn create_program(&self, chan: Sender) { + let program = gl::create_program(); + chan.send(program).unwrap(); + } + + fn create_shader(&self, shader_type: u32, chan: Sender) { + let shader = gl::create_shader(shader_type); + chan.send(shader).unwrap(); + } + + fn draw_arrays(&self, mode: u32, first: i32, count: i32) { + gl::draw_arrays(mode, first, count); + } + + fn enable_vertex_attrib_array(&self, attrib_id: u32) { + gl::enable_vertex_attrib_array(attrib_id); + } + + fn get_attrib_location(&self, program_id: u32, name: String, chan: Sender ) { + let attrib_location = gl::get_attrib_location(program_id, name.as_slice()); + chan.send(attrib_location).unwrap(); + } + + fn get_shader_info_log(&self, shader_id: u32, chan: Sender) { + let info = gl::get_shader_info_log(shader_id); + chan.send(info).unwrap(); + } + + fn get_shader_parameter(&self, shader_id: u32, param_id: u32, chan: Sender) { + let parameter = gl::get_shader_iv(shader_id, param_id); + chan.send(parameter as i32).unwrap(); + } + + fn get_uniform_location(&self, program_id: u32, name: String, chan: Sender) { + let uniform_location = gl::get_uniform_location(program_id, name.as_slice()); + chan.send(uniform_location as u32).unwrap(); + } + + fn link_program(&self, program_id: u32) { + gl::link_program(program_id); + } + fn send_pixel_contents(&mut self, chan: Sender>) { // FIXME(#5652, dmarcos) Instead of a readback strategy we have // to layerize the canvas + let width = self.size.width as usize; + let height = self.size.height as usize; let mut pixels = gl::read_pixels(0, 0, - self.size.width as gl::GLsizei, - self.size.height as gl::GLsizei, - gl::RGBA, gl::UNSIGNED_BYTE); + self.size.width as gl::GLsizei, + self.size.height as gl::GLsizei, + gl::RGBA, gl::UNSIGNED_BYTE); + // flip image vertically (texture is upside down) + let orig_pixels = pixels.clone(); + let stride = width * 4; + for y in 0..height { + let dst_start = y * stride; + let src_start = (height - y - 1) * stride; + let src_slice = &orig_pixels[src_start .. src_start + stride]; + copy_memory(&mut pixels[dst_start .. dst_start + stride], + &src_slice[..stride]); + } // rgba -> bgra byte_swap(&mut pixels); chan.send(pixels).unwrap(); } + fn shader_source(&self, shader_id: u32, source_lines: Vec) { + let mut lines: Vec<&[u8]> = source_lines.iter().map(|line| line.as_bytes()).collect(); + gl::shader_source(shader_id, lines.as_mut_slice()); + } + + fn uniform_4fv(&self, uniform_id: u32, data: Vec) { + gl::uniform_4f(uniform_id as i32, data[0], data[1], data[2], data[3]); + } + + fn use_program(&self, program_id: u32) { + gl::use_program(program_id); + } + + fn vertex_attrib_pointer_f32(&self, attrib_id: u32, size: i32, + normalized: bool, stride: i32, offset: i64) { + gl::vertex_attrib_pointer_f32(attrib_id, size, normalized, stride, offset as u32); + } + + fn viewport(&self, x: i32, y: i32, width: i32, height: i32) { + gl::viewport(x, y, width, height); + } + fn recreate(&mut self, size: Size2D) { // TODO(ecoal95): GLContext should support a resize() method if size.width > self.original_context_size.width || diff --git a/servo/components/script/dom/mod.rs b/servo/components/script/dom/mod.rs index 00b7a05d348d..8c78cdb14208 100644 --- a/servo/components/script/dom/mod.rs +++ b/servo/components/script/dom/mod.rs @@ -325,7 +325,12 @@ pub mod urlsearchparams; pub mod userscripts; pub mod validitystate; pub mod virtualmethods; +pub mod webglobject; +pub mod webglbuffer; +pub mod webglprogram; pub mod webglrenderingcontext; +pub mod webglshader; +pub mod webgluniformlocation; pub mod websocket; pub mod window; pub mod worker; diff --git a/servo/components/script/dom/webglbuffer.rs b/servo/components/script/dom/webglbuffer.rs new file mode 100644 index 000000000000..e5535fa36ab1 --- /dev/null +++ b/servo/components/script/dom/webglbuffer.rs @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * 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 dom::bindings::codegen::Bindings::WebGLBufferBinding; +use dom::bindings::global::GlobalRef; +use dom::bindings::js::{Temporary, JSRef}; +use dom::bindings::utils::{Reflector, reflect_dom_object}; + +#[dom_struct] +pub struct WebGLBuffer { + reflector_: Reflector, + id: u32, +} + +impl WebGLBuffer { + fn new_inherited(id: u32) -> WebGLBuffer { + WebGLBuffer { + reflector_: Reflector::new(), + id: id, + } + } + + pub fn new(global: GlobalRef, id: u32) -> Temporary { + reflect_dom_object(box WebGLBuffer::new_inherited(id), global, WebGLBufferBinding::Wrap) + } +} + +pub trait WebGLBufferHelpers { + fn get_id(&self) -> u32; +} + +impl<'a> WebGLBufferHelpers for JSRef<'a, WebGLBuffer> { + fn get_id(&self) -> u32 { + self.id + } +} diff --git a/servo/components/script/dom/webglobject.rs b/servo/components/script/dom/webglobject.rs new file mode 100644 index 000000000000..7047c3fa6fd9 --- /dev/null +++ b/servo/components/script/dom/webglobject.rs @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * 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 dom::bindings::codegen::Bindings::WebGLObjectBinding; +use dom::bindings::global::GlobalRef; +use dom::bindings::js::{Temporary}; +use dom::bindings::utils::{Reflector, reflect_dom_object}; + +#[dom_struct] +pub struct WebGLObject { + reflector_: Reflector, +} + +impl WebGLObject { + fn new_inherited() -> WebGLObject { + WebGLObject { + reflector_: Reflector::new(), + } + } + + pub fn new(global: GlobalRef) -> Temporary { + reflect_dom_object(box WebGLObject::new_inherited(), global, WebGLObjectBinding::Wrap) + } +} diff --git a/servo/components/script/dom/webglprogram.rs b/servo/components/script/dom/webglprogram.rs new file mode 100644 index 000000000000..f8eeea9d7cbb --- /dev/null +++ b/servo/components/script/dom/webglprogram.rs @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * 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 dom::bindings::codegen::Bindings::WebGLProgramBinding; +use dom::bindings::global::GlobalRef; +use dom::bindings::js::{Temporary, JSRef}; +use dom::bindings::utils::{Reflector, reflect_dom_object}; + +#[dom_struct] +pub struct WebGLProgram { + reflector_: Reflector, + id: u32, +} + +impl WebGLProgram { + fn new_inherited(id: u32) -> WebGLProgram { + WebGLProgram { + reflector_: Reflector::new(), + id: id, + } + } + + pub fn new(global: GlobalRef, id: u32) -> Temporary { + reflect_dom_object(box WebGLProgram::new_inherited(id), global, WebGLProgramBinding::Wrap) + } +} + +pub trait WebGLProgramHelpers { + fn get_id(&self) -> u32; +} + +impl<'a> WebGLProgramHelpers for JSRef<'a, WebGLProgram> { + fn get_id(&self) -> u32 { + self.id + } +} diff --git a/servo/components/script/dom/webglrenderingcontext.rs b/servo/components/script/dom/webglrenderingcontext.rs index a521f469d1db..e470dca128fb 100644 --- a/servo/components/script/dom/webglrenderingcontext.rs +++ b/servo/components/script/dom/webglrenderingcontext.rs @@ -5,13 +5,23 @@ use canvas::webgl_paint_task::WebGLPaintTask; use canvas::canvas_msg::{CanvasMsg, CanvasWebGLMsg, CanvasCommonMsg}; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding; -use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; +use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{ WebGLRenderingContextMethods, WebGLRenderingContextConstants}; use dom::bindings::global::{GlobalRef, GlobalField}; use dom::bindings::js::{JS, JSRef, LayoutJS, Temporary}; use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::htmlcanvaselement::{HTMLCanvasElement}; +use dom::webglbuffer::{WebGLBuffer, WebGLBufferHelpers}; +use dom::webglshader::{WebGLShader, WebGLShaderHelpers}; +use dom::webglprogram::{WebGLProgram, WebGLProgramHelpers}; +use dom::webgluniformlocation::{WebGLUniformLocation, WebGLUniformLocationHelpers}; use geom::size::Size2D; -use std::sync::mpsc::{Sender}; +use js::jsapi::{JSContext, JSObject}; +use js::jsfriendapi::bindgen::{JS_GetFloat32ArrayData, JS_GetObjectAsArrayBufferView}; +use js::jsval::{JSVal, NullValue, Int32Value}; +use std::mem; +use std::ptr; +use std::sync::mpsc::{channel, Sender}; +use util::str::DOMString; #[dom_struct] pub struct WebGLRenderingContext { @@ -59,13 +69,212 @@ impl Drop for WebGLRenderingContext { } impl<'a> WebGLRenderingContextMethods for JSRef<'a, WebGLRenderingContext> { - fn Clear(self, mask: u32) -> () { + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 + fn AttachShader(self, program: Option>, shader: Option>) { + let program_id = match program { + Some(program) => program.get_id(), + None => return, + }; + let shader_id = match shader { + Some(shader) => shader.get_id(), + None => return, + }; + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::AttachShader(program_id, shader_id))).unwrap() + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 + fn BindBuffer(self, buffer_type: u32, buffer: Option>) { + let buffer_id = match buffer { + Some(buffer) => buffer.get_id(), + None => return, + }; + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::BindBuffer(buffer_type, buffer_id))).unwrap() + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 + #[allow(unsafe_code)] + fn BufferData(self, cx: *mut JSContext, target: u32, data: Option<*mut JSObject>, usage: u32) { + let data = match data { + Some(data) => data, + None => return, + }; + let data_vec; + unsafe { + let mut length = 0; + let mut ptr = ptr::null_mut(); + let buffer_data = JS_GetObjectAsArrayBufferView(cx, data, &mut length, &mut ptr); + if buffer_data.is_null() { + panic!("Argument data to WebGLRenderingContext.bufferdata is not a Float32Array") + } + let data_f32 = JS_GetFloat32ArrayData(buffer_data, cx); + let data_vec_length = length / mem::size_of::() as u32; + data_vec = Vec::from_raw_buf(data_f32, data_vec_length as usize); + } + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::BufferData(target, data_vec, usage))).unwrap() + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11 + fn Clear(self, mask: u32) { self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::Clear(mask))).unwrap() } - fn ClearColor(self, red: f32, green: f32, blue: f32, alpha: f32) -> (){ + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 + fn ClearColor(self, red: f32, green: f32, blue: f32, alpha: f32) { self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::ClearColor(red, green, blue, alpha))).unwrap() } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 + fn CompileShader(self, shader: Option>) { + let shader_id = match shader { + Some(shader) => shader.get_id(), + None => return, + }; + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::CompileShader(shader_id))).unwrap() + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 + fn CreateBuffer(self) -> Option> { + let (sender, receiver) = channel::(); + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::CreateBuffer(sender))).unwrap(); + Some(WebGLBuffer::new(self.global.root().r(), receiver.recv().unwrap())) + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 + fn CreateProgram(self) -> Option> { + let (sender, receiver) = channel::(); + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::CreateProgram(sender))).unwrap(); + Some(WebGLProgram::new(self.global.root().r(), receiver.recv().unwrap())) + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 + fn CreateShader(self, shader_type: u32) -> Option> { + let (sender, receiver) = channel::(); + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::CreateShader(shader_type, sender))).unwrap(); + Some(WebGLShader::new(self.global.root().r(), receiver.recv().unwrap())) + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11 + fn DrawArrays(self, mode: u32, first: i32, count: i32) { + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DrawArrays(mode, first, count))).unwrap() + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 + fn EnableVertexAttribArray(self, attrib_id: u32) { + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::EnableVertexAttribArray(attrib_id))).unwrap() + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 + fn GetAttribLocation(self, program: Option>, name: DOMString) -> i32 { + let program_id = match program { + Some(program) => program.get_id(), + None => return -1, + }; + let (sender, receiver) = channel::(); + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::GetAttribLocation(program_id, name, sender))).unwrap(); + receiver.recv().unwrap() + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 + fn GetShaderInfoLog(self, shader: Option>) -> Option { + let shader_id = match shader { + Some(shader) => shader.get_id(), + None => return None, + }; + let (sender, receiver) = channel::(); + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::GetShaderInfoLog(shader_id, sender))).unwrap(); + let info = receiver.recv().unwrap(); + Some(info) + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 + fn GetShaderParameter(self, _: *mut JSContext, shader: Option>, param_id: u32) -> JSVal { + let shader_id = match shader { + Some(shader) => shader.get_id(), + None => return NullValue(), + }; + let (sender, receiver) = channel::(); + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::GetShaderParameter(shader_id, param_id, sender))).unwrap(); + Int32Value(receiver.recv().unwrap()) + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 + fn GetUniformLocation(self, program: Option>, name: DOMString) -> Option> { + let program_id = match program { + Some(program) => program.get_id(), + None => return None, + }; + let (sender, receiver) = channel::(); + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::GetUniformLocation(program_id, name, sender))).unwrap(); + Some(WebGLUniformLocation::new(self.global.root().r(), receiver.recv().unwrap())) + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 + fn LinkProgram(self, program: Option>) { + let program_id = match program { + Some(program) => program.get_id(), + None => return, + }; + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::LinkProgram(program_id))).unwrap() + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 + fn ShaderSource(self, shader: Option>, source: DOMString) { + let shader_id = match shader { + Some(shader) => shader.get_id(), + None => return, + }; + let source_lines: Vec = source.trim() + .split(|c: char| c == '\n') + .map(|line: &str| String::from_str(line) + "\n") + .collect(); + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::ShaderSource(shader_id, source_lines))).unwrap() + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 + #[allow(unsafe_code)] + fn Uniform4fv(self, cx: *mut JSContext, uniform: Option>, data: Option<*mut JSObject>) { + let uniform_id = match uniform { + Some(uniform) => uniform.get_id(), + None => return, + }; + let data = match data { + Some(data) => data, + None => return, + }; + let data_vec: Vec; + unsafe { + let data_f32 = JS_GetFloat32ArrayData(data, cx); + data_vec = Vec::from_raw_buf(data_f32, 4); + } + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::Uniform4fv(uniform_id, data_vec))).unwrap() + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 + fn UseProgram(self, program: Option>) { + let program_id = match program { + Some(program) => program.get_id(), + None => return, + }; + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::UseProgram(program_id as u32))).unwrap() + } + + // 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) { + match data_type { + WebGLRenderingContextConstants::FLOAT => { + self.renderer.send( + CanvasMsg::WebGL(CanvasWebGLMsg::VertexAttribPointer2f(attrib_id, size, normalized, stride, offset))).unwrap() + } + _ => panic!("VertexAttribPointer: Data Type not supported") + } + + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4 + fn Viewport(self, x: i32, y: i32, width: i32, height: i32) { + self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::Viewport(x, y, width, height))).unwrap() + } } pub trait LayoutCanvasWebGLRenderingContextHelpers { diff --git a/servo/components/script/dom/webglshader.rs b/servo/components/script/dom/webglshader.rs new file mode 100644 index 000000000000..795dc8c865b3 --- /dev/null +++ b/servo/components/script/dom/webglshader.rs @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * 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 dom::bindings::codegen::Bindings::WebGLShaderBinding; +use dom::bindings::global::GlobalRef; +use dom::bindings::js::{Temporary, JSRef}; +use dom::bindings::utils::{Reflector, reflect_dom_object}; + +#[dom_struct] +pub struct WebGLShader { + reflector_: Reflector, + id: u32, +} + +impl WebGLShader { + fn new_inherited(id: u32) -> WebGLShader { + WebGLShader { + reflector_: Reflector::new(), + id: id, + } + } + + pub fn new(global: GlobalRef, id: u32) -> Temporary { + reflect_dom_object(box WebGLShader::new_inherited(id), global, WebGLShaderBinding::Wrap) + } +} + +pub trait WebGLShaderHelpers { + fn get_id(&self) -> u32; +} + +impl<'a> WebGLShaderHelpers for JSRef<'a, WebGLShader> { + fn get_id(&self) -> u32 { + self.id + } +} + diff --git a/servo/components/script/dom/webgluniformlocation.rs b/servo/components/script/dom/webgluniformlocation.rs new file mode 100644 index 000000000000..18e175f3bc26 --- /dev/null +++ b/servo/components/script/dom/webgluniformlocation.rs @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * 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 dom::bindings::codegen::Bindings::WebGLUniformLocationBinding; +use dom::bindings::global::GlobalRef; +use dom::bindings::js::{Temporary, JSRef}; +use dom::bindings::utils::{Reflector, reflect_dom_object}; + +#[dom_struct] +pub struct WebGLUniformLocation { + reflector_: Reflector, + id: u32, +} + +impl WebGLUniformLocation { + fn new_inherited(id: u32) -> WebGLUniformLocation { + WebGLUniformLocation { + reflector_: Reflector::new(), + id: id, + } + } + + pub fn new(global: GlobalRef, id: u32) -> Temporary { + reflect_dom_object(box WebGLUniformLocation::new_inherited(id), global, WebGLUniformLocationBinding::Wrap) + } +} + +pub trait WebGLUniformLocationHelpers { + fn get_id(&self) -> u32; +} + +impl<'a> WebGLUniformLocationHelpers for JSRef<'a, WebGLUniformLocation> { + fn get_id(&self) -> u32 { + self.id + } +} diff --git a/servo/components/script/dom/webidls/WebGLBuffer.webidl b/servo/components/script/dom/webidls/WebGLBuffer.webidl new file mode 100644 index 000000000000..418e9ef231e2 --- /dev/null +++ b/servo/components/script/dom/webidls/WebGLBuffer.webidl @@ -0,0 +1,7 @@ +// +// WebGL IDL definitions scraped from the Khronos specification: +// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.4 +// + +interface WebGLBuffer : WebGLObject { +}; diff --git a/servo/components/script/dom/webidls/WebGLObject.webidl b/servo/components/script/dom/webidls/WebGLObject.webidl new file mode 100644 index 000000000000..468f3762b44b --- /dev/null +++ b/servo/components/script/dom/webidls/WebGLObject.webidl @@ -0,0 +1,7 @@ +// +// WebGL IDL definitions scraped from the Khronos specification: +// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.3 +// + +interface WebGLObject { +}; diff --git a/servo/components/script/dom/webidls/WebGLProgram.webidl b/servo/components/script/dom/webidls/WebGLProgram.webidl new file mode 100644 index 000000000000..80b2d535931b --- /dev/null +++ b/servo/components/script/dom/webidls/WebGLProgram.webidl @@ -0,0 +1,7 @@ +// +// WebGL IDL definitions scraped from the Khronos specification: +// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.6 +// + +interface WebGLProgram : WebGLObject { +}; diff --git a/servo/components/script/dom/webidls/WebGLRenderingContext.webidl b/servo/components/script/dom/webidls/WebGLRenderingContext.webidl index aa1d35356354..0aeb3077ee55 100644 --- a/servo/components/script/dom/webidls/WebGLRenderingContext.webidl +++ b/servo/components/script/dom/webidls/WebGLRenderingContext.webidl @@ -1,4 +1,3 @@ -// AUTOGENERATED FILE -- DO NOT EDIT -- SEE Makefile // // WebGL IDL definitions scraped from the Khronos specification: // https://www.khronos.org/registry/webgl/specs/latest/ @@ -34,30 +33,15 @@ dictionary WebGLContextAttributes { GLboolean failIfMajorPerformanceCaveat = false; }; -//interface WebGLObject { -//}; - -//interface WebGLBuffer : WebGLObject { -//}; - //interface WebGLFramebuffer : WebGLObject { //}; -//interface WebGLProgram : WebGLObject { -//}; - //interface WebGLRenderbuffer : WebGLObject { //}; -//interface WebGLShader : WebGLObject { -//}; - //interface WebGLTexture : WebGLObject { //}; -//interface WebGLUniformLocation { -//}; - //interface WebGLActiveInfo { // readonly attribute GLint size; // readonly attribute GLenum type; @@ -75,18 +59,18 @@ interface WebGLRenderingContextBase { /* ClearBufferMask */ - //const GLenum DEPTH_BUFFER_BIT = 0x00000100; - //const GLenum STENCIL_BUFFER_BIT = 0x00000400; + const GLenum DEPTH_BUFFER_BIT = 0x00000100; + const GLenum STENCIL_BUFFER_BIT = 0x00000400; const GLenum COLOR_BUFFER_BIT = 0x00004000; /* BeginMode */ - //const GLenum POINTS = 0x0000; - //const GLenum LINES = 0x0001; - //const GLenum LINE_LOOP = 0x0002; - //const GLenum LINE_STRIP = 0x0003; - //const GLenum TRIANGLES = 0x0004; - //const GLenum TRIANGLE_STRIP = 0x0005; - //const GLenum TRIANGLE_FAN = 0x0006; + const GLenum POINTS = 0x0000; + const GLenum LINES = 0x0001; + const GLenum LINE_LOOP = 0x0002; + const GLenum LINE_STRIP = 0x0003; + const GLenum TRIANGLES = 0x0004; + const GLenum TRIANGLE_STRIP = 0x0005; + const GLenum TRIANGLE_FAN = 0x0006; /* AlphaFunction (not supported in ES20) */ /* NEVER */ @@ -141,14 +125,14 @@ interface WebGLRenderingContextBase //const GLenum BLEND_COLOR = 0x8005; /* Buffer Objects */ - //const GLenum ARRAY_BUFFER = 0x8892; - //const GLenum ELEMENT_ARRAY_BUFFER = 0x8893; - //const GLenum ARRAY_BUFFER_BINDING = 0x8894; - //const GLenum ELEMENT_ARRAY_BUFFER_BINDING = 0x8895; + const GLenum ARRAY_BUFFER = 0x8892; + const GLenum ELEMENT_ARRAY_BUFFER = 0x8893; + const GLenum ARRAY_BUFFER_BINDING = 0x8894; + const GLenum ELEMENT_ARRAY_BUFFER_BINDING = 0x8895; - //const GLenum STREAM_DRAW = 0x88E0; - //const GLenum STATIC_DRAW = 0x88E4; - //const GLenum DYNAMIC_DRAW = 0x88E8; + const GLenum STREAM_DRAW = 0x88E0; + const GLenum STATIC_DRAW = 0x88E4; + const GLenum DYNAMIC_DRAW = 0x88E8; //const GLenum BUFFER_SIZE = 0x8764; //const GLenum BUFFER_USAGE = 0x8765; @@ -260,13 +244,13 @@ interface WebGLRenderingContextBase //const GLenum GENERATE_MIPMAP_HINT = 0x8192; /* DataType */ - //const GLenum BYTE = 0x1400; - //const GLenum UNSIGNED_BYTE = 0x1401; - //const GLenum SHORT = 0x1402; - //const GLenum UNSIGNED_SHORT = 0x1403; - //const GLenum INT = 0x1404; - //const GLenum UNSIGNED_INT = 0x1405; - //const GLenum FLOAT = 0x1406; + const GLenum BYTE = 0x1400; + const GLenum UNSIGNED_BYTE = 0x1401; + const GLenum SHORT = 0x1402; + const GLenum UNSIGNED_SHORT = 0x1403; + const GLenum INT = 0x1404; + const GLenum UNSIGNED_INT = 0x1405; + const GLenum FLOAT = 0x1406; /* PixelFormat */ //const GLenum DEPTH_COMPONENT = 0x1902; @@ -283,8 +267,8 @@ interface WebGLRenderingContextBase //const GLenum UNSIGNED_SHORT_5_6_5 = 0x8363; /* Shaders */ - //const GLenum FRAGMENT_SHADER = 0x8B30; - //const GLenum VERTEX_SHADER = 0x8B31; + const GLenum FRAGMENT_SHADER = 0x8B30; + const GLenum VERTEX_SHADER = 0x8B31; //const GLenum MAX_VERTEX_ATTRIBS = 0x8869; //const GLenum MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB; //const GLenum MAX_VARYING_VECTORS = 0x8DFC; @@ -430,7 +414,7 @@ interface WebGLRenderingContextBase //const GLenum IMPLEMENTATION_COLOR_READ_FORMAT = 0x8B9B; /* Shader Source */ - //const GLenum COMPILE_STATUS = 0x8B81; + const GLenum COMPILE_STATUS = 0x8B81; /* Shader Precision-Specified Types */ //const GLenum LOW_FLOAT = 0x8DF0; @@ -504,9 +488,9 @@ interface WebGLRenderingContextBase //object? getExtension(DOMString name); //void activeTexture(GLenum texture); - //void attachShader(WebGLProgram? program, WebGLShader? shader); + void attachShader(WebGLProgram? program, WebGLShader? shader); //void bindAttribLocation(WebGLProgram? program, GLuint index, DOMString name); - //void bindBuffer(GLenum target, WebGLBuffer? buffer); + void bindBuffer(GLenum target, WebGLBuffer? buffer); //void bindFramebuffer(GLenum target, WebGLFramebuffer? framebuffer); //void bindRenderbuffer(GLenum target, WebGLRenderbuffer? renderbuffer); //void bindTexture(GLenum target, WebGLTexture? texture); @@ -517,9 +501,13 @@ interface WebGLRenderingContextBase //void blendFuncSeparate(GLenum srcRGB, GLenum dstRGB, // GLenum srcAlpha, GLenum dstAlpha); - //typedef (ArrayBuffer or ArrayBufferView) BufferDataSource; + // typedef (ArrayBuffer or ArrayBufferView) BufferDataSource; //void bufferData(GLenum target, GLsizeiptr size, GLenum usage); - //void bufferData(GLenum target, BufferDataSource? data, GLenum usage); + // FIXME(dmarcos) The function below is the original function in the webIdl: + // void bufferData(GLenum target, BufferDataSource? data, GLenum usage); + // The Code genearator doesn't handle BufferDataSource so we're using 'optional object' + // in the meantime + void bufferData(GLenum target, optional object data, GLenum usage); //void bufferSubData(GLenum target, GLintptr offset, BufferDataSource? data); //[WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target); @@ -528,7 +516,7 @@ interface WebGLRenderingContextBase //void clearDepth(GLclampf depth); //void clearStencil(GLint s); //void colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); - //void compileShader(WebGLShader? shader); + void compileShader(WebGLShader? shader); //void compressedTexImage2D(GLenum target, GLint level, GLenum internalformat, // GLsizei width, GLsizei height, GLint border, @@ -544,11 +532,11 @@ interface WebGLRenderingContextBase //void copyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, // GLint x, GLint y, GLsizei width, GLsizei height); - //WebGLBuffer? createBuffer(); + WebGLBuffer? createBuffer(); //WebGLFramebuffer? createFramebuffer(); - //WebGLProgram? createProgram(); + WebGLProgram? createProgram(); //WebGLRenderbuffer? createRenderbuffer(); - //WebGLShader? createShader(GLenum type); + WebGLShader? createShader(GLenum type); //WebGLTexture? createTexture(); //void cullFace(GLenum mode); @@ -566,11 +554,11 @@ interface WebGLRenderingContextBase //void detachShader(WebGLProgram? program, WebGLShader? shader); //void disable(GLenum cap); //void disableVertexAttribArray(GLuint index); - //void drawArrays(GLenum mode, GLint first, GLsizei count); + void drawArrays(GLenum mode, GLint first, GLsizei count); //void drawElements(GLenum mode, GLsizei count, GLenum type, GLintptr offset); //void enable(GLenum cap); - //void enableVertexAttribArray(GLuint index); + void enableVertexAttribArray(GLuint index); //void finish(); //void flush(); //void framebufferRenderbuffer(GLenum target, GLenum attachment, @@ -586,7 +574,7 @@ interface WebGLRenderingContextBase //WebGLActiveInfo? getActiveUniform(WebGLProgram? program, GLuint index); //sequence? getAttachedShaders(WebGLProgram? program); - //[WebGLHandlesContextLoss] GLint getAttribLocation(WebGLProgram? program, DOMString name); + [WebGLHandlesContextLoss] GLint getAttribLocation(WebGLProgram? program, DOMString name); //any getBufferParameter(GLenum target, GLenum pname); //any getParameter(GLenum pname); @@ -598,9 +586,9 @@ interface WebGLRenderingContextBase //any getProgramParameter(WebGLProgram? program, GLenum pname); //DOMString? getProgramInfoLog(WebGLProgram? program); //any getRenderbufferParameter(GLenum target, GLenum pname); - //any getShaderParameter(WebGLShader? shader, GLenum pname); + any getShaderParameter(WebGLShader? shader, GLenum pname); //WebGLShaderPrecisionFormat? getShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype); - //DOMString? getShaderInfoLog(WebGLShader? shader); + DOMString? getShaderInfoLog(WebGLShader? shader); //DOMString? getShaderSource(WebGLShader? shader); @@ -608,7 +596,7 @@ interface WebGLRenderingContextBase //any getUniform(WebGLProgram? program, WebGLUniformLocation? location); - //WebGLUniformLocation? getUniformLocation(WebGLProgram? program, DOMString name); + WebGLUniformLocation? getUniformLocation(WebGLProgram? program, DOMString name); //any getVertexAttrib(GLuint index, GLenum pname); @@ -623,7 +611,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); @@ -635,7 +623,7 @@ interface WebGLRenderingContextBase //void sampleCoverage(GLclampf value, GLboolean invert); //void scissor(GLint x, GLint y, GLsizei width, GLsizei height); - //void shaderSource(WebGLShader? shader, DOMString source); + void shaderSource(WebGLShader? shader, DOMString source); //void stencilFunc(GLenum func, GLint ref, GLuint mask); //void stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask); @@ -682,7 +670,11 @@ interface WebGLRenderingContextBase //void uniform3iv(WebGLUniformLocation? location, Int32Array v); //void uniform3iv(WebGLUniformLocation? location, sequence v); //void uniform4f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - //void uniform4fv(WebGLUniformLocation? location, Float32Array v); + // FIXME(dmarcos) The function below is the original function in the webIdl: + // void uniform4fv(WebGLUniformLocation? location, Float32Array v); + // The Code genearator doesn't handle BufferDataSource so we're using 'optional object' + // in the meantime + void uniform4fv(WebGLUniformLocation? location, optional object v); //void uniform4fv(WebGLUniformLocation? location, sequence v); //void uniform4i(WebGLUniformLocation? location, GLint x, GLint y, GLint z, GLint w); //void uniform4iv(WebGLUniformLocation? location, Int32Array v); @@ -701,7 +693,7 @@ interface WebGLRenderingContextBase //void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, // sequence value); - //void useProgram(WebGLProgram? program); + void useProgram(WebGLProgram? program); //void validateProgram(WebGLProgram? program); //void vertexAttrib1f(GLuint indx, GLfloat x); @@ -716,10 +708,10 @@ interface WebGLRenderingContextBase //void vertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); //void vertexAttrib4fv(GLuint indx, Float32Array values); //void vertexAttrib4fv(GLuint indx, sequence values); - //void vertexAttribPointer(GLuint indx, GLint size, GLenum type, - // GLboolean normalized, GLsizei stride, GLintptr offset); + void vertexAttribPointer(GLuint indx, GLint size, GLenum type, + GLboolean normalized, GLsizei stride, GLintptr offset); - //void viewport(GLint x, GLint y, GLsizei width, GLsizei height); + void viewport(GLint x, GLint y, GLsizei width, GLsizei height); }; interface WebGLRenderingContext diff --git a/servo/components/script/dom/webidls/WebGLShader.webidl b/servo/components/script/dom/webidls/WebGLShader.webidl new file mode 100644 index 000000000000..c308e303da9e --- /dev/null +++ b/servo/components/script/dom/webidls/WebGLShader.webidl @@ -0,0 +1,7 @@ +// +// WebGL IDL definitions scraped from the Khronos specification: +// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.8 +// + +interface WebGLShader : WebGLObject { +}; diff --git a/servo/components/script/dom/webidls/WebGLUniformLocation.webidl b/servo/components/script/dom/webidls/WebGLUniformLocation.webidl new file mode 100644 index 000000000000..2331c90c9614 --- /dev/null +++ b/servo/components/script/dom/webidls/WebGLUniformLocation.webidl @@ -0,0 +1,7 @@ +// +// WebGL IDL definitions scraped from the Khronos specification: +// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.10 +// + +interface WebGLUniformLocation { +}; diff --git a/servo/tests/html/test_webgl_triangle.html b/servo/tests/html/test_webgl_triangle.html new file mode 100644 index 000000000000..b55a746b4a2b --- /dev/null +++ b/servo/tests/html/test_webgl_triangle.html @@ -0,0 +1,108 @@ + + + + + WebGL Triangle Test + + +
+ +
+ + + + +