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

webgl: premultiplication, y flipping, and format conversion #15122

Merged
merged 4 commits into from Feb 3, 2017

Conversation

anholt
Copy link
Contributor

@anholt anholt commented Jan 20, 2017

This series implements a bunch of the texture unpack path features for WebGL. There are known issues with big-endian systems noted in the comments, but I don't know of a clean way to cast from Vec<u16> to Vec<u8> (which, if we had one, would make this code much cleaner anyway).


  • ./mach build -d does not report any errors
  • ./mach test-tidy does not report any errors
  • These changes fix #__ (github issue number if applicable).
  • There are tests for these changes OR
  • These changes do not require tests because _____

This change is Reviewable

@highfive
Copy link

Heads up! This PR modifies the following files:

  • @KiChjang: components/script/dom/webglrenderingcontext.rs
  • @fitzgen: components/script/dom/webglrenderingcontext.rs
  • @emilio: components/script/dom/webglrenderingcontext.rs

@highfive highfive added the S-awaiting-review There is new code that needs to be reviewed. label Jan 20, 2017
Copy link
Member

@emilio emilio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Only minor comments, thanks for doing this!

// implementation. If a packed pixel format is specified
// which would imply loss of bits of precision from the image
// data, this loss of precision must occur."
fn rgba8_image_to_tex_image_data(&self,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Consider making this a doc comment.

fn rgba8_image_to_tex_image_data(&self,
format: TexFormat,
data_type: TexDataType,
pixels: Vec<u8> ) -> Vec<u8> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Remove the extra space after Vec<u8>.

// into an enum yet so there's a default case here. All
// WebGL types are 4 bytes per pixel or smaller, so just
// return the incoming RGBA8 pixels in this path.
_ => pixels
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe asserting (at least in debug builds), or marking as unreachable! would help catch errors?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, looks like unreachable!() should always panic. I thought I'd seen something in my other debugging that suggested that it didn't panic.

internal_format: TexFormat,
data_type: TexDataType,
width: usize,
height: usize) -> Vec<u8> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this only creates a vector of the same capacity as pixels, seems like we could flip in place? the logic would be a bit more complicated though, maybe mentioning it with a comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're passed in a non-mut Vec at the top of the tex_image()s since we shouldn't be rewriting the JS's array. We could potentially see that we're going to be chaining more than one of these fixups and use a single mut Vec that we operate on, but that sounded messy.

format: TexFormat,
data_type: TexDataType,
pixels: Vec<u8>) -> Vec<u8> {
if !(self.texture_unpacking_settings.get().contains(PREMULTIPLY_ALPHA)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Unnecessary parentheses.

fn premultiply_pixels(&self,
format: TexFormat,
data_type: TexDataType,
pixels: Vec<u8>) -> Vec<u8> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as above, this only returns a vector of the same size as pixels, right?

If that's the case, probably we should also premultiply in-place, either using &mut [u8], or mut pixels: Vec<u8>.

Mind at least mentioning it here (and filing a followup maybe?)

[WebGL test #1095: at (0, 4) expected: 0,0,0,255 was 0,0,255,255]
expected: FAIL

[WebGL test #1097: at (0, 8) expected: 0,0,0,255 w
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, poor test, I was wondering where the diffstat came from, awesome! :)

@@ -112,6 +112,11 @@ fn has_invalid_blend_constants(arg1: u32, arg2: u32) -> bool {
(_, _) => false
}
}

fn multiply_u8_pixel(a: u8, b: u8) -> u8 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: We have code for premultiplication in components/canvas_traits/lib.rs. They contain code similar to this, you may consider putting it there (or even all the premultiplication subroutines? Though that's not great because they aren't used anywhere else).

Anyway, your choice :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had noticed that, but I didn't imagine that that code would want to grow some sort of format enum for handling different GL formats.

// is coherent with the image.
//
// RGB8 should be easy to support too
// TODO(anholt): What other incoming formats do we
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for now Servo stores all its images internally as RGBA8, so we don't need to worry about it I think.

premul
}

_ => pixels
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this also unreachable? If not, consider commenting which cases do we expect? Otherwise, mark as such?

@emilio
Copy link
Member

emilio commented Jan 20, 2017

Regarding casting Vecs, you probably can do something using slice::from_raw_parts{_mut}, but I think we should only introduce unsafe code if totally necessary. Probably the conversion is not going to be more costly than the IPC message, but if we want to optimize it we could use that I think.

@Ms2ger
Copy link
Contributor

Ms2ger commented Jan 20, 2017

Perhaps https://docs.rs/byteorder/1.0.0/byteorder/ would help.

Copy link
Member

@emilio emilio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r=me, thanks Eric :)

@emilio
Copy link
Member

emilio commented Jan 21, 2017

@bors-servo r+

@bors-servo
Copy link
Contributor

📌 Commit 41a4f63 has been approved by emilio

@highfive highfive added S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. and removed S-awaiting-review There is new code that needs to be reviewed. labels Jan 21, 2017
@bors-servo
Copy link
Contributor

⌛ Testing commit 41a4f63 with merge 82e854a...

bors-servo pushed a commit that referenced this pull request Jan 21, 2017
webgl: premultiplication, y flipping, and format conversion

<!-- Please describe your changes on the following line: -->
This series implements a bunch of the texture unpack path features for WebGL.  There are known issues with big-endian systems noted in the comments, but I don't know of a clean way to cast from `Vec<u16>` to `Vec<u8>` (which, if we had one, would make this code much cleaner anyway).

---
<!-- 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
- [ ] These changes fix #__ (github issue number if applicable).

<!-- Either: -->
- [x] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15122)
<!-- Reviewable:end -->
@bors-servo
Copy link
Contributor

💔 Test failed - mac-rel-wpt2

@highfive highfive added S-tests-failed The changes caused existing tests to fail. and removed S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. labels Jan 21, 2017
@anholt
Copy link
Contributor Author

anholt commented Jan 23, 2017

OK, I think I know the cause of that Mac failure: not having unpack alignment support.

@emilio
Copy link
Member

emilio commented Jan 28, 2017

We could mark those as failing on mac if you want, I think this is worth landing

This fixes a couple of tests doing RGBA/ubyte image uploads with
flipping.  Other tests with flipping get their expectations changed,
because some other feature is missing (premultiplication or
ImageData/canvas format conversion)
The code was returning RGBA8 data from the non-raw sources (HTML
canvas elements, JS ImageData, etc.), but we then validated and passed
that rgba8 data as if it was whatever format/datatype was specified in
TexImage2D/TexSubImage2D, so the pixels would come out as garbage.

It would seem like we could just rewrite the passed in format/datatype
for the TexImage call to be RGBA/UNSIGNED_BYTE, but that would leave
incorrect levels of precision if the internalformat didn't match the
format/datatype (and older desktop implementations often ignore the
internalformat in choosing their internal format, anyway).
Now the affected testcase only fails due to unpack alignment.
@anholt
Copy link
Contributor Author

anholt commented Jan 28, 2017

I'm actually testing the unpack fix now.

We were setting it to whatever value from {1,2,4,8} the user requested
and otherwise ignoring it.  There were two problems there:

1) Validation ignored it, so GL could read outside of the user's array
   in TexImage() or TexSubImage() if the aligment was greater than
   cpp.

2) TexImage()/TexSubImage() from image/canvas sources wasn't packing
   its data according to the unpack alignment.

To fix this, start tracking the user-requested alignment in the DOM
side of the context.  Set the GL's alignment to 1 for image/canvas
sources or the user's value for array sources, and pass the user's
alignment in to validation so that it can figure out the correct size
of image that the GL will ready.
@highfive highfive added S-awaiting-review There is new code that needs to be reviewed. and removed S-tests-failed The changes caused existing tests to fail. labels Jan 29, 2017
Copy link
Member

@emilio emilio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a uber-nit, s/ready.$/read./ in the last commit message, but I don't really want to block landing this on it.

let expected_byte_length = width * height * element_size * components / components_per_element;
return Ok(expected_byte_length);
if height == 0 {
return Ok(0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Since you early-return, there's no need for the else branch, but not a big deal.

@emilio
Copy link
Member

emilio commented Feb 3, 2017

@bors-servo r+

Thanks!

@bors-servo
Copy link
Contributor

📌 Commit fcef92f has been approved by emilio

@highfive highfive added S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. and removed S-awaiting-review There is new code that needs to be reviewed. labels Feb 3, 2017
@bors-servo
Copy link
Contributor

⌛ Testing commit fcef92f with merge 536c0d7...

bors-servo pushed a commit that referenced this pull request Feb 3, 2017
webgl: premultiplication, y flipping, and format conversion

<!-- Please describe your changes on the following line: -->
This series implements a bunch of the texture unpack path features for WebGL.  There are known issues with big-endian systems noted in the comments, but I don't know of a clean way to cast from `Vec<u16>` to `Vec<u8>` (which, if we had one, would make this code much cleaner anyway).

---
<!-- 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
- [ ] These changes fix #__ (github issue number if applicable).

<!-- Either: -->
- [x] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15122)
<!-- Reviewable:end -->
@bors-servo
Copy link
Contributor

☀️ Test successful - android, arm32, arm64, linux-dev, linux-rel-css, linux-rel-wpt, mac-dev-unit, mac-rel-css, mac-rel-wpt1, mac-rel-wpt2, windows-gnu-dev, windows-msvc-dev
Approved by: emilio
Pushing 536c0d7 to master...

@bors-servo bors-servo merged commit fcef92f into servo:master Feb 3, 2017
@highfive highfive removed the S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. label Feb 3, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants