Modify skiaserve to support drawTo

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1651403003

Review URL: https://codereview.chromium.org/1651403003
This commit is contained in:
joshualitt 2016-02-02 11:07:39 -08:00 committed by Commit bot
parent bf907e628f
commit 136f517627
2 changed files with 107 additions and 46 deletions

View File

@ -12,12 +12,24 @@
{
'target_name': 'skiaserve',
'type': 'executable',
'sources': [
'<!@(python find.py ../tools/skiaserve "*.cpp")',
],
'include_dirs': [
'../src/core',
'../src/ports',
'../src/utils/debugger',
'../tools/json',
],
'sources': [
# Stuff for the debug canvas
'../src/utils/debugger/SkDrawCommand.h',
'../src/utils/debugger/SkDrawCommand.cpp',
'../src/utils/debugger/SkDebugCanvas.h',
'../src/utils/debugger/SkDebugCanvas.cpp',
'../src/utils/debugger/SkObjectParser.h',
'../src/utils/debugger/SkObjectParser.cpp',
'../src/utils/debugger/SkOverdrawMode.h',
'../src/utils/debugger/SkOverdrawMode.cpp',
'<!@(python find.py ../tools/skiaserve "*.cpp")',
],
'dependencies': [
'flags.gyp:flags',
'gputest.gyp:skgputest',

View File

@ -9,6 +9,7 @@
#include "GrContextFactory.h"
#include "SkCanvas.h"
#include "SkCommandLineFlags.h"
#include "SkDebugCanvas.h"
#include "SkJSONCanvas.h"
#include "SkPicture.h"
#include "SkStream.h"
@ -61,15 +62,12 @@ struct UploadContext {
struct Request {
Request() : fUploadContext(nullptr) {}
UploadContext* fUploadContext;
SkAutoTUnref<SkData> fPNG;
SkAutoTUnref<SkPicture> fPicture;
SkAutoTUnref<SkDebugCanvas> fDebugCanvas;
};
// TODO factor this out into functions, also handle CPU path
bool setupAndDrawToCanvas(Request* request, SkString* error) {
GrContextOptions grContextOpts;
SkAutoTDelete<GrContextFactory> factory(new GrContextFactory(grContextOpts));
SkSurface* setupSurface(GrContextFactory* factory) {
GrContext* context = factory->get(GrContextFactory::kNative_GLContextType,
GrContextFactory::kNone_GLContextOptions);
int maxRTSize = context->caps()->maxRenderTargetSize();
@ -78,41 +76,43 @@ bool setupAndDrawToCanvas(Request* request, SkString* error) {
kN32_SkColorType, kPremul_SkAlphaType);
uint32_t flags = 0;
SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(context,
SkSurface::kNo_Budgeted, info,
0, &props));
SkASSERT(surface.get());
SkSurface* surface = SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0,
&props);
SkASSERT(surface);
SkGLContext* gl = factory->getContextInfo(GrContextFactory::kNative_GLContextType,
GrContextFactory::kNone_GLContextOptions).fGLContext;
gl->makeCurrent();
return surface;
}
// draw
request->fPicture.reset(
SkPicture::CreateFromStream(request->fUploadContext->fStream.detachAsStream()));
if (!request->fPicture.get()) {
error->appendf("Could not create picture from stream.\n");
return false;
}
SkCanvas* canvas = surface->getCanvas();
canvas->drawPicture(request->fPicture);
SkData* writeCanvasToPng(SkCanvas* canvas) {
// capture pixels
SkBitmap bmp;
bmp.setInfo(canvas->imageInfo());
if (!canvas->readPixels(&bmp, 0, 0)) {
error->appendf("Can't read canvas pixels.\n");
return false;
fprintf(stderr, "Can't read pixels\n");
return nullptr;
}
// write to png
request->fPNG.reset(SkImageEncoder::EncodeData(bmp, SkImageEncoder::kPNG_Type, 100));
if (!request->fPNG) {
error->appendf("Can't encode a PNG.\n");
return false;
SkData* png = SkImageEncoder::EncodeData(bmp, SkImageEncoder::kPNG_Type, 100);
if (!png) {
fprintf(stderr, "Can't encode to png\n");
return nullptr;
}
return true;
return png;
}
SkData* setupAndDrawToCanvasReturnPng(SkDebugCanvas* debugCanvas, int n) {
GrContextOptions grContextOpts;
SkAutoTDelete<GrContextFactory> factory(new GrContextFactory(grContextOpts));
SkAutoTUnref<SkSurface> surface(setupSurface(factory.get()));
SkASSERT(debugCanvas);
SkCanvas* canvas = surface->getCanvas();
debugCanvas->drawTo(canvas, n);
return writeCanvasToPng(canvas);
}
static const size_t kBufferSize = 1024;
@ -140,10 +140,10 @@ static int SendData(MHD_Connection* connection, const SkData* data, const char*
return ret;
}
static int SendJSON(MHD_Connection* connection, SkPicture* picture) {
static int SendJSON(MHD_Connection* connection, SkDebugCanvas* debugCanvas, int n) {
SkDynamicMemoryWStream stream;
SkAutoTUnref<SkJSONCanvas> jsonCanvas(new SkJSONCanvas(kImageWidth, kImageHeight, stream));
jsonCanvas->drawPicture(picture);
debugCanvas->drawTo(jsonCanvas, n);
jsonCanvas->finish();
SkAutoTUnref<SkData> data(stream.copyToData());
@ -177,21 +177,50 @@ public:
virtual ~UrlHandler() {}
virtual bool canHandle(const char* method, const char* url) = 0;
virtual int handle(Request* request, MHD_Connection* connection,
const char* url, const char* method,
const char* upload_data, size_t* upload_data_size) = 0;
};
class InfoHandler : public UrlHandler {
public:
bool canHandle(const char* method, const char* url) override {
return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
0 == strcmp(url, "/cmd");
const char* kBasePath = "/cmd";
return 0 == strncmp(url, kBasePath, strlen(kBasePath));
}
int handle(Request* request, MHD_Connection* connection,
const char* url, const char* method,
const char* upload_data, size_t* upload_data_size) override {
if (request->fPicture.get()) {
return SendJSON(connection, request->fPicture);
SkTArray<SkString> commands;
SkStrSplit(url, "/", &commands);
if (!request->fPicture.get() || commands.count() > 3) {
return MHD_NO;
}
// /cmd or /cmd/N or /cmd/N/[0|1]
if (commands.count() == 1 && 0 == strcmp(method, MHD_HTTP_METHOD_GET)) {
int n = request->fDebugCanvas->getSize() - 1;
return SendJSON(connection, request->fDebugCanvas, n);
}
// /cmd/N, for now only delete supported
if (commands.count() == 2 && 0 == strcmp(method, MHD_HTTP_METHOD_DELETE)) {
int n;
sscanf(commands[1].c_str(), "%d", &n);
request->fDebugCanvas->deleteDrawCommandAt(n);
return MHD_YES;
}
// /cmd/N/[0|1]
if (commands.count() == 3 && 0 == strcmp(method, MHD_HTTP_METHOD_POST)) {
int n, toggle;
sscanf(commands[1].c_str(), "%d", &n);
sscanf(commands[2].c_str(), "%d", &toggle);
request->fDebugCanvas->toggleCommand(n, toggle);
return MHD_YES;
}
return MHD_NO;
}
};
@ -205,13 +234,25 @@ public:
}
int handle(Request* request, MHD_Connection* connection,
const char* url, const char* method,
const char* upload_data, size_t* upload_data_size) override {
if (request->fPNG.get()) {
SkData* data = request->fPNG.get();
return SendData(connection, data, "image/png");
SkTArray<SkString> commands;
SkStrSplit(url, "/", &commands);
if (!request->fPicture.get() || commands.count() > 2) {
return MHD_NO;
}
return MHD_NO;
int n;
// /img or /img/N
if (commands.count() == 1) {
n = request->fDebugCanvas->getSize() - 1;
} else {
sscanf(commands[1].c_str(), "%d", &n);
}
SkAutoTUnref<SkData> data(setupAndDrawToCanvasReturnPng(request->fDebugCanvas, n));
return SendData(connection, data, "image/png");
}
};
@ -223,6 +264,7 @@ public:
}
int handle(Request* request, MHD_Connection* connection,
const char* url, const char* method,
const char* upload_data, size_t* upload_data_size) override {
UploadContext* uc = request->fUploadContext;
@ -251,13 +293,18 @@ public:
MHD_destroy_post_processor(uc->fPostProcessor);
uc->fPostProcessor = nullptr;
// TODO response
SkString error;
if (!setupAndDrawToCanvas(request, &error)) {
// TODO send error
return MHD_YES;
// parse picture from stream
request->fPicture.reset(
SkPicture::CreateFromStream(request->fUploadContext->fStream.detachAsStream()));
if (!request->fPicture.get()) {
fprintf(stderr, "Could not create picture from stream.\n");
return MHD_NO;
}
// pour picture into debug canvas
request->fDebugCanvas.reset(new SkDebugCanvas(kImageWidth, kImageHeight));
request->fDebugCanvas->drawPicture(request->fPicture);
// clear upload context
delete request->fUploadContext;
request->fUploadContext = nullptr;
@ -274,6 +321,7 @@ public:
}
int handle(Request* request, MHD_Connection* connection,
const char* url, const char* method,
const char* upload_data, size_t* upload_data_size) override {
return SendTemplate(connection);
}
@ -298,7 +346,8 @@ public:
const char* upload_data, size_t* upload_data_size) const {
for (int i = 0; i < fHandlers.count(); i++) {
if (fHandlers[i]->canHandle(method, url)) {
return fHandlers[i]->handle(request, connection, upload_data, upload_data_size);
return fHandlers[i]->handle(request, connection, url, method, upload_data,
upload_data_size);
}
}
return MHD_NO;