Skip to content
This repository has been archived by the owner on Apr 3, 2020. It is now read-only.

Commit

Permalink
Optimize render passes with single quads
Browse files Browse the repository at this point in the history
Many effects (masks, replicas, filters) generate render passes for
simplicity in the code.  However, in the cases where the pass contains a
single quad with a texture, that resulting texture could just be used as
the input texture instead of the render pass itself.

The complication is mostly that render passes and tile textures are
flipped relative to each other (oops) and so some knowledge of this has
to leak into drawing render passes.

This is done by detecting such render passes inside of DirectRenderer,
storing the TileQuad that would have been drawn, skipping allocating the
pass and rendering it, and then calling a slightly modified version of
DrawRenderPassQuad with the TileQuad's resource.  The check for which
render passes can be supported is conservative to start.

This optimization usually will not be supported on mac because skia
does not support textures with texture rectangle targets as input.

BUG=254639,606672
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

Review-Url: https://codereview.chromium.org/1960543002
Cr-Commit-Position: refs/heads/master@{#399060}
  • Loading branch information
quisquous authored and Commit bot committed Jun 10, 2016
1 parent 3e75809 commit ff3dc65
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 72 deletions.
23 changes: 20 additions & 3 deletions cc/output/direct_renderer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,26 @@ DirectRenderer::DirectRenderer(RendererClient* client,

DirectRenderer::~DirectRenderer() {}

const TileDrawQuad* DirectRenderer::CanPassBeDrawnDirectly(
const RenderPass* pass) {
return nullptr;
}

void DirectRenderer::DecideRenderPassAllocationsForFrame(
const RenderPassList& render_passes_in_draw_order) {
render_pass_bypass_quads_.clear();

std::unordered_map<RenderPassId, gfx::Size, RenderPassIdHash>
render_passes_in_frame;
for (size_t i = 0; i < render_passes_in_draw_order.size(); ++i)
for (size_t i = 0; i < render_passes_in_draw_order.size(); ++i) {
RenderPass* pass = render_passes_in_draw_order[i].get();
if (const TileDrawQuad* tile_quad = CanPassBeDrawnDirectly(pass)) {
render_pass_bypass_quads_[pass->id] = *tile_quad;
continue;
}
render_passes_in_frame.insert(std::pair<RenderPassId, gfx::Size>(
render_passes_in_draw_order[i]->id,
RenderPassTextureSize(render_passes_in_draw_order[i].get())));
pass->id, RenderPassTextureSize(pass)));
}

std::vector<RenderPassId> passes_to_delete;
for (auto pass_iter = render_pass_textures_.begin();
Expand Down Expand Up @@ -405,6 +417,11 @@ void DirectRenderer::FlushPolygons(
void DirectRenderer::DrawRenderPassAndExecuteCopyRequests(
DrawingFrame* frame,
RenderPass* render_pass) {
if (render_pass_bypass_quads_.find(render_pass->id) !=
render_pass_bypass_quads_.end()) {
return;
}

DrawRenderPass(frame, render_pass);

bool first_request = true;
Expand Down
8 changes: 8 additions & 0 deletions cc/output/direct_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "cc/output/ca_layer_overlay.h"
#include "cc/output/overlay_processor.h"
#include "cc/output/renderer.h"
#include "cc/quads/tile_draw_quad.h"
#include "cc/raster/task_graph_runner.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/scoped_resource.h"
Expand All @@ -39,6 +40,11 @@ class CC_EXPORT DirectRenderer : public Renderer {
bool disable_picture_quad_image_filtering) override;
virtual void SwapBuffersComplete() {}

// If a pass contains a single tile draw quad and can be drawn without
// a render pass (e.g. applying a filter directly to the tile quad)
// return that quad, otherwise return null.
virtual const TileDrawQuad* CanPassBeDrawnDirectly(const RenderPass* pass);

struct CC_EXPORT DrawingFrame {
DrawingFrame();
~DrawingFrame();
Expand Down Expand Up @@ -152,6 +158,8 @@ class CC_EXPORT DirectRenderer : public Renderer {
std::unique_ptr<ScopedResource>,
RenderPassIdHash>
render_pass_textures_;
std::unordered_map<RenderPassId, TileDrawQuad, RenderPassIdHash>
render_pass_bypass_quads_;
OutputSurface* output_surface_;
ResourceProvider* resource_provider_;
std::unique_ptr<OverlayProcessor> overlay_processor_;
Expand Down
142 changes: 113 additions & 29 deletions cc/output/gl_renderer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,8 @@ void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame,

static sk_sp<SkImage> WrapTexture(
const ResourceProvider::ScopedReadLockGL& lock,
GrContext* context) {
GrContext* context,
bool flip_texture) {
// Wrap a given texture in a Ganesh platform texture.
GrBackendTextureDesc backend_texture_description;
GrGLTextureInfo texture_info;
Expand All @@ -600,7 +601,8 @@ static sk_sp<SkImage> WrapTexture(
backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
backend_texture_description.fTextureHandle =
skia::GrGLTextureInfoToGrBackendObject(texture_info);
backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin;
backend_texture_description.fOrigin =
flip_texture ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;

return SkImage::MakeFromTexture(context, backend_texture_description);
}
Expand All @@ -612,16 +614,19 @@ static sk_sp<SkImage> ApplyImageFilter(
const gfx::RectF& dst_rect,
const gfx::Vector2dF& scale,
sk_sp<SkImageFilter> filter,
ScopedResource* source_texture_resource,
const Resource* source_texture_resource,
SkIPoint* offset,
SkIRect* subset) {
SkIRect* subset,
bool flip_texture) {
if (!filter || !use_gr_context)
return nullptr;

ResourceProvider::ScopedReadLockGL lock(resource_provider,
source_texture_resource->id());

sk_sp<SkImage> src_image = WrapTexture(lock, use_gr_context->context());
sk_sp<SkImage> src_image =
WrapTexture(lock, use_gr_context->context(), flip_texture);

if (!src_image) {
TRACE_EVENT_INSTANT0("cc",
"ApplyImageFilter wrap background texture failed",
Expand All @@ -636,7 +641,7 @@ static sk_sp<SkImage> ApplyImageFilter(
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());
SkIRect in_subset = SkIRect::MakeWH(src_rect.width(), src_rect.height());
sk_sp<SkImage> image = src_image->makeWithFilter(filter.get(), in_subset,
clip_bounds, subset, offset);

Expand Down Expand Up @@ -852,7 +857,9 @@ sk_sp<SkImage> GLRenderer::ApplyBackgroundFilters(
ResourceProvider::ScopedReadLockGL lock(resource_provider_,
background_texture->id());

sk_sp<SkImage> src_image = WrapTexture(lock, use_gr_context->context());
bool flip_texture = true;
sk_sp<SkImage> src_image =
WrapTexture(lock, use_gr_context->context(), flip_texture);
if (!src_image) {
TRACE_EVENT_INSTANT0(
"cc", "ApplyBackgroundFilters wrap background texture failed",
Expand Down Expand Up @@ -910,14 +917,82 @@ gfx::QuadF MapQuadToLocalSpace(const gfx::Transform& device_transform,
return local_quad;
}

const TileDrawQuad* GLRenderer::CanPassBeDrawnDirectly(const RenderPass* pass) {
// Can only collapse a single tile quad.
if (pass->quad_list.size() != 1)
return nullptr;
// If we need copy requests, then render pass has to exist.
if (!pass->copy_requests.empty())
return nullptr;

const DrawQuad* quad = *pass->quad_list.BackToFrontBegin();
// Hack: this could be supported by concatenating transforms, but
// in practice if there is one quad, it is at the origin of the render pass.
if (!quad->shared_quad_state->quad_to_target_transform.IsIdentity())
return nullptr;
// The quad is expected to be the entire layer so that AA edges are correct.
if (gfx::Rect(quad->shared_quad_state->quad_layer_bounds) != quad->rect)
return nullptr;
if (quad->material != DrawQuad::TILED_CONTENT)
return nullptr;

const TileDrawQuad* tile_quad = TileDrawQuad::MaterialCast(quad);
// Hack: this could be supported by passing in a subrectangle to draw
// render pass, although in practice if there is only one quad there
// will be no border texels on the input.
if (tile_quad->tex_coord_rect != gfx::RectF(tile_quad->rect))
return nullptr;
// Tile quad features not supported in render pass shaders.
if (tile_quad->swizzle_contents || tile_quad->nearest_neighbor)
return nullptr;
// BUG=skia:3868, Skia currently doesn't support texture rectangle inputs.
// See also the DCHECKs about GL_TEXTURE_2D in DrawRenderPassQuad.
GLenum target =
resource_provider_->GetResourceTextureTarget(tile_quad->resource_id());
if (target != GL_TEXTURE_2D)
return nullptr;
#if defined(OS_MACOSX)
// On Macs, this path can sometimes lead to all black output.
// TODO(enne): investigate this and remove this hack.
return nullptr;
#endif

return tile_quad;
}

void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
const RenderPassDrawQuad* quad,
const gfx::QuadF* clip_region) {
ScopedResource* contents_texture =
render_pass_textures_[quad->render_pass_id].get();
DCHECK(contents_texture);
DCHECK(contents_texture->id());

auto bypass = render_pass_bypass_quads_.find(quad->render_pass_id);
if (bypass != render_pass_bypass_quads_.end()) {
TileDrawQuad* tile_quad = &bypass->second;
// RGBA_8888 here is arbitrary and unused.
Resource tile_resource(tile_quad->resource_id(), tile_quad->texture_size,
ResourceFormat::RGBA_8888);
// The projection matrix used by GLRenderer has a flip. As tile texture
// inputs are oriented opposite to framebuffer outputs, don't flip via
// texture coords and let the projection matrix naturallyd o it.
bool flip_texture = false;
DrawRenderPassQuadInternal(frame, quad, clip_region, &tile_resource,
flip_texture);
} else {
ScopedResource* contents_texture =
render_pass_textures_[quad->render_pass_id].get();
DCHECK(contents_texture);
DCHECK(contents_texture->id());
// See above comments about texture flipping. When the input is a
// render pass, it needs to an extra flip to be oriented correctly.
bool flip_texture = true;
DrawRenderPassQuadInternal(frame, quad, clip_region, contents_texture,
flip_texture);
}
}

void GLRenderer::DrawRenderPassQuadInternal(DrawingFrame* frame,
const RenderPassDrawQuad* quad,
const gfx::QuadF* clip_region,
const Resource* contents_texture,
bool flip_texture) {
SkMatrix scale_matrix;
scale_matrix.setScale(quad->filters_scale.x(), quad->filters_scale.y());
gfx::RectF dst_rect(quad->filters.MapRect(quad->rect, scale_matrix));
Expand Down Expand Up @@ -1022,7 +1097,6 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
SkScalar color_matrix[20];
bool use_color_matrix = false;
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(
Expand Down Expand Up @@ -1057,13 +1131,12 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
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) {
filter_image = ApplyImageFilter(
ScopedUseGrContext::Create(this, frame), resource_provider_,
src_rect, dst_rect, quad->filters_scale, std::move(filter),
contents_texture, &offset, &subset, flip_texture);
if (!filter_image)
return;
}
filter_image_id = skia::GrBackendObjectToGrGLTextureInfo(
filter_image->getTextureHandle(true))
->fID;
Expand All @@ -1074,6 +1147,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
gfx::RectF(src_rect.x() + offset.fX, src_rect.y() + offset.fY,
subset.width(), subset.height());
src_offset.SetPoint(subset.x(), subset.y());
// If the output of the filter needs to be flipped.
flip_texture =
filter_image->getTexture()->origin() == kBottomLeft_GrSurfaceOrigin;
}
Expand Down Expand Up @@ -1199,6 +1273,8 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
gl_->Uniform4f(locations.tex_transform, tex_rect.x(), 1.0f - tex_rect.y(),
tex_rect.width(), -tex_rect.height());
} else {
// Tile textures are oriented opposite the framebuffer, so can use
// the projection transform to do the flip.
gl_->Uniform4f(locations.tex_transform, tex_rect.x(), tex_rect.y(),
tex_rect.width(), tex_rect.height());
}
Expand All @@ -1214,16 +1290,24 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
mask_uv_rect.Scale(quad->mask_texture_size.width(),
quad->mask_texture_size.height());
}

// 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_rect.height() + mask_uv_rect.y());
gl_->Uniform2f(locations.mask_tex_coord_scale,
mask_uv_rect.width() / tex_rect.width(),
-mask_uv_rect.height() / tex_rect.height());
if (flip_texture) {
// 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_rect.height() + mask_uv_rect.y());
gl_->Uniform2f(locations.mask_tex_coord_scale,
mask_uv_rect.width() / tex_rect.width(),
-mask_uv_rect.height() / tex_rect.height());
} else {
// Tile textures are oriented the same way as mask textures.
gl_->Uniform2f(locations.mask_tex_coord_offset, mask_uv_rect.x(),
mask_uv_rect.y());
gl_->Uniform2f(locations.mask_tex_coord_scale,
mask_uv_rect.width() / tex_rect.width(),
mask_uv_rect.height() / tex_rect.height());
}

last_texture_unit = 1;
}
Expand Down
7 changes: 7 additions & 0 deletions cc/output/gl_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,16 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
ScopedResource* background_texture,
const gfx::RectF& rect);

const TileDrawQuad* CanPassBeDrawnDirectly(const RenderPass* pass) override;

void DrawRenderPassQuad(DrawingFrame* frame,
const RenderPassDrawQuad* quadi,
const gfx::QuadF* clip_region);
void DrawRenderPassQuadInternal(DrawingFrame* frame,
const RenderPassDrawQuad* quad,
const gfx::QuadF* clip_region,
const Resource* contents_texture,
bool is_render_pass_input);
void DrawSolidColorQuad(const DrawingFrame* frame,
const SolidColorDrawQuad* quad,
const gfx::QuadF* clip_region);
Expand Down
Binary file modified cc/test/data/rotated_drop_shadow_filter_gl.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cc/test/data/rotated_drop_shadow_filter_sw.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 15 additions & 3 deletions cc/test/solid_color_content_layer_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,25 @@ SolidColorContentLayerClient::PaintContentsToDisplayList(
sk_sp<SkCanvas> canvas =
sk_ref_sp(recorder.beginRecording(gfx::RectToSkRect(clip)));

canvas->clear(SK_ColorTRANSPARENT);

if (border_size_ != 0) {
SkPaint paint;
paint.setStyle(SkPaint::kFill_Style);
paint.setColor(border_color_);
canvas->drawRect(
SkRect::MakeXYWH(clip.x(), clip.y(), clip.width(), clip.height()),
paint);
}

SkPaint paint;
paint.setStyle(SkPaint::kFill_Style);
paint.setColor(color_);

canvas->clear(SK_ColorTRANSPARENT);
canvas->drawRect(
SkRect::MakeXYWH(clip.x(), clip.y(), clip.width(), clip.height()), paint);
SkRect::MakeXYWH(clip.x() + border_size_, clip.y() + border_size_,
clip.width() - 2 * border_size_,
clip.height() - 2 * border_size_),
paint);

DisplayItemListSettings settings;
settings.use_cached_picture = false;
Expand Down
12 changes: 11 additions & 1 deletion cc/test/solid_color_content_layer_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@ namespace cc {
class SolidColorContentLayerClient : public ContentLayerClient {
public:
explicit SolidColorContentLayerClient(SkColor color, gfx::Size size)
: color_(color), size_(size) {}
: color_(color), size_(size), border_size_(0), border_color_(0) {}
explicit SolidColorContentLayerClient(SkColor color,
gfx::Size size,
int border_size,
SkColor border_color)
: color_(color),
size_(size),
border_size_(border_size),
border_color_(border_color) {}

gfx::Rect PaintableRegion() override;

Expand All @@ -29,6 +37,8 @@ class SolidColorContentLayerClient : public ContentLayerClient {
private:
SkColor color_;
gfx::Size size_;
int border_size_;
SkColor border_color_;
};

} // namespace cc
Expand Down
Loading

0 comments on commit ff3dc65

Please sign in to comment.