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

[WIP] Simplify texture names and support more than two textures in the shaders. #534

Merged
merged 2 commits into from
Nov 10, 2016

Conversation

nical
Copy link
Contributor

@nical nical commented Nov 7, 2016

WebRender currently mostly assumes two reusable texture slots: the color and mask textures, which are sometimes used as color and color, and will soon be also used for other purposes like the Y, U and V planes (requiring an extra slot).
The way some shaders refer to the mask texture (sMask) as an extra color texture is confusing, and while it is most often used as a mask, the fact that it is sometimes not used as such means one can never know for sure until careful review of the corresponding shader code.
We also need more samplers for some effects such as YUV images.

I propose that the reusable samplers have generic names (sTexture0, sTexture1, etc.) which are used in the generic places (for example the device mostly does not know whether a texture is used as a color, a mask or a YUV plane), with a collection of specific name aliases (COLOR_TEXTURE_0, MASK_TEXTURE, Y_TEXTURE, etc.) for the code manipulating the samplers for specific purposes. This applies to both the shaders and the various data structures generated in the render backend.


This change is Reviewable

@nical
Copy link
Contributor Author

nical commented Nov 7, 2016

This is a work in progress (do not land), I haven't yet figured out all of the places where to use generic names versus specific (for example I have a hunch that mask_texture_id in prim_store.rs may used as a non-mask texture but I am not sure).
I'd also like to use this refactoring to add extra samplers where they'll be needed for yuv images and rebase my video work on top of this if the approach is good.

Feedback welcome!

@Ms2ger Ms2ger changed the title Use generic names for the reusable samplers and add specific aliases. [WIP] Use generic names for the reusable samplers and add specific aliases. Nov 7, 2016
@kvark
Copy link
Member

kvark commented Nov 7, 2016

This redirection would allow us to use less texture slots, so can be useful if we see the problem with the texture slots on the horizon. Alternatively, If we don't anticipate the problem, we can continue using pre-defined slots for stuff, just make it more clean (i.e. add sColorExtra instead of re-using sMask), which has a benefit of simpler code.

@nical
Copy link
Contributor Author

nical commented Nov 7, 2016

I'm all for not aliasing the sampler names if we have the budget to do so. As long as I can trust the variable names when I read the code I am happy.

we'd have:

  • sColor
  • sSecondaryColor (for blending)
  • sMask
  • sYTexture
  • sUTexture
  • sVTexture

It would not be too bad to reuse "color" for the yuv planes so we could have instead:

  • sColor0 (most things, including Y plane)
  • sColor1 (blending, U plane)
  • sColor2 (V plane)
  • sMask

That's for the shaders. The rust side of things has the same naming issue (even harder to understand in my opinion) which my patch doesn't properly address yet.

@glennw
Copy link
Member

glennw commented Nov 7, 2016

I'd prefer not to alias the names right now - we can deal with that if/when we hit it. Having sColor0-2 and sMask seems good to me.

@bors-servo
Copy link
Contributor

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

@nical
Copy link
Contributor Author

nical commented Nov 8, 2016

Sounds good to me, I'll update the PR.

@nical
Copy link
Contributor Author

nical commented Nov 8, 2016

The latest version is still a work in progress. Shaders can receive up to 3 color textures plus 1 mask. AlphaBatchKey specifies the four textures (instead of a color and something that is either a mask or a color but is called mask), I haven't gotten to the primitive store yet, but something similar needs to happen there.

Note that these four SourceTexture enums end up taking a lot more space that two texture ids. If that's an issue we can optimize the SourceTexture data structure (for example encode the external key in the TextureId using some of the spare bits in the target member to differentiate between the two).

@nical nical changed the title [WIP] Use generic names for the reusable samplers and add specific aliases. [WIP] Simplify texture names and support more than two textures in the shaders. Nov 8, 2016
@nical
Copy link
Contributor Author

nical commented Nov 8, 2016

Things are starting to come together. I have removed the SourceTexture/ExternalImage part, which I'll come back with in a separate pull request.

This PR now does the following things:

  • Stop reusing texture names for other things (for instance using mask_texture to store a secondary color), both in the shaders and the rust code.
  • Support up to three color textures, in preparation for the YUV image work.

Copy link
Member

@kvark kvark left a comment

Choose a reason for hiding this comment

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

Looks good! Got a few non-critical nits to address.

@@ -58,7 +58,7 @@ float do_clip(vec2 pos) {
vec2 clamped_mask_uv = repeat_mask ? fract(vMaskUv) :
clamp(vMaskUv, vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 source_uv = clamped_mask_uv * vClipMaskUvRect.zw + vClipMaskUvRect.xy;
float mask_alpha = texture(sMask, source_uv).r; //careful: texture has type A8
float mask_alpha = texture(sMask, source_uv).r; //careful: texture has type A8
Copy link
Member

Choose a reason for hiding this comment

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

accidental spacing?

@@ -341,6 +341,8 @@ impl TextureId {
target: gl::TEXTURE_2D,
}
}

pub fn is_invalid(&self) -> bool { *self == TextureId::invalid() }
Copy link
Member

Choose a reason for hiding this comment

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

while certainly useful, I think it would be better to avoid double-negative, and have is_valid() method instead

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 originally had is_valid, but all call sites were negating it if !texture.is_valid() { ... so I ended up bundling the negation in the function. I don't mind either way, whichever you prefer works for me.

Copy link
Member

Choose a reason for hiding this comment

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

Perf-wise, marking it #[inline] makes both equally efficient, and !texture.is_valid() takes even 1 less char than texture.is_invalid(), so it's not like we are sacrificing compactness for clarity here :)

}

// In some places we need to temporarily bind a texture to any slot.
pub const DEFAULT_SAMPLER: TextureSampler = TextureSampler::Color0;
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps, we can lean more to the "texture" part of the concept, since eventually we'll have separate samplers from textures, and this term (DEFAULT_SAMPLER) will be misleading. Maybe DEFAULT_TEXTURE?

/// Optional textures that can be used as a source in the shaders.
/// Textures that are not used by the batch are equal to TextureId::invalid().
#[derive(Copy, Clone, Debug)]
pub struct PrimitiveBatchTextures {
Copy link
Member

Choose a reason for hiding this comment

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

that's nice! Although, FYI the mask one may be gone soon.

@@ -93,7 +93,7 @@ pub enum ImagePrimitiveKind {
#[derive(Debug)]
pub struct ImagePrimitiveCpu {
pub kind: ImagePrimitiveKind,
pub color_texture_id: TextureId,
pub color_texture: TextureId,
Copy link
Member

Choose a reason for hiding this comment

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

any reason you didn't like the _id at the end?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that's an artifact from when I had replaced some of the TextureId by the SourceTexture enum (and thus removed the _id suffix) before splitting that out for a future PR. I'll correct that.

self.device.bind_texture(TextureSampler::Mask, mask_texture_id);

// TODO(nical): This will force all unused slots to be bound to the invalid
// TextureId. Should we just leave them out?
Copy link
Member

Choose a reason for hiding this comment

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

yeah, no need to touch what is not used
if a texture is used and not provided (thus forcing us to bind invalid()), that's a bug we should be chasing and fixing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

FWIW we already explicitly bind to TextureId::invalid in some places such as

self.device.bind_texture(TextureSampler::Mask, TextureId::invalid());

The renderer currently also does that for the color and mask textures every time.

In practice it unbinds the texture since the "invalid" gl handle is 0 under the hood.

I don't know if unbinding an unused texture slot after a pass that used it has any noticeable overhead so I added the comment bu it's probably not a big deal.

}

impl PrimitiveBatchTextures {
pub fn no_texture() -> Self {
Copy link
Member

Choose a reason for hiding this comment

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

perhaps just empty() ?

self.device.delete_buffer(ubo);
}
let max_prim_items = self.max_prim_blends;
self.draw_ubo_batch(ubo_data, shader,
Copy link
Member

Choose a reason for hiding this comment

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

interesting. @glennw do you remember why draw_ubo_batch wasn't used here in the first place?

Copy link
Member

Choose a reason for hiding this comment

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

Hmmm, I'm not sure - possibly just an oversight.

self.color_texture_id == other.color_texture_id) &&
(self.mask_texture_id == TextureId::invalid() || other.mask_texture_id == TextureId::invalid() ||
self.mask_texture_id == other.mask_texture_id)
(self.textures.colors[0].is_invalid() || other.textures.colors[0].is_invalid() ||
Copy link
Member

Choose a reason for hiding this comment

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

could use some iteration here for DRY

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.

@nical This looks great, it tidies up the code a lot and adds support for the extra texture slots we need.

I was a little confused why you had come across usage of sMask as a color texture - then I realised there are a heap of old, unused shaders in the resource dir. I've removed them in #542.

So you'll need to rebase after that lands, which should be easy. Apart from that and the couple of minor comments, this should be good to merge if you're happy with it after that?

self.device.delete_buffer(ubo);
}
let max_prim_items = self.max_prim_blends;
self.draw_ubo_batch(ubo_data, shader,
Copy link
Member

Choose a reason for hiding this comment

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

Hmmm, I'm not sure - possibly just an oversight.

self.color_texture_id == other.color_texture_id) &&
(self.mask_texture_id == TextureId::invalid() || other.mask_texture_id == TextureId::invalid() ||
self.mask_texture_id == other.mask_texture_id)
(!self.textures.colors[0].is_valid() || !other.textures.colors[0].is_valid() ||
Copy link
Member

Choose a reason for hiding this comment

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

Can we add a (inline) function to check if two textures are compatible? That would make this function a lot easier to read.

@bors-servo
Copy link
Contributor

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

@glennw
Copy link
Member

glennw commented Nov 9, 2016

@nical BTW, I've finished up the work I was doing for text-shadow to allow me to work on the texture cache. This is mostly related to improvements for handling the glyph cache, but is likely to overlap quite a bit with the SourceTexture / ExternalTexture stuff you mentioned - so we should discuss that at some point. In the meantime, let's get this PR finished up and merged as soon as we can :)

@nical nical force-pushed the sampler-names branch 2 times, most recently from 6a379df to c2bf9c9 Compare November 9, 2016 14:25
@nical
Copy link
Contributor Author

nical commented Nov 9, 2016

I rebased everything on top of current master (which was epic, I should have squashed the commits before rather than after doing that), and squashed it down to one commit.

@bors-servo
Copy link
Contributor

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

@glennw
Copy link
Member

glennw commented Nov 10, 2016

@bors-servo r+

@bors-servo
Copy link
Contributor

📌 Commit 5b8f55f has been approved by glennw

@bors-servo
Copy link
Contributor

⌛ Testing commit 5b8f55f with merge 00a8818...

bors-servo pushed a commit that referenced this pull request Nov 10, 2016
[WIP] Simplify texture names and support more than two textures in the shaders.

WebRender currently mostly assumes two reusable texture slots: the color and mask textures, which are sometimes used as color and color, and will soon be also used for other purposes like the Y, U and V planes (requiring an extra slot).
The way some shaders refer to the mask texture (sMask) as an extra color texture is confusing, and while it is most often used as a mask, the fact that it is sometimes not used as such means one can never know for sure until careful review of the corresponding shader code.
We also need more samplers for some effects such as YUV images.

I propose that the reusable samplers have generic names (sTexture0, sTexture1, etc.) which are used in the generic places (for example the device mostly does not know whether a texture is used as a color, a mask or a YUV plane), with a collection of specific name aliases (COLOR_TEXTURE_0, MASK_TEXTURE, Y_TEXTURE, etc.) for the code manipulating the samplers for specific purposes. This applies to both the shaders and the various data structures generated in the render backend.

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

☀️ Test successful - status-travis

@bors-servo bors-servo merged commit 5b8f55f into servo:master Nov 10, 2016
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.

5 participants