-
Notifications
You must be signed in to change notification settings - Fork 290
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
Image mask support #445
Conversation
@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 :) |
@glennw thanks for taking a look! |
@kvark Yep, that's right - we put (almost) everything in an atlas, so it should batch together nicely :) |
☔ The latest upstream changes (presumably #432) made this pull request unmergeable. Please resolve the merge conflicts. |
Rebased now, the implementation follows the route you laid out - passing the clip rectangles via the batch data instead of uniforms. |
☔ The latest upstream changes (presumably #461) made this pull request unmergeable. Please resolve the merge conflicts. |
There was a problem hiding this 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; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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]; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this 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)); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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"))] |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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),
}
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
@kvark Looks good! Let's squash and get this merged :) |
Do you want a single commit? Or 2-3?
|
@kvark The smallest number of commits that make sense as individual commits. 2-3 is fine if that makes sense. |
Includes the new DummyResource struct as well as a non-clipping gradient shader.
@bors-servo r+ |
📌 Commit 1e33028 has been approved by |
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 -->
☀️ Test successful - status-travis |
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