Add overdraw debugging feature to Skia pipelines
Test: Compared to OpenGL pipeline and sanity checked with understanding of the drawing pipeline. Also wrote a unit test. BUG:32370375 Change-Id: Iab397d21f0def725fa89551d48c764c67fd2bda8
This commit is contained in:
@@ -188,8 +188,9 @@ void RenderNode::prepareTree(TreeInfo& info) {
|
||||
ATRACE_CALL();
|
||||
LOG_ALWAYS_FATAL_IF(!info.damageAccumulator, "DamageAccumulator missing");
|
||||
|
||||
// Functors don't correctly handle stencil usage of overdraw debugging - shove 'em in a layer.
|
||||
bool functorsNeedLayer = Properties::debugOverdraw;
|
||||
// The OpenGL renderer reserves the stencil buffer for overdraw debugging. Functors
|
||||
// will need to be drawn in a layer.
|
||||
bool functorsNeedLayer = Properties::debugOverdraw && !Properties::isSkiaEnabled();
|
||||
|
||||
prepareTreeImpl(info, functorsNeedLayer);
|
||||
}
|
||||
|
||||
@@ -165,13 +165,22 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
|
||||
}
|
||||
renderNode->getLayerSurface()->draw(canvas, 0, 0, paint);
|
||||
|
||||
if (CC_UNLIKELY(Properties::debugLayersUpdates
|
||||
&& !renderNode->getSkiaLayer()->hasRenderedSinceRepaint)) {
|
||||
if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) {
|
||||
renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true;
|
||||
SkPaint layerPaint;
|
||||
layerPaint.setColor(0x7f00ff00);
|
||||
canvas->drawRect(bounds, layerPaint);
|
||||
if (CC_UNLIKELY(Properties::debugLayersUpdates)) {
|
||||
SkPaint layerPaint;
|
||||
layerPaint.setColor(0x7f00ff00);
|
||||
canvas->drawRect(bounds, layerPaint);
|
||||
} else if (CC_UNLIKELY(Properties::debugOverdraw)) {
|
||||
// Render transparent rect to increment overdraw for repaint area.
|
||||
// This can be "else if" because flashing green on layer updates
|
||||
// will also increment the overdraw if it happens to be turned on.
|
||||
SkPaint transparentPaint;
|
||||
transparentPaint.setColor(SK_ColorTRANSPARENT);
|
||||
canvas->drawRect(bounds, transparentPaint);
|
||||
}
|
||||
}
|
||||
|
||||
// composing a software layer with alpha
|
||||
} else if (properties.effectiveLayerType() == LayerType::Software) {
|
||||
SkPaint paint;
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "utils/TraceUtils.h"
|
||||
#include <SkOSFile.h>
|
||||
#include <SkOverdrawCanvas.h>
|
||||
#include <SkOverdrawColorFilter.h>
|
||||
#include <SkPicture.h>
|
||||
#include <SkPictureRecorder.h>
|
||||
#include <SkPixelSerializer.h>
|
||||
@@ -192,6 +194,34 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli
|
||||
}
|
||||
}
|
||||
|
||||
renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas);
|
||||
|
||||
if (skpCaptureEnabled() && recordingPicture) {
|
||||
sk_sp<SkPicture> picture = recorder->finishRecordingAsPicture();
|
||||
if (picture->approximateOpCount() > 0) {
|
||||
SkFILEWStream stream(prop);
|
||||
if (stream.isValid()) {
|
||||
PngPixelSerializer serializer;
|
||||
picture->serialize(&stream, &serializer);
|
||||
stream.flush();
|
||||
SkDebugf("Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(), prop);
|
||||
}
|
||||
}
|
||||
surface->getCanvas()->drawPicture(picture);
|
||||
}
|
||||
|
||||
if (CC_UNLIKELY(Properties::debugOverdraw)) {
|
||||
renderOverdraw(layers, clip, nodes, contentDrawBounds, surface);
|
||||
}
|
||||
|
||||
ATRACE_NAME("flush commands");
|
||||
canvas->flush();
|
||||
}
|
||||
|
||||
void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
|
||||
const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
|
||||
SkCanvas* canvas) {
|
||||
|
||||
canvas->clipRect(clip, SkRegion::kReplace_Op);
|
||||
|
||||
if (!opaque) {
|
||||
@@ -250,23 +280,6 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli
|
||||
canvas->restoreToCount(count);
|
||||
layer++;
|
||||
}
|
||||
|
||||
if (skpCaptureEnabled() && recordingPicture) {
|
||||
sk_sp<SkPicture> picture = recorder->finishRecordingAsPicture();
|
||||
if (picture->approximateOpCount() > 0) {
|
||||
SkFILEWStream stream(prop);
|
||||
if (stream.isValid()) {
|
||||
PngPixelSerializer serializer;
|
||||
picture->serialize(&stream, &serializer);
|
||||
stream.flush();
|
||||
SkDebugf("Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(), prop);
|
||||
}
|
||||
}
|
||||
surface->getCanvas()->drawPicture(picture);
|
||||
}
|
||||
|
||||
ATRACE_NAME("flush commands");
|
||||
canvas->flush();
|
||||
}
|
||||
|
||||
void SkiaPipeline::dumpResourceCacheUsage() const {
|
||||
@@ -283,6 +296,40 @@ void SkiaPipeline::dumpResourceCacheUsage() const {
|
||||
ALOGD("%s", log.c_str());
|
||||
}
|
||||
|
||||
// Overdraw debugging
|
||||
|
||||
// These colors should be kept in sync with Caches::getOverdrawColor() with a few differences.
|
||||
// This implementation:
|
||||
// (1) Requires transparent entries for "no overdraw" and "single draws".
|
||||
// (2) Requires premul colors (instead of unpremul).
|
||||
// (3) Requires RGBA colors (instead of BGRA).
|
||||
static const uint32_t kOverdrawColors[2][6] = {
|
||||
{ 0x00000000, 0x00000000, 0x2f2f0000, 0x2f002f00, 0x3f00003f, 0x7f00007f, },
|
||||
{ 0x00000000, 0x00000000, 0x2f2f0000, 0x4f004f4f, 0x5f50335f, 0x7f00007f, },
|
||||
};
|
||||
|
||||
void SkiaPipeline::renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
|
||||
const std::vector<sp<RenderNode>>& nodes, const Rect &contentDrawBounds,
|
||||
sk_sp<SkSurface> surface) {
|
||||
// Set up the overdraw canvas.
|
||||
SkImageInfo offscreenInfo = SkImageInfo::MakeA8(surface->width(), surface->height());
|
||||
sk_sp<SkSurface> offscreen = surface->makeSurface(offscreenInfo);
|
||||
SkOverdrawCanvas overdrawCanvas(offscreen->getCanvas());
|
||||
|
||||
// Fake a redraw to replay the draw commands. This will increment the alpha channel
|
||||
// each time a pixel would have been drawn.
|
||||
// Pass true for opaque so we skip the clear - the overdrawCanvas is already zero
|
||||
// initialized.
|
||||
renderFrameImpl(layers, clip, nodes, true, contentDrawBounds, &overdrawCanvas);
|
||||
sk_sp<SkImage> counts = offscreen->makeImageSnapshot();
|
||||
|
||||
// Draw overdraw colors to the canvas. The color filter will convert counts to colors.
|
||||
SkPaint paint;
|
||||
const SkPMColor* colors = kOverdrawColors[static_cast<int>(Properties::overdrawColorSet)];
|
||||
paint.setColorFilter(SkOverdrawColorFilter::Make(colors));
|
||||
surface->getCanvas()->drawImage(counts.get(), 0.0f, 0.0f, &paint);
|
||||
}
|
||||
|
||||
} /* namespace skiapipeline */
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
|
||||
@@ -107,6 +107,18 @@ protected:
|
||||
renderthread::RenderThread& mRenderThread;
|
||||
|
||||
private:
|
||||
void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
|
||||
const std::vector< sp<RenderNode> >& nodes, bool opaque, const Rect &contentDrawBounds,
|
||||
SkCanvas* canvas);
|
||||
|
||||
/**
|
||||
* Debugging feature. Draws a semi-transparent overlay on each pixel, indicating
|
||||
* how many times it has been drawn.
|
||||
*/
|
||||
void renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
|
||||
const std::vector< sp<RenderNode> >& nodes, const Rect &contentDrawBounds,
|
||||
sk_sp<SkSurface>);
|
||||
|
||||
TaskManager mTaskManager;
|
||||
std::vector<sk_sp<SkImage>> mPinnedImages;
|
||||
static float mLightRadius;
|
||||
|
||||
@@ -179,3 +179,53 @@ RENDERTHREAD_TEST(SkiaPipeline, renderLayer) {
|
||||
redNode->setLayerSurface(sk_sp<SkSurface>());
|
||||
blueNode->setLayerSurface(sk_sp<SkSurface>());
|
||||
}
|
||||
|
||||
RENDERTHREAD_TEST(SkiaPipeline, renderOverdraw) {
|
||||
ScopedProperty<bool> prop(Properties::debugOverdraw, true);
|
||||
|
||||
auto whiteNode = TestUtils::createSkiaNode(0, 0, 1, 1,
|
||||
[](RenderProperties& props, SkiaRecordingCanvas& canvas) {
|
||||
canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
|
||||
});
|
||||
LayerUpdateQueue layerUpdateQueue;
|
||||
SkRect dirty = SkRect::MakeXYWH(0, 0, 1, 1);
|
||||
std::vector<sp<RenderNode>> renderNodes;
|
||||
renderNodes.push_back(whiteNode);
|
||||
bool opaque = true;
|
||||
android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1);
|
||||
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
|
||||
auto surface = SkSurface::MakeRasterN32Premul(1, 1);
|
||||
|
||||
// Initialize the canvas to blue.
|
||||
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
|
||||
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
|
||||
|
||||
// Single draw, should be white.
|
||||
pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
|
||||
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
|
||||
|
||||
// 1 Overdraw, should be blue blended onto white.
|
||||
renderNodes.push_back(whiteNode);
|
||||
pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
|
||||
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0d0ff);
|
||||
|
||||
// 2 Overdraw, should be green blended onto white
|
||||
renderNodes.push_back(whiteNode);
|
||||
pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
|
||||
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0ffd0);
|
||||
|
||||
// 3 Overdraw, should be pink blended onto white.
|
||||
renderNodes.push_back(whiteNode);
|
||||
pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
|
||||
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffffc0c0);
|
||||
|
||||
// 4 Overdraw, should be red blended onto white.
|
||||
renderNodes.push_back(whiteNode);
|
||||
pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
|
||||
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
|
||||
|
||||
// 5 Overdraw, should be red blended onto white.
|
||||
renderNodes.push_back(whiteNode);
|
||||
pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
|
||||
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user