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; |
} |