Skip to content

Commit c625672

Browse files
author
bors-servo
authored
Auto merge of #528 - nical:yuv, r=glennw
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 -->
2 parents a237f9b + 6c4cf7d commit c625672

11 files changed

+371
-7
lines changed

webrender/res/prim_shared.glsl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,33 @@ Image fetch_image(int index) {
595595
return image;
596596
}
597597

598+
// YUV color spaces
599+
#define YUV_REC601 1
600+
#define YUV_REC709 2
601+
602+
struct YuvImage {
603+
vec4 y_st_rect;
604+
vec4 u_st_rect;
605+
vec4 v_st_rect;
606+
vec2 size;
607+
int color_space;
608+
};
609+
610+
YuvImage fetch_yuv_image(int index) {
611+
YuvImage image;
612+
613+
ivec2 uv = get_fetch_uv_4(index);
614+
615+
image.y_st_rect = texelFetchOffset(sData64, uv, 0, ivec2(0, 0));
616+
image.u_st_rect = texelFetchOffset(sData64, uv, 0, ivec2(1, 0));
617+
image.v_st_rect = texelFetchOffset(sData64, uv, 0, ivec2(2, 0));
618+
vec4 size_color_space = texelFetchOffset(sData64, uv, 0, ivec2(3, 0));
619+
image.size = size_color_space.xy;
620+
image.color_space = int(size_color_space.z);
621+
622+
return image;
623+
}
624+
598625
struct BoxShadow {
599626
vec4 src_rect;
600627
vec4 bs_rect;

webrender/res/ps_yuv_image.fs.glsl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#line 1
2+
/* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5+
6+
void main(void) {
7+
#ifdef WR_FEATURE_TRANSFORM
8+
float alpha = 0.0;
9+
vec2 pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
10+
11+
// We clamp the texture coordinate calculation here to the local rectangle boundaries,
12+
// which makes the edge of the texture stretch instead of repeat.
13+
vec2 relative_pos_in_rect =
14+
clamp(pos, vLocalRect.xy, vLocalRect.xy + vLocalRect.zw) - vLocalRect.xy;
15+
#else
16+
float alpha = 1.0;;
17+
vec2 relative_pos_in_rect = vLocalPos;
18+
#endif
19+
20+
alpha = min(alpha, do_clip());
21+
22+
vec2 st_y = vTextureOffsetY + relative_pos_in_rect / vStretchSize * vTextureSizeY;
23+
vec2 st_u = vTextureOffsetU + relative_pos_in_rect / vStretchSize * vTextureSizeUv;
24+
vec2 st_v = vTextureOffsetV + relative_pos_in_rect / vStretchSize * vTextureSizeUv;
25+
26+
float y = texture(sColor0, st_y).r;
27+
float u = texture(sColor1, st_u).r;
28+
float v = texture(sColor2, st_v).r;
29+
30+
// See the vertex shader for an explanation of where the constants come from.
31+
vec3 rgb = vYuvColorMatrix * vec3(y - 0.06275, u - 0.50196, v - 0.50196);
32+
oFragColor = vec4(rgb, alpha);
33+
}

webrender/res/ps_yuv_image.glsl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
flat varying vec2 vTextureOffsetY; // Offset of the y plane into the texture atlas.
6+
flat varying vec2 vTextureOffsetU; // Offset of the u plane into the texture atlas.
7+
flat varying vec2 vTextureOffsetV; // Offset of the v plane into the texture atlas.
8+
flat varying vec2 vTextureSizeY; // Size of the y plane in the texture atlas.
9+
flat varying vec2 vTextureSizeUv; // Size of the u and v planes in the texture atlas.
10+
flat varying vec2 vStretchSize;
11+
12+
flat varying mat3 vYuvColorMatrix;
13+
14+
#ifdef WR_FEATURE_TRANSFORM
15+
varying vec3 vLocalPos;
16+
flat varying vec4 vLocalRect;
17+
#else
18+
varying vec2 vLocalPos;
19+
#endif

webrender/res/ps_yuv_image.vs.glsl

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#line 1
2+
/* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5+
6+
void main(void) {
7+
Primitive prim = load_primitive(gl_InstanceID);
8+
#ifdef WR_FEATURE_TRANSFORM
9+
TransformVertexInfo vi = write_transform_vertex(prim.local_rect,
10+
prim.local_clip_rect,
11+
prim.layer,
12+
prim.tile);
13+
vLocalRect = vi.clipped_local_rect;
14+
vLocalPos = vi.local_pos;
15+
#else
16+
VertexInfo vi = write_vertex(prim.local_rect,
17+
prim.local_clip_rect,
18+
prim.layer,
19+
prim.tile);
20+
vLocalPos = vi.local_clamped_pos - vi.local_rect.p0;
21+
#endif
22+
23+
YuvImage image = fetch_yuv_image(prim.prim_index);
24+
25+
vec2 y_texture_size = vec2(textureSize(sColor0, 0));
26+
vec2 y_st0 = image.y_st_rect.xy / y_texture_size;
27+
vec2 y_st1 = image.y_st_rect.zw / y_texture_size;
28+
29+
vTextureSizeY = y_st1 - y_st0;
30+
vTextureOffsetY = y_st0;
31+
32+
vec2 uv_texture_size = vec2(textureSize(sColor1, 0));
33+
vec2 u_st0 = image.u_st_rect.xy / uv_texture_size;
34+
vec2 u_st1 = image.u_st_rect.zw / uv_texture_size;
35+
36+
vec2 v_st0 = image.v_st_rect.xy / uv_texture_size;
37+
vec2 v_st1 = image.v_st_rect.zw / uv_texture_size;
38+
39+
// This assumes the U and V surfaces have the same size.
40+
vTextureSizeUv = u_st1 - u_st0;
41+
vTextureOffsetU = u_st0;
42+
vTextureOffsetV = v_st0;
43+
44+
vStretchSize = image.size;
45+
46+
// The constants added to the Y, U and V components are applied in the fragment shader.
47+
if (image.color_space == YUV_REC601) {
48+
// From Rec601:
49+
// [R] [1.1643835616438356, 0.0, 1.5960267857142858 ] [Y - 16]
50+
// [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708 ] x [U - 128]
51+
// [B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [V - 128]
52+
//
53+
// For the range [0,1] instead of [0,255].
54+
vYuvColorMatrix = mat3(
55+
1.16438, 0.0, 1.59603,
56+
1.16438, -0.39176, -0.81297,
57+
1.16438, 2.01723, 0.0
58+
);
59+
} else { // if (image.color_space == YUV_REC709)
60+
// From Rec709:
61+
// [R] [1.1643835616438356, 4.2781193979771426e-17, 1.7927410714285714] [Y - 16]
62+
// [G] = [1.1643835616438358, -0.21324861427372963, -0.532909328559444 ] x [U - 128]
63+
// [B] [1.1643835616438356, 2.1124017857142854, 0.0 ] [V - 128]
64+
//
65+
// For the range [0,1] instead of [0,255]:
66+
vYuvColorMatrix = mat3(
67+
1.16438, 0.0, 1.79274,
68+
1.16438, -0.21325, -0.53291,
69+
1.16438, 2.11240, 0.0
70+
);
71+
}
72+
}

webrender/src/frame.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,14 @@ impl Frame {
714714
info.image_key,
715715
info.image_rendering);
716716
}
717+
SpecificDisplayItem::YuvImage(ref info) => {
718+
context.builder.add_yuv_image(LayerRect::from_untyped(&item.rect),
719+
&item.clip,
720+
info.y_image_key,
721+
info.u_image_key,
722+
info.v_image_key,
723+
info.color_space);
724+
}
717725
SpecificDisplayItem::Text(ref text_info) => {
718726
context.builder.add_text(LayerRect::from_untyped(&item.rect),
719727
&item.clip,

webrender/src/internal_types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,4 +440,4 @@ pub enum LowLevelFilterOp {
440440
pub enum CompositionOp {
441441
MixBlend(MixBlendMode),
442442
Filter(LowLevelFilterOp),
443-
}
443+
}

webrender/src/prim_store.rs

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::mem;
1212
use std::usize;
1313
use tiling::RenderTask;
1414
use util::TransformedRect;
15-
use webrender_traits::{AuxiliaryLists, ColorF, ImageKey, ImageRendering};
15+
use webrender_traits::{AuxiliaryLists, ColorF, ImageKey, ImageRendering, YuvColorSpace};
1616
use webrender_traits::{ClipRegion, ComplexClipRegion, ItemRange, GlyphKey};
1717
use webrender_traits::{FontKey, FontRenderMode, WebGLContextId};
1818
use webrender_traits::{device_length, DeviceIntRect, DeviceIntSize};
@@ -73,6 +73,7 @@ pub enum PrimitiveKind {
7373
Rectangle,
7474
TextRun,
7575
Image,
76+
YuvImage,
7677
Border,
7778
Gradient,
7879
BoxShadow,
@@ -144,6 +145,45 @@ pub struct ImagePrimitiveGpu {
144145
pub tile_spacing: LayerSize,
145146
}
146147

148+
#[derive(Debug)]
149+
pub struct YuvImagePrimitiveCpu {
150+
pub y_key: ImageKey,
151+
pub u_key: ImageKey,
152+
pub v_key: ImageKey,
153+
pub y_texture_id: SourceTexture,
154+
pub u_texture_id: SourceTexture,
155+
pub v_texture_id: SourceTexture,
156+
}
157+
158+
#[derive(Debug, Clone)]
159+
pub struct YuvImagePrimitiveGpu {
160+
pub y_uv0: DevicePoint,
161+
pub y_uv1: DevicePoint,
162+
pub u_uv0: DevicePoint,
163+
pub u_uv1: DevicePoint,
164+
pub v_uv0: DevicePoint,
165+
pub v_uv1: DevicePoint,
166+
pub size: LayerSize,
167+
pub color_space: f32,
168+
pub padding: f32,
169+
}
170+
171+
impl YuvImagePrimitiveGpu {
172+
pub fn new(size: LayerSize, color_space: YuvColorSpace) -> Self {
173+
YuvImagePrimitiveGpu {
174+
y_uv0: DevicePoint::zero(),
175+
y_uv1: DevicePoint::zero(),
176+
u_uv0: DevicePoint::zero(),
177+
u_uv1: DevicePoint::zero(),
178+
v_uv0: DevicePoint::zero(),
179+
v_uv1: DevicePoint::zero(),
180+
size: size,
181+
color_space: color_space as u32 as f32,
182+
padding: 0.0,
183+
}
184+
}
185+
}
186+
147187
#[derive(Debug, Clone)]
148188
pub struct BorderPrimitiveCpu {
149189
pub inner_rect: LayerRect,
@@ -362,6 +402,7 @@ pub enum PrimitiveContainer {
362402
Rectangle(RectanglePrimitive),
363403
TextRun(TextRunPrimitiveCpu, TextRunPrimitiveGpu),
364404
Image(ImagePrimitiveCpu, ImagePrimitiveGpu),
405+
YuvImage(YuvImagePrimitiveCpu, YuvImagePrimitiveGpu),
365406
Border(BorderPrimitiveCpu, BorderPrimitiveGpu),
366407
Gradient(GradientPrimitiveCpu, GradientPrimitiveGpu),
367408
BoxShadow(BoxShadowPrimitiveGpu, Vec<LayerRect>),
@@ -372,6 +413,7 @@ pub struct PrimitiveStore {
372413
pub cpu_bounding_rects: Vec<Option<DeviceIntRect>>,
373414
pub cpu_text_runs: Vec<TextRunPrimitiveCpu>,
374415
pub cpu_images: Vec<ImagePrimitiveCpu>,
416+
pub cpu_yuv_images: Vec<YuvImagePrimitiveCpu>,
375417
pub cpu_gradients: Vec<GradientPrimitiveCpu>,
376418
pub cpu_metadata: Vec<PrimitiveMetadata>,
377419
pub cpu_borders: Vec<BorderPrimitiveCpu>,
@@ -398,6 +440,7 @@ impl PrimitiveStore {
398440
cpu_bounding_rects: Vec::new(),
399441
cpu_text_runs: Vec::new(),
400442
cpu_images: Vec::new(),
443+
cpu_yuv_images: Vec::new(),
401444
cpu_gradients: Vec::new(),
402445
cpu_borders: Vec::new(),
403446
gpu_geometry: GpuStore::new(),
@@ -487,6 +530,24 @@ impl PrimitiveStore {
487530
self.cpu_images.push(image_cpu);
488531
metadata
489532
}
533+
PrimitiveContainer::YuvImage(image_cpu, image_gpu) => {
534+
let gpu_address = self.gpu_data64.push(image_gpu);
535+
536+
let metadata = PrimitiveMetadata {
537+
is_opaque: true,
538+
clip_source: clip_source,
539+
clip_cache_info: clip_info,
540+
prim_kind: PrimitiveKind::YuvImage,
541+
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_yuv_images.len()),
542+
gpu_prim_index: gpu_address,
543+
gpu_data_address: GpuStoreAddress(0),
544+
gpu_data_count: 0,
545+
render_task: None,
546+
};
547+
548+
self.cpu_yuv_images.push(image_cpu);
549+
metadata
550+
}
490551
PrimitiveContainer::Border(border_cpu, border_gpu) => {
491552
let gpu_address = self.gpu_data128.push(border_gpu);
492553

@@ -663,6 +724,33 @@ impl PrimitiveStore {
663724
}
664725
image_cpu.color_texture_id = texture_id;
665726
}
727+
PrimitiveKind::YuvImage => {
728+
let image_cpu = &mut self.cpu_yuv_images[metadata.cpu_prim_index.0];
729+
let image_gpu: &mut YuvImagePrimitiveGpu = unsafe {
730+
mem::transmute(self.gpu_data64.get_mut(metadata.gpu_prim_index))
731+
};
732+
733+
if image_cpu.y_texture_id == SourceTexture::Invalid {
734+
let y_cache_item = resource_cache.get_cached_image(image_cpu.y_key, ImageRendering::Auto);
735+
image_cpu.y_texture_id = y_cache_item.texture_id;
736+
image_gpu.y_uv0 = y_cache_item.uv0;
737+
image_gpu.y_uv1 = y_cache_item.uv1;
738+
}
739+
740+
if image_cpu.u_texture_id == SourceTexture::Invalid {
741+
let u_cache_item = resource_cache.get_cached_image(image_cpu.u_key, ImageRendering::Auto);
742+
image_cpu.u_texture_id = u_cache_item.texture_id;
743+
image_gpu.u_uv0 = u_cache_item.uv0;
744+
image_gpu.u_uv1 = u_cache_item.uv1;
745+
}
746+
747+
if image_cpu.v_texture_id == SourceTexture::Invalid {
748+
let v_cache_item = resource_cache.get_cached_image(image_cpu.v_key, ImageRendering::Auto);
749+
image_cpu.v_texture_id = v_cache_item.texture_id;
750+
image_gpu.v_uv0 = v_cache_item.uv0;
751+
image_gpu.v_uv1 = v_cache_item.uv1;
752+
}
753+
}
666754
}
667755
}
668756

@@ -851,6 +939,17 @@ impl PrimitiveStore {
851939
ImagePrimitiveKind::WebGL(..) => {}
852940
}
853941
}
942+
PrimitiveKind::YuvImage => {
943+
let image_cpu = &mut self.cpu_yuv_images[metadata.cpu_prim_index.0];
944+
prim_needs_resolve = true;
945+
946+
resource_cache.request_image(image_cpu.y_key, ImageRendering::Auto);
947+
resource_cache.request_image(image_cpu.u_key, ImageRendering::Auto);
948+
resource_cache.request_image(image_cpu.v_key, ImageRendering::Auto);
949+
950+
// TODO(nical): Currently assuming no tile_spacing for yuv images.
951+
metadata.is_opaque = true;
952+
}
854953
PrimitiveKind::Gradient => {
855954
let gradient = &mut self.cpu_gradients[metadata.cpu_prim_index.0];
856955
if gradient.cache_dirty {
@@ -973,6 +1072,14 @@ impl From<GradientStop> for GpuBlock32 {
9731072
}
9741073
}
9751074

1075+
impl From<YuvImagePrimitiveGpu> for GpuBlock64 {
1076+
fn from(data: YuvImagePrimitiveGpu) -> GpuBlock64 {
1077+
unsafe {
1078+
mem::transmute::<YuvImagePrimitiveGpu, GpuBlock64>(data)
1079+
}
1080+
}
1081+
}
1082+
9761083
impl From<ClipRect> for GpuBlock32 {
9771084
fn from(data: ClipRect) -> GpuBlock32 {
9781085
unsafe {

0 commit comments

Comments
 (0)