Skip to content

Image mask support #445

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

Merged
merged 2 commits into from
Oct 26, 2016
Merged

Image mask support #445

merged 2 commits into from
Oct 26, 2016

Conversation

kvark
Copy link
Member

@kvark kvark commented Oct 17, 2016

Closes #405

I'm not completely sure if this is the right approach, hoping to get some review/feedback to proceed. The API and logic works for me with wr_sample, although the implementation lacks a lot of features to support, like image repeating and layout transformations.


This change is Reviewable

@glennw
Copy link
Member

glennw commented Oct 17, 2016

@kvark Thanks! The general idea here seems good - the public API looks fine to me.

In terms of implementation, I try to avoid using uniform variables whenever possible, to simplify how the batching code works and reduce batch breaks. Instead, what I'd suggest is adding fields to the Clip struct in tiling.rs, and modifying the code in prim_shared to fetch the data from there. That way, there shouldn't be any need to change the batching code at all.

Let me know if that doesn't make sense or you foresee any issues with that :)

@kvark
Copy link
Member Author

kvark commented Oct 18, 2016

@glennw thanks for taking a look!
I've actually considered that (passing via Clip) but then thought that since the image itself is being passed as a uniform sampler, it doesn't make sense to pass the associated data per batch.
Now that I think of it though, the image we pass is an atlas, so it makes perfect sense to have different source/dest rectangles per batch given that these refer to different sub-images within the atlas.
I'll implement the proposed change and get back to you ;)

@glennw
Copy link
Member

glennw commented Oct 18, 2016

@kvark Yep, that's right - we put (almost) everything in an atlas, so it should batch together nicely :)

@bors-servo
Copy link
Contributor

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

@kvark
Copy link
Member Author

kvark commented Oct 21, 2016

Rebased now, the implementation follows the route you laid out - passing the clip rectangles via the batch data instead of uniforms.

@bors-servo
Copy link
Contributor

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

Copy link
Member

@glennw glennw left a comment

Choose a reason for hiding this comment

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

Looks pretty good, just a few minor issues / questions. I rebased it locally on my machine to test with, there was only a couple of minor conflicts to fix up.

@@ -5,6 +5,8 @@

flat varying vec4 vClipRect;
flat varying vec4 vClipRadius;
flat varying vec4 vClipMaskUvRect;
flat varying vec4 vClipMaskScreenRect;
Copy link
Member

Choose a reason for hiding this comment

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

We should probably rename this to be something like vClipMaskLocalRect, since (I think) it's in the local space of the primitive rectangle?

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

return rect;
}

struct MaskRect {
Copy link
Member

Choose a reason for hiding this comment

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

Could we rename these fields to be a bit more descriptive? Perhaps uv_rect and local_mask_rect or something like that?

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

@@ -206,12 +209,19 @@ impl ClipCorner {
}

#[derive(Debug, Clone)]
pub struct MaskRect {
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps rename this to ImageMaskInfo or something like that?

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

@@ -552,6 +553,11 @@ impl Renderer {
let data64_texture = VertexDataTexture::new(&mut device);
let data128_texture = VertexDataTexture::new(&mut device);

let dummy_mask_texture = device.create_texture_ids(1)[0];
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if this will cause unnecessary batch breaks when there are clips that don't have masks. We could probably insert a dummy mask into the atlas instead of creating a separate texture. But that doesn't matter for now, we can do it as a follow up if it's an issue.

Copy link
Member Author

Choose a reason for hiding this comment

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

I had a hard time figuring out how to properly assign a default masking texture for this case. Ended up introducing DummyResources struct to store the white texture as well the opaque one (which were previously forgotten but still created). Let me know if there is a better solution please.

@@ -702,6 +704,23 @@ impl RenderTask {
pub const SCREEN_TILE_SIZE: i32 = 64;
pub const RENDERABLE_CACHE_SIZE: DevicePixel = DevicePixel(2048);

/// Per-batch clipping info merged with the mask image.
#[derive(Clone, Debug)]
pub struct MaskedClip {
Copy link
Member

Choose a reason for hiding this comment

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

Instead of introducing a new structure here, could we just add the fields/struct to the Clip structure? The Clip structure already handles simple / complex clips, it seems like it's probably reasonable to make the Clip structure able to handle any number of clip types. If we do that, we won't need to modify the API of all the FrameBuilder methods.

Copy link
Member Author

@kvark kvark Oct 24, 2016

Choose a reason for hiding this comment

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

MaskedClip is a part of the Clip, so moving the fields in there directly would break the API as much regardless. The reason I even introduced this was to pack both rectangles into a single 32 byte gpu block, instead of having a 16 byte pad after each.

Copy link
Member

@glennw glennw left a comment

Choose a reason for hiding this comment

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

Nearly there! :)

vec2 local_pos = vPos;
#endif

alpha = min(alpha, do_clip(local_pos));
Copy link
Member

Choose a reason for hiding this comment

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

This contains a do_clip() call which fails to compile.

Copy link
Member Author

Choose a reason for hiding this comment

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

oh, nicely spotted!

@@ -676,7 +693,7 @@ impl Renderer {
fn enable_msaa(&self, _: bool) {
}

#[cfg(any(target_os = "windows", unix))]
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
Copy link
Member

Choose a reason for hiding this comment

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

Mistake during rebase to change this?

Copy link
Member Author

Choose a reason for hiding this comment

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

weird indeed, fixed


/// Per-batch clipping info merged with the mask image.
#[derive(Clone, Debug)]
pub struct MaskedClip {
Copy link
Member

@glennw glennw Oct 24, 2016

Choose a reason for hiding this comment

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

I'm still not sure about having this struct. Could we have something like:

struct Clip {
  // existing clip rect and corners
  pub mask: Option<MaskImageSource>,
}

And then use that to construct the data to be put in the gpu blocks during prim prepare / cache?

I might be missing something as I haven't actually tried this - but it sounds like it might be a simpler API if it works.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm following the existing style in here. Clip structure (contrary to ClipRegion) is supposed to map semi-directly to the GPU. At least it seems it should, given that the shader side has the same structs (Clip, ClipRect, ClipCorner).
If I add Option<MaskImageSource>, that would make it inconsistent, since:

pub enum MaskImageSource {
    User(ImageKey),
    Renderer(TextureId),
}

Copy link
Member

Choose a reason for hiding this comment

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

I can see your point about the consistency aspect of the structure internals, but I think having the public API type for FrameBuilder be called Clip is important. How about as a compromise we keep the structure layout as is, but rename Clip -> ClipGpu and make it private, and rename MaskedClip -> Clip?

Copy link
Member Author

Choose a reason for hiding this comment

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

agreed, fixed now

oFragColor = vColor * vec4(1, 1, 1, alpha);

#ifdef WR_FEATURE_TRANSFORM
Copy link
Member Author

Choose a reason for hiding this comment

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

@glennw
Looks like we were multiplying the alpha twice. I assume this was a mistake.

@glennw
Copy link
Member

glennw commented Oct 25, 2016

@kvark Looks good! Let's squash and get this merged :)

@kvark
Copy link
Member Author

kvark commented Oct 25, 2016

Do you want a single commit? Or 2-3?

On Oct 25, 2016, at 16:54, Glenn Watson notifications@github.com wrote:

@kvark Looks good! Let's squash and get this merged :)


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

@glennw
Copy link
Member

glennw commented Oct 25, 2016

@kvark The smallest number of commits that make sense as individual commits. 2-3 is fine if that makes sense.

kvark added 2 commits October 25, 2016 19:11
Includes the new DummyResource struct as well as a non-clipping gradient shader.
@glennw
Copy link
Member

glennw commented Oct 25, 2016

@bors-servo r+

@bors-servo
Copy link
Contributor

📌 Commit 1e33028 has been approved by glennw

@bors-servo
Copy link
Contributor

⌛ Testing commit 1e33028 with merge f13e95b...

bors-servo pushed a commit that referenced this pull request Oct 26, 2016
Image mask support

Closes #405

I'm not completely sure if this is the right approach, hoping to get some review/feedback to proceed. The API and logic works for me with `wr_sample`, although the implementation lacks a lot of features to support, like image repeating and layout transformations.

<!-- 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/445)
<!-- Reviewable:end -->
@bors-servo
Copy link
Contributor

☀️ Test successful - status-travis

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.

3 participants