Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements enough WebGL spec to draw a triangle #5820

Merged
merged 1 commit into from May 3, 2015
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -52,8 +52,27 @@ pub enum Canvas2dMsg {

#[derive(Clone)]
pub enum CanvasWebGLMsg {
AttachShader(u32, u32),
BindBuffer(u32, u32),
BufferData(u32, Vec<f32>, u32),
Clear(u32),
ClearColor(f32, f32, f32, f32),
CompileShader(u32),
CreateBuffer(Sender<u32>),
CreateProgram(Sender<u32>),
CreateShader(u32, Sender<u32>),
DrawArrays(u32, i32, i32),
EnableVertexAttribArray(u32),
GetAttribLocation(u32, String, Sender<i32>),
GetShaderInfoLog(u32, Sender<String>),
GetShaderParameter(u32, u32, Sender<i32>),
GetUniformLocation(u32, String, Sender<u32>),
LinkProgram(u32),
ShaderSource(u32, Vec<String>),
Uniform4fv(u32, Vec<f32>),
UseProgram(u32),
VertexAttribPointer2f(u32, i32, bool, i32, i64),
Viewport(i32, i32, i32, i32),
}

#[derive(Clone)]
@@ -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<f32>, 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<u32>) {
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<u32>) {
let program = gl::create_program();
chan.send(program).unwrap();
}

fn create_shader(&self, shader_type: u32, chan: Sender<u32>) {
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<i32> ) {
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<String>) {
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<i32>) {
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<u32>) {
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<Vec<u8>>) {
// 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<String>) {
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<f32>) {
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<i32>) {
// TODO(ecoal95): GLContext should support a resize() method
if size.width > self.original_context_size.width ||
@@ -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;
@@ -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<WebGLBuffer> {
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
}
}
@@ -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<WebGLObject> {
reflect_dom_object(box WebGLObject::new_inherited(), global, WebGLObjectBinding::Wrap)
}
}
@@ -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<WebGLProgram> {
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
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.