aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/webglrenderingcontext.rs
diff options
context:
space:
mode:
authorDaniel Robertson <dan.robertson@anidata.org>2016-05-21 10:50:47 -0400
committerDaniel Robertson <dan.robertson@anidata.org>2016-05-23 22:29:23 -0400
commit867cd9be293d18c3d1ddedd7e6ae886f04da1b0e (patch)
treed2e2513a5e4af362e1f3c98a3338ad2851d87e8d /components/script/dom/webglrenderingcontext.rs
parentf1efeb00af4cbc2a63e09d7c50b603dd1fee2df5 (diff)
downloadservo-867cd9be293d18c3d1ddedd7e6ae886f04da1b0e.tar.gz
servo-867cd9be293d18c3d1ddedd7e6ae886f04da1b0e.zip
Impl copyTexImage2D and copyTexSubImage2D
Implement copyTexImage2D and copyTexSubImage2D for WebGLRenderingContext.
Diffstat (limited to 'components/script/dom/webglrenderingcontext.rs')
-rw-r--r--components/script/dom/webglrenderingcontext.rs322
1 files changed, 227 insertions, 95 deletions
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 241aa0aa60e..854095495a1 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -234,70 +234,32 @@ impl WebGLRenderingContext {
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;
+ fn texture_for_target(&self, target: u32) -> Option<Root<WebGLTexture>> {
+ 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()
},
- };
-
- // 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;
+ _ => None,
}
+ }
- // 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;
+ fn face_index_for_target(&self, target: u32) -> Option<u8> {
+ match target {
+ constants::TEXTURE_2D => Some(0),
+ constants::TEXTURE_CUBE_MAP_POSITIVE_X => Some(0),
+ constants::TEXTURE_CUBE_MAP_NEGATIVE_X => Some(1),
+ constants::TEXTURE_CUBE_MAP_POSITIVE_Y => Some(2),
+ constants::TEXTURE_CUBE_MAP_NEGATIVE_Y => Some(3),
+ constants::TEXTURE_CUBE_MAP_POSITIVE_Z => Some(4),
+ constants::TEXTURE_CUBE_MAP_NEGATIVE_Z => Some(5),
+ _ => None
}
+ }
+ fn validate_tex_internal_format(&self, internal_format: u32) -> bool {
// GL_INVALID_VALUE is generated if internal_format is not an
// accepted format.
match internal_format {
@@ -306,39 +268,51 @@ impl WebGLRenderingContext {
constants::RGB |
constants::RGBA |
constants::LUMINANCE |
- constants::LUMINANCE_ALPHA => {},
+ constants::LUMINANCE_ALPHA => true,
_ => {
self.webgl_error(InvalidValue);
- return false;
+ false
},
}
+ }
- // GL_INVALID_OPERATION is generated if format does not
- // match internal_format.
- if format != internal_format {
- self.webgl_error(InvalidOperation);
+
+ fn validate_tex_image_2d_parameters(&self,
+ target: u32,
+ level: i32,
+ internal_format: u32,
+ width: i32,
+ height: i32,
+ border: i32,
+ format: u32,
+ data_type: u32) -> bool {
+ // Validate common tex image parameters
+ if !self.validate_common_tex_image_parameters(target, level, width, height) {
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);
+ // 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;
+ },
+ }
+
+ // Validate internal_format
+ if !self.validate_tex_internal_format(internal_format) {
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);
+ // GL_INVALID_OPERATION is generated if format does not
+ // match internal_format.
+ if format != internal_format {
+ self.webgl_error(InvalidOperation);
return false;
}
@@ -369,6 +343,82 @@ impl WebGLRenderingContext {
true
}
+ fn validate_common_tex_image_parameters(&self,
+ target: u32,
+ level: i32,
+ width: i32,
+ height: i32) -> 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.
+ //
+ // max_size is 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 (texture, max) = match target {
+ constants::TEXTURE_2D
+ => (self.bound_texture_2d.get(), self.limits.max_tex_size),
+ 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.limits.max_cube_map_tex_size),
+ _ => {
+ 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;
+ }
+
+ 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 level is less than 0.
+ //
+ // GL_INVALID_VALUE is generated if width or height is less than 0
+ if width < 0 || height < 0 || level < 0 ||
+ width as u32 > max || height as u32 > max {
+ self.webgl_error(InvalidValue);
+ return false;
+ }
+
+ // 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.
+ if level > (max as f32).log2() as i32 {
+ 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;
+ }
+
+ true
+ }
+
fn tex_image_2d(&self,
target: u32,
level: i32,
@@ -380,11 +430,11 @@ impl WebGLRenderingContext {
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));
+ debug_assert!(self.validate_tex_image_2d_parameters(target, level,
+ internal_format,
+ width, height,
+ border, format,
+ data_type));
let slot = match target {
constants::TEXTURE_2D
@@ -791,6 +841,88 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
self.webgl_error(InvalidEnum)
}
+ // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
+ fn CopyTexImage2D(&self, target: u32, level: i32, internal_format: u32,
+ x: i32, y: i32, width: i32, height: i32, border: i32) {
+ // Validate common tex image parameters
+ if !self.validate_common_tex_image_parameters(target, level, width, height) ||
+ !self.validate_tex_internal_format(internal_format) {
+ return;
+ }
+
+ // GL_INVALID_VALUE is generated if the border is not 0
+ if border != 0 {
+ self.webgl_error(InvalidValue);
+ return;
+ }
+
+ let texture = self.texture_for_target(target).unwrap();
+ let face_index = self.face_index_for_target(target).unwrap();
+
+ // We have already validated level
+ let image_info = texture.image_info_at_face(face_index, level as u32);
+
+ // The color buffer components can be dropped during the conversion to the
+ // internal_format, but new components cannot be added
+ let invalid_format = match image_info.internal_format() {
+ Some(src_format) => match (src_format, internal_format) {
+ (constants::ALPHA, constants::ALPHA) | (constants::RGB, constants::RGB) |
+ (constants::RGB, constants::LUMINANCE) | (constants::RGBA, _) => false,
+ _ => true,
+ },
+ None => false,
+ };
+
+ // GL_INVALID_OPERATION is generated if the color buffer cannot be
+ // converted to the internal_format
+ if invalid_format {
+ self.webgl_error(InvalidOperation);
+ return;
+ }
+
+ // 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));
+
+ let msg = WebGLCommand::CopyTexImage2D(target, level, internal_format, x, y,
+ width, height, border);
+
+ self.ipc_renderer.send(CanvasMsg::WebGL(msg)).unwrap()
+ }
+
+ // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
+ fn CopyTexSubImage2D(&self, target: u32, level: i32, xoffset: i32, yoffset: i32,
+ x: i32, y: i32, width: i32, height: i32) {
+ // Validate common tex image parameters
+ if !self.validate_common_tex_image_parameters(target, level, width, height) {
+ return;
+ }
+
+ let texture = self.texture_for_target(target).unwrap();
+ let face_index = self.face_index_for_target(target).unwrap();
+
+ // We have already validated level
+ let image_info = texture.image_info_at_face(face_index, level as u32);
+
+ // GL_INVALID_VALUE is generated if:
+ // - xoffset or yoffset is less than 0
+ // - x offset plus the width is greater than the texture width
+ // - y offset plus the height is greater than the texture height
+ if xoffset < 0 || ((xoffset + width) as u32) > image_info.width() ||
+ yoffset < 0 || ((yoffset + height) as u32) > image_info.height() {
+ self.webgl_error(InvalidValue);
+ return;
+ }
+
+ let msg = WebGLCommand::CopyTexSubImage2D(target, level, xoffset, yoffset,
+ x, y, width, height);
+
+ self.ipc_renderer.send(CanvasMsg::WebGL(msg)).unwrap();
+ }
+
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11
fn Clear(&self, mask: u32) {
self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::Clear(mask))).unwrap();
@@ -1738,13 +1870,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
format: u32,
data_type: u32,
data: Option<*mut JSObject>) {
- if !self.validate_tex_image_parameters(target,
- level,
- internal_format,
- width, height,
- border,
- format,
- data_type) {
+ if !self.validate_tex_image_2d_parameters(target,
+ level,
+ internal_format,
+ width, height,
+ border,
+ format,
+ data_type) {
return; // Error handled in validate()
}
@@ -1883,9 +2015,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
};
// NB: Border must be zero
- if !self.validate_tex_image_parameters(target, level, internal_format,
- size.width, size.height, 0,
- format, data_type) {
+ if !self.validate_tex_image_2d_parameters(target, level, internal_format,
+ size.width, size.height, 0,
+ format, data_type) {
return; // Error handled in validate()
}