mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Auto merge of #10443 - emilio:webgl-teximage2d-overload, r=jdm
webgl: Implement the pending texImage2D overload, and add more validation This is a large-ish refactor of the Texture2D code, but it should be easier to read and of course more correct. I tried to annotate every error condition with a spec paragraph. I made just a reftest to ensure this works as intended, since I expect #10373 to land pretty soon. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/10443) <!-- Reviewable:end -->
This commit is contained in:
commit
f1defb446e
15 changed files with 615 additions and 137 deletions
|
@ -23,6 +23,7 @@ pub struct WebGLProgram {
|
||||||
webgl_object: WebGLObject,
|
webgl_object: WebGLObject,
|
||||||
id: u32,
|
id: u32,
|
||||||
is_deleted: Cell<bool>,
|
is_deleted: Cell<bool>,
|
||||||
|
linked: Cell<bool>,
|
||||||
fragment_shader: MutNullableHeap<JS<WebGLShader>>,
|
fragment_shader: MutNullableHeap<JS<WebGLShader>>,
|
||||||
vertex_shader: MutNullableHeap<JS<WebGLShader>>,
|
vertex_shader: MutNullableHeap<JS<WebGLShader>>,
|
||||||
#[ignore_heap_size_of = "Defined in ipc-channel"]
|
#[ignore_heap_size_of = "Defined in ipc-channel"]
|
||||||
|
@ -35,6 +36,7 @@ impl WebGLProgram {
|
||||||
webgl_object: WebGLObject::new_inherited(),
|
webgl_object: WebGLObject::new_inherited(),
|
||||||
id: id,
|
id: id,
|
||||||
is_deleted: Cell::new(false),
|
is_deleted: Cell::new(false),
|
||||||
|
linked: Cell::new(false),
|
||||||
fragment_shader: Default::default(),
|
fragment_shader: Default::default(),
|
||||||
vertex_shader: Default::default(),
|
vertex_shader: Default::default(),
|
||||||
renderer: renderer,
|
renderer: renderer,
|
||||||
|
@ -71,19 +73,27 @@ impl WebGLProgram {
|
||||||
|
|
||||||
/// glLinkProgram
|
/// glLinkProgram
|
||||||
pub fn link(&self) {
|
pub fn link(&self) {
|
||||||
|
self.linked.set(false);
|
||||||
|
|
||||||
|
match self.fragment_shader.get() {
|
||||||
|
Some(ref shader) if shader.successfully_compiled() => {},
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.vertex_shader.get() {
|
||||||
|
Some(ref shader) if shader.successfully_compiled() => {},
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.linked.set(true);
|
||||||
|
|
||||||
self.renderer.send(CanvasMsg::WebGL(WebGLCommand::LinkProgram(self.id))).unwrap();
|
self.renderer.send(CanvasMsg::WebGL(WebGLCommand::LinkProgram(self.id))).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// glUseProgram
|
/// glUseProgram
|
||||||
pub fn use_program(&self) -> WebGLResult<()> {
|
pub fn use_program(&self) -> WebGLResult<()> {
|
||||||
match self.fragment_shader.get() {
|
if !self.linked.get() {
|
||||||
Some(ref shader) if shader.successfully_compiled() => {},
|
return Err(WebGLError::InvalidOperation);
|
||||||
_ => return Err(WebGLError::InvalidOperation),
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.vertex_shader.get() {
|
|
||||||
Some(ref shader) if shader.successfully_compiled() => {},
|
|
||||||
_ => return Err(WebGLError::InvalidOperation),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.renderer.send(CanvasMsg::WebGL(WebGLCommand::UseProgram(self.id))).unwrap();
|
self.renderer.send(CanvasMsg::WebGL(WebGLCommand::UseProgram(self.id))).unwrap();
|
||||||
|
|
|
@ -3,12 +3,12 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use canvas_traits::{CanvasCommonMsg, CanvasMsg};
|
use canvas_traits::{CanvasCommonMsg, CanvasMsg};
|
||||||
use dom::bindings::codegen::Bindings::WebGLActiveInfoBinding::WebGLActiveInfoMethods;
|
|
||||||
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
|
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
|
||||||
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{WebGLRenderingContextMethods};
|
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{WebGLRenderingContextMethods};
|
||||||
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{self, WebGLContextAttributes};
|
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{self, WebGLContextAttributes};
|
||||||
use dom::bindings::codegen::UnionTypes::ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
|
use dom::bindings::codegen::UnionTypes::ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
|
||||||
use dom::bindings::conversions::{ToJSValConvertible, array_buffer_view_to_vec_checked, array_buffer_view_to_vec};
|
use dom::bindings::conversions::{ToJSValConvertible, array_buffer_view_data_checked};
|
||||||
|
use dom::bindings::conversions::{array_buffer_view_to_vec_checked, array_buffer_view_to_vec};
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::inheritance::Castable;
|
use dom::bindings::inheritance::Castable;
|
||||||
use dom::bindings::js::{JS, LayoutJS, MutNullableHeap, Root};
|
use dom::bindings::js::{JS, LayoutJS, MutNullableHeap, Root};
|
||||||
|
@ -67,45 +67,6 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum UniformType {
|
|
||||||
Int,
|
|
||||||
IntVec2,
|
|
||||||
IntVec3,
|
|
||||||
IntVec4,
|
|
||||||
Float,
|
|
||||||
FloatVec2,
|
|
||||||
FloatVec3,
|
|
||||||
FloatVec4,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UniformType {
|
|
||||||
fn element_count(&self) -> usize {
|
|
||||||
match *self {
|
|
||||||
UniformType::Int => 1,
|
|
||||||
UniformType::IntVec2 => 2,
|
|
||||||
UniformType::IntVec3 => 3,
|
|
||||||
UniformType::IntVec4 => 4,
|
|
||||||
UniformType::Float => 1,
|
|
||||||
UniformType::FloatVec2 => 2,
|
|
||||||
UniformType::FloatVec3 => 3,
|
|
||||||
UniformType::FloatVec4 => 4,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_gl_constant(&self) -> u32 {
|
|
||||||
match *self {
|
|
||||||
UniformType::Int => constants::INT,
|
|
||||||
UniformType::IntVec2 => constants::INT_VEC2,
|
|
||||||
UniformType::IntVec3 => constants::INT_VEC3,
|
|
||||||
UniformType::IntVec4 => constants::INT_VEC4,
|
|
||||||
UniformType::Float => constants::FLOAT,
|
|
||||||
UniformType::FloatVec2 => constants::FLOAT_VEC2,
|
|
||||||
UniformType::FloatVec3 => constants::FLOAT_VEC3,
|
|
||||||
UniformType::FloatVec4 => constants::FLOAT_VEC4,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct WebGLRenderingContext {
|
pub struct WebGLRenderingContext {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
|
@ -224,7 +185,7 @@ impl WebGLRenderingContext {
|
||||||
// https://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf#nameddest=section-2.10.4
|
// https://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf#nameddest=section-2.10.4
|
||||||
fn validate_uniform_parameters<T>(&self,
|
fn validate_uniform_parameters<T>(&self,
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
type_: UniformType,
|
uniform_type: UniformSetterType,
|
||||||
data: Option<&[T]>) -> bool {
|
data: Option<&[T]>) -> bool {
|
||||||
let uniform = match uniform {
|
let uniform = match uniform {
|
||||||
Some(uniform) => uniform,
|
Some(uniform) => uniform,
|
||||||
|
@ -232,8 +193,8 @@ impl WebGLRenderingContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
let program = self.current_program.get();
|
let program = self.current_program.get();
|
||||||
let program = match program {
|
match program {
|
||||||
Some(ref program) if program.id() == uniform.program_id() => program,
|
Some(ref program) if program.id() == uniform.program_id() => {},
|
||||||
_ => {
|
_ => {
|
||||||
self.webgl_error(InvalidOperation);
|
self.webgl_error(InvalidOperation);
|
||||||
return false;
|
return false;
|
||||||
|
@ -248,28 +209,200 @@ impl WebGLRenderingContext {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(autrilla): Don't request this every time, cache it
|
// TODO(emilio): Get more complex uniform info from ANGLE, and use it to
|
||||||
let active_uniform = match program.get_active_uniform(
|
// properly validate that the uniform setter type is compatible with the
|
||||||
uniform.id() as u32) {
|
// uniform type, and that the uniform size matches.
|
||||||
Ok(active_uniform) => active_uniform,
|
if data.len() % uniform_type.element_count() != 0 {
|
||||||
Err(_) => {
|
|
||||||
self.webgl_error(InvalidOperation);
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if data.len() % type_.element_count() != 0 ||
|
|
||||||
(data.len() / type_.element_count() > active_uniform.Size() as usize) {
|
|
||||||
self.webgl_error(InvalidOperation);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if type_.as_gl_constant() != active_uniform.Type() {
|
|
||||||
self.webgl_error(InvalidOperation);
|
self.webgl_error(InvalidOperation);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_tex_image_parameters(&self,
|
||||||
|
target: u32,
|
||||||
|
level: i32,
|
||||||
|
internal_format: u32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
border: i32,
|
||||||
|
format: u32,
|
||||||
|
data_type: u32) -> bool {
|
||||||
|
// GL_INVALID_ENUM is generated if target is not GL_TEXTURE_2D,
|
||||||
|
// GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||||
|
// GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||||
|
// GL_TEXTURE_CUBE_MAP_POSITIVE_Z, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z.
|
||||||
|
let texture = match target {
|
||||||
|
constants::TEXTURE_2D
|
||||||
|
=> self.bound_texture_2d.get(),
|
||||||
|
constants::TEXTURE_CUBE_MAP_POSITIVE_X |
|
||||||
|
constants::TEXTURE_CUBE_MAP_NEGATIVE_X |
|
||||||
|
constants::TEXTURE_CUBE_MAP_POSITIVE_Y |
|
||||||
|
constants::TEXTURE_CUBE_MAP_NEGATIVE_Y |
|
||||||
|
constants::TEXTURE_CUBE_MAP_POSITIVE_Z |
|
||||||
|
constants::TEXTURE_CUBE_MAP_NEGATIVE_Z
|
||||||
|
=> self.bound_texture_cube_map.get(),
|
||||||
|
_ => {
|
||||||
|
self.webgl_error(InvalidEnum);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// If an attempt is made to call this function with no
|
||||||
|
// WebGLTexture bound, an INVALID_OPERATION error is generated.
|
||||||
|
if texture.is_none() {
|
||||||
|
self.webgl_error(InvalidOperation);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_INVALID_ENUM is generated if data_type is not an accepted value.
|
||||||
|
match data_type {
|
||||||
|
constants::UNSIGNED_BYTE |
|
||||||
|
constants::UNSIGNED_SHORT_4_4_4_4 |
|
||||||
|
constants::UNSIGNED_SHORT_5_5_5_1 |
|
||||||
|
constants::UNSIGNED_SHORT_5_6_5 => {},
|
||||||
|
_ => {
|
||||||
|
self.webgl_error(InvalidEnum);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO(emilio): GL_INVALID_VALUE may be generated if
|
||||||
|
// level is greater than log_2(max), where max is
|
||||||
|
// the returned value of GL_MAX_TEXTURE_SIZE when
|
||||||
|
// target is GL_TEXTURE_2D or GL_MAX_CUBE_MAP_TEXTURE_SIZE
|
||||||
|
// when target is not GL_TEXTURE_2D.
|
||||||
|
let is_cubic = target != constants::TEXTURE_2D;
|
||||||
|
|
||||||
|
// GL_INVALID_VALUE is generated if target is one of the
|
||||||
|
// six cube map 2D image targets and the width and height
|
||||||
|
// parameters are not equal.
|
||||||
|
if is_cubic && width != height {
|
||||||
|
self.webgl_error(InvalidValue);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_INVALID_VALUE is generated if internal_format is not an
|
||||||
|
// accepted format.
|
||||||
|
match internal_format {
|
||||||
|
constants::DEPTH_COMPONENT |
|
||||||
|
constants::ALPHA |
|
||||||
|
constants::RGB |
|
||||||
|
constants::RGBA |
|
||||||
|
constants::LUMINANCE |
|
||||||
|
constants::LUMINANCE_ALPHA => {},
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
self.webgl_error(InvalidValue);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_INVALID_OPERATION is generated if format does not
|
||||||
|
// match internal_format.
|
||||||
|
if format != internal_format {
|
||||||
|
self.webgl_error(InvalidOperation);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_INVALID_VALUE is generated if level is less than 0.
|
||||||
|
//
|
||||||
|
// GL_INVALID_VALUE is generated if width or height is less than 0
|
||||||
|
// or greater than GL_MAX_TEXTURE_SIZE when target is GL_TEXTURE_2D or
|
||||||
|
// GL_MAX_CUBE_MAP_TEXTURE_SIZE when target is not GL_TEXTURE_2D.
|
||||||
|
//
|
||||||
|
// TODO(emilio): Check limits
|
||||||
|
if width < 0 || height < 0 || level < 0 {
|
||||||
|
self.webgl_error(InvalidValue);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_INVALID_VALUE is generated if level is greater than zero and the
|
||||||
|
// texture is not power of two.
|
||||||
|
if level > 0 &&
|
||||||
|
(!(width as u32).is_power_of_two() ||
|
||||||
|
!(height as u32).is_power_of_two()) {
|
||||||
|
self.webgl_error(InvalidValue);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_INVALID_VALUE is generated if border is not 0.
|
||||||
|
if border != 0 {
|
||||||
|
self.webgl_error(InvalidValue);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_INVALID_OPERATION is generated if type is GL_UNSIGNED_SHORT_4_4_4_4 or
|
||||||
|
// GL_UNSIGNED_SHORT_5_5_5_1 and format is not GL_RGBA.
|
||||||
|
//
|
||||||
|
// GL_INVALID_OPERATION is generated if type is
|
||||||
|
// GL_UNSIGNED_SHORT_5_6_5 and format is not GL_RGB.
|
||||||
|
match data_type {
|
||||||
|
constants::UNSIGNED_SHORT_4_4_4_4 |
|
||||||
|
constants::UNSIGNED_SHORT_5_5_5_1 if format != constants::RGBA => {
|
||||||
|
self.webgl_error(InvalidOperation);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
constants::UNSIGNED_SHORT_5_6_5 if format != constants::RGB => {
|
||||||
|
self.webgl_error(InvalidOperation);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tex_image_2d(&self,
|
||||||
|
target: u32,
|
||||||
|
level: i32,
|
||||||
|
internal_format: u32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
border: i32,
|
||||||
|
format: u32,
|
||||||
|
data_type: u32,
|
||||||
|
pixels: Vec<u8>) { // NB: pixels should NOT be premultipied
|
||||||
|
// This should be validated before reaching this function
|
||||||
|
debug_assert!(self.validate_tex_image_parameters(target, level,
|
||||||
|
internal_format,
|
||||||
|
width, height,
|
||||||
|
border, format,
|
||||||
|
data_type));
|
||||||
|
|
||||||
|
let slot = match target {
|
||||||
|
constants::TEXTURE_2D
|
||||||
|
=> self.bound_texture_2d.get(),
|
||||||
|
_ => self.bound_texture_cube_map.get(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let texture = slot.as_ref().expect("No bound texture found after validation");
|
||||||
|
|
||||||
|
if format == constants::RGBA &&
|
||||||
|
data_type == constants::UNSIGNED_BYTE &&
|
||||||
|
self.texture_unpacking_settings.get().contains(PREMULTIPLY_ALPHA) {
|
||||||
|
// TODO(emilio): premultiply here.
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(emilio): Flip Y axis if necessary here
|
||||||
|
|
||||||
|
// TexImage2D depth is always equal to 1
|
||||||
|
handle_potential_webgl_error!(self, texture.initialize(target,
|
||||||
|
width as u32,
|
||||||
|
height as u32, 1,
|
||||||
|
internal_format,
|
||||||
|
level as u32));
|
||||||
|
|
||||||
|
|
||||||
|
// TODO(emilio): Invert axis, convert colorspace, premultiply alpha if requested
|
||||||
|
let msg = WebGLCommand::TexImage2D(target, level, internal_format as i32,
|
||||||
|
width, height, format, data_type, pixels);
|
||||||
|
|
||||||
|
self.ipc_renderer
|
||||||
|
.send(CanvasMsg::WebGL(msg))
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,6 +616,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
Err(e) => return self.webgl_error(e),
|
Err(e) => return self.webgl_error(e),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
slot.set(None);
|
||||||
// Unbind the current buffer
|
// Unbind the current buffer
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::BindBuffer(target, 0)))
|
.send(CanvasMsg::WebGL(WebGLCommand::BindBuffer(target, 0)))
|
||||||
|
@ -526,7 +660,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
let slot = match target {
|
let slot = match target {
|
||||||
constants::TEXTURE_2D => &self.bound_texture_2d,
|
constants::TEXTURE_2D => &self.bound_texture_2d,
|
||||||
constants::TEXTURE_CUBE_MAP => &self.bound_texture_cube_map,
|
constants::TEXTURE_CUBE_MAP => &self.bound_texture_cube_map,
|
||||||
|
|
||||||
_ => return self.webgl_error(InvalidEnum),
|
_ => return self.webgl_error(InvalidEnum),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -566,20 +699,24 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
constants::ELEMENT_ARRAY_BUFFER => self.bound_buffer_element_array.get(),
|
constants::ELEMENT_ARRAY_BUFFER => self.bound_buffer_element_array.get(),
|
||||||
_ => return self.webgl_error(InvalidEnum),
|
_ => return self.webgl_error(InvalidEnum),
|
||||||
};
|
};
|
||||||
|
|
||||||
let bound_buffer = match bound_buffer {
|
let bound_buffer = match bound_buffer {
|
||||||
Some(bound_buffer) => bound_buffer,
|
Some(bound_buffer) => bound_buffer,
|
||||||
None => return self.webgl_error(InvalidValue),
|
None => return self.webgl_error(InvalidValue),
|
||||||
};
|
};
|
||||||
|
|
||||||
match usage {
|
match usage {
|
||||||
constants::STREAM_DRAW |
|
constants::STREAM_DRAW |
|
||||||
constants::STATIC_DRAW |
|
constants::STATIC_DRAW |
|
||||||
constants::DYNAMIC_DRAW => (),
|
constants::DYNAMIC_DRAW => (),
|
||||||
_ => return self.webgl_error(InvalidEnum),
|
_ => return self.webgl_error(InvalidEnum),
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = match data {
|
let data = match data {
|
||||||
Some(data) => data,
|
Some(data) => data,
|
||||||
None => return self.webgl_error(InvalidValue),
|
None => return self.webgl_error(InvalidValue),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(data_vec) = array_buffer_view_to_vec::<u8>(data) {
|
if let Some(data_vec) = array_buffer_view_to_vec::<u8>(data) {
|
||||||
handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, &data_vec, usage));
|
handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, &data_vec, usage));
|
||||||
} else {
|
} else {
|
||||||
|
@ -1109,7 +1246,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
fn Uniform1f(&self,
|
fn Uniform1f(&self,
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
val: f32) {
|
val: f32) {
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::Float, Some(&[val])) {
|
if self.validate_uniform_parameters(uniform, UniformSetterType::Float, Some(&[val])) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform1f(uniform.unwrap().id(), val)))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform1f(uniform.unwrap().id(), val)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1120,7 +1257,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
fn Uniform1i(&self,
|
fn Uniform1i(&self,
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
val: i32) {
|
val: i32) {
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::Int, Some(&[val])) {
|
if self.validate_uniform_parameters(uniform, UniformSetterType::Int, Some(&[val])) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform1i(uniform.unwrap().id(), val)))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform1i(uniform.unwrap().id(), val)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1133,7 +1270,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
data: Option<*mut JSObject>) {
|
data: Option<*mut JSObject>) {
|
||||||
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<i32>(d));
|
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<i32>(d));
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::Int, data_vec.as_ref().map(Vec::as_slice)) {
|
if self.validate_uniform_parameters(uniform, UniformSetterType::Int, data_vec.as_ref().map(Vec::as_slice)) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform1iv(uniform.unwrap().id(), data_vec.unwrap())))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform1iv(uniform.unwrap().id(), data_vec.unwrap())))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1146,7 +1283,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
data: Option<*mut JSObject>) {
|
data: Option<*mut JSObject>) {
|
||||||
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<f32>(d));
|
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<f32>(d));
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::Float, data_vec.as_ref().map(Vec::as_slice)) {
|
if self.validate_uniform_parameters(uniform, UniformSetterType::Float, data_vec.as_ref().map(Vec::as_slice)) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform1fv(uniform.unwrap().id(), data_vec.unwrap())))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform1fv(uniform.unwrap().id(), data_vec.unwrap())))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1157,7 +1294,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
fn Uniform2f(&self,
|
fn Uniform2f(&self,
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
x: f32, y: f32) {
|
x: f32, y: f32) {
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::FloatVec2, Some(&[x, y])) {
|
if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec2, Some(&[x, y])) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform2f(uniform.unwrap().id(), x, y)))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform2f(uniform.unwrap().id(), x, y)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1170,7 +1307,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
data: Option<*mut JSObject>) {
|
data: Option<*mut JSObject>) {
|
||||||
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<f32>(d));
|
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<f32>(d));
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::FloatVec2, data_vec.as_ref().map(Vec::as_slice)) {
|
if self.validate_uniform_parameters(uniform,
|
||||||
|
UniformSetterType::FloatVec2,
|
||||||
|
data_vec.as_ref().map(Vec::as_slice)) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform2fv(uniform.unwrap().id(), data_vec.unwrap())))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform2fv(uniform.unwrap().id(), data_vec.unwrap())))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1181,7 +1320,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
fn Uniform2i(&self,
|
fn Uniform2i(&self,
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
x: i32, y: i32) {
|
x: i32, y: i32) {
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::IntVec2, Some(&[x, y])) {
|
if self.validate_uniform_parameters(uniform,
|
||||||
|
UniformSetterType::IntVec2,
|
||||||
|
Some(&[x, y])) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform2i(uniform.unwrap().id(), x, y)))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform2i(uniform.unwrap().id(), x, y)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1194,7 +1335,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
data: Option<*mut JSObject>) {
|
data: Option<*mut JSObject>) {
|
||||||
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<i32>(d));
|
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<i32>(d));
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::IntVec2, data_vec.as_ref().map(Vec::as_slice)) {
|
if self.validate_uniform_parameters(uniform,
|
||||||
|
UniformSetterType::IntVec2,
|
||||||
|
data_vec.as_ref().map(Vec::as_slice)) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform2iv(uniform.unwrap().id(), data_vec.unwrap())))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform2iv(uniform.unwrap().id(), data_vec.unwrap())))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1205,7 +1348,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
fn Uniform3f(&self,
|
fn Uniform3f(&self,
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
x: f32, y: f32, z: f32) {
|
x: f32, y: f32, z: f32) {
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::FloatVec3, Some(&[x, y, z])) {
|
if self.validate_uniform_parameters(uniform,
|
||||||
|
UniformSetterType::FloatVec3,
|
||||||
|
Some(&[x, y, z])) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform3f(uniform.unwrap().id(), x, y, z)))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform3f(uniform.unwrap().id(), x, y, z)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1218,7 +1363,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
data: Option<*mut JSObject>) {
|
data: Option<*mut JSObject>) {
|
||||||
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<f32>(d));
|
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<f32>(d));
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::FloatVec3, data_vec.as_ref().map(Vec::as_slice)) {
|
if self.validate_uniform_parameters(uniform,
|
||||||
|
UniformSetterType::FloatVec3,
|
||||||
|
data_vec.as_ref().map(Vec::as_slice)) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform3fv(uniform.unwrap().id(), data_vec.unwrap())))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform3fv(uniform.unwrap().id(), data_vec.unwrap())))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1229,7 +1376,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
fn Uniform3i(&self,
|
fn Uniform3i(&self,
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
x: i32, y: i32, z: i32) {
|
x: i32, y: i32, z: i32) {
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::IntVec3, Some(&[x, y, z])) {
|
if self.validate_uniform_parameters(uniform,
|
||||||
|
UniformSetterType::IntVec3,
|
||||||
|
Some(&[x, y, z])) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform3i(uniform.unwrap().id(), x, y, z)))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform3i(uniform.unwrap().id(), x, y, z)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1242,7 +1391,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
data: Option<*mut JSObject>) {
|
data: Option<*mut JSObject>) {
|
||||||
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<i32>(d));
|
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<i32>(d));
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::IntVec3, data_vec.as_ref().map(Vec::as_slice)) {
|
if self.validate_uniform_parameters(uniform,
|
||||||
|
UniformSetterType::IntVec3,
|
||||||
|
data_vec.as_ref().map(Vec::as_slice)) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform3iv(uniform.unwrap().id(), data_vec.unwrap())))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform3iv(uniform.unwrap().id(), data_vec.unwrap())))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1253,7 +1404,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
fn Uniform4i(&self,
|
fn Uniform4i(&self,
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
x: i32, y: i32, z: i32, w: i32) {
|
x: i32, y: i32, z: i32, w: i32) {
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::IntVec4, Some(&[x, y, z, w])) {
|
if self.validate_uniform_parameters(uniform,
|
||||||
|
UniformSetterType::IntVec4,
|
||||||
|
Some(&[x, y, z, w])) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform4i(uniform.unwrap().id(), x, y, z, w)))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform4i(uniform.unwrap().id(), x, y, z, w)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1267,7 +1420,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
data: Option<*mut JSObject>) {
|
data: Option<*mut JSObject>) {
|
||||||
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<i32>(d));
|
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<i32>(d));
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::IntVec4, data_vec.as_ref().map(Vec::as_slice)) {
|
if self.validate_uniform_parameters(uniform,
|
||||||
|
UniformSetterType::IntVec4,
|
||||||
|
data_vec.as_ref().map(Vec::as_slice)) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform4iv(uniform.unwrap().id(), data_vec.unwrap())))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform4iv(uniform.unwrap().id(), data_vec.unwrap())))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1278,7 +1433,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
fn Uniform4f(&self,
|
fn Uniform4f(&self,
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
x: f32, y: f32, z: f32, w: f32) {
|
x: f32, y: f32, z: f32, w: f32) {
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::FloatVec4, Some(&[x, y, z, w])) {
|
if self.validate_uniform_parameters(uniform,
|
||||||
|
UniformSetterType::FloatVec4,
|
||||||
|
Some(&[x, y, z, w])) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform4f(uniform.unwrap().id(), x, y, z, w)))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform4f(uniform.unwrap().id(), x, y, z, w)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1291,7 +1448,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
uniform: Option<&WebGLUniformLocation>,
|
uniform: Option<&WebGLUniformLocation>,
|
||||||
data: Option<*mut JSObject>) {
|
data: Option<*mut JSObject>) {
|
||||||
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<f32>(d));
|
let data_vec = data.and_then(|d| array_buffer_view_to_vec::<f32>(d));
|
||||||
if self.validate_uniform_parameters(uniform, UniformType::FloatVec4, data_vec.as_ref().map(Vec::as_slice)) {
|
if self.validate_uniform_parameters(uniform,
|
||||||
|
UniformSetterType::FloatVec4,
|
||||||
|
data_vec.as_ref().map(Vec::as_slice)) {
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::WebGL(WebGLCommand::Uniform4fv(uniform.unwrap().id(), data_vec.unwrap())))
|
.send(CanvasMsg::WebGL(WebGLCommand::Uniform4fv(uniform.unwrap().id(), data_vec.unwrap())))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1400,28 +1559,112 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
||||||
fn TexImage2D(&self,
|
fn TexImage2D(&self,
|
||||||
|
_cx: *mut JSContext,
|
||||||
target: u32,
|
target: u32,
|
||||||
level: i32,
|
level: i32,
|
||||||
internal_format: u32,
|
internal_format: u32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
border: i32,
|
||||||
format: u32,
|
format: u32,
|
||||||
data_type: u32,
|
data_type: u32,
|
||||||
source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>) {
|
data: Option<*mut JSObject>) {
|
||||||
let texture = match target {
|
if !self.validate_tex_image_parameters(target,
|
||||||
constants::TEXTURE_2D => self.bound_texture_2d.get(),
|
level,
|
||||||
constants::TEXTURE_CUBE_MAP => self.bound_texture_cube_map.get(),
|
internal_format,
|
||||||
_ => return self.webgl_error(InvalidEnum),
|
width, height,
|
||||||
|
border,
|
||||||
|
format,
|
||||||
|
data_type) {
|
||||||
|
return; // Error handled in validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(emilio, #10693): Add type-safe wrappers to validations
|
||||||
|
let (element_size, components_per_element) = match data_type {
|
||||||
|
constants::UNSIGNED_BYTE => (1, 1),
|
||||||
|
constants::UNSIGNED_SHORT_5_6_5 => (2, 3),
|
||||||
|
constants::UNSIGNED_SHORT_5_5_5_1 |
|
||||||
|
constants::UNSIGNED_SHORT_4_4_4_4 => (2, 4),
|
||||||
|
_ => unreachable!(), // previously validated
|
||||||
};
|
};
|
||||||
if texture.is_none() {
|
|
||||||
|
let components = match format {
|
||||||
|
constants::DEPTH_COMPONENT => 1,
|
||||||
|
constants::ALPHA => 1,
|
||||||
|
constants::LUMINANCE => 1,
|
||||||
|
constants::LUMINANCE_ALPHA => 2,
|
||||||
|
constants::RGB => 3,
|
||||||
|
constants::RGBA => 4,
|
||||||
|
_ => unreachable!(), // previously validated
|
||||||
|
};
|
||||||
|
|
||||||
|
// If data is non-null, the type of pixels must match the type of the
|
||||||
|
// data to be read.
|
||||||
|
// If it is UNSIGNED_BYTE, a Uint8Array must be supplied;
|
||||||
|
// if it is UNSIGNED_SHORT_5_6_5, UNSIGNED_SHORT_4_4_4_4,
|
||||||
|
// or UNSIGNED_SHORT_5_5_5_1, a Uint16Array must be supplied.
|
||||||
|
// If the types do not match, an INVALID_OPERATION error is generated.
|
||||||
|
let received_size = if let Some(data) = data {
|
||||||
|
if unsafe { array_buffer_view_data_checked::<u16>(data).is_some() } {
|
||||||
|
2
|
||||||
|
} else if unsafe { array_buffer_view_data_checked::<u8>(data).is_some() } {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
return self.webgl_error(InvalidOperation);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
element_size
|
||||||
|
};
|
||||||
|
|
||||||
|
if received_size != element_size {
|
||||||
return self.webgl_error(InvalidOperation);
|
return self.webgl_error(InvalidOperation);
|
||||||
}
|
}
|
||||||
// TODO(emilio): Validate more parameters
|
|
||||||
|
// NOTE: width and height are positive or zero due to validate()
|
||||||
|
let expected_byte_length = width * height * element_size * components / components_per_element;
|
||||||
|
|
||||||
|
|
||||||
|
// If data is null, a buffer of sufficient size
|
||||||
|
// initialized to 0 is passed.
|
||||||
|
let buff = if let Some(data) = data {
|
||||||
|
array_buffer_view_to_vec::<u8>(data)
|
||||||
|
.expect("Can't reach here without being an ArrayBufferView!")
|
||||||
|
} else {
|
||||||
|
vec![0u8; expected_byte_length as usize]
|
||||||
|
};
|
||||||
|
|
||||||
|
if buff.len() != expected_byte_length as usize {
|
||||||
|
return self.webgl_error(InvalidOperation);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tex_image_2d(target, level,
|
||||||
|
internal_format,
|
||||||
|
width, height, border,
|
||||||
|
format, data_type, buff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
||||||
|
fn TexImage2D_(&self,
|
||||||
|
target: u32,
|
||||||
|
level: i32,
|
||||||
|
internal_format: u32,
|
||||||
|
format: u32,
|
||||||
|
data_type: u32,
|
||||||
|
source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>) {
|
||||||
let source = match source {
|
let source = match source {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE: Getting the pixels probably can be short-circuited if some
|
||||||
|
// parameter is invalid.
|
||||||
|
//
|
||||||
|
// Nontheless, since it's the error case, I'm not totally sure the
|
||||||
|
// complexity is worth it.
|
||||||
let (pixels, size) = match source {
|
let (pixels, size) = match source {
|
||||||
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::ImageData(image_data) => {
|
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::ImageData(image_data) => {
|
||||||
let global = self.global();
|
let global = self.global();
|
||||||
|
@ -1443,7 +1686,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
let size = Size2D::new(img.width as i32, img.height as i32);
|
let size = Size2D::new(img.width as i32, img.height as i32);
|
||||||
// TODO(emilio): Validate that the format argument is coherent with the image.
|
|
||||||
|
// TODO(emilio): Validate that the format argument
|
||||||
|
// is coherent with the image.
|
||||||
|
//
|
||||||
// RGB8 should be easy to support too
|
// RGB8 should be easy to support too
|
||||||
let mut data = match img.format {
|
let mut data = match img.format {
|
||||||
PixelFormat::RGBA8 => img.bytes.to_vec(),
|
PixelFormat::RGBA8 => img.bytes.to_vec(),
|
||||||
|
@ -1454,8 +1700,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
|
|
||||||
(data, size)
|
(data, size)
|
||||||
},
|
},
|
||||||
// TODO(emilio): Getting canvas data is implemented in CanvasRenderingContext2D, but
|
// TODO(emilio): Getting canvas data is implemented in CanvasRenderingContext2D,
|
||||||
// we need to refactor it moving it to `HTMLCanvasElement` and supporting WebGLContext
|
// but we need to refactor it moving it to `HTMLCanvasElement` and support
|
||||||
|
// WebGLContext (probably via GetPixels()).
|
||||||
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLCanvasElement(canvas) => {
|
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLCanvasElement(canvas) => {
|
||||||
let canvas = canvas.r();
|
let canvas = canvas.r();
|
||||||
if let Some((mut data, size)) = canvas.fetch_all_data() {
|
if let Some((mut data, size)) = canvas.fetch_all_data() {
|
||||||
|
@ -1469,25 +1716,17 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
=> unimplemented!(),
|
=> unimplemented!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if size.width < 0 || size.height < 0 || level < 0 {
|
// NB: Border must be zero
|
||||||
self.webgl_error(WebGLError::InvalidOperation);
|
if !self.validate_tex_image_parameters(target, level, internal_format,
|
||||||
|
size.width, size.height, 0,
|
||||||
|
format, data_type) {
|
||||||
|
return; // Error handled in validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(emilio): Invert axis, convert colorspace, premultiply alpha if requested
|
self.tex_image_2d(target, level,
|
||||||
let msg = WebGLCommand::TexImage2D(target, level, internal_format as i32,
|
internal_format,
|
||||||
size.width, size.height,
|
size.width, size.height, 0,
|
||||||
format, data_type, pixels);
|
format, data_type, pixels)
|
||||||
|
|
||||||
// depth is always 1 when coming from html elements
|
|
||||||
handle_potential_webgl_error!(self, texture.unwrap().initialize(size.width as u32,
|
|
||||||
size.height as u32,
|
|
||||||
1,
|
|
||||||
internal_format,
|
|
||||||
level as u32));
|
|
||||||
|
|
||||||
self.ipc_renderer
|
|
||||||
.send(CanvasMsg::WebGL(msg))
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
|
||||||
|
@ -1512,3 +1751,62 @@ impl LayoutCanvasWebGLRenderingContextHelpers for LayoutJS<WebGLRenderingContext
|
||||||
(*self.unsafe_get()).ipc_renderer.clone()
|
(*self.unsafe_get()).ipc_renderer.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum UniformSetterType {
|
||||||
|
Int,
|
||||||
|
IntVec2,
|
||||||
|
IntVec3,
|
||||||
|
IntVec4,
|
||||||
|
Float,
|
||||||
|
FloatVec2,
|
||||||
|
FloatVec3,
|
||||||
|
FloatVec4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UniformSetterType {
|
||||||
|
pub fn element_count(&self) -> usize {
|
||||||
|
match *self {
|
||||||
|
UniformSetterType::Int => 1,
|
||||||
|
UniformSetterType::IntVec2 => 2,
|
||||||
|
UniformSetterType::IntVec3 => 3,
|
||||||
|
UniformSetterType::IntVec4 => 4,
|
||||||
|
UniformSetterType::Float => 1,
|
||||||
|
UniformSetterType::FloatVec2 => 2,
|
||||||
|
UniformSetterType::FloatVec3 => 3,
|
||||||
|
UniformSetterType::FloatVec4 => 4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_compatible_with(&self, gl_type: u32) -> bool {
|
||||||
|
gl_type == self.as_gl_constant() || match *self {
|
||||||
|
// Sampler uniform variables have an index value (the index of the
|
||||||
|
// texture), and as such they have to be set as ints
|
||||||
|
UniformSetterType::Int => gl_type == constants::SAMPLER_2D ||
|
||||||
|
gl_type == constants::SAMPLER_CUBE,
|
||||||
|
// Don't ask me why, but it seems we must allow setting bool
|
||||||
|
// uniforms with uniform1f.
|
||||||
|
//
|
||||||
|
// See the WebGL conformance test
|
||||||
|
// conformance/uniforms/gl-uniform-bool.html
|
||||||
|
UniformSetterType::Float => gl_type == constants::BOOL,
|
||||||
|
UniformSetterType::FloatVec2 => gl_type == constants::BOOL_VEC2,
|
||||||
|
UniformSetterType::FloatVec3 => gl_type == constants::BOOL_VEC3,
|
||||||
|
UniformSetterType::FloatVec4 => gl_type == constants::BOOL_VEC4,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_gl_constant(&self) -> u32 {
|
||||||
|
match *self {
|
||||||
|
UniformSetterType::Int => constants::INT,
|
||||||
|
UniformSetterType::IntVec2 => constants::INT_VEC2,
|
||||||
|
UniformSetterType::IntVec3 => constants::INT_VEC3,
|
||||||
|
UniformSetterType::IntVec4 => constants::INT_VEC4,
|
||||||
|
UniformSetterType::Float => constants::FLOAT,
|
||||||
|
UniformSetterType::FloatVec2 => constants::FLOAT_VEC2,
|
||||||
|
UniformSetterType::FloatVec3 => constants::FLOAT_VEC3,
|
||||||
|
UniformSetterType::FloatVec4 => constants::FLOAT_VEC4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -116,6 +116,11 @@ impl WebGLShader {
|
||||||
}
|
}
|
||||||
|
|
||||||
*self.info_log.borrow_mut() = Some(validator.info_log());
|
*self.info_log.borrow_mut() = Some(validator.info_log());
|
||||||
|
// TODO(emilio): More data (like uniform data) should be collected
|
||||||
|
// here to properly validate uniforms.
|
||||||
|
//
|
||||||
|
// This requires a more complex interface with ANGLE, using C++
|
||||||
|
// bindings and being extremely cautious about destructing things.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ pub struct WebGLTexture {
|
||||||
/// The target to which this texture was bound the first time
|
/// The target to which this texture was bound the first time
|
||||||
target: Cell<Option<u32>>,
|
target: Cell<Option<u32>>,
|
||||||
is_deleted: Cell<bool>,
|
is_deleted: Cell<bool>,
|
||||||
is_initialized: Cell<bool>,
|
|
||||||
/// Stores information about mipmap levels and cubemap faces.
|
/// Stores information about mipmap levels and cubemap faces.
|
||||||
#[ignore_heap_size_of = "Arrays are cumbersome"]
|
#[ignore_heap_size_of = "Arrays are cumbersome"]
|
||||||
image_info_array: DOMRefCell<[ImageInfo; MAX_LEVEL_COUNT * MAX_FACE_COUNT]>,
|
image_info_array: DOMRefCell<[ImageInfo; MAX_LEVEL_COUNT * MAX_FACE_COUNT]>,
|
||||||
|
@ -51,7 +50,6 @@ impl WebGLTexture {
|
||||||
id: id,
|
id: id,
|
||||||
target: Cell::new(None),
|
target: Cell::new(None),
|
||||||
is_deleted: Cell::new(false),
|
is_deleted: Cell::new(false),
|
||||||
is_initialized: Cell::new(false),
|
|
||||||
face_count: Cell::new(0),
|
face_count: Cell::new(0),
|
||||||
base_mipmap_level: 0,
|
base_mipmap_level: 0,
|
||||||
image_info_array: DOMRefCell::new([ImageInfo::new(); MAX_LEVEL_COUNT * MAX_FACE_COUNT]),
|
image_info_array: DOMRefCell::new([ImageInfo::new(); MAX_LEVEL_COUNT * MAX_FACE_COUNT]),
|
||||||
|
@ -105,7 +103,13 @@ impl WebGLTexture {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize(&self, width: u32, height: u32, depth: u32, internal_format: u32, level: u32) -> WebGLResult<()> {
|
pub fn initialize(&self,
|
||||||
|
target: u32,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
depth: u32,
|
||||||
|
internal_format: u32,
|
||||||
|
level: u32) -> WebGLResult<()> {
|
||||||
let image_info = ImageInfo {
|
let image_info = ImageInfo {
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
|
@ -113,10 +117,18 @@ impl WebGLTexture {
|
||||||
internal_format: Some(internal_format),
|
internal_format: Some(internal_format),
|
||||||
is_initialized: true,
|
is_initialized: true,
|
||||||
};
|
};
|
||||||
self.set_image_infos_at_level(level, image_info);
|
|
||||||
|
|
||||||
self.is_initialized.set(true);
|
let face = match target {
|
||||||
|
constants::TEXTURE_2D | constants::TEXTURE_CUBE_MAP_POSITIVE_X => 0,
|
||||||
|
constants::TEXTURE_CUBE_MAP_NEGATIVE_X => 1,
|
||||||
|
constants::TEXTURE_CUBE_MAP_POSITIVE_Y => 2,
|
||||||
|
constants::TEXTURE_CUBE_MAP_NEGATIVE_Y => 3,
|
||||||
|
constants::TEXTURE_CUBE_MAP_POSITIVE_Z => 4,
|
||||||
|
constants::TEXTURE_CUBE_MAP_NEGATIVE_Z => 5,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.set_image_infos_at_level_and_face(level, face, image_info);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,12 +142,12 @@ impl WebGLTexture {
|
||||||
};
|
};
|
||||||
|
|
||||||
let base_image_info = self.base_image_info().unwrap();
|
let base_image_info = self.base_image_info().unwrap();
|
||||||
|
|
||||||
if !base_image_info.is_initialized() {
|
if !base_image_info.is_initialized() {
|
||||||
return Err(WebGLError::InvalidOperation);
|
return Err(WebGLError::InvalidOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if target == constants::TEXTURE_CUBE_MAP && !self.is_cube_complete() {
|
let is_cubic = target == constants::TEXTURE_CUBE_MAP;
|
||||||
|
if is_cubic && !self.is_cube_complete() {
|
||||||
return Err(WebGLError::InvalidOperation);
|
return Err(WebGLError::InvalidOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,6 +274,8 @@ impl WebGLTexture {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_cube_complete(&self) -> bool {
|
fn is_cube_complete(&self) -> bool {
|
||||||
|
debug_assert!(self.face_count.get() == 6);
|
||||||
|
|
||||||
let image_info = self.base_image_info().unwrap();
|
let image_info = self.base_image_info().unwrap();
|
||||||
if !image_info.is_defined() {
|
if !image_info.is_defined() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -294,11 +308,16 @@ impl WebGLTexture {
|
||||||
|
|
||||||
fn set_image_infos_at_level(&self, level: u32, image_info: ImageInfo) {
|
fn set_image_infos_at_level(&self, level: u32, image_info: ImageInfo) {
|
||||||
for face in 0..self.face_count.get() {
|
for face in 0..self.face_count.get() {
|
||||||
let pos = (level * self.face_count.get() as u32) + face as u32;
|
self.set_image_infos_at_level_and_face(level, face, image_info);
|
||||||
self.image_info_array.borrow_mut()[pos as usize] = image_info;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_image_infos_at_level_and_face(&self, level: u32, face: u8, image_info: ImageInfo) {
|
||||||
|
debug_assert!(face < self.face_count.get());
|
||||||
|
let pos = (level * self.face_count.get() as u32) + face as u32;
|
||||||
|
self.image_info_array.borrow_mut()[pos as usize] = image_info;
|
||||||
|
}
|
||||||
|
|
||||||
fn base_image_info(&self) -> Option<ImageInfo> {
|
fn base_image_info(&self) -> Option<ImageInfo> {
|
||||||
assert!((self.base_mipmap_level as usize) < MAX_LEVEL_COUNT);
|
assert!((self.base_mipmap_level as usize) < MAX_LEVEL_COUNT);
|
||||||
|
|
||||||
|
@ -341,7 +360,7 @@ impl ImageInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_defined(&self) -> bool {
|
fn is_defined(&self) -> bool {
|
||||||
!self.internal_format.is_none()
|
self.internal_format.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_max_mimap_levels(&self) -> u32 {
|
fn get_max_mimap_levels(&self) -> u32 {
|
||||||
|
|
|
@ -28,10 +28,7 @@ impl WebGLUniformLocation {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
box WebGLUniformLocation::new_inherited(id, program_id), global, WebGLUniformLocationBinding::Wrap)
|
box WebGLUniformLocation::new_inherited(id, program_id), global, WebGLUniformLocationBinding::Wrap)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl WebGLUniformLocation {
|
|
||||||
pub fn id(&self) -> i32 {
|
pub fn id(&self) -> i32 {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
|
@ -632,6 +632,10 @@ interface WebGLRenderingContextBase
|
||||||
//void texImage2D(GLenum target, GLint level, GLenum internalformat,
|
//void texImage2D(GLenum target, GLint level, GLenum internalformat,
|
||||||
// GLsizei width, GLsizei height, GLint border, GLenum format,
|
// GLsizei width, GLsizei height, GLint border, GLenum format,
|
||||||
// GLenum type, ArrayBufferView? pixels);
|
// GLenum type, ArrayBufferView? pixels);
|
||||||
|
// FIXME: SM interface arguments
|
||||||
|
void texImage2D(GLenum target, GLint level, GLenum internalformat,
|
||||||
|
GLsizei width, GLsizei height, GLint border, GLenum format,
|
||||||
|
GLenum type, optional object data);
|
||||||
void texImage2D(GLenum target, GLint level, GLenum internalformat,
|
void texImage2D(GLenum target, GLint level, GLenum internalformat,
|
||||||
GLenum format, GLenum type, TexImageSource? source); // May throw DOMException
|
GLenum format, GLenum type, TexImageSource? source); // May throw DOMException
|
||||||
|
|
||||||
|
|
|
@ -3,3 +3,6 @@
|
||||||
[WebGL test #0: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
|
[WebGL test #0: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[WebGL test #1: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[bufferDataBadArgs.html]
|
|
||||||
type: testharness
|
|
||||||
[WebGL test #0: testBufferData]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[texImage2D.html]
|
|
||||||
type: testharness
|
|
||||||
[WebGL test #0: testTexImage2D]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -3,3 +3,6 @@
|
||||||
[WebGL test #0: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
|
[WebGL test #0: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[WebGL test #1: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -6,3 +6,6 @@
|
||||||
[WebGL test #3: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
|
[WebGL test #3: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[WebGL test #11: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -3,3 +3,6 @@
|
||||||
[WebGL test #1: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
|
[WebGL test #1: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[WebGL test #4: successfullyParsed should be true (of type boolean). Was undefined (of type undefined).]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -5816,6 +5816,18 @@
|
||||||
"url": "/_mozilla/mozilla/webgl/draw_arrays_simple.html"
|
"url": "/_mozilla/mozilla/webgl/draw_arrays_simple.html"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"mozilla/webgl/tex_image_2d_abv.html": [
|
||||||
|
{
|
||||||
|
"path": "mozilla/webgl/tex_image_2d_abv.html",
|
||||||
|
"references": [
|
||||||
|
[
|
||||||
|
"/_mozilla/mozilla/webgl/tex_image_2d_abv_ref.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"url": "/_mozilla/mozilla/webgl/tex_image_2d_abv.html"
|
||||||
|
}
|
||||||
|
],
|
||||||
"mozilla/webgl/tex_image_2d_canvas.html": [
|
"mozilla/webgl/tex_image_2d_canvas.html": [
|
||||||
{
|
{
|
||||||
"path": "mozilla/webgl/tex_image_2d_canvas.html",
|
"path": "mozilla/webgl/tex_image_2d_canvas.html",
|
||||||
|
@ -12490,6 +12502,18 @@
|
||||||
"url": "/_mozilla/mozilla/webgl/draw_arrays_simple.html"
|
"url": "/_mozilla/mozilla/webgl/draw_arrays_simple.html"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"mozilla/webgl/tex_image_2d_abv.html": [
|
||||||
|
{
|
||||||
|
"path": "mozilla/webgl/tex_image_2d_abv.html",
|
||||||
|
"references": [
|
||||||
|
[
|
||||||
|
"/_mozilla/mozilla/webgl/tex_image_2d_abv_ref.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"url": "/_mozilla/mozilla/webgl/tex_image_2d_abv.html"
|
||||||
|
}
|
||||||
|
],
|
||||||
"mozilla/webgl/tex_image_2d_canvas.html": [
|
"mozilla/webgl/tex_image_2d_canvas.html": [
|
||||||
{
|
{
|
||||||
"path": "mozilla/webgl/tex_image_2d_canvas.html",
|
"path": "mozilla/webgl/tex_image_2d_canvas.html",
|
||||||
|
|
106
tests/wpt/mozilla/tests/mozilla/webgl/tex_image_2d_abv.html
Normal file
106
tests/wpt/mozilla/tests/mozilla/webgl/tex_image_2d_abv.html
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>WebGL: texImage2D with Array Buffer View</title>
|
||||||
|
<link rel="match" href="tex_image_2d_abv_ref.html">
|
||||||
|
<style>html, body { margin: 0; padding: 0; }</style>
|
||||||
|
<!-- This reftest should show a 512x512px red square -->
|
||||||
|
<canvas id="c" width="512" height="512"></canvas>
|
||||||
|
<script id="vertex_shader" type="x-shader/x-vertex">
|
||||||
|
precision mediump float;
|
||||||
|
attribute vec2 a_texCoord;
|
||||||
|
attribute vec2 a_position;
|
||||||
|
varying vec2 v_texCoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = vec4(a_position, 0, 1);
|
||||||
|
v_texCoord = a_texCoord;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="fragment_shader" type="x-shader/x-fragment">
|
||||||
|
precision mediump float;
|
||||||
|
uniform sampler2D u_image;
|
||||||
|
varying vec2 v_texCoord;
|
||||||
|
void main() {
|
||||||
|
gl_FragColor = texture2D(u_image, v_texCoord);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
var gl = document.getElementById('c').getContext('webgl');
|
||||||
|
|
||||||
|
// Clear black
|
||||||
|
gl.clearColor(1, 1, 1, 1);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
// Create the program
|
||||||
|
var vertex_shader = gl.createShader(gl.VERTEX_SHADER),
|
||||||
|
fragment_shader = gl.createShader(gl.FRAGMENT_SHADER),
|
||||||
|
program = gl.createProgram();
|
||||||
|
|
||||||
|
gl.shaderSource(vertex_shader,
|
||||||
|
document.getElementById('vertex_shader').textContent);
|
||||||
|
gl.shaderSource(fragment_shader,
|
||||||
|
document.getElementById('fragment_shader').textContent);
|
||||||
|
gl.compileShader(vertex_shader);
|
||||||
|
gl.compileShader(fragment_shader);
|
||||||
|
gl.attachShader(program, vertex_shader);
|
||||||
|
gl.attachShader(program, fragment_shader);
|
||||||
|
console.log(gl.getShaderInfoLog(vertex_shader));
|
||||||
|
console.log(gl.getShaderInfoLog(fragment_shader));
|
||||||
|
gl.linkProgram(program);
|
||||||
|
gl.useProgram(program);
|
||||||
|
|
||||||
|
// Get the position from the fragment shader
|
||||||
|
var position = gl.getAttribLocation(program, "a_position");
|
||||||
|
var tex_position = gl.getAttribLocation(program, "a_texCoord");
|
||||||
|
|
||||||
|
var texture_coordinates = new Float32Array([
|
||||||
|
0.0, 0.0,
|
||||||
|
1.0, 0.0,
|
||||||
|
0.0, 1.0,
|
||||||
|
0.0, 1.0,
|
||||||
|
1.0, 0.0,
|
||||||
|
1.0, 1.0
|
||||||
|
]);
|
||||||
|
|
||||||
|
var texture_buffer = gl.createBuffer();
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, texture_buffer);
|
||||||
|
gl.bufferData(gl.ARRAY_BUFFER, texture_coordinates, gl.STATIC_DRAW);
|
||||||
|
gl.enableVertexAttribArray(tex_position);
|
||||||
|
gl.vertexAttribPointer(tex_position, 2, gl.FLOAT, false, 0, 0);
|
||||||
|
|
||||||
|
var square_data = new Float32Array([
|
||||||
|
-1.0, 1.0, // top left
|
||||||
|
1.0, 1.0, // top right
|
||||||
|
-1.0, -1.0, // bottom left
|
||||||
|
-1.0, -1.0, // bottom left
|
||||||
|
1.0, 1.0, // top right
|
||||||
|
1.0, -1.0 // bottom right
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create a buffer for the square with the square
|
||||||
|
// vertex data
|
||||||
|
var square_buffer = gl.createBuffer();
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, square_buffer);
|
||||||
|
gl.bufferData(gl.ARRAY_BUFFER, square_data, gl.STATIC_DRAW);
|
||||||
|
|
||||||
|
gl.enableVertexAttribArray(position);
|
||||||
|
gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);
|
||||||
|
|
||||||
|
// Load the texture and draw
|
||||||
|
var tex = gl.createTexture();
|
||||||
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||||
|
console.log(gl.getError() == gl.NO_ERROR);
|
||||||
|
|
||||||
|
|
||||||
|
// Create a 1x1 red texture, but repeated.
|
||||||
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0,
|
||||||
|
gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255]));
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||||
|
console.log(gl.getError() == gl.NO_ERROR);
|
||||||
|
|
||||||
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
|
</script>
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>ref: WebGL: texImage2D with Array Buffer View</title>
|
||||||
|
<style>
|
||||||
|
html, body { margin: 0; padding: 0; }
|
||||||
|
div {
|
||||||
|
width: 512px;
|
||||||
|
height: 512px;
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<!-- This reftest should show a 512x512px red square -->
|
||||||
|
<div></div>
|
Loading…
Add table
Add a link
Reference in a new issue