Auto merge of #26787 - szeged:texi2d_3, r=jdm

Add support for WebGL2 TexImage2D

Adds initial support for one of the WebGL2 `TexImage2D` call.

I've enabled the `tests/wpt/webgl/tests/deqp/` tests.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix part of #26512
- [x] There are tests for these changes

@mmatyas @zakorgy @jdm
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
bors-servo 2020-06-18 09:58:55 -04:00 committed by GitHub
commit 1b55ab5804
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 254 additions and 49 deletions

4
Cargo.lock generated
View file

@ -5346,9 +5346,9 @@ dependencies = [
[[package]] [[package]]
name = "sparkle" name = "sparkle"
version = "0.1.24" version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7cd7f292661a533c2a7e239af495ba63891b5723c3a6d48712b2e3823466174" checksum = "7184285ed8ddbf106cda8fef17f584207fc64a03125e3694c324b19b708825fa"
dependencies = [ dependencies = [
"gl_generator 0.13.1", "gl_generator 0.13.1",
] ]

View file

@ -35,7 +35,7 @@ pixels = { path = "../pixels" }
raqote = { version = "0.8", features = ["text"] } raqote = { version = "0.8", features = ["text"] }
servo_arc = { path = "../servo_arc" } servo_arc = { path = "../servo_arc" }
servo_config = { path = "../config" } servo_config = { path = "../config" }
sparkle = "0.1.24" sparkle = "0.1.25"
style = { path = "../style" } style = { path = "../style" }
# NOTE: the sm-angle feature only enables ANGLE on Windows, not other platforms! # NOTE: the sm-angle feature only enables ANGLE on Windows, not other platforms!
surfman = { version = "0.2", features = ["sm-angle", "sm-angle-default"] } surfman = { version = "0.2", features = ["sm-angle", "sm-angle-default"] }

View file

@ -927,7 +927,7 @@ impl WebGLThread {
0, 0,
gl::RGBA, gl::RGBA,
gl::UNSIGNED_BYTE, gl::UNSIGNED_BYTE,
None, gl::TexImageSource::Pixels(None),
); );
self.dom_outputs.insert( self.dom_outputs.insert(
pipeline_id, pipeline_id,
@ -1593,7 +1593,31 @@ impl WebGLImpl {
0, 0,
format.as_gl_constant(), format.as_gl_constant(),
effective_data_type, effective_data_type,
Some(&pixels), gl::TexImageSource::Pixels(Some(&pixels)),
);
},
WebGLCommand::TexImage2DPBO {
target,
level,
internal_format,
size,
format,
effective_data_type,
unpacking_alignment,
offset,
} => {
gl.pixel_store_i(gl::UNPACK_ALIGNMENT, unpacking_alignment as i32);
gl.tex_image_2d(
target,
level as i32,
internal_format.as_gl_constant() as i32,
size.width as i32,
size.height as i32,
0,
format.as_gl_constant(),
effective_data_type,
gl::TexImageSource::BufferOffset(offset),
); );
}, },
WebGLCommand::TexSubImage2D { WebGLCommand::TexSubImage2D {

View file

@ -398,6 +398,16 @@ pub enum WebGLCommand {
pixel_format: Option<PixelFormat>, pixel_format: Option<PixelFormat>,
data: TruncatedDebug<IpcSharedMemory>, data: TruncatedDebug<IpcSharedMemory>,
}, },
TexImage2DPBO {
target: u32,
level: u32,
internal_format: TexFormat,
size: Size2D<u32>,
format: TexFormat,
effective_data_type: u32,
unpacking_alignment: u32,
offset: i64,
},
TexSubImage2D { TexSubImage2D {
target: u32, target: u32,
level: u32, level: u32,

View file

@ -29,7 +29,8 @@ use crate::dom::webglprogram::WebGLProgram;
use crate::dom::webglquery::WebGLQuery; use crate::dom::webglquery::WebGLQuery;
use crate::dom::webglrenderbuffer::WebGLRenderbuffer; use crate::dom::webglrenderbuffer::WebGLRenderbuffer;
use crate::dom::webglrenderingcontext::{ use crate::dom::webglrenderingcontext::{
uniform_get, uniform_typed, Operation, TexPixels, VertexAttrib, WebGLRenderingContext, uniform_get, uniform_typed, Operation, TexPixels, TexSource, VertexAttrib,
WebGLRenderingContext,
}; };
use crate::dom::webglsampler::{WebGLSampler, WebGLSamplerValue}; use crate::dom::webglsampler::{WebGLSampler, WebGLSamplerValue};
use crate::dom::webglshader::WebGLShader; use crate::dom::webglshader::WebGLShader;
@ -2917,6 +2918,79 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6 /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6
fn TexImage2D__( fn TexImage2D__(
&self,
target: u32,
level: i32,
internalformat: i32,
width: i32,
height: i32,
border: i32,
format: u32,
type_: u32,
pbo_offset: i64,
) -> Fallible<()> {
let pixel_unpack_buffer = match self.bound_pixel_unpack_buffer.get() {
Some(pixel_unpack_buffer) => pixel_unpack_buffer,
None => return Ok(self.base.webgl_error(InvalidOperation)),
};
if let Some(tf_buffer) = self.bound_transform_feedback_buffer.get() {
if pixel_unpack_buffer == tf_buffer {
return Ok(self.base.webgl_error(InvalidOperation));
}
}
if pbo_offset < 0 || pbo_offset as usize > pixel_unpack_buffer.capacity() {
return Ok(self.base.webgl_error(InvalidValue));
}
let unpacking_alignment = self.base.texture_unpacking_alignment();
let validator = TexImage2DValidator::new(
&self.base,
target,
level,
internalformat as u32,
width,
height,
border,
format,
type_,
);
let TexImage2DValidatorResult {
texture,
target,
width,
height,
level,
border,
internal_format,
format,
data_type,
} = match validator.validate() {
Ok(result) => result,
Err(_) => return Ok(()),
};
self.base.tex_image_2d(
&texture,
target,
data_type,
internal_format,
format,
level,
border,
unpacking_alignment,
Size2D::new(width, height),
TexSource::BufferOffset(pbo_offset),
);
Ok(())
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6
fn TexImage2D___(
&self, &self,
target: u32, target: u32,
level: i32, level: i32,
@ -2975,7 +3049,8 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
level, level,
border, border,
unpacking_alignment, unpacking_alignment,
pixels, pixels.size(),
TexSource::Pixels(pixels),
); );
Ok(()) Ok(())
@ -2983,7 +3058,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6 /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.6
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn TexImage2D___( fn TexImage2D____(
&self, &self,
target: u32, target: u32,
level: i32, level: i32,
@ -3060,6 +3135,8 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
return Ok(self.base.webgl_error(InvalidOperation)); return Ok(self.base.webgl_error(InvalidOperation));
} }
let size = Size2D::new(width, height);
self.base.tex_image_2d( self.base.tex_image_2d(
&texture, &texture,
target, target,
@ -3069,7 +3146,8 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
level, level,
border, border,
unpacking_alignment, unpacking_alignment,
TexPixels::from_array(buff, Size2D::new(width, height)), size,
TexSource::Pixels(TexPixels::from_array(buff, size)),
); );
Ok(()) Ok(())

View file

@ -613,12 +613,13 @@ impl WebGLRenderingContext {
level, level,
0, 0,
1, 1,
TexPixels::new( size,
TexSource::Pixels(TexPixels::new(
IpcSharedMemory::from_bytes(&pixels), IpcSharedMemory::from_bytes(&pixels),
size, size,
PixelFormat::RGBA8, PixelFormat::RGBA8,
true, true,
), )),
); );
false false
@ -756,15 +757,16 @@ impl WebGLRenderingContext {
level: u32, level: u32,
_border: u32, _border: u32,
unpacking_alignment: u32, unpacking_alignment: u32,
pixels: TexPixels, size: Size2D<u32>,
source: TexSource,
) { ) {
// TexImage2D depth is always equal to 1. // TexImage2D depth is always equal to 1.
handle_potential_webgl_error!( handle_potential_webgl_error!(
self, self,
texture.initialize( texture.initialize(
target, target,
pixels.size.width, size.width,
pixels.size.height, size.height,
1, 1,
format, format,
level, level,
@ -775,12 +777,6 @@ impl WebGLRenderingContext {
let settings = self.texture_unpacking_settings.get(); let settings = self.texture_unpacking_settings.get();
let dest_premultiplied = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA); let dest_premultiplied = settings.contains(TextureUnpacking::PREMULTIPLY_ALPHA);
let alpha_treatment = match (pixels.premultiplied, dest_premultiplied) {
(true, false) => Some(AlphaTreatment::Unmultiply),
(false, true) => Some(AlphaTreatment::Premultiply),
_ => None,
};
let y_axis_treatment = if settings.contains(TextureUnpacking::FLIP_Y_AXIS) { let y_axis_treatment = if settings.contains(TextureUnpacking::FLIP_Y_AXIS) {
YAxisTreatment::Flipped YAxisTreatment::Flipped
} else { } else {
@ -795,21 +791,43 @@ impl WebGLRenderingContext {
.extension_manager .extension_manager
.effective_type(data_type.as_gl_constant()); .effective_type(data_type.as_gl_constant());
// TODO(emilio): convert colorspace if requested. match source {
self.send_command(WebGLCommand::TexImage2D { TexSource::Pixels(pixels) => {
target: target.as_gl_constant(), let alpha_treatment = match (pixels.premultiplied, dest_premultiplied) {
level, (true, false) => Some(AlphaTreatment::Unmultiply),
internal_format, (false, true) => Some(AlphaTreatment::Premultiply),
size: pixels.size, _ => None,
format, };
data_type,
effective_data_type, // TODO(emilio): convert colorspace if requested.
unpacking_alignment, self.send_command(WebGLCommand::TexImage2D {
alpha_treatment, target: target.as_gl_constant(),
y_axis_treatment, level,
pixel_format: pixels.pixel_format, internal_format,
data: pixels.data.into(), size,
}); format,
data_type,
effective_data_type,
unpacking_alignment,
alpha_treatment,
y_axis_treatment,
pixel_format: pixels.pixel_format,
data: pixels.data.into(),
});
},
TexSource::BufferOffset(offset) => {
self.send_command(WebGLCommand::TexImage2DPBO {
target: target.as_gl_constant(),
level,
internal_format,
size,
format,
effective_data_type,
unpacking_alignment,
offset,
});
},
}
if let Some(fb) = self.bound_draw_framebuffer.get() { if let Some(fb) = self.bound_draw_framebuffer.get() {
fb.invalidate_texture(&*texture); fb.invalidate_texture(&*texture);
@ -839,9 +857,9 @@ impl WebGLRenderingContext {
// - x offset plus the width is greater than the texture width // - x offset plus the width is greater than the texture width
// - y offset plus the height is greater than the texture height // - y offset plus the height is greater than the texture height
if xoffset < 0 || if xoffset < 0 ||
(xoffset as u32 + pixels.size.width) > image_info.width() || (xoffset as u32 + pixels.size().width) > image_info.width() ||
yoffset < 0 || yoffset < 0 ||
(yoffset as u32 + pixels.size.height) > image_info.height() (yoffset as u32 + pixels.size().height) > image_info.height()
{ {
return self.webgl_error(InvalidValue); return self.webgl_error(InvalidValue);
} }
@ -884,7 +902,7 @@ impl WebGLRenderingContext {
level, level,
xoffset, xoffset,
yoffset, yoffset,
size: pixels.size, size: pixels.size(),
format, format,
data_type, data_type,
effective_data_type, effective_data_type,
@ -4319,6 +4337,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
return Ok(()); return Ok(());
} }
let size = Size2D::new(width, height);
self.tex_image_2d( self.tex_image_2d(
&texture, &texture,
target, target,
@ -4328,7 +4348,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
level, level,
border, border,
unpacking_alignment, unpacking_alignment,
TexPixels::from_array(buff, Size2D::new(width, height)), size,
TexSource::Pixels(TexPixels::from_array(buff, size)),
); );
Ok(()) Ok(())
@ -4358,8 +4379,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
target, target,
level, level,
internal_format as u32, internal_format as u32,
pixels.size.width as i32, pixels.size().width as i32,
pixels.size.height as i32, pixels.size().height as i32,
0, 0,
format, format,
data_type, data_type,
@ -4391,7 +4412,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
target, target,
level, level,
internal_format, internal_format,
pixels.size, pixels.size(),
data_type, data_type,
) { ) {
// FIXME(nox): What is the spec for this? No error is emitted ever // FIXME(nox): What is the spec for this? No error is emitted ever
@ -4408,7 +4429,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
level, level,
border, border,
1, 1,
pixels, pixels.size(),
TexSource::Pixels(pixels),
); );
Ok(()) Ok(())
} }
@ -4568,8 +4590,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
target, target,
level, level,
format, format,
pixels.size.width as i32, pixels.size().width as i32,
pixels.size.height as i32, pixels.size().height as i32,
0, 0,
format, format,
data_type, data_type,
@ -4910,6 +4932,15 @@ impl TexPixels {
premultiplied: false, premultiplied: false,
} }
} }
pub fn size(&self) -> Size2D<u32> {
self.size
}
}
pub enum TexSource {
Pixels(TexPixels),
BufferOffset(i64),
} }
#[derive(JSTraceable)] #[derive(JSTraceable)]

View file

@ -505,9 +505,9 @@ interface mixin WebGL2RenderingContextOverloads
GLenum format, GLenum type, TexImageSource source); // May throw DOMException GLenum format, GLenum type, TexImageSource source); // May throw DOMException
// WebGL2 entrypoints: // WebGL2 entrypoints:
//[Throws] [Throws]
//void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
// GLint border, GLenum format, GLenum type, GLintptr pboOffset); GLint border, GLenum format, GLenum type, GLintptr pboOffset);
[Throws] [Throws]
void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type, GLint border, GLenum format, GLenum type,

View file

@ -1,5 +1,4 @@
[simultaneous_binding.html] [simultaneous_binding.html]
expected: ERROR
[WebGL test #12: getError expected: INVALID_OPERATION. Was NO_ERROR : drawArrays: buffer used as vertex attrib and tf simultaneously] [WebGL test #12: getError expected: INVALID_OPERATION. Was NO_ERROR : drawArrays: buffer used as vertex attrib and tf simultaneously]
expected: FAIL expected: FAIL
@ -75,3 +74,66 @@
[WebGL test #17: getError expected: INVALID_OPERATION. Was NO_ERROR : drawElements: buffer used as uniform buffer and tf simultaneously] [WebGL test #17: getError expected: INVALID_OPERATION. Was NO_ERROR : drawElements: buffer used as uniform buffer and tf simultaneously]
expected: FAIL expected: FAIL
[WebGL test #110: getError expected: NO_ERROR. Was INVALID_OPERATION : PIXEL_UNPACK_BUFFER is not bound for transform feedback]
expected: FAIL
[WebGL test #101: getError expected: INVALID_OPERATION. Was NO_ERROR : bufferSubData with double bound buffer]
expected: FAIL
[WebGL test #85: getError expected: INVALID_OPERATION. Was NO_ERROR : PIXEL_PACK_BUFFER is bound for transform feedback]
expected: FAIL
[WebGL test #118: getError expected: INVALID_OPERATION. Was NO_ERROR : copyBufferSubData with double bound buffer]
expected: FAIL
[WebGL test #104: getError expected: INVALID_OPERATION. Was NO_ERROR : copyBufferSubData with double bound buffer]
expected: FAIL
[WebGL test #114: getError expected: INVALID_OPERATION. Was NO_ERROR : bufferData with double bound buffer]
expected: FAIL
[WebGL test #103: getError expected: INVALID_OPERATION. Was NO_ERROR : copyBufferSubData with double bound buffer]
expected: FAIL
[WebGL test #116: getError expected: INVALID_OPERATION. Was NO_ERROR : getBufferSubData with double bound buffer]
expected: FAIL
[WebGL test #88: getError expected: INVALID_OPERATION. Was NO_ERROR : getBufferSubData with double bound buffer]
expected: FAIL
[WebGL test #113: getError expected: INVALID_OPERATION. Was NO_ERROR : PIXEL_PACK_BUFFER is bound for transform feedback]
expected: FAIL
[WebGL test #83: getError expected: INVALID_OPERATION. Was NO_ERROR : PIXEL_UNPACK_BUFFER is bound for transform feedback]
expected: FAIL
[WebGL test #117: getError expected: INVALID_OPERATION. Was NO_ERROR : copyBufferSubData with double bound buffer]
expected: FAIL
[WebGL test #100: getError expected: INVALID_OPERATION. Was NO_ERROR : bufferData with double bound buffer]
expected: FAIL
[WebGL test #89: getError expected: INVALID_OPERATION. Was NO_ERROR : copyBufferSubData with double bound buffer]
expected: FAIL
[WebGL test #102: getError expected: INVALID_OPERATION. Was NO_ERROR : getBufferSubData with double bound buffer]
expected: FAIL
[WebGL test #111: getError expected: INVALID_OPERATION. Was NO_ERROR : PIXEL_UNPACK_BUFFER is bound for transform feedback]
expected: FAIL
[WebGL test #87: getError expected: INVALID_OPERATION. Was NO_ERROR : bufferSubData with double bound buffer]
expected: FAIL
[WebGL test #99: getError expected: INVALID_OPERATION. Was NO_ERROR : PIXEL_PACK_BUFFER is bound for transform feedback]
expected: FAIL
[WebGL test #86: getError expected: INVALID_OPERATION. Was NO_ERROR : bufferData with double bound buffer]
expected: FAIL
[WebGL test #90: getError expected: INVALID_OPERATION. Was NO_ERROR : copyBufferSubData with double bound buffer]
expected: FAIL
[WebGL test #115: getError expected: INVALID_OPERATION. Was NO_ERROR : bufferSubData with double bound buffer]
expected: FAIL