Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3104)

Unified Diff: cc/output/gl_renderer.cc

Issue 1959033002: cc: optimize Skia image filter application via SkImage::makeWithFilter(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Win pixeltest tweakage Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | cc/test/data/blur_filter_with_clip_gl.png » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/output/gl_renderer.cc
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 3c96d3b93c10eb87874c99bb4c0d1dd6c44b575d..7cf5a00face44d5bfa4fdf49f6e805ae4d5b209c 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -53,8 +53,6 @@
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
-#include "third_party/skia/include/gpu/GrTexture.h"
-#include "third_party/skia/include/gpu/GrTextureProvider.h"
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
#include "third_party/skia/include/gpu/gl/GrGLTypes.h"
#include "ui/gfx/geometry/quad_f.h"
@@ -141,16 +139,6 @@ BlendMode BlendModeFromSkXfermode(SkXfermode::Mode mode) {
}
}
-void RoundUpToPow2(gfx::RectF* rect) {
- float w, h;
- for (w = 1.f; w < rect->width(); w *= 2.f) {
- }
- for (h = 1.f; h < rect->height(); h *= 2.f) {
- }
- rect->set_width(w);
- rect->set_height(h);
-}
-
// Smallest unit that impact anti-aliasing output. We use this to
// determine when anti-aliasing is unnecessary.
const float kAntiAliasingEpsilon = 1.0f / 1024.0f;
@@ -599,6 +587,24 @@ void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame,
gl_->DrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0);
}
+static sk_sp<SkImage> WrapTexture(
+ const ResourceProvider::ScopedReadLockGL& lock,
+ GrContext* context) {
+ // Wrap a given texture in a Ganesh platform texture.
+ GrBackendTextureDesc backend_texture_description;
+ GrGLTextureInfo texture_info;
+ texture_info.fTarget = lock.target();
+ texture_info.fID = lock.texture_id();
+ backend_texture_description.fWidth = lock.texture_size().width();
+ backend_texture_description.fHeight = lock.texture_size().height();
+ backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
+ backend_texture_description.fTextureHandle =
+ skia::GrGLTextureInfoToGrBackendObject(texture_info);
+ backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin;
+
+ return SkImage::MakeFromTexture(context, backend_texture_description);
+}
+
static sk_sp<SkImage> ApplyImageFilter(
std::unique_ptr<GLRenderer::ScopedUseGrContext> use_gr_context,
ResourceProvider* resource_provider,
@@ -606,31 +612,16 @@ static sk_sp<SkImage> ApplyImageFilter(
const gfx::RectF& dst_rect,
const gfx::Vector2dF& scale,
sk_sp<SkImageFilter> filter,
- ScopedResource* source_texture_resource) {
- if (!filter)
- return nullptr;
-
- if (!use_gr_context)
+ ScopedResource* source_texture_resource,
+ SkIPoint* offset,
+ SkIRect* subset) {
+ if (!filter || !use_gr_context)
return nullptr;
ResourceProvider::ScopedReadLockGL lock(resource_provider,
source_texture_resource->id());
- // Wrap the source texture in a Ganesh platform texture.
- GrBackendTextureDesc backend_texture_description;
- GrGLTextureInfo texture_info;
- texture_info.fTarget = lock.target();
- texture_info.fID = lock.texture_id();
- backend_texture_description.fWidth = source_texture_resource->size().width();
- backend_texture_description.fHeight =
- source_texture_resource->size().height();
- backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
- backend_texture_description.fTextureHandle =
- skia::GrGLTextureInfoToGrBackendObject(texture_info);
- backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin;
-
- sk_sp<SkImage> src_image = SkImage::MakeFromTexture(
- use_gr_context->context(), backend_texture_description);
+ sk_sp<SkImage> src_image = WrapTexture(lock, use_gr_context->context());
if (!src_image) {
TRACE_EVENT_INSTANT0("cc",
"ApplyImageFilter wrap background texture failed",
@@ -638,35 +629,24 @@ static sk_sp<SkImage> ApplyImageFilter(
return nullptr;
}
- // Create surface to draw into.
- SkImageInfo dst_info =
- SkImageInfo::MakeN32Premul(dst_rect.width(), dst_rect.height());
- sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(
- use_gr_context->context(), SkBudgeted::kYes, dst_info);
- if (!surface) {
- TRACE_EVENT_INSTANT0("cc", "ApplyImageFilter surface allocation failed",
- TRACE_EVENT_SCOPE_THREAD);
- return nullptr;
- }
-
SkMatrix local_matrix;
- local_matrix.setScale(scale.x(), scale.y());
+ local_matrix.setTranslate(-src_rect.x(), -src_rect.y());
+ local_matrix.postScale(scale.x(), scale.y());
+
+ SkIRect clip_bounds = gfx::RectFToSkRect(dst_rect).roundOut();
+ clip_bounds.offset(-src_rect.x(), -src_rect.y());
+ filter = filter->makeWithLocalMatrix(local_matrix);
+ SkIRect in_subset = SkIRect::MakeWH(src_image->width(), src_image->height());
+ sk_sp<SkImage> image = src_image->makeWithFilter(filter.get(), in_subset,
+ clip_bounds, subset, offset);
- SkPaint paint;
- paint.setImageFilter(filter->makeWithLocalMatrix(local_matrix));
- surface->getCanvas()->translate(-dst_rect.x(), -dst_rect.y());
- surface->getCanvas()->drawImage(src_image, src_rect.x(), src_rect.y(),
- &paint);
- // Flush the drawing before source texture read lock goes out of scope.
- // Skia API does not guarantee that when the SkImage goes out of scope,
- // its externally referenced resources would force the rendering to be
- // flushed.
- surface->getCanvas()->flush();
- sk_sp<SkImage> image = surface->makeImageSnapshot();
if (!image || !image->isTextureBacked()) {
return nullptr;
}
+ // Force a flush of the Skia pipeline before we switch back to the compositor
+ // context.
+ image->getTextureHandle(true);
CHECK(image->isTextureBacked());
return image;
}
@@ -859,13 +839,57 @@ sk_sp<SkImage> GLRenderer::ApplyBackgroundFilters(
ScopedResource* background_texture,
const gfx::RectF& rect) {
DCHECK(ShouldApplyBackgroundFilters(quad));
+ auto use_gr_context = ScopedUseGrContext::Create(this, frame);
sk_sp<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter(
quad->background_filters, gfx::SizeF(background_texture->size()));
- sk_sp<SkImage> background_with_filters = ApplyImageFilter(
- ScopedUseGrContext::Create(this, frame), resource_provider_, rect, rect,
- quad->filters_scale, std::move(filter), background_texture);
- return background_with_filters;
+ // TODO(senorblanco): background filters should be moved to the
+ // makeWithFilter fast-path, and go back to calling ApplyImageFilter().
+ // See http://crbug.com/613233.
+ if (!filter || !use_gr_context)
+ return nullptr;
+
+ ResourceProvider::ScopedReadLockGL lock(resource_provider_,
+ background_texture->id());
+
+ sk_sp<SkImage> src_image = WrapTexture(lock, use_gr_context->context());
+ if (!src_image) {
+ TRACE_EVENT_INSTANT0(
+ "cc", "ApplyBackgroundFilters wrap background texture failed",
+ TRACE_EVENT_SCOPE_THREAD);
+ return nullptr;
+ }
+
+ // Create surface to draw into.
+ SkImageInfo dst_info =
+ SkImageInfo::MakeN32Premul(rect.width(), rect.height());
+ sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(
+ use_gr_context->context(), SkBudgeted::kYes, dst_info);
+ if (!surface) {
+ TRACE_EVENT_INSTANT0("cc",
+ "ApplyBackgroundFilters surface allocation failed",
+ TRACE_EVENT_SCOPE_THREAD);
+ return nullptr;
+ }
+
+ SkMatrix local_matrix;
+ local_matrix.setScale(quad->filters_scale.x(), quad->filters_scale.y());
+
+ SkPaint paint;
+ paint.setImageFilter(filter->makeWithLocalMatrix(local_matrix));
+ surface->getCanvas()->translate(-rect.x(), -rect.y());
+ surface->getCanvas()->drawImage(src_image, rect.x(), rect.y(), &paint);
+ // Flush the drawing before source texture read lock goes out of scope.
+ // Skia API does not guarantee that when the SkImage goes out of scope,
+ // its externally referenced resources would force the rendering to be
+ // flushed.
+ surface->getCanvas()->flush();
+ sk_sp<SkImage> image = surface->makeImageSnapshot();
+ if (!image || !image->isTextureBacked()) {
+ return nullptr;
+ }
+
+ return image;
}
// Map device space quad to local space. Device_transform has no 3d
@@ -997,7 +1021,9 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
GLuint filter_image_id = 0;
SkScalar color_matrix[20];
bool use_color_matrix = false;
- gfx::RectF rect = gfx::RectF(quad->rect);
+ gfx::Size texture_size = contents_texture->size();
+ bool flip_texture = true;
+ gfx::Point src_offset;
if (!quad->filters.IsEmpty()) {
sk_sp<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter(
quad->filters, gfx::SizeF(contents_texture->size()));
@@ -1028,19 +1054,28 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
if (dst_rect.IsEmpty()) {
return;
}
- // Expand dst_rect size to the nearest power of 2, in order to get
- // more cache hits in Skia's texture cache.
- RoundUpToPow2(&dst_rect);
- filter_image = ApplyImageFilter(
- ScopedUseGrContext::Create(this, frame), resource_provider_, rect,
- dst_rect, quad->filters_scale, std::move(filter), contents_texture);
+ SkIPoint offset;
+ SkIRect subset;
+ gfx::RectF src_rect(quad->rect);
+ filter_image = ApplyImageFilter(ScopedUseGrContext::Create(this, frame),
+ resource_provider_, src_rect, dst_rect,
+ quad->filters_scale, std::move(filter),
+ contents_texture, &offset, &subset);
if (!filter_image) {
return;
}
filter_image_id = skia::GrBackendObjectToGrGLTextureInfo(
filter_image->getTextureHandle(true))
->fID;
+ texture_size.set_width(filter_image->width());
+ texture_size.set_height(filter_image->height());
DCHECK(filter_image_id);
+ dst_rect =
+ gfx::RectF(src_rect.x() + offset.fX, src_rect.y() + offset.fY,
+ subset.width(), subset.height());
+ src_offset.SetPoint(subset.x(), subset.y());
+ flip_texture =
+ filter_image->getTexture()->origin() == kBottomLeft_GrSurfaceOrigin;
}
}
}
@@ -1152,25 +1187,21 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
program->fragment_shader().FillLocations(&locations);
gl_->Uniform1i(locations.sampler, 0);
}
- float tex_scale_x, tex_scale_y;
- if (filter_image) {
- // Skia filters always return SkImages with snug textures.
- tex_scale_x = tex_scale_y = 1.0f;
- } else {
- tex_scale_x = quad->rect.width() /
- static_cast<float>(contents_texture->size().width());
- tex_scale_y = quad->rect.height() /
- static_cast<float>(contents_texture->size().height());
- }
- DCHECK_LE(tex_scale_x, 1.0f);
- DCHECK_LE(tex_scale_y, 1.0f);
+ gfx::RectF tex_rect(src_offset.x(), src_offset.y(), dst_rect.width(),
+ dst_rect.height());
+ tex_rect.Scale(1.0f / texture_size.width(), 1.0f / texture_size.height());
DCHECK(locations.tex_transform != -1 || IsContextLost());
- // Flip the content vertically in the shader, as the RenderPass input
- // texture is already oriented the same way as the framebuffer, but the
- // projection transform does a flip.
- gl_->Uniform4f(locations.tex_transform, 0.0f, 1.0f, tex_scale_x,
- -tex_scale_y);
+ if (flip_texture) {
+ // Flip the content vertically in the shader, as the RenderPass input
+ // texture is already oriented the same way as the framebuffer, but the
+ // projection transform does a flip.
+ gl_->Uniform4f(locations.tex_transform, tex_rect.x(), 1.0f - tex_rect.y(),
+ tex_rect.width(), -tex_rect.height());
+ } else {
+ gl_->Uniform4f(locations.tex_transform, tex_rect.x(), tex_rect.y(),
+ tex_rect.width(), tex_rect.height());
+ }
GLint last_texture_unit = 0;
if (locations.mask_sampler != -1) {
@@ -1187,11 +1218,12 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
// Mask textures are oriented vertically flipped relative to the framebuffer
// and the RenderPass contents texture, so we flip the tex coords from the
// RenderPass texture to find the mask texture coords.
- gl_->Uniform2f(locations.mask_tex_coord_offset, mask_uv_rect.x(),
- mask_uv_rect.height() / tex_scale_y + mask_uv_rect.y());
+ gl_->Uniform2f(
+ locations.mask_tex_coord_offset, mask_uv_rect.x(),
+ mask_uv_rect.height() / tex_rect.height() + mask_uv_rect.y());
gl_->Uniform2f(locations.mask_tex_coord_scale,
- mask_uv_rect.width() / tex_scale_x,
- -mask_uv_rect.height() / tex_scale_y);
+ mask_uv_rect.width() / tex_rect.width(),
+ -mask_uv_rect.height() / tex_rect.height());
last_texture_unit = 1;
}
« no previous file with comments | « no previous file | cc/test/data/blur_filter_with_clip_gl.png » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698