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

Refactor WebGL implementation to move logic inside the DOM interfaces #6380

Merged
merged 4 commits into from Jul 6, 2015
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

webgl: Refactor implementation to move logic inside the DOM interfaces

This improves the encapsulation and consistency in our WebGL
implementation.

Also allows to implement new methods such as `getShaderSource()`.

It will also allow us to use `delete()` in the destructors of them (note
that we will want to keep track of them from the context).
  • Loading branch information
emilio committed Jul 6, 2015
commit b1765c68821d12a21cd304f7dffaa3bdc8f101e4
@@ -361,19 +361,35 @@ impl WebGLPaintTask {
gl::enable_vertex_attrib_array(attrib_id);
}

fn get_attrib_location(&self, program_id: u32, name: String, chan: Sender<i32> ) {
fn get_attrib_location(&self, program_id: u32, name: String, chan: Sender<Option<i32>> ) {
let attrib_location = gl::get_attrib_location(program_id, &name);

let attrib_location = if attrib_location == -1 {
None
} else {
Some(attrib_location)
};

chan.send(attrib_location).unwrap();
}

fn get_shader_info_log(&self, shader_id: u32, chan: Sender<String>) {
fn get_shader_info_log(&self, shader_id: u32, chan: Sender<Option<String>>) {
// TODO(ecoal95): Right now we always return a value, we should
// check for gl errors and return None there
let info = gl::get_shader_info_log(shader_id);
chan.send(info).unwrap();
chan.send(Some(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_shader_parameter(&self, shader_id: u32, param_id: u32, chan: Sender<WebGLShaderParameter>) {
let result = match param_id {
gl::SHADER_TYPE =>
WebGLShaderParameter::Int(gl::get_shader_iv(shader_id, param_id)),
gl::DELETE_STATUS | gl::COMPILE_STATUS =>
WebGLShaderParameter::Bool(gl::get_shader_iv(shader_id, param_id) != 0),
_ => panic!("Unexpected shader parameter type"),
};

chan.send(result).unwrap();
}

fn get_uniform_location(&self, program_id: u32, name: String, chan: Sender<Option<i32>>) {
@@ -107,9 +107,9 @@ pub enum CanvasWebGLMsg {
BindTexture(u32, u32),
DrawArrays(u32, i32, i32),
EnableVertexAttribArray(u32),
GetAttribLocation(u32, String, Sender<i32>),
GetShaderInfoLog(u32, Sender<String>),
GetShaderParameter(u32, u32, Sender<i32>),
GetShaderInfoLog(u32, Sender<Option<String>>),
GetShaderParameter(u32, u32, Sender<WebGLShaderParameter>),
GetAttribLocation(u32, String, Sender<Option<i32>>),
GetUniformLocation(u32, String, Sender<Option<i32>>),
LinkProgram(u32),
ShaderSource(u32, String),
@@ -121,6 +121,24 @@ pub enum CanvasWebGLMsg {
DrawingBufferHeight(Sender<i32>),
}

#[derive(Clone)]
pub enum WebGLError {
InvalidEnum,
InvalidOperation,
InvalidValue,
OutOfMemory,
ContextLost,
}

pub type WebGLResult<T> = Result<T, WebGLError>;

#[derive(Clone)]
pub enum WebGLShaderParameter {
Int(i32),
Bool(bool),
Invalid,
}

#[derive(Clone)]
pub enum CanvasCommonMsg {
Close,
@@ -5,35 +5,63 @@
// 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::Root;
use dom::bindings::js::{Temporary, JSRef};
use dom::bindings::utils::reflect_dom_object;
use dom::webglobject::WebGLObject;

use canvas_traits::{CanvasMsg, CanvasWebGLMsg};
use std::sync::mpsc::{channel, Sender};
use std::cell::Cell;

#[dom_struct]
pub struct WebGLBuffer {
webgl_object: WebGLObject,
id: u32,
is_deleted: Cell<bool>,
renderer: Sender<CanvasMsg>,
}

impl WebGLBuffer {
fn new_inherited(id: u32) -> WebGLBuffer {
fn new_inherited(renderer: Sender<CanvasMsg>, id: u32) -> WebGLBuffer {
WebGLBuffer {
webgl_object: WebGLObject::new_inherited(),
id: id,
is_deleted: Cell::new(false),
renderer: renderer,
}
}

pub fn new(global: GlobalRef, id: u32) -> Root<WebGLBuffer> {
reflect_dom_object(box WebGLBuffer::new_inherited(id), global, WebGLBufferBinding::Wrap)
pub fn maybe_new(global: GlobalRef, renderer: Sender<CanvasMsg>) -> Option<Root<WebGLBuffer>> {
let (sender, receiver) = channel();
renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::CreateBuffer(sender))).unwrap();
receiver.recv().unwrap()
.map(|buffer_id| WebGLBuffer::new(global, renderer, *buffer_id))
}

pub fn new(global: GlobalRef, renderer: Sender<CanvasMsg>, id: u32) -> Root<WebGLBuffer> {
reflect_dom_object(box WebGLBuffer::new_inherited(renderer, id), global, WebGLBufferBinding::Wrap)
}
}

pub trait WebGLBufferHelpers {
fn get_id(self) -> u32;
fn id(&self) -> u32;
fn bind(&self, target: u32);
fn delete(&self);
}

impl<'a> WebGLBufferHelpers for &'a WebGLBuffer {
fn get_id(self) -> u32 {
fn id(self) -> u32 {
self.id
}

fn bind(self, target: u32) {
self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::BindBuffer(target, self.id))).unwrap();
}

fn delete(self) {
if !self.is_deleted.get() {
self.is_deleted.set(true);
self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteBuffer(self.id))).unwrap();
}
}
}
@@ -9,31 +9,59 @@ use dom::bindings::js::Root;
use dom::bindings::utils::reflect_dom_object;
use dom::webglobject::WebGLObject;

use canvas_traits::{CanvasMsg, CanvasWebGLMsg};
use std::sync::mpsc::{channel, Sender};
use std::cell::Cell;

#[dom_struct]
pub struct WebGLFramebuffer {
webgl_object: WebGLObject,
id: u32,
is_deleted: Cell<bool>,
renderer: Sender<CanvasMsg>,
}

impl WebGLFramebuffer {
fn new_inherited(id: u32) -> WebGLFramebuffer {
fn new_inherited(renderer: Sender<CanvasMsg>, id: u32) -> WebGLFramebuffer {
WebGLFramebuffer {
webgl_object: WebGLObject::new_inherited(),
id: id,
is_deleted: Cell::new(false),
renderer: renderer,
}
}

pub fn new(global: GlobalRef, id: u32) -> Root<WebGLFramebuffer> {
reflect_dom_object(box WebGLFramebuffer::new_inherited(id), global, WebGLFramebufferBinding::Wrap)
pub fn maybe_new(global: GlobalRef, renderer: Sender<CanvasMsg>) -> Option<Root<WebGLFramebuffer>> {
let (sender, receiver) = channel();
renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::CreateFramebuffer(sender))).unwrap();
receiver.recv().unwrap()
.map(|fb_id| WebGLFramebuffer::new(global, renderer, *fb_id))
}

pub fn new(global: GlobalRef, renderer: Sender<CanvasMsg>, id: u32) -> Root<WebGLFramebuffer> {
reflect_dom_object(box WebGLFramebuffer::new_inherited(renderer, id), global, WebGLFramebufferBinding::Wrap)
}
}

pub trait WebGLFramebufferHelpers {
fn get_id(self) -> u32;
fn id(self) -> u32;
fn bind(self, target: u32);
fn delete(self);
}

impl<'a> WebGLFramebufferHelpers for &'a WebGLFramebuffer {
fn get_id(self) -> u32 {
impl<'a> WebGLFramebufferHelpers for JSRef<'a, WebGLFramebuffer> {
fn id(self) -> u32 {
self.id
}

fn bind(self, target: u32) {
self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::BindFramebuffer(target, self.id))).unwrap();
}

fn delete(self) {
if !self.is_deleted.get() {
self.is_deleted.set(true);
self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteFramebuffer(self.id))).unwrap();
}
}
}
@@ -13,27 +13,114 @@ use dom::webglobject::WebGLObject;
pub struct WebGLProgram {
webgl_object: WebGLObject,
id: u32,
is_deleted: Cell<bool>,
fragment_shader: MutNullableHeap<JS<WebGLShader>>,
vertex_shader: MutNullableHeap<JS<WebGLShader>>,
renderer: Sender<CanvasMsg>,
}

impl WebGLProgram {
fn new_inherited(id: u32) -> WebGLProgram {
fn new_inherited(renderer: Sender<CanvasMsg>, id: u32) -> WebGLProgram {
WebGLProgram {
webgl_object: WebGLObject::new_inherited(),
id: id,
is_deleted: Cell::new(false),
fragment_shader: Default::default(),
vertex_shader: Default::default(),
renderer: renderer,
}
}

pub fn new(global: GlobalRef, id: u32) -> Root<WebGLProgram> {
reflect_dom_object(box WebGLProgram::new_inherited(id), global, WebGLProgramBinding::Wrap)
pub fn maybe_new(global: GlobalRef, renderer: Sender<CanvasMsg>) -> Option<Root<WebGLProgram>> {
let (sender, receiver) = channel();
renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::CreateProgram(sender))).unwrap();
receiver.recv().unwrap()
.map(|program_id| WebGLProgram::new(global, renderer, *program_id))
}

pub fn new(global: GlobalRef, renderer: Sender<CanvasMsg>, id: u32) -> Root<WebGLProgram> {
reflect_dom_object(box WebGLProgram::new_inherited(renderer, id), global, WebGLProgramBinding::Wrap)
}
}

pub trait WebGLProgramHelpers {
fn get_id(self) -> u32;
fn delete(self);
fn link(self);
fn use_program(self);
fn attach_shader(self, shader: JSRef<WebGLShader>) -> WebGLResult<()>;
fn get_attrib_location(self, name: String) -> WebGLResult<Option<i32>>;
fn get_uniform_location(self, name: String) -> WebGLResult<Option<i32>>;
}

impl<'a> WebGLProgramHelpers for &'a WebGLProgram {
fn get_id(self) -> u32 {
self.id
/// glDeleteProgram
fn delete(self) {
if !self.is_deleted.get() {
self.is_deleted.set(true);
self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::DeleteProgram(self.id))).unwrap();
}
}

/// glLinkProgram
fn link(self) {
self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::LinkProgram(self.id))).unwrap();
}

/// glUseProgram
fn use_program(self) {
self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::UseProgram(self.id))).unwrap();
}

/// glAttachShader
fn attach_shader(self, shader: &'a WebGLShader) -> WebGLResult<()> {
let shader_slot = match shader.gl_type() {
constants::FRAGMENT_SHADER => &self.fragment_shader,
constants::VERTEX_SHADER => &self.vertex_shader,
_ => return Err(WebGLError::InvalidOperation),
};

// TODO(ecoal95): Differenciate between same shader already assigned and other previous
// shader.
if shader_slot.get().is_some() {
return Err(WebGLError::InvalidOperation);
}

shader_slot.set(Some(JS::from_rooted(shader)));

self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::AttachShader(self.id, shader.id()))).unwrap();

Ok(())
}

/// glGetAttribLocation
fn get_attrib_location(self, name: String) -> WebGLResult<Option<i32>> {
if name.len() > MAX_UNIFORM_AND_ATTRIBUTE_LEN {
return Err(WebGLError::InvalidValue);
}

// Check if the name is reserved
if name.starts_with("webgl") || name.starts_with("_webgl_") {
return Ok(None);
}

let (sender, receiver) = channel();
self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::GetAttribLocation(self.id, name, sender))).unwrap();
Ok(receiver.recv().unwrap())
}

/// glGetUniformLocation
fn get_uniform_location(self, name: String) -> WebGLResult<Option<i32>> {
if name.len() > MAX_UNIFORM_AND_ATTRIBUTE_LEN {
return Err(WebGLError::InvalidValue);
}

// Check if the name is reserved
if name.starts_with("webgl") || name.starts_with("_webgl_") {
return Ok(None);
}

let (sender, receiver) = channel();
self.renderer.send(CanvasMsg::WebGL(CanvasWebGLMsg::GetUniformLocation(self.id, name, sender))).unwrap();
Ok(receiver.recv().unwrap())
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.