Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 20b177a

Browse files
Nathaniel NifongSkia Commit-Bot
authored andcommitted
Parse android layer annotations in debugger, play back layers
Bug: skia:9626 Change-Id: I3ae8fa83520690f9af534e9ab0b70834d7890fb0 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/256100 Commit-Queue: Nathaniel Nifong <nifong@google.com> Reviewed-by: Kevin Lubick <kjlubick@google.com>
1 parent ed58654 commit 20b177a

File tree

11 files changed

+618
-48
lines changed

11 files changed

+618
-48
lines changed

BUILD.gn

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,7 @@ if (target_cpu == "wasm") {
10341034
"tools/SkSharingProc.cpp",
10351035
"tools/UrlDataManager.cpp",
10361036
"tools/debugger/DebugCanvas.cpp",
1037+
"tools/debugger/DebugLayerManager.cpp",
10371038
"tools/debugger/DrawCommand.cpp",
10381039
"tools/debugger/JsonWriteBuffer.cpp",
10391040
]
@@ -1455,6 +1456,7 @@ if (skia_enable_tools) {
14551456
"tools/ToolUtils.cpp",
14561457
"tools/UrlDataManager.cpp",
14571458
"tools/debugger/DebugCanvas.cpp",
1459+
"tools/debugger/DebugLayerManager.cpp",
14581460
"tools/debugger/DrawCommand.cpp",
14591461
"tools/debugger/JsonWriteBuffer.cpp",
14601462
"tools/fonts/RandomScalerContext.cpp",
@@ -1998,6 +2000,7 @@ if (skia_enable_tools) {
19982000
"fuzz/oss_fuzz/FuzzTextBlobDeserialize.cpp",
19992001
"tools/UrlDataManager.cpp",
20002002
"tools/debugger/DebugCanvas.cpp",
2003+
"tools/debugger/DebugLayerManager.cpp",
20012004
"tools/debugger/DrawCommand.cpp",
20022005
"tools/debugger/JsonWriteBuffer.cpp",
20032006
]
@@ -2416,6 +2419,7 @@ if (skia_enable_tools) {
24162419
sources = [
24172420
"tools/UrlDataManager.cpp",
24182421
"tools/debugger/DebugCanvas.cpp",
2422+
"tools/debugger/DebugLayerManager.cpp",
24192423
"tools/debugger/DrawCommand.cpp",
24202424
"tools/debugger/JsonWriteBuffer.cpp",
24212425
"tools/mdbviz/MainWindow.cpp",

experimental/wasm-skp-debugger/debugger_bindings.cpp

Lines changed: 77 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@
1313
#include "tools/SkSharingProc.h"
1414
#include "tools/UrlDataManager.h"
1515
#include "tools/debugger/DebugCanvas.h"
16+
#include "tools/debugger/DebugLayerManager.h"
1617

18+
#include <memory>
19+
#include <string>
20+
#include <string_view>
21+
#include <vector>
1722
#include <emscripten.h>
1823
#include <emscripten/bind.h>
1924

@@ -98,10 +103,20 @@ class SkpDebugPlayer {
98103
SkDebugf("Constrained command index (%d) within this frame's length (%d)\n", index, cmdlen);
99104
index = cmdlen-1;
100105
}
106+
auto* canvas = surface->getCanvas();
107+
canvas->clear(SK_ColorTRANSPARENT);
101108
frames[fp]->drawTo(surface->getCanvas(), index);
102109
surface->getCanvas()->flush();
103110
}
104111

112+
// Draws to the end of the current frame.
113+
void draw(SkSurface* surface) {
114+
auto* canvas = surface->getCanvas();
115+
canvas->clear(SK_ColorTRANSPARENT);
116+
frames[fp]->draw(surface->getCanvas());
117+
surface->getCanvas()->flush();
118+
}
119+
105120
const SkIRect& getBounds() { return fBounds; }
106121

107122
// The following three operations apply to every frame because they are overdraw features.
@@ -201,6 +216,11 @@ class SkpDebugPlayer {
201216
return toSimpleImageInfo(fImages[index]->imageInfo(), fImages[index].get());
202217
}
203218

219+
// return a list of layer draw events that happened at the beginning of this frame.
220+
std::vector<DebugLayerManager::DrawEventSummary> getLayerDrawEvents() {
221+
return fLayerManager->summarizeEvents(fp);
222+
}
223+
204224
private:
205225

206226
// Loads a single frame (traditional) skp file from the provided data stream and returns
@@ -215,54 +235,57 @@ class SkpDebugPlayer {
215235
SkDebugf("Parsed SKP file.\n");
216236
// Make debug canvas using bounds from SkPicture
217237
fBounds = picture->cullRect().roundOut();
218-
std::unique_ptr<DebugCanvas> debugDanvas = std::make_unique<DebugCanvas>(fBounds);
219-
SkDebugf("DebugCanvas created.\n");
238+
std::unique_ptr<DebugCanvas> debugCanvas = std::make_unique<DebugCanvas>(fBounds);
220239

221240
// Only draw picture to the debug canvas once.
222-
debugDanvas->drawPicture(picture);
223-
SkDebugf("Added picture with %d commands.\n", debugDanvas->getSize());
224-
return debugDanvas;
241+
debugCanvas->drawPicture(picture);
242+
return debugCanvas;
225243
}
226244

227245
void loadMultiFrame(SkMemoryStream* stream) {
246+
// Attempt to deserialize with an image sharing serial proc.
247+
auto deserialContext = std::make_unique<SkSharingDeserialContext>();
248+
SkDeserialProcs procs;
249+
procs.fImageProc = SkSharingDeserialContext::deserializeImage;
250+
procs.fImageCtx = deserialContext.get();
251+
252+
int page_count = SkMultiPictureDocumentReadPageCount(stream);
253+
if (!page_count) {
254+
SkDebugf("Not a MultiPictureDocument");
255+
return;
256+
}
257+
SkDebugf("Expecting %d frames\n", page_count);
228258

229-
// Attempt to deserialize with an image sharing serial proc.
230-
auto deserialContext = std::make_unique<SkSharingDeserialContext>();
231-
SkDeserialProcs procs;
232-
procs.fImageProc = SkSharingDeserialContext::deserializeImage;
233-
procs.fImageCtx = deserialContext.get();
259+
std::vector<SkDocumentPage> pages(page_count);
260+
if (!SkMultiPictureDocumentRead(stream, pages.data(), page_count, &procs)) {
261+
SkDebugf("Reading frames from MultiPictureDocument failed");
262+
return;
263+
}
234264

235-
int page_count = SkMultiPictureDocumentReadPageCount(stream);
236-
if (!page_count) {
237-
SkDebugf("Not a MultiPictureDocument");
238-
return;
239-
}
240-
SkDebugf("Expecting %d frames\n", page_count);
265+
fLayerManager = std::make_unique<DebugLayerManager>();
241266

242-
std::vector<SkDocumentPage> pages(page_count);
243-
if (!SkMultiPictureDocumentRead(stream, pages.data(), page_count, &procs)) {
244-
SkDebugf("Reading frames from MultiPictureDocument failed");
245-
return;
246-
}
267+
int i = 0;
268+
for (const auto& page : pages) {
269+
i++;
270+
// Make debug canvas using bounds from SkPicture
271+
fBounds = page.fPicture->cullRect().roundOut();
272+
std::unique_ptr<DebugCanvas> debugCanvas = std::make_unique<DebugCanvas>(fBounds);
273+
debugCanvas->setLayerManagerAndFrame(fLayerManager.get(), i);
247274

248-
for (const auto& page : pages) {
249-
// Make debug canvas using bounds from SkPicture
250-
fBounds = page.fPicture->cullRect().roundOut();
251-
std::unique_ptr<DebugCanvas> debugDanvas = std::make_unique<DebugCanvas>(fBounds);
252-
// Only draw picture to the debug canvas once.
253-
debugDanvas->drawPicture(page.fPicture);
254-
SkDebugf("Added picture with %d commands.\n", debugDanvas->getSize());
255-
256-
if (debugDanvas->getSize() <=0 ){
257-
SkDebugf("Skipped corrupted frame, had %d commands \n", debugDanvas->getSize());
258-
continue;
259-
}
260-
debugDanvas->setOverdrawViz(false);
261-
debugDanvas->setDrawGpuOpBounds(false);
262-
debugDanvas->setClipVizColor(SK_ColorTRANSPARENT);
263-
frames.push_back(std::move(debugDanvas));
275+
// Only draw picture to the debug canvas once.
276+
debugCanvas->drawPicture(page.fPicture);
277+
278+
if (debugCanvas->getSize() <=0 ){
279+
SkDebugf("Skipped corrupted frame, had %d commands \n", debugCanvas->getSize());
280+
continue;
264281
}
265-
fImages = deserialContext->fImages;
282+
// If you don't set these, they're undefined.
283+
debugCanvas->setOverdrawViz(false);
284+
debugCanvas->setDrawGpuOpBounds(false);
285+
debugCanvas->setClipVizColor(SK_ColorTRANSPARENT);
286+
frames.push_back(std::move(debugCanvas));
287+
}
288+
fImages = deserialContext->fImages;
266289
}
267290

268291
// A vector of DebugCanvas, each one initialized to a frame of the animation.
@@ -285,6 +308,10 @@ class SkpDebugPlayer {
285308
// find anything. TODO(nifong): Unify these two numbering schemes in CollatingCanvas.
286309
UrlDataManager udm;
287310

311+
// A structure holding the picture information needed to draw any layers used in an mskp file
312+
// individual frames hold a pointer to it, store draw events, and request images from it.
313+
// it is stateful and is set to the current frame at all times.
314+
std::unique_ptr<DebugLayerManager> fLayerManager;
288315
};
289316

290317
#if SK_SUPPORT_GPU
@@ -356,6 +383,7 @@ EMSCRIPTEN_BINDINGS(my_module) {
356383
.constructor<>()
357384
.function("loadSkp", &SkpDebugPlayer::loadSkp, allow_raw_pointers())
358385
.function("drawTo", &SkpDebugPlayer::drawTo, allow_raw_pointers())
386+
.function("draw", &SkpDebugPlayer::draw, allow_raw_pointers())
359387
.function("getBounds", &SkpDebugPlayer::getBounds)
360388
.function("setOverdrawVis", &SkpDebugPlayer::setOverdrawVis)
361389
.function("setClipVizColor", &SkpDebugPlayer::setClipVizColor)
@@ -369,14 +397,24 @@ EMSCRIPTEN_BINDINGS(my_module) {
369397
.function("getFrameCount", &SkpDebugPlayer::getFrameCount)
370398
.function("getImageResource", &SkpDebugPlayer::getImageResource)
371399
.function("getImageCount", &SkpDebugPlayer::getImageCount)
372-
.function("getImageInfo", &SkpDebugPlayer::getImageInfo);
400+
.function("getImageInfo", &SkpDebugPlayer::getImageInfo)
401+
.function("getLayerDrawEvents", &SkpDebugPlayer::getLayerDrawEvents);
373402

374403
// Structs used as arguments or returns to the functions above
375404
value_object<SkIRect>("SkIRect")
376405
.field("fLeft", &SkIRect::fLeft)
377406
.field("fTop", &SkIRect::fTop)
378407
.field("fRight", &SkIRect::fRight)
379408
.field("fBottom", &SkIRect::fBottom);
409+
// emscripten provided the following convenience function for binding vector<T>
410+
// https://emscripten.org/docs/api_reference/bind.h.html#_CPPv415register_vectorPKc
411+
register_vector<DebugLayerManager::DrawEventSummary>("VectorDrawEventSummary");
412+
value_object<DebugLayerManager::DrawEventSummary>("DebugLayerManager::DrawEventSummary")
413+
.field("nodeId", &DebugLayerManager::DrawEventSummary::nodeId)
414+
.field("fullRedraw", &DebugLayerManager::DrawEventSummary::fullRedraw)
415+
.field("commandCount", &DebugLayerManager::DrawEventSummary::commandCount)
416+
.field("layerWidth", &DebugLayerManager::DrawEventSummary::layerWidth)
417+
.field("layerHeight", &DebugLayerManager::DrawEventSummary::layerHeight);
380418

381419
// Symbols needed by cpu.js to perform surface creation and flushing.
382420
enum_<SkColorType>("ColorType")

gn/tests.gni

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ tests_sources = [
5050
"$_tests/ColorTest.cpp",
5151
"$_tests/CopySurfaceTest.cpp",
5252
"$_tests/CubicMapTest.cpp",
53+
"$_tests/DebugLayerManagerTest.cpp",
5354
"$_tests/DashPathEffectTest.cpp",
5455
"$_tests/DataRefTest.cpp",
5556
"$_tests/DefaultPathRendererTest.cpp",

tests/DebugLayerManagerTest.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright 2019 Google Inc.
3+
*
4+
* Use of this source code is governed by a BSD-style license that can be
5+
* found in the LICENSE file.
6+
*/
7+
8+
#include "include/core/SkPaint.h"
9+
#include "include/core/SkPicture.h"
10+
#include "include/core/SkPictureRecorder.h"
11+
#include "include/core/SkRect.h"
12+
#include "tests/Test.h"
13+
#include "tools/debugger/DebugLayerManager.h"
14+
15+
// Adds one full update, one partial update, and requests one image a few frames later.
16+
static void test_basic(skiatest::Reporter* reporter) {
17+
// prepare supporting objects
18+
int layerWidth = 100;
19+
int layerHeight = 100;
20+
21+
// make a picture that fully updates the layer
22+
SkPictureRecorder rec;
23+
SkCanvas* canvas = rec.beginRecording(layerWidth, layerHeight);
24+
canvas->clear(0x00000000);
25+
SkPaint paint;
26+
paint.setColor(SK_ColorBLUE);
27+
canvas->drawOval(SkRect::MakeLTRB(1,1,99,99), paint);
28+
canvas->flush();
29+
auto picture1 = rec.finishRecordingAsPicture();
30+
SkIRect dirtyRectFull = SkIRect::MakeLTRB(0, 0, layerWidth, layerHeight);
31+
32+
// make a second picture that acts as a partial update.
33+
SkPictureRecorder rec2;
34+
canvas = rec2.beginRecording(layerWidth, layerHeight);
35+
paint.setColor(SK_ColorGREEN);
36+
canvas->drawOval(SkRect::MakeLTRB(40,40,60,60), paint);
37+
canvas->flush();
38+
auto picture2 = rec2.finishRecordingAsPicture();
39+
SkIRect dirtyRectPartial = SkIRect::MakeLTRB(40,40,60,60);
40+
41+
int node = 2;
42+
43+
// create and exercise DebugLayerManager
44+
DebugLayerManager dlm;
45+
dlm.storeSkPicture(node, 0, picture1, dirtyRectFull);
46+
dlm.storeSkPicture(node, 10, picture2, dirtyRectPartial);
47+
auto frames = dlm.listFramesForNode(node);
48+
49+
// Confirm the layer manager stored these at the right places.
50+
REPORTER_ASSERT(reporter, frames.size() == 2);
51+
REPORTER_ASSERT(reporter, frames[0] == 0);
52+
REPORTER_ASSERT(reporter, frames[1] == 10);
53+
54+
SkPixmap pixmap;
55+
// request an image of the layer between the two updates.
56+
for (int i=0; i<10; i++) {
57+
auto image = dlm.getLayerAsImage(node, i);
58+
REPORTER_ASSERT(reporter, image->width() == layerWidth);
59+
REPORTER_ASSERT(reporter, image->height() == layerHeight);
60+
// confirm center is blue, proving only first pic was drawn.
61+
image->peekPixels(&pixmap);
62+
SkColor paintColor = pixmap.getColor(50, 50);
63+
REPORTER_ASSERT(reporter, paintColor == SK_ColorBLUE);
64+
}
65+
66+
// For any images after the second draw, confirm the center is green, but the area just outside
67+
// that smaller circle is still blue, proving dlm drew both pictures.
68+
for (int i=10; i<12; i++) {
69+
auto image = dlm.getLayerAsImage(node, i);
70+
REPORTER_ASSERT(reporter, image->width() == layerWidth);
71+
REPORTER_ASSERT(reporter, image->height() == layerHeight);
72+
image->peekPixels(&pixmap);
73+
auto innerColor = pixmap.getColor(50, 50);
74+
REPORTER_ASSERT(reporter, innerColor == SK_ColorGREEN);
75+
auto outerColor = pixmap.getColor(10, 50);
76+
REPORTER_ASSERT(reporter, outerColor == SK_ColorBLUE);
77+
}
78+
79+
80+
}
81+
82+
DEF_TEST(DebugLayerManagerTest, reporter) {
83+
test_basic(reporter);
84+
}

0 commit comments

Comments
 (0)