Commit 63874f8d authored by Dongseong Hwang's avatar Dongseong Hwang Committed by Commit Bot

Reland "Fix HTML5 video blurry"

Original CL: https://codereview.chromium.org/2418173002/

Revert CL: https://codereview.chromium.org/2463103002/
https://codereview.chromium.org/2474073004
https://codereview.chromium.org/2544893006

Since it was reverted long time ago, reimplement it from the scratch.

HW decoded video is blurry, because crbug.com/575587 shinked visual rect by 1
pixel, if coded rect is larger than visual rect. This fixed bleeding texture,
but caused blurry issue.

Meanwhile, crbug.com/429640 fixed bleeding texture for software YUV video in
the elegant way. It clamps all texture coordinates to this maximum value in the
fragment shader.

This CL removes the 1 pixel hack and applies the way to TextureDrawQuad and
StreamVideoDrawQuad.

In addition, Video overlay requires this fix because there is noticible
transition between GPU composition and hardware overlay.

TEST=cc_unittests PrecisionSamplerShadersCompile/PrecisionSamplerShaderPixelTest.ShadersCompile
chrome on http://browsertests.herokuapp.com/media/sharpness.html using amd64-generic
BUG=615325, 683347

Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I63c8736a365f0024513bfe1e999bc7beb7321da5
Reviewed-on: https://chromium-review.googlesource.com/567809
Commit-Queue: Dongseong Hwang <dongseong.hwang@intel.com>
Reviewed-by: default avatarccameron chromium <ccameron@chromium.org>
Reviewed-by: default avatarKenneth Russell <kbr@chromium.org>
Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Reviewed-by: default avatarDongseong Hwang <dongseong.hwang@intel.com>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488504}
parent 65326efd
......@@ -191,17 +191,10 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
if (visible_quad_rect.IsEmpty())
return;
// Pixels for macroblocked formats. To prevent sampling outside the visible
// rect, stretch the video if needed.
gfx::Rect visible_sample_rect = frame_->visible_rect();
if (visible_rect.width() < coded_size.width() && visible_rect.width() > 1)
visible_sample_rect.set_width(visible_rect.width() - 1);
if (visible_rect.height() < coded_size.height() && visible_rect.height() > 1)
visible_sample_rect.set_height(visible_rect.height() - 1);
const float tex_width_scale =
static_cast<float>(visible_sample_rect.width()) / coded_size.width();
static_cast<float>(visible_rect.width()) / coded_size.width();
const float tex_height_scale =
static_cast<float>(visible_sample_rect.height()) / coded_size.height();
static_cast<float>(visible_rect.height()) / coded_size.height();
switch (frame_resource_type_) {
// TODO(danakj): Remove this, hide it in the hardware path.
......@@ -267,12 +260,12 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
static_cast<float>(ya_tex_size.width()) / uv_tex_size.width();
float uv_subsampling_factor_y =
static_cast<float>(ya_tex_size.height()) / uv_tex_size.height();
gfx::RectF ya_tex_coord_rect(visible_sample_rect);
gfx::RectF ya_tex_coord_rect(visible_rect);
gfx::RectF uv_tex_coord_rect(
visible_sample_rect.x() / uv_subsampling_factor_x,
visible_sample_rect.y() / uv_subsampling_factor_y,
visible_sample_rect.width() / uv_subsampling_factor_x,
visible_sample_rect.height() / uv_subsampling_factor_y);
visible_rect.x() / uv_subsampling_factor_x,
visible_rect.y() / uv_subsampling_factor_y,
visible_rect.width() / uv_subsampling_factor_x,
visible_rect.height() / uv_subsampling_factor_y);
YUVVideoDrawQuad* yuv_video_quad =
render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
......
......@@ -85,6 +85,21 @@ Float4 UVTransform(const TextureDrawQuad* quad) {
return xform;
}
// To prevent sampling outside the visible rect.
Float4 UVClampRect(gfx::RectF uv_visible_rect,
const gfx::Size& texture_size,
SamplerType sampler) {
gfx::SizeF half_texel(0.5f, 0.5f);
if (sampler != SAMPLER_TYPE_2D_RECT) {
half_texel.Scale(1.f / texture_size.width(), 1.f / texture_size.height());
} else {
uv_visible_rect.Scale(texture_size.width(), texture_size.height());
}
uv_visible_rect.Inset(half_texel.width(), half_texel.height());
return {{uv_visible_rect.x(), uv_visible_rect.y(), uv_visible_rect.right(),
uv_visible_rect.bottom()}};
}
Float4 PremultipliedColor(SkColor color, float opacity) {
const float factor = 1.0f / 255.0f;
const float alpha = opacity * SkColorGetA(color) * factor;
......@@ -2275,6 +2290,15 @@ void GLRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
current_program_->tex_matrix_location(), false, gl_matrix);
SetShaderOpacity(quad);
gfx::Size texture_size = lock.size();
gfx::Vector2dF uv = quad->matrix.Scale2d();
gfx::RectF uv_visible_rect(0, 0, uv.x(), uv.y());
const SamplerType sampler = SamplerTypeFromTextureTarget(lock.target());
Float4 tex_clamp_rect = UVClampRect(uv_visible_rect, texture_size, sampler);
gl_->Uniform4f(current_program_->tex_clamp_rect_location(),
tex_clamp_rect.data[0], tex_clamp_rect.data[1],
tex_clamp_rect.data[2], tex_clamp_rect.data[3]);
if (!clip_region) {
DrawQuadGeometry(current_frame()->projection_matrix,
quad->shared_quad_state->quad_to_target_transform,
......@@ -2345,6 +2369,16 @@ void GLRenderer::FlushTextureQuadCache(BoundGeometry flush_binding) {
static_cast<int>(draw_cache_.uv_xform_data.size()),
reinterpret_cast<float*>(&draw_cache_.uv_xform_data.front()));
if (current_program_->tex_clamp_rect_location() != -1) {
// Draw batching is not allowed with texture clamping.
DCHECK_EQ(1u, draw_cache_.matrix_data.size());
gl_->Uniform4f(current_program_->tex_clamp_rect_location(),
draw_cache_.tex_clamp_rect_data.data[0],
draw_cache_.tex_clamp_rect_data.data[1],
draw_cache_.tex_clamp_rect_data.data[2],
draw_cache_.tex_clamp_rect_data.data[3]);
}
if (draw_cache_.background_color != SK_ColorTRANSPARENT) {
Float4 background_color =
PremultipliedColor(draw_cache_.background_color, 1.f);
......@@ -2379,6 +2413,7 @@ void GLRenderer::FlushTextureQuadCache(BoundGeometry flush_binding) {
draw_cache_.uv_xform_data.resize(0);
draw_cache_.vertex_opacity_data.resize(0);
draw_cache_.matrix_data.resize(0);
draw_cache_.tex_clamp_rect_data = Float4();
// If we had a clipped binding, prepare the shared binding for the
// next inserts.
......@@ -2406,10 +2441,13 @@ void GLRenderer::EnqueueTextureQuad(const TextureDrawQuad* quad,
quad->resource_id());
const SamplerType sampler = SamplerTypeFromTextureTarget(lock.target());
bool need_tex_clamp_rect = !quad->resource_size_in_pixels().IsEmpty() &&
(quad->uv_top_left != gfx::PointF(0, 0) ||
quad->uv_bottom_right != gfx::PointF(1, 1));
ProgramKey program_key = ProgramKey::Texture(
tex_coord_precision, sampler,
quad->premultiplied_alpha ? PREMULTIPLIED_ALPHA : NON_PREMULTIPLIED_ALPHA,
quad->background_color != SK_ColorTRANSPARENT);
quad->background_color != SK_ColorTRANSPARENT, need_tex_clamp_rect);
int resource_id = quad->resource_id();
size_t max_quads = StaticGeometryBinding::NUM_QUADS;
......@@ -2442,6 +2480,18 @@ void GLRenderer::EnqueueTextureQuad(const TextureDrawQuad* quad,
}
draw_cache_.uv_xform_data.push_back(uv_transform);
if (need_tex_clamp_rect) {
DCHECK_EQ(1u, draw_cache_.uv_xform_data.size());
gfx::Size texture_size = quad->resource_size_in_pixels();
DCHECK(!texture_size.IsEmpty());
gfx::RectF uv_visible_rect(
quad->uv_top_left.x(), quad->uv_top_left.y(),
quad->uv_bottom_right.x() - quad->uv_top_left.x(),
quad->uv_bottom_right.y() - quad->uv_top_left.y());
Float4 tex_clamp_rect = UVClampRect(uv_visible_rect, texture_size, sampler);
draw_cache_.tex_clamp_rect_data = tex_clamp_rect;
}
// Generate the vertex opacity
const float opacity = quad->shared_quad_state->opacity;
draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[0] * opacity);
......@@ -2479,7 +2529,8 @@ void GLRenderer::EnqueueTextureQuad(const TextureDrawQuad* quad,
PrepareGeometry(CLIPPED_BINDING);
clipped_geometry_->InitializeCustomQuadWithUVs(scaled_region, uv);
FlushTextureQuadCache(CLIPPED_BINDING);
} else if (gl_composited_overlay_candidate_quad_border_) {
} else if (gl_composited_overlay_candidate_quad_border_ ||
need_tex_clamp_rect) {
FlushTextureQuadCache(SHARED_BINDING);
}
}
......
......@@ -44,6 +44,9 @@ struct TexturedQuadDrawCache {
std::vector<float> vertex_opacity_data;
std::vector<Float16> matrix_data;
// Don't batch if tex clamp rect is given.
Float4 tex_clamp_rect_data;
private:
DISALLOW_COPY_AND_ASSIGN(TexturedQuadDrawCache);
};
......
......@@ -218,14 +218,22 @@ class GLRendererShaderPixelTest : public GLRendererPixelTest {
return;
}
TestShader(
ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA, false));
TestShader(
ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA, true));
TestShader(ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA,
false, true));
TestShader(ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA,
false, false));
TestShader(ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA,
true, true));
TestShader(ProgramKey::Texture(precision, sampler, PREMULTIPLIED_ALPHA,
true, false));
TestShader(ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA,
false));
TestShader(
ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA, true));
false, true));
TestShader(ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA,
false, false));
TestShader(ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA,
true, true));
TestShader(ProgramKey::Texture(precision, sampler, NON_PREMULTIPLIED_ALPHA,
true, false));
TestShader(ProgramKey::Tile(precision, sampler, NO_AA, NO_SWIZZLE, false));
TestShader(ProgramKey::Tile(precision, sampler, NO_AA, DO_SWIZZLE, false));
TestShader(ProgramKey::Tile(precision, sampler, USE_AA, NO_SWIZZLE, false));
......
......@@ -25,6 +25,7 @@ bool ProgramKey::operator==(const ProgramKey& other) const {
is_opaque_ == other.is_opaque_ &&
premultiplied_alpha_ == other.premultiplied_alpha_ &&
has_background_color_ == other.has_background_color_ &&
has_tex_clamp_rect_ == other.has_tex_clamp_rect_ &&
mask_mode_ == other.mask_mode_ &&
mask_for_background_ == other.mask_for_background_ &&
has_color_matrix_ == other.has_color_matrix_ &&
......@@ -73,13 +74,15 @@ ProgramKey ProgramKey::Tile(TexCoordPrecision precision,
ProgramKey ProgramKey::Texture(TexCoordPrecision precision,
SamplerType sampler,
PremultipliedAlphaMode premultiplied_alpha,
bool has_background_color) {
bool has_background_color,
bool has_tex_clamp_rect) {
ProgramKey result;
result.type_ = PROGRAM_TYPE_TEXTURE;
result.precision_ = precision;
result.sampler_ = sampler;
result.premultiplied_alpha_ = premultiplied_alpha;
result.has_background_color_ = has_background_color;
result.has_tex_clamp_rect_ = has_tex_clamp_rect;
return result;
}
......
......@@ -84,7 +84,8 @@ class CC_EXPORT ProgramKey {
static ProgramKey Texture(TexCoordPrecision precision,
SamplerType sampler,
PremultipliedAlphaMode premultiplied_alpha,
bool has_background_color);
bool has_background_color,
bool has_tex_clamp_rect);
// TODO(ccameron): Merge |mask_for_background| into MaskMode.
static ProgramKey RenderPass(TexCoordPrecision precision,
......@@ -129,6 +130,8 @@ class CC_EXPORT ProgramKey {
ColorConversionMode color_conversion_mode_ = COLOR_CONVERSION_MODE_NONE;
const gfx::ColorTransform* color_transform_ = nullptr;
bool has_tex_clamp_rect_ = false;
};
struct ProgramKeyHash {
......@@ -147,7 +150,8 @@ struct ProgramKeyHash {
(static_cast<size_t>(key.has_color_matrix_) << 23) ^
(static_cast<size_t>(key.yuv_alpha_texture_mode_) << 24) ^
(static_cast<size_t>(key.uv_texture_mode_) << 25) ^
(static_cast<size_t>(key.color_conversion_mode_) << 26);
(static_cast<size_t>(key.color_conversion_mode_) << 26) ^
(static_cast<size_t>(key.has_tex_clamp_rect_) << 28);
}
};
......@@ -257,6 +261,9 @@ class Program : public ProgramBindingBase {
int color_offset_location() const {
return fragment_shader_.color_offset_location_;
}
int tex_clamp_rect_location() const {
return fragment_shader_.tex_clamp_rect_location_;
}
int y_texture_location() const {
return fragment_shader_.y_texture_location_;
}
......@@ -346,11 +353,12 @@ class Program : public ProgramBindingBase {
vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_VEC4;
vertex_shader_.has_matrix_ = true;
vertex_shader_.has_vertex_opacity_ = true;
vertex_shader_.use_uniform_arrays_ = true;
vertex_shader_.use_uniform_arrays_ = !key.has_tex_clamp_rect_;
// Initialize fragment program.
fragment_shader_.has_varying_alpha_ = true;
fragment_shader_.has_background_color_ = key.has_background_color_;
fragment_shader_.has_tex_clamp_rect_ = key.has_tex_clamp_rect_;
}
void InitializeRenderPassProgram(const ProgramKey& key) {
......
......@@ -257,7 +257,7 @@ std::string VertexShader::GetShaderString() const {
}
// Read the index variables.
if (use_uniform_arrays_ ||
if (use_uniform_arrays_ || has_vertex_opacity_ ||
position_source_ == POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM) {
HDR("attribute float a_index;");
SRC("// Compute indices for uniform arrays.");
......@@ -370,9 +370,12 @@ std::string VertexShader::GetShaderString() const {
// Write varying vertex opacity.
if (has_vertex_opacity_) {
DCHECK(use_uniform_arrays_);
HDR("uniform float opacity[NUM_QUADS * 4];");
HDR("varying float v_alpha;");
if (use_uniform_arrays_) {
HDR("uniform float opacity[NUM_QUADS * 4];");
} else {
HDR("uniform float opacity[4];");
}
SRC("v_alpha = opacity[vertex_index];");
}
......@@ -422,6 +425,8 @@ void FragmentShader::Init(GLES2Interface* context,
uniforms.push_back("alpha");
if (has_background_color_)
uniforms.push_back("background_color");
if (has_tex_clamp_rect_)
uniforms.push_back("tex_clamp_rect");
switch (input_color_type_) {
case INPUT_COLOR_SOURCE_RGBA_TEXTURE:
uniforms.push_back("s_texture");
......@@ -476,6 +481,8 @@ void FragmentShader::Init(GLES2Interface* context,
alpha_location_ = locations[index++];
if (has_background_color_)
background_color_location_ = locations[index++];
if (has_tex_clamp_rect_)
tex_clamp_rect_location_ = locations[index++];
switch (input_color_type_) {
case INPUT_COLOR_SOURCE_RGBA_TEXTURE:
sampler_location_ = locations[index++];
......@@ -831,15 +838,25 @@ std::string FragmentShader::GetShaderSource() const {
SRC(" fragmentTexTransform.xy;");
SRC("vec4 texColor = TextureLookup(s_texture, texCoord);");
DCHECK(!ignore_sampler_type_);
DCHECK(!has_tex_clamp_rect_);
} else {
SRC("// Texture lookup");
if (ignore_sampler_type_)
if (ignore_sampler_type_) {
SRC("vec4 texColor = texture2D(s_texture, v_texCoord);");
else
SRC("vec4 texColor = TextureLookup(s_texture, v_texCoord);");
DCHECK(!has_tex_clamp_rect_);
} else {
SRC("TexCoordPrecision vec2 texCoord = v_texCoord;");
if (has_tex_clamp_rect_) {
HDR("uniform vec4 tex_clamp_rect;");
SRC("texCoord = max(tex_clamp_rect.xy,");
SRC(" min(tex_clamp_rect.zw, texCoord));");
}
SRC("vec4 texColor = TextureLookup(s_texture, texCoord);");
}
}
break;
case INPUT_COLOR_SOURCE_YUV_TEXTURES:
DCHECK(!has_tex_clamp_rect_);
// Compute the clamped texture coordinates for the YA and UV textures.
HDR("uniform SamplerType y_texture;");
SRC("// YUV texture lookup and conversion to RGB.");
......@@ -875,6 +892,7 @@ std::string FragmentShader::GetShaderSource() const {
case INPUT_COLOR_SOURCE_UNIFORM:
DCHECK(!ignore_sampler_type_);
DCHECK(!has_rgba_fragment_tex_transform_);
DCHECK(!has_tex_clamp_rect_);
HDR("uniform vec4 color;");
SRC("// Uniform color");
SRC("vec4 texColor = color;");
......
......@@ -277,6 +277,9 @@ class FragmentShader {
bool has_background_color_ = false;
int background_color_location_ = -1;
bool has_tex_clamp_rect_ = false;
int tex_clamp_rect_location_ = -1;
TexCoordPrecision tex_coord_precision_ = TEX_COORD_PRECISION_NA;
SamplerType sampler_type_ = SAMPLER_TYPE_NA;
......
......@@ -63,3 +63,9 @@ class PixelExpectations(GpuTestExpectations):
# TODO(junov): update reference images
self.Fail('Pixel_CSSFilterEffects', ['mac'], bug=721727)
self.Fail('Pixel_CSSFilterEffects_NoOverlays', ['mac'], bug=721727)
# TODO(dshwang): remove these after new reference images are generated.
self.Fail('Pixel_DirectComposition_Video_MP4', bug=615325)
self.Fail('Pixel_DirectComposition_Video_VP9', bug=615325)
self.Fail('Pixel_Video_MP4', bug=615325)
self.Fail('Pixel_Video_VP9', bug=615325)
......@@ -141,13 +141,13 @@ def DefaultPages(base_name):
'pixel_video_mp4.html',
base_name + '_Video_MP4',
test_rect=[0, 0, 300, 300],
revision=4),
revision=5),
PixelTestPage(
'pixel_video_vp9.html',
base_name + '_Video_VP9',
test_rect=[0, 0, 300, 300],
revision=4),
revision=5),
]
......@@ -501,13 +501,13 @@ def DirectCompositionPages(base_name):
'pixel_video_mp4.html',
base_name + '_DirectComposition_Video_MP4',
test_rect=[0, 0, 300, 300],
revision=3,
revision=4,
browser_args=browser_args),
PixelTestPage(
'pixel_video_vp9.html',
base_name + '_DirectComposition_Video_VP9',
test_rect=[0, 0, 300, 300],
revision=4,
revision=5,
browser_args=browser_args),
]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment