-
Notifications
You must be signed in to change notification settings - Fork 282
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
Add a YUV image shader. #528
Conversation
At the moment this is very incomplete. The shader is created but other than that it is not integrated in webrender yet. Feedback on the approach are welcome! |
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 good, although I'd prefer to see the actual usage code as well.
#ifdef WR_YUV_IMAGE | ||
uniform sampler2D sYTexture; | ||
// TODO: investigate storing the U and V planes in the same texture. | ||
uniform sampler2D sUTexture; |
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 do you think we can afford allocating 2 more slots for the UV stuff? Doesn't look like they are going to be used for anything else, and we are limited to 16 slots in total.
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 think that's fine - we can fix that when it becomes a problem. I can very easily reduce the number of samplers currently in use by combining some of the vertex data textures too, so I don't expect it to be a problem in the near future.
float y = texture(sYTexture, st).a; | ||
float u = texture(sUTexture, st).a; | ||
float v = texture(sVTexture, st).a; | ||
oFragColor.rgb = uYuvColorMatrix * vec3(y - 0.06275, u - 0.50196, v - 0.50196); |
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.
nit: wondering why not having mat4 uYuvColorMatrix
to avoid magic constants here
This is a work in progress, I don't think it is landable in its current state. It will become more easily testable as Jerry and I fill the gaps (Jerry is working on exposing externally allocated textures to WR, which will add APIs to exercise that code). I hesitated about reusing existing sampler names. If the 16 samplers limit is an issue (currently 10 of them so 13 with YUV), we should make that less confusing in the shader code (just name them The color conversion was shamefully copy-pasted from gecko's own YUV shader, I had the same reaction about folding the the magic constants in the matrix, but I postponed the investigation. I'd rather make sure I am going in the right direction before ironing out the details. |
@nical ok, understood. I'm rather in favour of the current approach with clear texture names. I think you are safe to re-use the color texture for the Y channel, thus adding only 2 more textures. |
The last commit added a mostly unimplemented ExternalImage primitive batch data type. The bulk of the external image stuff will be implemented by @JerryShih, I just added the minimum to be able to see how to plug the yuv stuff into the renderer. It would also make sense to add a way to use non-external YUV images, but the render backend seems to be written in a way that it expects at most two source textures for all primitives (color and mask). Making it work with more textures might require a bit of refactoring (not sure, still digging). |
#ifdef WR_YUV_IMAGE | ||
uniform sampler2D sYTexture; | ||
// TODO: investigate storing the U and V planes in the same texture. | ||
uniform sampler2D sUTexture; |
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 think that's fine - we can fix that when it becomes a problem. I can very easily reduce the number of samplers currently in use by combining some of the vertex data textures too, so I don't expect it to be a problem in the near future.
@@ -141,6 +141,8 @@ impl VertexDataTexture { | |||
} | |||
|
|||
const TRANSFORM_FEATURE: &'static [&'static str] = &["TRANSFORM"]; | |||
const YUV_TRANSFORM_FEATURE: &'static [&'static str] = &["TRANSFORM", "YUV_IMAGE"]; |
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 changed how features work in this PR - #527 - once that lands it should be possible to simplify this a bit (take a look at how the text subpx shader is created).
@@ -513,6 +530,22 @@ impl Renderer { | |||
&mut device, | |||
options.precache_shaders); | |||
|
|||
let ps_yuv_image = PrimitiveShader { |
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.
Should be possible to create as a normal PrimitiveShader once the changes mentioned above land.
|
||
if has_complex_clip { | ||
// TODO(nical) | ||
unimplemented!(); |
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 make a println!() warning rather than panic?
} | ||
|
||
// TODO(nical) needs its own GPU_TAG? | ||
self.gpu_profile.add_marker(GPU_TAG_PRIM_IMAGE); |
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.
Yup, let's add a new GPU tag - just so we can see what the shader costs of the YUV conversion are like.
@nical This looks like a great start! :) Is there a way to remove the PrimitiveBatchData::External type and treat it as a normal PrimitiveBatchData::Image? It doesn't seem conceptually right for the source of the image to require a different batch type. The current Image batch type supports both normal images, and also webgl images - if we could extend this to handle external images, I think that would be ideal. This might require a bit of thought on how to modify the image batch support to handle rgb vs. yuv textures - but seems like a better place to handle the different image source types. Ping me sometime during the week and we discuss? |
Pieces of code with The main difference between the Image and ExternalImage primitives is that the former refers to texture ids directly and the texture ids are generated in the render backend thread, while the latter adds a level of indirection so that the texture ids are generated on the renderer and the backend thread only sees an external image key. It would certainly make more sense to have PrimitiveBatchData variants correspond to the "type of work to do to render the primitive" rather than how ids are rooted through the system. I was hesitant to make invasive changes, but I'll happily merge the two variants into something that supports both modes. |
20160c4
to
833bc24
Compare
Quick update: I rebased this PR on top of PR #534 (had to untangle a mess of commits mixed in random order between the three things I am working on, but hopefully I didn't loose anything in the process). Previously the shader was using only one set of texture coordinates (it was assuming the Y, U and V planes were in their own textures), and moving away from this means the shader ends up being quite different from the image one, so I moved it into its own files. The shader is in a completely broken WIP state right now. |
37aa244
to
fb3fa99
Compare
Update: The PR is now in a landable state (or close, depending on reviews). YUV is handled by a special shader and supports the Rec601 and Rec709 color spaces (the two that gecko's GL compositor appear to support). The color space is specified per-primitive and the right conversion matrix is selected in the vertex shader because it seemed simpler to implement that way, but we could change that to specify the matrix using an uniform instead, and make sure different yuv images using the texture cache don't get batched together. I've tested it without using a reference image so I haven't verified that the colors are 100% correct, but it seems to work and it will be much easier to test once we have video working with webrender in Gecko. There is one bug, however, which is the one described in issue #586 and affects all types of images: If a texture is stretched to fit the size on screen, its texture coordinates end up stretched incorrectly by a small but very noticeable amount, causing the U and V channel (which are typically half the size of the Y channel), to not line up with the Y channel (unless they are all the same size which almost never happens in practice). |
Reviewed 12 of 12 files at r3. webrender/res/prim_shared.glsl, line 613 at r3 (raw file):
This should be get_fetch_uv_4 webrender/src/prim_store.rs, line 173 at r3 (raw file):
Should be able to avoid unsafe here, by doing something like: let color_space = color_space as u32 as f32; webrender_traits/src/display_list.rs, line 107 at r3 (raw file):
nit: indentation Comments from Reviewable |
@nical Looks great! Added a few minor issues, this is good to merge after they are fixed. |
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 good! Although I wonder how it worked with using get_fetch_uv_2
instead of get_fetch_uv_4
.
Oh boy! yeah, get_fetch_uv_2 "worked" because I only had one yuv image in my test so the offset was always zero. |
YUV images are handled by a dedicated shader which reads the Y, U and V planes from separate texture samplers and computes the rgb values using the Rec601 or Rec709 color spaces.
Reviewed 4 of 4 files at r4. Comments from Reviewable |
Review status: all files reviewed at latest revision, 9 unresolved discussions. Comments from Reviewable |
@bors-servo r+ |
📌 Commit 6c4cf7d has been approved by |
⚡ Test exempted - status |
Add a YUV image shader. The YUV image shader is implemented in the image shader using #ifdefs for feature selection since most of the code is identical. <!-- 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/528) <!-- Reviewable:end -->
The YUV image shader is implemented in the image shader using #ifdefs for feature selection since most of the code is identical.
This change is![Reviewable](https://camo.githubusercontent.com/1541c4039185914e83657d3683ec25920c672c6c5c7ab4240ee7bff601adec0b/68747470733a2f2f72657669657761626c652e696f2f7265766965775f627574746f6e2e737667)