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:
parent
3902628e35
commit
de5df65812
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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'));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user