Adding support for playback to L32/S32/F16 canvas.

Playback of my test GM works correctly on both raster and GPU, in all three modes.

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

Review URL: https://codereview.chromium.org/1893393002
This commit is contained in:
brianosman 2016-04-19 10:16:53 -07:00 committed by Commit bot
parent 1bf3e71ad0
commit 7831295c63
6 changed files with 111 additions and 17 deletions

View File

@ -40,6 +40,7 @@
'microhttpd.gyp:microhttpd', 'microhttpd.gyp:microhttpd',
'skia_lib.gyp:skia_lib', 'skia_lib.gyp:skia_lib',
'tools.gyp:crash_handler', 'tools.gyp:crash_handler',
'tools.gyp:picture_utils',
'tools.gyp:proc_stats', 'tools.gyp:proc_stats',
'tools.gyp:resources', 'tools.gyp:resources',
'tools.gyp:url_data_manager', 'tools.gyp:url_data_manager',

View File

@ -9,6 +9,7 @@
#include "SkPictureRecorder.h" #include "SkPictureRecorder.h"
#include "SkPixelSerializer.h" #include "SkPixelSerializer.h"
#include "picture_utils.h"
using namespace sk_gpu_test; using namespace sk_gpu_test;
@ -19,7 +20,8 @@ static int kDefaultHeight = 1080;
Request::Request(SkString rootUrl) Request::Request(SkString rootUrl)
: fUploadContext(nullptr) : fUploadContext(nullptr)
, fUrlDataManager(rootUrl) , fUrlDataManager(rootUrl)
, fGPUEnabled(false) { , fGPUEnabled(false)
, fColorMode(0) {
// create surface // create surface
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
GrContextOptions grContextOpts; GrContextOptions grContextOpts;
@ -39,10 +41,7 @@ Request::~Request() {
SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) { SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
SkBitmap* bmp = new SkBitmap(); SkBitmap* bmp = new SkBitmap();
SkIRect bounds = this->getBounds(); bmp->setInfo(canvas->imageInfo());
SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(),
kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
bmp->setInfo(info);
if (!canvas->readPixels(bmp, 0, 0)) { if (!canvas->readPixels(bmp, 0, 0)) {
fprintf(stderr, "Can't read pixels\n"); fprintf(stderr, "Can't read pixels\n");
return nullptr; return nullptr;
@ -55,9 +54,14 @@ SkData* Request::writeCanvasToPng(SkCanvas* canvas) {
SkAutoTDelete<SkBitmap> bmp(this->getBitmapFromCanvas(canvas)); SkAutoTDelete<SkBitmap> bmp(this->getBitmapFromCanvas(canvas));
SkASSERT(bmp); SkASSERT(bmp);
// Convert to format suitable for PNG output
sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bmp);
SkASSERT(encodedBitmap.get());
// write to png // write to png
SkDynamicMemoryWStream buffer; SkDynamicMemoryWStream buffer;
SkDrawCommand::WritePNG((const png_bytep) bmp->getPixels(), bmp->width(), bmp->height(), SkDrawCommand::WritePNG((const png_bytep) encodedBitmap->writable_data(),
bmp->width(), bmp->height(),
buffer); buffer);
return buffer.copyToData(); return buffer.copyToData();
} }
@ -138,25 +142,50 @@ SkIRect Request::getBounds() {
return bounds; return bounds;
} }
namespace {
struct ColorAndProfile {
SkColorType fColorType;
SkColorProfileType fProfileType;
bool fGammaCorrect;
};
ColorAndProfile ColorModes[] = {
{ kN32_SkColorType, kLinear_SkColorProfileType, false },
{ kN32_SkColorType, kSRGB_SkColorProfileType, true },
{ kRGBA_F16_SkColorType, kLinear_SkColorProfileType, true },
};
}
SkSurface* Request::createCPUSurface() { SkSurface* Request::createCPUSurface() {
SkIRect bounds = this->getBounds(); SkIRect bounds = this->getBounds();
SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), kN32_SkColorType, ColorAndProfile cap = ColorModes[fColorMode];
kPremul_SkAlphaType); SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
return SkSurface::MakeRaster(info).release(); kPremul_SkAlphaType, cap.fProfileType);
uint32_t flags = cap.fGammaCorrect ? SkSurfaceProps::kGammaCorrect_Flag : 0;
SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
return SkSurface::MakeRaster(info, &props).release();
} }
SkSurface* Request::createGPUSurface() { SkSurface* Request::createGPUSurface() {
GrContext* context = this->getContext(); GrContext* context = this->getContext();
SkIRect bounds = this->getBounds(); SkIRect bounds = this->getBounds();
SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), ColorAndProfile cap = ColorModes[fColorMode];
kN32_SkColorType, kPremul_SkAlphaType); SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
uint32_t flags = 0; kPremul_SkAlphaType, cap.fProfileType);
uint32_t flags = cap.fGammaCorrect ? SkSurfaceProps::kGammaCorrect_Flag : 0;
SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType); SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0,
&props).release(); &props).release();
return surface; return surface;
} }
bool Request::setColorMode(int mode) {
fColorMode = mode;
return enableGPU(fGPUEnabled);
}
bool Request::enableGPU(bool enable) { bool Request::enableGPU(bool enable) {
if (enable) { if (enable) {
SkSurface* surface = this->createGPUSurface(); SkSurface* surface = this->createGPUSurface();
@ -167,8 +196,10 @@ bool Request::enableGPU(bool enable) {
// When we switch to GPU, there seems to be some mystery draws in the canvas. So we // When we switch to GPU, there seems to be some mystery draws in the canvas. So we
// draw once to flush the pipe // draw once to flush the pipe
// TODO understand what is actually happening here // TODO understand what is actually happening here
fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp()); if (fDebugCanvas) {
this->getCanvas()->flush(); fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
this->getCanvas()->flush();
}
return true; return true;
} }
@ -206,6 +237,7 @@ SkData* Request::getJsonOps(int n) {
Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas); Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu"); root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu");
root["drawGpuBatchBounds"] = Json::Value(fDebugCanvas->getDrawGpuBatchBounds()); root["drawGpuBatchBounds"] = Json::Value(fDebugCanvas->getDrawGpuBatchBounds());
root["colorMode"] = Json::Value(fColorMode);
SkDynamicMemoryWStream stream; SkDynamicMemoryWStream stream;
stream.writeText(Json::FastWriter().write(root).c_str()); stream.writeText(Json::FastWriter().write(root).c_str());
@ -250,9 +282,12 @@ SkColor Request::getPixel(int x, int y) {
canvas->flush(); canvas->flush();
SkAutoTDelete<SkBitmap> bitmap(this->getBitmapFromCanvas(canvas)); SkAutoTDelete<SkBitmap> bitmap(this->getBitmapFromCanvas(canvas));
SkASSERT(bitmap); SkASSERT(bitmap);
bitmap->lockPixels();
uint8_t* start = ((uint8_t*) bitmap->getPixels()) + (y * bitmap->width() + x) * 4; // Convert to format suitable for inspection
sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bitmap);
SkASSERT(encodedBitmap.get());
const uint8_t* start = encodedBitmap->bytes() + ((y * bitmap->width() + x) * 4);
SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]); SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
bitmap->unlockPixels();
return result; return result;
} }

View File

@ -41,6 +41,7 @@ struct Request {
SkCanvas* getCanvas(); SkCanvas* getCanvas();
SkBitmap* getBitmapFromCanvas(SkCanvas* canvas); SkBitmap* getBitmapFromCanvas(SkCanvas* canvas);
bool enableGPU(bool enable); bool enableGPU(bool enable);
bool setColorMode(int mode);
bool hasPicture() const { return SkToBool(fPicture.get()); } bool hasPicture() const { return SkToBool(fPicture.get()); }
int getLastOp() const { return fDebugCanvas->getSize() - 1; } int getLastOp() const { return fDebugCanvas->getSize() - 1; }
@ -74,6 +75,7 @@ private:
sk_gpu_test::GrContextFactory* fContextFactory; sk_gpu_test::GrContextFactory* fContextFactory;
SkAutoTUnref<SkSurface> fSurface; SkAutoTUnref<SkSurface> fSurface;
bool fGPUEnabled; bool fGPUEnabled;
int fColorMode;
}; };
#endif #endif

View File

@ -39,6 +39,7 @@ public:
fHandlers.push_back(new BreakHandler); fHandlers.push_back(new BreakHandler);
fHandlers.push_back(new BatchesHandler); fHandlers.push_back(new BatchesHandler);
fHandlers.push_back(new BatchBoundsHandler); fHandlers.push_back(new BatchBoundsHandler);
fHandlers.push_back(new ColorModeHandler);
} }
~UrlManager() { ~UrlManager() {

View File

@ -0,0 +1,42 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "UrlHandler.h"
#include "microhttpd.h"
#include "../Request.h"
#include "../Response.h"
using namespace Response;
bool ColorModeHandler::canHandle(const char* method, const char* url) {
static const char* kBasePath = "/colorMode/";
return 0 == strcmp(method, MHD_HTTP_METHOD_POST) &&
0 == strncmp(url, kBasePath, strlen(kBasePath));
}
int ColorModeHandler::handle(Request* request, MHD_Connection* connection,
const char* url, const char* method,
const char* upload_data, size_t* upload_data_size) {
SkTArray<SkString> commands;
SkStrSplit(url, "/", &commands);
if (commands.count() != 2) {
return MHD_NO;
}
int mode;
if (1 != sscanf(commands[1].c_str(), "%d", &mode)) {
return MHD_NO;
}
bool success = request->setColorMode(mode);
if (!success) {
return SendError(connection, "Unable to create requested surface");
}
return SendOK(connection);
}

View File

@ -128,3 +128,16 @@ public:
const char* url, const char* method, const char* url, const char* method,
const char* upload_data, size_t* upload_data_size) override; const char* upload_data, size_t* upload_data_size) override;
}; };
/**
* Controls how rendering is performed (L32, S32, F16).
* Posting to /colorMode/0 turns on L32, /colorMode/1 turns on sRGB,
* /colorMode/2 turns on FP16.
*/
class ColorModeHandler : public UrlHandler {
public:
bool canHandle(const char* method, const char* url) override;
int handle(Request* request, MHD_Connection* connection,
const char* url, const char* method,
const char* upload_data, size_t* upload_data_size) override;
};