Index: cc/output/shader.cc |
diff --git a/cc/output/shader.cc b/cc/output/shader.cc |
index b5d163862d14e010aa19d5bcd083278366ed34b4..a34ce07bad174bcf9a20f44831f26a2681b267be 100644 |
--- a/cc/output/shader.cc |
+++ b/cc/output/shader.cc |
@@ -2028,9 +2028,11 @@ FragmentShaderYUVVideo::FragmentShaderYUVVideo() |
resource_multiplier_location_(-1), |
resource_offset_location_(-1) {} |
-void FragmentShaderYUVVideo::SetFeatures(bool use_alpha_texture, |
+void FragmentShaderYUVVideo::SetFeatures(SamplerType sampler, |
+ bool use_alpha_texture, |
bool use_nv12, |
bool use_color_lut) { |
+ sampler_ = sampler; |
use_alpha_texture_ = use_alpha_texture; |
use_nv12_ = use_nv12; |
use_color_lut_ = use_color_lut; |
@@ -2050,6 +2052,8 @@ void FragmentShaderYUVVideo::Init(GLES2Interface* context, |
"resource_offset", |
"yuv_matrix", |
"yuv_adj", |
+ "ya_size", |
+ "uv_subsampling_factor", |
"alpha", |
"ya_clamp_rect", |
"uv_clamp_rect", |
@@ -2080,9 +2084,14 @@ void FragmentShaderYUVVideo::Init(GLES2Interface* context, |
yuv_matrix_location_ = locations[8]; |
yuv_adj_location_ = locations[9]; |
} |
- alpha_location_ = locations[10]; |
- ya_clamp_rect_location_ = locations[11]; |
- uv_clamp_rect_location_ = locations[12]; |
+ if (sampler_ != SAMPLER_TYPE_2D_RECT) { |
+ ya_size_location_ = locations[10]; |
+ } else { |
+ uv_subsampling_factor_location_ = locations[11]; |
+ } |
+ alpha_location_ = locations[12]; |
+ ya_clamp_rect_location_ = locations[13]; |
+ uv_clamp_rect_location_ = locations[14]; |
} |
std::string FragmentShaderYUVVideo::GetShaderString(TexCoordPrecision precision, |
@@ -2097,13 +2106,87 @@ std::string FragmentShaderYUVVideo::GetShaderString(TexCoordPrecision precision, |
uniform vec4 ya_clamp_rect; |
uniform vec4 uv_clamp_rect; |
}); |
- |
- std::string functions = ""; |
+ // SHADER0 cannot handle #define |
+ head += "\n"; |
+ head += " #define PLANE_TYPE int\n"; |
+ head += " #define YA 1\n"; |
+ head += " #define UV 2\n"; |
+ |
+ std::string functions = SHADER0([]() { |
+ vec2 TextureLookupBilinearInternal(SamplerType sampler, vec2 snap_tex_coord, |
+ vec2 unit_texel, vec2 factor) { |
+ vec2 s1 = TextureLookup(sampler, snap_tex_coord).xy; |
+ vec2 s2 = |
+ TextureLookup(sampler, snap_tex_coord + vec2(unit_texel.x, 0.)).xy; |
+ vec2 s3 = |
+ TextureLookup(sampler, snap_tex_coord + vec2(0., unit_texel.y)).xy; |
+ vec2 s4 = TextureLookup(sampler, snap_tex_coord + unit_texel).xy; |
+ return mix(mix(s1, s2, factor.x), mix(s3, s4, factor.x), factor.y); |
+ } |
+ }); |
+ if (sampler_ == SAMPLER_TYPE_2D_RECT) { |
+ head += " uniform vec2 uv_subsampling_factor;\n"; |
+ functions += SHADER0([]() { |
+ vec2 TextureLookupBilinear(SamplerType sampler, vec2 tex_coord, |
+ PLANE_TYPE type) { |
+ vec2 ya_tex_coord = tex_coord; |
+ if (type == UV) { |
+ ya_tex_coord = tex_coord / uv_subsampling_factor; |
+ } |
+ vec2 unnorm_tex_coord = ya_tex_coord - vec2(0.5); |
+ vec2 f = fract(unnorm_tex_coord); |
+ vec2 texel_offset = floor(unnorm_tex_coord) - floor(ya_tex_coord); |
+ vec2 unit_texel = vec2(1.); |
+ if (type == UV) { |
+ texel_offset = texel_offset * uv_subsampling_factor; |
+ unit_texel = unit_texel * uv_subsampling_factor; |
+ } |
+ vec2 snap_tex_coord = |
+ floor(tex_coord) + (unit_texel * 0.5) + texel_offset; |
+ return TextureLookupBilinearInternal(sampler, snap_tex_coord, |
+ unit_texel, f); |
+ } |
+ }); |
+ } else { |
+ head += " uniform vec2 ya_size;\n"; |
+ functions += SHADER0([]() { |
+ // refer to Mesa sample_2d_linear() in s_texfilter.c |
+ // https://cs.chromium.org/chromium/src/third_party/mesa/src/src/mesa/swrast/s_texfilter.c?q=sample_2d_linear&sq=package:chromium |
+ // |
+ // This shader needs a custom bilinear filter because U plane can be |
+ // smaller than Y plane. |
+ // For example, look at the following figures. When the current fragment |
+ // samples the middle point of (3, 3) texel of Y texture, it points out |
+ // upper left of (1, 1) texel of U texture. The default GL_LINEAR samples |
+ // 4 texels of U plane, while it samples only (3, 3) texel of Y plane. |
+ // TextureLookupBilinear() samples U plane with Y plane fraction to |
+ // sample like Y plane. |
+ // Y 4x4 U 2x2 U sampling by GL_LINEAR |
+ // +-+-+-+-+ +--+--+ +--+--+ |
+ // | | | | | | | | | | | |
+ // +-------+ | | | | +--++ |
+ // | | | | | +-----+ +-----| |
+ // +-------+ | |· | | ||·|| |
+ // | | |·| | | | | | +--+| |
+ // +-------+ +--+--+ +-----+ |
+ // | | | | | |
+ // +-+-+-+-+ |
+ vec2 TextureLookupBilinear(SamplerType sampler, vec2 tex_coord, |
+ PLANE_TYPE type) { |
+ vec2 unit_texel = 1.0 / ya_size; |
+ vec2 unnorm_tex_coord = (tex_coord * ya_size) - vec2(0.5); |
+ vec2 f = fract(unnorm_tex_coord); |
+ vec2 snap_tex_coord = (floor(unnorm_tex_coord) + vec2(0.5)) / ya_size; |
+ return TextureLookupBilinearInternal(sampler, snap_tex_coord, |
+ unit_texel, f); |
+ } |
+ }); |
+ } |
if (use_nv12_) { |
head += " uniform SamplerType uv_texture;\n"; |
functions += SHADER0([]() { |
vec2 GetUV(vec2 uv_clamped) { |
- return TextureLookup(uv_texture, uv_clamped).xy; |
+ return TextureLookupBilinear(uv_texture, uv_clamped, UV); |
} |
}); |
} else { |
@@ -2111,8 +2194,8 @@ std::string FragmentShaderYUVVideo::GetShaderString(TexCoordPrecision precision, |
head += " uniform SamplerType v_texture;\n"; |
functions += SHADER0([]() { |
vec2 GetUV(vec2 uv_clamped) { |
- return vec2(TextureLookup(u_texture, uv_clamped).x, |
- TextureLookup(v_texture, uv_clamped).x); |
+ return vec2(TextureLookupBilinear(u_texture, uv_clamped, UV).x, |
+ TextureLookupBilinear(v_texture, uv_clamped, UV).x); |
} |
}); |
} |
@@ -2121,7 +2204,7 @@ std::string FragmentShaderYUVVideo::GetShaderString(TexCoordPrecision precision, |
head += " uniform SamplerType a_texture;\n"; |
functions += SHADER0([]() { |
float GetAlpha(vec2 ya_clamped) { |
- return alpha * TextureLookup(a_texture, ya_clamped).x; |
+ return alpha * TextureLookupBilinear(a_texture, ya_clamped, YA).x; |
} |
}); |
} else { |
@@ -2165,7 +2248,7 @@ std::string FragmentShaderYUVVideo::GetShaderString(TexCoordPrecision precision, |
void main() { |
vec2 ya_clamped = |
max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord)); |
- float y_raw = TextureLookup(y_texture, ya_clamped).x; |
+ float y_raw = TextureLookupBilinear(y_texture, ya_clamped, YA).x; |
vec2 uv_clamped = |
max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord)); |
vec3 yuv = vec3(y_raw, GetUV(uv_clamped)); |