fill out more of SkDebugCanvas interface
Added methods for toggling clip viz, overdraw viz, gpu bound viz.
methods for getting number of commands, toggling command visibility and deleting commands.
Added method for writing out json command list.
bound methods with emscrpiten and connected up to buttons in barebones interface to prove they're working.
Bug: skia:
Change-Id: I3f733b13db00ce5d14b1b5170de8fb66102c8b14
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/199938
Commit-Queue: Nathaniel Nifong <nifong@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
diff --git a/experimental/wasm-skp-debugger/compile.sh b/experimental/wasm-skp-debugger/compile.sh
index b095422..ed9cdf1 100755
--- a/experimental/wasm-skp-debugger/compile.sh
+++ b/experimental/wasm-skp-debugger/compile.sh
@@ -110,7 +110,7 @@
-Itools/debugger \
-DSK_DISABLE_AAA \
-DSK_DISABLE_DAA \
- -std=c++14 \
+ -std=c++17 \
--pre-js $BASE_DIR/cpu.js \
--post-js $BASE_DIR/ready.js \
--bind \
diff --git a/experimental/wasm-skp-debugger/debugger/index.html b/experimental/wasm-skp-debugger/debugger/index.html
index 1abfb11..469716c 100644
--- a/experimental/wasm-skp-debugger/debugger/index.html
+++ b/experimental/wasm-skp-debugger/debugger/index.html
@@ -10,7 +10,7 @@
DebuggerInit({
locateFile: (file) => '/node_modules/debugger/bin/'+file,
}).ready().then((Debugger) => {
- const surface = Debugger.MakeSWCanvasSurface('debugger_view');
+ let surface;
const player = new Debugger.SkpDebugPlayer();
// Define an event handler for the file input dialog
@@ -35,38 +35,85 @@
fileMem.set(fileContents);
// Hand off pointer to wasm
player.loadSkp(fileMemPtr, size);
+ // From the loaded commands, Debugger now knows the bounds.
+ let bounds = player.getBounds();
+ // Resize our canvas to match
+ canvas = document.getElementById('debugger_view');
+ canvas.width = bounds.fRight - bounds.fLeft;
+ canvas.height = bounds.fBottom - bounds.fTop;
+ surface = Debugger.MakeSWCanvasSurface('debugger_view');
+
+ document.getElementById('command-count').innerHTML = player.getSize();
+ player.setClipVizColor(0);
};
reader.readAsArrayBuffer(file);
}
function playFile() {
- interval = Number(document.getElementById('interval').value)
- var intervalID = setInterval(function(){
+ interval = parseFloat(document.getElementById('interval').value);
+ var intervalID = setInterval(function() {
if (index < 789){
player.drawTo(surface, index);
surface.flush();
index++;
- console.log("index = "+index);
}
}, interval);
}
document.getElementById('file-input')
- .addEventListener('change', readSkpFile, false);
+ .addEventListener('change', readSkpFile);
- document.getElementById('playbutton')
- .addEventListener('click', playFile, false);
+ document.getElementById('play_button')
+ .addEventListener('click', playFile);
+
+ document.getElementById('overdraw')
+ .addEventListener('change', function(e) {
+ player.setOverdrawVis(e.target.checked);
+ });
+
+ document.getElementById('gpu_op_bounds')
+ .addEventListener('change', function(e) {
+ player.setGpuOpBounds(e.target.checked);
+ });
+
+ document.getElementById('clip_viz_color')
+ .addEventListener('change', function(e) {
+ // Remove the '#' from the hex color string.
+ // prepend an alpha value (0x50 or about 30%)
+ // then convert to an integer.
+ colorInt = parseInt("50"+e.target.value.substring(1),16);
+ player.setClipVizColor(colorInt);
+ });
+
+ document.getElementById('disable_clip_viz')
+ .addEventListener('click', function(e) {
+ // Setting the clip viz to transparent black makes it invisible.
+ player.setClipVizColor(0);
+ });
+
+ document.getElementById('get_json_command_list')
+ .addEventListener('click', function(e) {
+ result = player.jsonCommandList(surface);
+ console.log('getjsoncommandlist result '+result.substring(0,100)+'...');
+ commands = JSON.parse(result);
+ console.log('parsed json');
+ });
});
</script>
</head>
<body>
- <canvas id=debugger_view width=720 height=1280></canvas>
+ <canvas id=debugger_view width=400 height=400></canvas>
<div style="float:right">
- <input type="file" id="file-input" /><br>
- <input type="button" id="playbutton" value="Play" />
+ <input type="file" id="file-input" /> | <span id="command-count">0</span> commands<br>
+ <input type="button" id="play_button" value="Play" />
command interval in ms
- <input type="text" id="interval" value="20" />
+ <input type="text" id="interval" value="20" /><br>
+ <input type="checkbox" id="overdraw" /> Overdraw vis<br>
+ <input type="checkbox" id="gpu_op_bounds" /> GPU Op bounds<br>
+ <input type="color" id="clip_viz_color" />Clip visualization color
+ <input type="button" id="disable_clip_viz" value="Disable" /><br>
+ <input type="button" id="get_json_command_list" value="Get JSON Command List" /><br>
<div>
<div style="float:clear"></div>
</body>
diff --git a/experimental/wasm-skp-debugger/debugger_bindings.cpp b/experimental/wasm-skp-debugger/debugger_bindings.cpp
index fc44c4a..339bbe2 100644
--- a/experimental/wasm-skp-debugger/debugger_bindings.cpp
+++ b/experimental/wasm-skp-debugger/debugger_bindings.cpp
@@ -6,8 +6,11 @@
*/
#include "SkDebugCanvas.h"
+#include "SkJSONWriter.h"
#include "SkPicture.h"
#include "SkSurface.h"
+#include "UrlDataManager.h"
+
#include <emscripten.h>
#include <emscripten/bind.h>
@@ -28,7 +31,6 @@
public:
SkpDebugPlayer() {}
-
/* loadSkp deserializes a skp file that has been copied into the shared WASM memory.
* cptr - a pointer to the data to deserialize.
* length - length of the data in bytes.
@@ -41,9 +43,6 @@
*/
void loadSkp(uintptr_t cptr, int length) {
const auto* data = reinterpret_cast<const uint8_t*>(cptr);
- // todo: pass in bounds
- fDebugCanvas.reset(new SkDebugCanvas(720, 1280));
- SkDebugf("SkDebugCanvas created.\n");
// note overloaded = operator that actually does a move
fPicture = SkPicture::MakeFromData(data, length);
if (!fPicture) {
@@ -51,6 +50,11 @@
return;
}
SkDebugf("Parsed SKP file.\n");
+ // Make debug canvas using bounds from SkPicture
+ fBounds = fPicture->cullRect().roundOut();
+ fDebugCanvas.reset(new SkDebugCanvas(fBounds));
+ SkDebugf("SkDebugCanvas created.\n");
+
// Only draw picture to the debug canvas once.
fDebugCanvas->drawPicture(fPicture);
SkDebugf("Added picture with %d commands.\n", fDebugCanvas->getSize());
@@ -64,10 +68,49 @@
surface->getCanvas()->flush();
}
+ const SkIRect& getBounds() { return fBounds; }
+
+ void setOverdrawVis(bool on) { fDebugCanvas->setOverdrawViz(on); }
+ void setGpuOpBounds(bool on) { fDebugCanvas->setDrawGpuOpBounds(on); }
+ void setClipVizColor(JSColor color) {
+ SkDebugf("Setting clip vis color to %d\n", color);
+ fDebugCanvas->setClipVizColor(SkColor(color));
+ }
+ int getSize() const { return fDebugCanvas->getSize(); }
+ void deleteCommand(int index) { fDebugCanvas->deleteDrawCommandAt(index); }
+ void setCommandVisibility(int index, bool visible) {
+ fDebugCanvas->toggleCommand(index, visible);
+ }
+
+ // Return the command list in JSON representation as a string
+ std::string jsonCommandList(sk_sp<SkSurface> surface) {
+ SkDynamicMemoryWStream stream;
+ SkJSONWriter writer(&stream, SkJSONWriter::Mode::kFast);
+ // Note that the root url provided here may need to change in the production deployment.
+ // this will be prepended to any links that are created in the json command list.
+ UrlDataManager udm(SkString("/"));
+ writer.beginObject(); // root
+
+ // Some vals currently hardcoded until gpu is supported
+ writer.appendString("mode", "cpu");
+ writer.appendBool("drawGpuOpBounds", fDebugCanvas->getDrawGpuOpBounds());
+ writer.appendS32("colorMode", SkColorType::kRGBA_8888_SkColorType);
+ fDebugCanvas->toJSON(writer, udm, getSize(), surface->getCanvas());
+
+ writer.endObject(); // root
+ writer.flush();
+ auto skdata = stream.detachAsData();
+ // Convert skdata to string_view, which accepts a length
+ std::string_view data_view(reinterpret_cast<const char*>(skdata->data()), skdata->size());
+ // and string_view to string, which emscripten understands.
+ return std::string(data_view);
+ }
+
private:
// admission of ignorance - don't know when to use unique pointer or sk_sp
std::unique_ptr<SkDebugCanvas> fDebugCanvas;
sk_sp<SkPicture> fPicture;
+ SkIRect fBounds;
};
using namespace emscripten;
@@ -76,8 +119,22 @@
// The main class that the JavaScript in index.html uses
class_<SkpDebugPlayer>("SkpDebugPlayer")
.constructor<>()
- .function("loadSkp", &SkpDebugPlayer::loadSkp, allow_raw_pointers())
- .function("drawTo", &SkpDebugPlayer::drawTo, allow_raw_pointers());
+ .function("loadSkp", &SkpDebugPlayer::loadSkp, allow_raw_pointers())
+ .function("drawTo", &SkpDebugPlayer::drawTo, allow_raw_pointers())
+ .function("getBounds", &SkpDebugPlayer::getBounds)
+ .function("setOverdrawVis", &SkpDebugPlayer::setOverdrawVis)
+ .function("setClipVizColor", &SkpDebugPlayer::setClipVizColor)
+ .function("getSize", &SkpDebugPlayer::getSize)
+ .function("deleteCommand", &SkpDebugPlayer::deleteCommand)
+ .function("setCommandVisibility", &SkpDebugPlayer::setCommandVisibility)
+ .function("jsonCommandList", &SkpDebugPlayer::jsonCommandList, allow_raw_pointers());
+
+ // Structs used as arguments or returns to the functions above
+ value_object<SkIRect>("SkIRect")
+ .field("fLeft", &SkIRect::fLeft)
+ .field("fTop", &SkIRect::fTop)
+ .field("fRight", &SkIRect::fRight)
+ .field("fBottom", &SkIRect::fBottom);
// Symbols needed by cpu.js to perform surface creation and flushing.
enum_<SkColorType>("ColorType")
diff --git a/tools/debugger/SkDebugCanvas.cpp b/tools/debugger/SkDebugCanvas.cpp
index 96c0de2..45eaf96 100644
--- a/tools/debugger/SkDebugCanvas.cpp
+++ b/tools/debugger/SkDebugCanvas.cpp
@@ -81,6 +81,10 @@
this->INHERITED::onClipRect(large, kReplace_SkClipOp, kHard_ClipEdgeStyle);
}
+SkDebugCanvas::SkDebugCanvas(SkIRect bounds) {
+ SkDebugCanvas(bounds.width(), bounds.height());
+}
+
SkDebugCanvas::~SkDebugCanvas() {
fCommandVector.deleteAll();
}
diff --git a/tools/debugger/SkDebugCanvas.h b/tools/debugger/SkDebugCanvas.h
index 194ce11..9ae2950 100644
--- a/tools/debugger/SkDebugCanvas.h
+++ b/tools/debugger/SkDebugCanvas.h
@@ -27,6 +27,8 @@
public:
SkDebugCanvas(int width, int height);
+ SkDebugCanvas(SkIRect bounds);
+
~SkDebugCanvas() override;
/**