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

Introduce color matrix filter. #2323

Merged
merged 1 commit into from Feb 1, 2018
Merged

Introduce color matrix filter. #2323

merged 1 commit into from Feb 1, 2018

Conversation

@eeejay
Copy link
Contributor

eeejay commented Jan 18, 2018

This is a patch I came up with for issue #2297. It's not very good! This is my first Rust patch, and I know nothing of graphics or shaders. But it works? And it passes all the ref tests.

For one, I increased the FilterOp enum type to be over 80 bytes.

Second, I badly abused the GPU cache. I'm not sure how to do this. Primitives are too small for storing a whole matrix.


This change is Reviewable

@glennw
Copy link
Member

glennw commented Jan 19, 2018

Reviewed 10 of 10 files at r1.
Review status: all files reviewed at latest revision, 4 unresolved discussions.


webrender/res/ps_blend.glsl, line 24 at r1 (raw file):

  ColorTransforms ctransform;

  ctransform.matrix = mat4(data[3], data[4], data[5], data[6]);

It wasn't really clear to me why this worked, starting to index from [3]. But I guess it's because the code passes the GPU cache address of the primitive, which already writes [local rect, local clip, color]. You mentioned this in the original commit, but it took me a bit to work out what was going on here :)


webrender/res/ps_blend.glsl, line 161 at r1 (raw file):

            break;
        case 10:
            oFragColor = vColorTransforms.matrix * Cs + vColorTransforms.multiplier;

It seems like the multiplier is really an offset? Perhaps it should be renamed?


webrender_api/src/display_item.rs, line 505 at r1 (raw file):

    Sepia(f32),
    DropShadow(LayoutVector2D, f32, ColorF),
    ColorMatrix([f32; 20]),

As you mentioned in your commit, increasing the size here isn't ideal. It's probably not that big of a deal - since there aren't that many filter ops on most pages, but it might show up in some of the benchmarks we run that do a lot of opacity ops. I think the "proper" solution is probably to store these in the display list in a separate place, and reference them. Thoughts @gankro?


wrench/src/yaml_helper.rs, line 565 at r1 (raw file):

                ("color-matrix", ref args, _) if args.len() == 1 => {
                    let mut matrix: [f32; 20] = [0.0; 20];
                    let str = format!("---\nmatrix: {}\n", args[0]);

It seems a little unfortunate to create a new yaml doc here. Could we modify the format slightly so that we can just read it as an array of floats, perhaps?


Comments from Reviewable

@glennw
Copy link
Member

glennw commented Jan 19, 2018

Thanks for the PR!

I made a few comments, but they are mostly just related to the stuff you already mentioned in your commit, or very minor details.

It's not clear to me right now where the best place would be to store that matrix data (both in the display list, and also how we get it to the GPU). I'll have a think over the next day or so and comment here. Some possibilities are:

  • Expanding the size of the Composite instance struct (might not be ideal due to batch storage issues).
  • Something similar to what you have now (it doesn't quite fit in with how the rest of the filter system works).
  • Having it in the GPU cache but stored as a separate entry with a different GPU address (need to think about this more).
  • Expanding the size of the render task data (might not be as bad as it sounds).
  • Storing it as a uniform array and breaking batches (doesn't really fit in with how the rest of the code works).

Any thoughts on the above or other ideas @kvark ? Any thoughts on the display list storage @gankro ?

Thanks!

@Gankra
Copy link
Contributor

Gankra commented Jan 19, 2018

That's pretty harsh bloat, yeah. We could certainly pull it out as a fixed-size aux-list in the same way we do gradient stops. Otherwise we could add a junk None-like variant to this enum so that my deserialize_in_place optimization is making the overall size of the variant less relevant.

@glennw
Copy link
Member

glennw commented Jan 22, 2018

Having thought about this over the weekend - I think storing it in the GPU cache as part of the Picture data (as you've done here) is basically correct. It does actually fit in well with how brush primitives work, which the blend shader will eventually be ported to.

I'll add a couple of extra comments related to that. Then, we'll need to work out the display list stuff mentioned above by @gankro and the other minor comments.

vec4 data[8] = fetch_from_resource_cache_8(address);
ColorTransforms ctransform;

ctransform.matrix = mat4(data[3], data[4], data[5], data[6]);

This comment has been minimized.

@glennw

glennw Jan 22, 2018

Member

I think it'd be clearer what's happening here if we pass in the modified address (offset), and then fetch the data from there.

@@ -4,13 +4,29 @@

#include shared,prim_shared

struct ColorTransforms {
mat4 matrix;

This comment has been minimized.

@glennw

glennw Jan 22, 2018

Member

nit: the rest of the file uses 4-space indentation.

@@ -1276,6 +1276,20 @@ impl PrimitiveStore {
let pic = &self.cpu_pictures[metadata.cpu_prim_index.0];
pic.write_gpu_blocks(&mut request);

match pic.kind {

This comment has been minimized.

@glennw

glennw Jan 22, 2018

Member

Can we move this inside the write_gpu_blocks method of the Picture type?

@bors-servo
Copy link
Contributor

bors-servo commented Jan 22, 2018

The latest upstream changes (presumably #2326) made this pull request unmergeable. Please resolve the merge conflicts.

@eeejay eeejay force-pushed the eeejay:colormatrix branch from 7935168 to 6e02ea8 Jan 23, 2018
@eeejay
Copy link
Contributor Author

eeejay commented Jan 23, 2018

Review status: 5 of 10 files reviewed at latest revision, 7 unresolved discussions.


webrender/res/ps_blend.glsl, line 24 at r1 (raw file):

Previously, glennw (Glenn Watson) wrote…

I think it'd be clearer what's happening here if we pass in the modified address (offset), and then fetch the data from there.

So have a constant "offset = 3", or pass offset as an argument to fetch_color_transforms?


webrender/res/ps_blend.glsl, line 24 at r1 (raw file):

Previously, glennw (Glenn Watson) wrote…

It wasn't really clear to me why this worked, starting to index from [3]. But I guess it's because the code passes the GPU cache address of the primitive, which already writes [local rect, local clip, color]. You mentioned this in the original commit, but it took me a bit to work out what was going on here :)

Interesting! I actually figured out the offset with trial and error.


webrender/res/ps_blend.glsl, line 161 at r1 (raw file):

Previously, glennw (Glenn Watson) wrote…

It seems like the multiplier is really an offset? Perhaps it should be renamed?

That looks like a bad name to me too. I misread an article about feColorMatrix and thought that was the name of that column. I'll rename it to offset.


wrench/src/yaml_helper.rs, line 565 at r1 (raw file):

Previously, glennw (Glenn Watson) wrote…

It seems a little unfortunate to create a new yaml doc here. Could we modify the format slightly so that we can just read it as an array of floats, perhaps?

Yeah. Made it a function that takes 20 arguments :)


Comments from Reviewable

@eeejay
Copy link
Contributor Author

eeejay commented Jan 23, 2018

Review status: 5 of 10 files reviewed at latest revision, 7 unresolved discussions.


webrender/res/ps_blend.glsl, line 8 at r1 (raw file):

Previously, glennw (Glenn Watson) wrote…

nit: the rest of the file uses 4-space indentation.

Done.


webrender/src/prim_store.rs, line 1279 at r1 (raw file):

Previously, glennw (Glenn Watson) wrote…

Can we move this inside the write_gpu_blocks method of the Picture type?

Done.


Comments from Reviewable

@eeejay
Copy link
Contributor Author

eeejay commented Jan 23, 2018

Review status: 5 of 10 files reviewed at latest revision, 7 unresolved discussions.


webrender_api/src/display_item.rs, line 505 at r1 (raw file):

Previously, glennw (Glenn Watson) wrote…

As you mentioned in your commit, increasing the size here isn't ideal. It's probably not that big of a deal - since there aren't that many filter ops on most pages, but it might show up in some of the benchmarks we run that do a lot of opacity ops. I think the "proper" solution is probably to store these in the display list in a separate place, and reference them. Thoughts @gankro?

I'm lost in the display list serialization code, and I'm not sure how to do this...


Comments from Reviewable

@glennw
Copy link
Member

glennw commented Jan 24, 2018

@gankro Can you offer any tips for implementing the display list changes above?

@Gankra
Copy link
Contributor

Gankra commented Jan 29, 2018

Sorry I was out with flu the last week. I want to spend a bit of today thinking over aux list stuff again since kvark has also been having trouble with this. Hopefully will get back to you tonight.

@Gankra
Copy link
Contributor

Gankra commented Jan 30, 2018

Ok so having looked at this, I'd like to proceed with the changes to FilterOp as-is, and I'll do a followup PR to optimize our aux-list processing (or not if we measure no impact).

The change I'm picturing is fairly straight-forward for me to implement.

@eeejay
Copy link
Contributor Author

eeejay commented Jan 30, 2018

Sounds good! I'm not sure how to use reviewable.io. But I think this pull request is ready for another round of reviews. I am PTO starting tomorrow till February 12th, so I'll be slow on followup.


Review status: 5 of 10 files reviewed at latest revision, 7 unresolved discussions.


Comments from Reviewable

@glennw
Copy link
Member

glennw commented Jan 30, 2018

@eeejay Sounds good, thanks! I'll do another review pass over this today.

Copy link
Member

glennw left a comment

Looks good! Just a couple of minor changes, then this should be ready to go.

vec4 offset;
};

varying ColorTransforms vColorTransform;

This comment has been minimized.

@glennw

glennw Jan 31, 2018

Member

We've had issues in the past with driver bugs when a struct is passed as a varying, unfortunately. See https://github.com/servo/webrender/wiki/Driver-issues#1157---varying-structs for details. The workaround is to only pass GLSL primitive types as varyings.

PictureKind::TextShadow { .. } |
PictureKind::Image { .. } => {
request.push([0.0; 4]);
PictureKind::TextShadow { .. } => {

This comment has been minimized.

@glennw

glennw Jan 31, 2018

Member

There are some code paths that rely on knowing the number of GPU blocks that a primitive writes (the brush / segment code). In this case, it's actually fine, since PictureKind::Image never passes through that path. However, it may do in the future. Could you add a comment here noting that this code will need to change if/when we start pushing Image pictures through the brush path?

@eeejay eeejay force-pushed the eeejay:colormatrix branch from 6e02ea8 to f537110 Jan 31, 2018
@eeejay
Copy link
Contributor Author

eeejay commented Jan 31, 2018

Followed up with the nits you mentioned. Hopefully this is mergable, if not I'll be back on the 12th!


Review status: 3 of 10 files reviewed at latest revision, 9 unresolved discussions.


webrender/res/ps_blend.glsl, line 12 at r2 (raw file):

Previously, glennw (Glenn Watson) wrote…

We've had issues in the past with driver bugs when a struct is passed as a varying, unfortunately. See https://github.com/servo/webrender/wiki/Driver-issues#1157---varying-structs for details. The workaround is to only pass GLSL primitive types as varyings.

Removing the structure and function.


webrender/src/picture.rs, line 599 at r2 (raw file):

Previously, glennw (Glenn Watson) wrote…

There are some code paths that rely on knowing the number of GPU blocks that a primitive writes (the brush / segment code). In this case, it's actually fine, since PictureKind::Image never passes through that path. However, it may do in the future. Could you add a comment here noting that this code will need to change if/when we start pushing Image pictures through the brush path?

Cool. I'll add a comment.


Comments from Reviewable

@glennw
Copy link
Member

glennw commented Jan 31, 2018

Thank you!

@bors-servo r+

@bors-servo
Copy link
Contributor

bors-servo commented Jan 31, 2018

📌 Commit f537110 has been approved by glennw

@bors-servo
Copy link
Contributor

bors-servo commented Feb 1, 2018

Testing commit f537110 with merge 47f5afa...

bors-servo added a commit that referenced this pull request Feb 1, 2018
Introduce color matrix filter.

This is a patch I came up with for issue #2297. It's not very good! This is my first Rust patch, and I know nothing of graphics or shaders. But it works? And it passes all the ref tests.

For one, I increased the FilterOp enum type to be over 80 bytes.

Second, I badly abused the GPU cache. I'm not sure how to do this. Primitives are too small for storing a whole matrix.

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

bors-servo commented Feb 1, 2018

☀️ Test successful - status-appveyor, status-taskcluster, status-travis
Approved by: glennw
Pushing 47f5afa to master...

@bors-servo bors-servo merged commit f537110 into servo:master Feb 1, 2018
3 of 4 checks passed
3 of 4 checks passed
code-review/reviewable 7 files, 9 discussions left (eeejay, glennw)
Details
Taskcluster (pull_request) TaskGroup: success
Details
continuous-integration/appveyor/pr AppVeyor build succeeded
Details
homu Test successful
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

4 participants
You can’t perform that action at this time.