changes to wasm debugger for UI integration

Bug: skia:
Change-Id: I8f00cbb6682c1fdf6c1bb5eb118a00f38b7005f1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/203730
Commit-Queue: Nathaniel Nifong <nifong@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
This commit is contained in:
Nathaniel Nifong 2019-03-28 13:08:51 -04:00 committed by Skia Commit-Bot
parent 3902628e35
commit de5df65812
6 changed files with 64 additions and 60 deletions

View File

@ -1,18 +1,17 @@
// Adds compile-time JS functions to handle creation and flushing of wasm's offscreen buffer
// to a visible element on the page.
(function(DebuggerView){
// Takes in an html id or a canvas element
DebuggerView.MakeSWCanvasSurface = function(idOrElement) {
let canvas = idOrElement;
if (canvas.tagName !== 'CANVAS') {
canvas = document.getElementById(idOrElement);
if (!canvas) {
throw 'Canvas with id ' + idOrElement + ' was not found';
}
}
// Takes a canvas element
DebuggerView.MakeSWCanvasSurface = function(canvas) {
// Set the canvas element to have a 2d non-gpu context. (constant until element is destroyed)
// We don't need the context in this scope, we just want the side effect.
canvas.getContext('2d', {
alpha: true,
depth: false
});
// Maybe better to use clientWidth/height. See:
// https://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html
let surface = DebuggerView.MakeSurface(canvas.width, canvas.height);
var surface = DebuggerView.MakeSurface(canvas.width, canvas.height);
if (surface) {
surface._canvas = canvas;
}
@ -26,25 +25,24 @@
}
DebuggerView.MakeSurface = function(width, height) {
/* @dict */
let imageInfo = {
var bufferLen = width * height * 4; // 4 bytes per pixel
// Allocate the buffer of pixels to be drawn into.
var pixelPtr = DebuggerView._malloc(bufferLen);
var imageInfo = {
'width': width,
'height': height,
// RGBA 8888 is the only pixel format we can show on an HTML canvas
'colorType': DebuggerView.ColorType.RGBA_8888,
// Since we are sending these pixels directly into the HTML canvas,
// We are sending these pixels directly into the HTML canvas,
// (and those pixels are un-premultiplied, i.e. straight r,g,b,a)
'alphaType': DebuggerView.AlphaType.Unpremul,
}
let pixelLen = width * height * 4; // it's 8888, so 4 bytes per pixel
// Allocate the buffer of pixels to be drawn into.
let pixelPtr = DebuggerView._malloc(pixelLen);
let surface = this._getRasterDirectSurface(imageInfo, pixelPtr, width*4);
var surface = this._getRasterDirectSurface(imageInfo, pixelPtr, width * 4);
if (surface) {
surface._canvas = null;
surface._width = width;
surface._height = height;
surface._pixelLen = pixelLen;
surface._bufferLen = bufferLen;
surface._pixelPtr = pixelPtr;
// rasterDirectSurface does not initialize the pixels, so we clear them
@ -62,8 +60,8 @@
// Do we have an HTML canvas to write the pixels to?
// We will not if this a GPU build or a raster surface, for example.
if (this._canvas) {
let pixels = new Uint8ClampedArray(DebuggerView.buffer, this._pixelPtr, this._pixelLen);
let imageData = new ImageData(pixels, this._width, this._height);
var pixels = new Uint8ClampedArray(DebuggerView.buffer, this._pixelPtr, this._bufferLen);
var imageData = new ImageData(pixels, this._width, this._height);
this._canvas.getContext('2d').putImageData(imageData, 0, 0);
}
};

View File

@ -42,7 +42,7 @@ DebuggerInit({
canvas.width = bounds.fRight - bounds.fLeft;
canvas.height = bounds.fBottom - bounds.fTop;
//Assume GPU selected initially
surface = Debugger.MakeWebGLCanvasSurface('debugger_view', canvas.width, canvas.height);
surface = Debugger.MakeWebGLCanvasSurface(canvas);
document.getElementById('command-count').innerHTML = player.getSize();
player.setClipVizColor(0);
@ -112,7 +112,7 @@ DebuggerInit({
.addEventListener('change', function(e) {
if (e.target.checked) {
replaceCanvas();
surface = Debugger.MakeWebGLCanvasSurface('debugger_view', canvas.width, canvas.height);
surface = Debugger.MakeWebGLCanvasSurface(document.getElementById('debugger_view'));
}
});
@ -120,7 +120,7 @@ DebuggerInit({
.addEventListener('change', function(e) {
if (e.target.checked) {
replaceCanvas();
surface = Debugger.MakeSWCanvasSurface('debugger_view');
surface = Debugger.MakeSWCanvasSurface(document.getElementById('debugger_view'));
}
});

View File

@ -81,9 +81,10 @@ class SkpDebugPlayer {
const SkIRect& getBounds() { return fBounds; }
void setOverdrawVis(bool on) { fDebugCanvas->setOverdrawViz(on); }
void setGpuOpBounds(bool on) { fDebugCanvas->setDrawGpuOpBounds(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(); }
@ -100,12 +101,30 @@ class SkpDebugPlayer {
// 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);
}
// Gets the clip and matrix of the last command drawn
std::string lastCommandInfo() {
SkMatrix vm = fDebugCanvas->getCurrentMatrix();
SkIRect clip = fDebugCanvas->getCurrentClip();
SkDynamicMemoryWStream stream;
SkJSONWriter writer(&stream, SkJSONWriter::Mode::kFast);
UrlDataManager udm(SkString("/"));
writer.beginObject(); // root
writer.appendName("ViewMatrix");
DrawCommand::MakeJsonMatrix(writer, vm);
writer.appendName("ClipRect");
DrawCommand::MakeJsonIRect(writer, clip);
writer.endObject(); // root
writer.flush();
@ -117,7 +136,6 @@ class SkpDebugPlayer {
}
private:
// admission of ignorance - don't know when to use unique pointer or sk_sp
std::unique_ptr<DebugCanvas> fDebugCanvas;
sk_sp<SkPicture> fPicture;
SkIRect fBounds;
@ -198,7 +216,9 @@ EMSCRIPTEN_BINDINGS(my_module) {
.function("getSize", &SkpDebugPlayer::getSize)
.function("deleteCommand", &SkpDebugPlayer::deleteCommand)
.function("setCommandVisibility", &SkpDebugPlayer::setCommandVisibility)
.function("jsonCommandList", &SkpDebugPlayer::jsonCommandList, allow_raw_pointers());
.function("setGpuOpBounds", &SkpDebugPlayer::setGpuOpBounds)
.function("jsonCommandList", &SkpDebugPlayer::jsonCommandList, allow_raw_pointers())
.function("lastCommandInfo", &SkpDebugPlayer::lastCommandInfo);
// Structs used as arguments or returns to the functions above
value_object<SkIRect>("SkIRect")
@ -211,7 +231,9 @@ EMSCRIPTEN_BINDINGS(my_module) {
enum_<SkColorType>("ColorType")
.value("RGBA_8888", SkColorType::kRGBA_8888_SkColorType);
enum_<SkAlphaType>("AlphaType")
.value("Unpremul", SkAlphaType::kUnpremul_SkAlphaType);
.value("Opaque", SkAlphaType::kOpaque_SkAlphaType)
.value("Premul", SkAlphaType::kPremul_SkAlphaType)
.value("Unpremul", SkAlphaType::kUnpremul_SkAlphaType);
value_object<SimpleImageInfo>("SkImageInfo")
.field("width", &SimpleImageInfo::width)
.field("height", &SimpleImageInfo::height)
@ -223,6 +245,7 @@ EMSCRIPTEN_BINDINGS(my_module) {
size_t rowBytes)->sk_sp<SkSurface> {
uint8_t* pixels = reinterpret_cast<uint8_t*>(pPtr);
SkImageInfo imageInfo = toSkImageInfo(ii);
SkDebugf("Made raster direct surface.\n");
return SkSurface::MakeRasterDirect(imageInfo, pixels, rowBytes, nullptr);
}), allow_raw_pointers());
class_<SkSurface>("SkSurface")

View File

@ -10,7 +10,8 @@
stencil: 0,
antialias: 1,
premultipliedAlpha: 1,
preserveDrawingBuffer: 0,
// for the zoom to be able to access the pixels. Incurs performance penalty
preserveDrawingBuffer: 1,
preferLowPowerToHighPerformance: 0,
failIfMajorPerformanceCaveat: 0,
majorVersion: 1,
@ -30,7 +31,7 @@
}
// GL is an enscripten provided helper
// See https://github.com/emscripten-core/emscripten/blob/incoming/src/library_webgl.js
let context = GL.createContext(canvas, contextAttributes);
var context = GL.createContext(canvas, contextAttributes);
if (!context) {
console.log('Could not get a WebGL context from the canvas element.');
}
@ -42,21 +43,8 @@
return makeWebGLContext(canvas, attrs);
};
// arg can be of types:
// - String - in which case it is interpreted as an id of a
// canvas element.
// - HTMLCanvasElement - in which the provided canvas element will
// be used directly.
// Width and height can be provided to override those on the canvas
// element, or specify a height for when a context is provided.
DebuggerView.MakeWebGLCanvasSurface = function(arg, width, height) {
var canvas = arg;
if (canvas.tagName !== 'CANVAS') {
canvas = document.getElementById(arg);
if (!canvas) {
throw 'Canvas with id ' + arg + ' was not found';
}
}
// canvas - a canvas element to use for this surface.
DebuggerView.MakeWebGLCanvasSurface = function(canvas) {
// we are ok with all the defaults
var ctx = DebuggerView.GetWebGLContext(canvas);
@ -64,10 +52,6 @@
throw 'failed to create webgl context: err ' + ctx;
}
if (!canvas && (!width || !height)) {
throw 'height and width must be provided with context';
}
var grcontext = this.MakeGrContext(ctx);
if (!grcontext) {
throw (
@ -77,9 +61,7 @@
// Maybe better to use clientWidth/height. See:
// https://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html
var surface = this.MakeOnScreenGLSurface(grcontext,
width || canvas.width,
height || canvas.height);
var surface = this.MakeOnScreenGLSurface(grcontext, canvas.width, canvas.height);
if (!surface) {
// Don't fall back silently in the debugger, the user explicitly controls which backend he
// wants via the UI. Calling function may catch this and show the user an error.

View File

@ -24,7 +24,7 @@ describe('Debugger\'s Startup Behavior', function() {
it('can load and draw a skp file', function(done) {
LoadDebugger.then(catchException(done, () => {
const surface = Debugger.MakeSWCanvasSurface('debugger_view');
const surface = Debugger.MakeSWCanvasSurface(document.getElementById('debugger_view'));
const player = new Debugger.SkpDebugPlayer();
fetch('/debugger/sample.skp').then(function(response) {
@ -51,6 +51,7 @@ describe('Debugger\'s Startup Behavior', function() {
surface.flush();
console.log('drew picture to canvas element');
surface.dispose();
done();
});
});

View File

@ -100,7 +100,7 @@ void DebugCanvas::drawTo(SkCanvas* originalCanvas, int index, int m) {
SkRect windowRect = SkRect::MakeWH(SkIntToScalar(originalCanvas->getBaseLayerSize().width()),
SkIntToScalar(originalCanvas->getBaseLayerSize().height()));
originalCanvas->clear(SK_ColorWHITE);
originalCanvas->clear(SK_ColorTRANSPARENT);
originalCanvas->resetMatrix();
if (!windowRect.isEmpty()) {
originalCanvas->clipRect(windowRect, kReplace_SkClipOp);