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

Unified Diff: cc/output/gl_renderer.cc

Issue 2612023002: cc: Implement overdraw feedback debugging feature. (Closed)
Patch Set: tracing support Created 3 years, 11 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
Index: cc/output/gl_renderer.cc
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index e1020caf4def2e10973e8c65449ed1ea1a6b3b37..140153a574e7a01a7074304422824cd97f5dab73 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -14,6 +14,7 @@
#include <string>
#include <vector>
+#include "base/barrier_closure.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/macros.h"
@@ -370,6 +371,16 @@ class GLRenderer::SyncQuery {
DISALLOW_COPY_AND_ASSIGN(SyncQuery);
};
+struct GLRenderer::PendingOverdrawQuery {
+ explicit PendingOverdrawQuery(unsigned query) : query(query) {}
+
+ base::CancelableClosure overdraw_callback;
+ const unsigned query;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PendingOverdrawQuery);
+};
+
GLRenderer::GLRenderer(const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider,
@@ -415,6 +426,13 @@ GLRenderer::~GLRenderer() {
pending_async_read_pixels_.pop_back();
}
+ while (!pending_overdraw_queries_.empty()) {
+ PendingOverdrawQuery* pending_query =
+ pending_overdraw_queries_.back().get();
+ pending_query->overdraw_callback.Cancel();
+ pending_overdraw_queries_.pop_back();
+ }
+
CleanupSharedObjects();
if (context_visibility_) {
@@ -425,6 +443,13 @@ GLRenderer::~GLRenderer() {
}
bool GLRenderer::CanPartialSwap() {
+ bool overdraw_tracing_enabled;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.overdraw"),
+ &overdraw_tracing_enabled);
+ // Overdraw tracing requires fullscreen updates.
+ if (overdraw_tracing_enabled)
+ return false;
auto* context_provider = output_surface_->context_provider();
return context_provider->ContextCapabilities().post_sub_buffer;
}
@@ -495,7 +520,9 @@ void GLRenderer::ClearFramebuffer(DrawingFrame* frame) {
else
gl_->ClearColor(0, 0, 1, 1);
- bool always_clear = false;
+ gl_->ClearStencil(0);
+
+ bool always_clear = overdraw_feedback_;
#ifndef NDEBUG
always_clear = true;
#endif
@@ -2763,8 +2790,11 @@ void GLRenderer::FinishDrawingFrame(DrawingFrame* frame) {
pending_sync_queries_.push_back(std::move(current_sync_query_));
}
- current_framebuffer_lock_ = nullptr;
swap_buffer_rect_.Union(frame->root_damage_rect);
+ if (overdraw_feedback_)
+ FlushOverdrawFeedback(frame, swap_buffer_rect_);
+
+ current_framebuffer_lock_ = nullptr;
gl_->Disable(GL_BLEND);
blend_shadow_ = false;
@@ -3002,6 +3032,9 @@ void GLRenderer::GetFramebufferPixelsAsync(
if (rect.IsEmpty())
return;
+ if (overdraw_feedback_)
+ FlushOverdrawFeedback(frame, rect);
+
gfx::Rect window_rect = MoveFromDrawToWindowSpace(frame, rect);
DCHECK_GE(window_rect.x(), 0);
DCHECK_GE(window_rect.y(), 0);
@@ -3202,7 +3235,10 @@ void GLRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) {
current_framebuffer_lock_ = nullptr;
output_surface_->BindFramebuffer();
- if (output_surface_->HasExternalStencilTest()) {
+ if (overdraw_feedback_) {
+ SetupOverdrawFeedback();
+ SetStencilEnabled(true);
+ } else if (output_surface_->HasExternalStencilTest()) {
output_surface_->ApplyExternalStencil();
SetStencilEnabled(true);
} else {
@@ -3218,7 +3254,6 @@ bool GLRenderer::BindFramebufferToTexture(DrawingFrame* frame,
// same texture again.
current_framebuffer_lock_ = nullptr;
- SetStencilEnabled(false);
gl_->BindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_);
current_framebuffer_lock_ =
base::MakeUnique<ResourceProvider::ScopedWriteLockGL>(
@@ -3227,10 +3262,31 @@ bool GLRenderer::BindFramebufferToTexture(DrawingFrame* frame,
unsigned texture_id = current_framebuffer_lock_->texture_id();
gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
texture_id, 0);
+ if (overdraw_feedback_) {
+ if (texture->size() != offscreen_stencil_renderbuffer_size_) {
+ gl_->BindRenderbuffer(GL_RENDERBUFFER,
+ offscreen_stencil_renderbuffer_id_);
+ gl_->RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8,
+ texture->size().width(),
+ texture->size().height());
+ gl_->BindRenderbuffer(GL_RENDERBUFFER, 0);
+ offscreen_stencil_renderbuffer_size_ = texture->size();
+ }
+ gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER,
+ offscreen_stencil_renderbuffer_id_);
+ }
DCHECK(gl_->CheckFramebufferStatus(GL_FRAMEBUFFER) ==
GL_FRAMEBUFFER_COMPLETE ||
IsContextLost());
+
+ if (overdraw_feedback_) {
+ SetupOverdrawFeedback();
+ SetStencilEnabled(true);
+ } else {
+ SetStencilEnabled(false);
+ }
return true;
}
@@ -3261,6 +3317,9 @@ void GLRenderer::InitializeSharedObjects() {
// Create an FBO for doing offscreen rendering.
gl_->GenFramebuffers(1, &offscreen_framebuffer_id_);
+ // Create a stencil buffer for doing offscreen rendering.
+ gl_->GenRenderbuffers(1, &offscreen_stencil_renderbuffer_id_);
Daniele Castagna 2017/01/09 18:53:06 Why not if (overdraw_feedback_) ?
reveman 2017/01/10 23:52:00 Done. By deferring this until needed.
+
shared_geometry_ =
base::MakeUnique<StaticGeometryBinding>(gl_, QuadVertexRect());
clipped_geometry_ = base::MakeUnique<DynamicGeometryBinding>(gl_);
@@ -3732,6 +3791,9 @@ void GLRenderer::CleanupSharedObjects() {
if (offscreen_framebuffer_id_)
gl_->DeleteFramebuffers(1, &offscreen_framebuffer_id_);
+ if (offscreen_stencil_renderbuffer_id_)
+ gl_->DeleteRenderbuffers(1, &offscreen_stencil_renderbuffer_id_);
+
ReleaseRenderPassTextures();
}
@@ -4064,4 +4126,137 @@ void GLRenderer::ScheduleRenderPassDrawQuad(
ca_layer_overlay->edge_aa_mask, bounds_rect, filter);
}
+void GLRenderer::SetupOverdrawFeedback() {
+ gl_->StencilFunc(GL_ALWAYS, 1, 0xffffffff);
+ // First two values are ignored as test always passes.
+ gl_->StencilOp(GL_KEEP, GL_KEEP, GL_INCR);
+ gl_->StencilMask(0xff);
+}
+
+void GLRenderer::FlushOverdrawFeedback(const DrawingFrame* frame,
+ const gfx::Rect& output_rect) {
+ // Return early if already flushed.
+ if (!stencil_shadow_)
+ return;
+
+ // Test only, keep everything.
+ gl_->StencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ gl_->StencilMask(0);
+
+ EnsureScissorTestDisabled();
+ SetBlendEnabled(true);
+
+ PrepareGeometry(SHARED_BINDING);
+
+ const DebugBorderProgram* program = GetDebugBorderProgram();
+ DCHECK(program && (program->initialized() || IsContextLost()));
+ SetUseProgram(program->program());
+
+ gfx::Transform render_matrix;
+ render_matrix.Translate(0.5 * output_rect.width() + output_rect.x(),
+ 0.5 * output_rect.height() + output_rect.y());
+ render_matrix.Scale(output_rect.width(), output_rect.height());
+ static float gl_matrix[16];
+ GLRenderer::ToGLMatrix(&gl_matrix[0],
+ frame->projection_matrix * render_matrix);
+ gl_->UniformMatrix4fv(program->vertex_shader().matrix_location(), 1, false,
+ &gl_matrix[0]);
+
+ // Produce hinting for the amount of overdraw on screen for each pixel by
+ // drawing hint colors to the framebuffer based on the current stencil value.
+ struct {
+ int category;
+ GLenum func;
+ GLint ref;
+ SkColor color;
+ } stencil_tests[] = {
+ {1, GL_EQUAL, 2, 0x2f0000ff}, // Blue: Overdrawn once.
+ {2, GL_EQUAL, 3, 0x2f00ff00}, // Green: Overdrawn twice.
+ {3, GL_EQUAL, 4, 0x3fff0000}, // Pink: Overdrawn three times.
+ {4, GL_LESS, 4, 0x7fff0000}, // Red: Overdrawn four or more times.
+ };
+
+ // Occlusion queries can be expensive, so only collect trace data if we select
+ // cc.debug.overdraw.
+ bool tracing_enabled;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.overdraw"), &tracing_enabled);
+
+ // Trace only the root render pass.
+ if (frame->current_render_pass != frame->root_render_pass)
+ tracing_enabled = false;
+
+ base::Closure barrier = base::BarrierClosure(
+ arraysize(stencil_tests),
+ base::Bind(&GLRenderer::UpdateOverdrawCounter, base::Unretained(this)));
+
+ for (const auto& test : stencil_tests) {
+ if (tracing_enabled) {
+ GLuint query = 0;
+ gl_->GenQueriesEXT(1, &query);
+ // TODO(reveman): Use SAMPLES_PASSED_ARB when available for exact amount
+ // of overdraw.
+ gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, query);
+
+ std::unique_ptr<PendingOverdrawQuery> pending_overdraw_query(
+ new PendingOverdrawQuery(query));
+ pending_overdraw_queries_.push_back(std::move(pending_overdraw_query));
+ }
+
+ gl_->StencilFunc(test.func, test.ref, 0xffffffff);
+ Float4 color = PremultipliedColor(test.color);
+ gl_->Uniform4fv(program->fragment_shader().color_location(), 1, color.data);
+ gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
+
+ if (tracing_enabled) {
+ base::Closure overdraw_feedback_callback = base::Bind(
+ &GLRenderer::OverdrawFeedback, base::Unretained(this),
+ pending_overdraw_queries_.back()->query, test.category, barrier);
+
+ // Save the overdraw_feedback_callback so it can be cancelled.
+ pending_overdraw_queries_.back()->overdraw_callback.Reset(
+ overdraw_feedback_callback);
+ base::Closure cancelable_callback =
+ pending_overdraw_queries_.back()->overdraw_callback.callback();
+
+ gl_->EndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
+ context_support_->SignalQuery(pending_overdraw_queries_.back()->query,
+ cancelable_callback);
+ }
+ }
+
+ gl_->StencilFunc(GL_ALWAYS, 0, 0xffffffff);
+ gl_->Disable(GL_STENCIL_TEST);
+ stencil_shadow_ = false;
+}
+
+void GLRenderer::OverdrawFeedback(unsigned query,
+ int category,
+ base::Closure barrier) {
+ DCHECK(!pending_overdraw_queries_.empty());
+ DCHECK_EQ(pending_overdraw_queries_.front()->query, query);
+ pending_overdraw_queries_.pop_front();
+
+ unsigned result = 0;
+ if (query) {
+ gl_->GetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT, &result);
+ gl_->DeleteQueriesEXT(1, &query);
+ }
+
+ if (result)
+ current_overdraw_.insert(category);
+ else
+ current_overdraw_.erase(category);
+
+ barrier.Run();
+}
+
+void GLRenderer::UpdateOverdrawCounter() const {
+ // Report overdraw as multiple of the screen size. ie. 1x for the whole
+ // screen is 1.0. Note: this will always report the worst overdraw on screen
+ // as the overdraw for the whole screen until SAMPLES_PASSED_ARB is supported.
+ TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.overdraw"), "GPU Overdraw",
+ current_overdraw_.empty() ? 0 : *current_overdraw_.rbegin());
+}
+
} // namespace cc

Powered by Google App Engine
This is Rietveld 408576698