1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "tools/skiaserve/Request.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include <memory> 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_ci#include "include/core/SkPictureRecorder.h" 13cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 14cb93a386Sopenharmony_ci#include "src/utils/SkJSONWriter.h" 15cb93a386Sopenharmony_ci#include "tools/ToolUtils.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ciusing namespace sk_gpu_test; 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_cistatic int kDefaultWidth = 1920; 20cb93a386Sopenharmony_cistatic int kDefaultHeight = 1080; 21cb93a386Sopenharmony_cistatic int kMaxWidth = 8192; 22cb93a386Sopenharmony_cistatic int kMaxHeight = 8192; 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ciRequest::Request(SkString rootUrl) 26cb93a386Sopenharmony_ci : fUploadContext(nullptr) 27cb93a386Sopenharmony_ci , fUrlDataManager(rootUrl) 28cb93a386Sopenharmony_ci , fGPUEnabled(false) 29cb93a386Sopenharmony_ci , fOverdraw(false) 30cb93a386Sopenharmony_ci , fColorMode(0) { 31cb93a386Sopenharmony_ci // create surface 32cb93a386Sopenharmony_ci GrContextOptions grContextOpts; 33cb93a386Sopenharmony_ci fContextFactory = new GrContextFactory(grContextOpts); 34cb93a386Sopenharmony_ci} 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ciRequest::~Request() { 37cb93a386Sopenharmony_ci if (fContextFactory) { 38cb93a386Sopenharmony_ci delete fContextFactory; 39cb93a386Sopenharmony_ci } 40cb93a386Sopenharmony_ci} 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_cisk_sp<SkData> Request::writeCanvasToPng(SkCanvas* canvas) { 43cb93a386Sopenharmony_ci // capture pixels 44cb93a386Sopenharmony_ci SkBitmap bmp; 45cb93a386Sopenharmony_ci bmp.allocPixels(canvas->imageInfo()); 46cb93a386Sopenharmony_ci SkAssertResult(canvas->readPixels(bmp, 0, 0)); 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci // write to an opaque png (black background) 49cb93a386Sopenharmony_ci SkDynamicMemoryWStream buffer; 50cb93a386Sopenharmony_ci DrawCommand::WritePNG(bmp, buffer); 51cb93a386Sopenharmony_ci return buffer.detachAsData(); 52cb93a386Sopenharmony_ci} 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ciSkCanvas* Request::getCanvas() { 55cb93a386Sopenharmony_ci#ifdef SK_GL 56cb93a386Sopenharmony_ci GrContextFactory* factory = fContextFactory; 57cb93a386Sopenharmony_ci GLTestContext* gl = factory->getContextInfo(GrContextFactory::kGL_ContextType, 58cb93a386Sopenharmony_ci GrContextFactory::ContextOverrides::kNone).glContext(); 59cb93a386Sopenharmony_ci if (!gl) { 60cb93a386Sopenharmony_ci gl = factory->getContextInfo(GrContextFactory::kGLES_ContextType, 61cb93a386Sopenharmony_ci GrContextFactory::ContextOverrides::kNone).glContext(); 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci if (gl) { 64cb93a386Sopenharmony_ci gl->makeCurrent(); 65cb93a386Sopenharmony_ci } 66cb93a386Sopenharmony_ci#endif 67cb93a386Sopenharmony_ci SkASSERT(fDebugCanvas); 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_ci // create the appropriate surface if necessary 70cb93a386Sopenharmony_ci if (!fSurface) { 71cb93a386Sopenharmony_ci this->enableGPU(fGPUEnabled); 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci SkCanvas* target = fSurface->getCanvas(); 74cb93a386Sopenharmony_ci return target; 75cb93a386Sopenharmony_ci} 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_cisk_sp<SkData> Request::drawToPng(int n, int m) { 78cb93a386Sopenharmony_ci //fDebugCanvas->setOverdrawViz(true); 79cb93a386Sopenharmony_ci auto* canvas = this->getCanvas(); 80cb93a386Sopenharmony_ci canvas->clear(SK_ColorTRANSPARENT); 81cb93a386Sopenharmony_ci fDebugCanvas->drawTo(canvas, n, m); 82cb93a386Sopenharmony_ci //fDebugCanvas->setOverdrawViz(false); 83cb93a386Sopenharmony_ci return writeCanvasToPng(this->getCanvas()); 84cb93a386Sopenharmony_ci} 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_cisk_sp<SkData> Request::writeOutSkp() { 87cb93a386Sopenharmony_ci // Playback into picture recorder 88cb93a386Sopenharmony_ci SkIRect bounds = this->getBounds(); 89cb93a386Sopenharmony_ci SkPictureRecorder recorder; 90cb93a386Sopenharmony_ci SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(bounds.width()), 91cb93a386Sopenharmony_ci SkIntToScalar(bounds.height())); 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci fDebugCanvas->draw(canvas); 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_ci return recorder.finishRecordingAsPicture()->serialize(); 96cb93a386Sopenharmony_ci} 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ciGrDirectContext* Request::directContext() { 99cb93a386Sopenharmony_ci auto result = fContextFactory->get(GrContextFactory::kGL_ContextType, 100cb93a386Sopenharmony_ci GrContextFactory::ContextOverrides::kNone); 101cb93a386Sopenharmony_ci if (!result) { 102cb93a386Sopenharmony_ci result = fContextFactory->get(GrContextFactory::kGLES_ContextType, 103cb93a386Sopenharmony_ci GrContextFactory::ContextOverrides::kNone); 104cb93a386Sopenharmony_ci } 105cb93a386Sopenharmony_ci return result; 106cb93a386Sopenharmony_ci} 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ciSkIRect Request::getBounds() { 109cb93a386Sopenharmony_ci SkIRect bounds; 110cb93a386Sopenharmony_ci if (fPicture) { 111cb93a386Sopenharmony_ci bounds = fPicture->cullRect().roundOut(); 112cb93a386Sopenharmony_ci if (fGPUEnabled) { 113cb93a386Sopenharmony_ci int maxRTSize = this->directContext()->maxRenderTargetSize(); 114cb93a386Sopenharmony_ci bounds = SkIRect::MakeWH(std::min(bounds.width(), maxRTSize), 115cb93a386Sopenharmony_ci std::min(bounds.height(), maxRTSize)); 116cb93a386Sopenharmony_ci } 117cb93a386Sopenharmony_ci } else { 118cb93a386Sopenharmony_ci bounds = SkIRect::MakeWH(kDefaultWidth, kDefaultHeight); 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci // We clip to kMaxWidth / kMaxHeight for performance reasons. 122cb93a386Sopenharmony_ci // TODO make this configurable 123cb93a386Sopenharmony_ci bounds = SkIRect::MakeWH(std::min(bounds.width(), kMaxWidth), 124cb93a386Sopenharmony_ci std::min(bounds.height(), kMaxHeight)); 125cb93a386Sopenharmony_ci return bounds; 126cb93a386Sopenharmony_ci} 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_cinamespace { 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_cistruct ColorAndProfile { 131cb93a386Sopenharmony_ci SkColorType fColorType; 132cb93a386Sopenharmony_ci bool fSRGB; 133cb93a386Sopenharmony_ci}; 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ciColorAndProfile ColorModes[] = { 136cb93a386Sopenharmony_ci { kN32_SkColorType, false }, 137cb93a386Sopenharmony_ci { kN32_SkColorType, true }, 138cb93a386Sopenharmony_ci { kRGBA_F16_SkColorType, true }, 139cb93a386Sopenharmony_ci}; 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci} // namespace 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ciSkSurface* Request::createCPUSurface() { 144cb93a386Sopenharmony_ci SkIRect bounds = this->getBounds(); 145cb93a386Sopenharmony_ci ColorAndProfile cap = ColorModes[fColorMode]; 146cb93a386Sopenharmony_ci auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType 147cb93a386Sopenharmony_ci ? SkColorSpace::MakeSRGBLinear() 148cb93a386Sopenharmony_ci : SkColorSpace::MakeSRGB(); 149cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::Make(bounds.size(), cap.fColorType, kPremul_SkAlphaType, 150cb93a386Sopenharmony_ci cap.fSRGB ? colorSpace : nullptr); 151cb93a386Sopenharmony_ci return SkSurface::MakeRaster(info).release(); 152cb93a386Sopenharmony_ci} 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_ciSkSurface* Request::createGPUSurface() { 155cb93a386Sopenharmony_ci auto context = this->directContext(); 156cb93a386Sopenharmony_ci SkIRect bounds = this->getBounds(); 157cb93a386Sopenharmony_ci ColorAndProfile cap = ColorModes[fColorMode]; 158cb93a386Sopenharmony_ci auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType 159cb93a386Sopenharmony_ci ? SkColorSpace::MakeSRGBLinear() 160cb93a386Sopenharmony_ci : SkColorSpace::MakeSRGB(); 161cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::Make(bounds.size(), cap.fColorType, kPremul_SkAlphaType, 162cb93a386Sopenharmony_ci cap.fSRGB ? colorSpace : nullptr); 163cb93a386Sopenharmony_ci SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info).release(); 164cb93a386Sopenharmony_ci return surface; 165cb93a386Sopenharmony_ci} 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_cibool Request::setOverdraw(bool enable) { 168cb93a386Sopenharmony_ci fOverdraw = enable; 169cb93a386Sopenharmony_ci return true; 170cb93a386Sopenharmony_ci} 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_cibool Request::setColorMode(int mode) { 173cb93a386Sopenharmony_ci fColorMode = mode; 174cb93a386Sopenharmony_ci return enableGPU(fGPUEnabled); 175cb93a386Sopenharmony_ci} 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_cibool Request::enableGPU(bool enable) { 178cb93a386Sopenharmony_ci if (enable) { 179cb93a386Sopenharmony_ci SkSurface* surface = this->createGPUSurface(); 180cb93a386Sopenharmony_ci if (surface) { 181cb93a386Sopenharmony_ci fSurface.reset(surface); 182cb93a386Sopenharmony_ci fGPUEnabled = true; 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_ci // When we switch to GPU, there seems to be some mystery draws in the canvas. So we 185cb93a386Sopenharmony_ci // draw once to flush the pipe 186cb93a386Sopenharmony_ci // TODO understand what is actually happening here 187cb93a386Sopenharmony_ci if (fDebugCanvas) { 188cb93a386Sopenharmony_ci fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp()); 189cb93a386Sopenharmony_ci fSurface->flush(); 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci return true; 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci return false; 195cb93a386Sopenharmony_ci } 196cb93a386Sopenharmony_ci fSurface.reset(this->createCPUSurface()); 197cb93a386Sopenharmony_ci fGPUEnabled = false; 198cb93a386Sopenharmony_ci return true; 199cb93a386Sopenharmony_ci} 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_cibool Request::initPictureFromStream(SkStream* stream) { 202cb93a386Sopenharmony_ci // parse picture from stream 203cb93a386Sopenharmony_ci fPicture = SkPicture::MakeFromStream(stream); 204cb93a386Sopenharmony_ci if (!fPicture) { 205cb93a386Sopenharmony_ci fprintf(stderr, "Could not create picture from stream.\n"); 206cb93a386Sopenharmony_ci return false; 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci // reinitialize canvas with the new picture dimensions 210cb93a386Sopenharmony_ci this->enableGPU(fGPUEnabled); 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_ci // pour picture into debug canvas 213cb93a386Sopenharmony_ci SkIRect bounds = this->getBounds(); 214cb93a386Sopenharmony_ci fDebugCanvas = std::make_unique<DebugCanvas>(bounds.width(), bounds.height()); 215cb93a386Sopenharmony_ci fDebugCanvas->drawPicture(fPicture); 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci // for some reason we need to 'flush' the debug canvas by drawing all of the ops 218cb93a386Sopenharmony_ci fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp()); 219cb93a386Sopenharmony_ci fSurface->flush(); 220cb93a386Sopenharmony_ci return true; 221cb93a386Sopenharmony_ci} 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_cisk_sp<SkData> Request::getJsonOps() { 224cb93a386Sopenharmony_ci SkCanvas* canvas = this->getCanvas(); 225cb93a386Sopenharmony_ci SkDynamicMemoryWStream stream; 226cb93a386Sopenharmony_ci SkJSONWriter writer(&stream, SkJSONWriter::Mode::kFast); 227cb93a386Sopenharmony_ci writer.beginObject(); // root 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_ci writer.appendString("mode", fGPUEnabled ? "gpu" : "cpu"); 230cb93a386Sopenharmony_ci writer.appendBool("drawGpuOpBounds", fDebugCanvas->getDrawGpuOpBounds()); 231cb93a386Sopenharmony_ci writer.appendS32("colorMode", fColorMode); 232cb93a386Sopenharmony_ci fDebugCanvas->toJSON(writer, fUrlDataManager, canvas); 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci writer.endObject(); // root 235cb93a386Sopenharmony_ci writer.flush(); 236cb93a386Sopenharmony_ci return stream.detachAsData(); 237cb93a386Sopenharmony_ci} 238cb93a386Sopenharmony_ci 239cb93a386Sopenharmony_cisk_sp<SkData> Request::getJsonOpsTask() { 240cb93a386Sopenharmony_ci SkCanvas* canvas = this->getCanvas(); 241cb93a386Sopenharmony_ci SkASSERT(fGPUEnabled); 242cb93a386Sopenharmony_ci SkDynamicMemoryWStream stream; 243cb93a386Sopenharmony_ci SkJSONWriter writer(&stream, SkJSONWriter::Mode::kFast); 244cb93a386Sopenharmony_ci 245cb93a386Sopenharmony_ci fDebugCanvas->toJSONOpsTask(writer, canvas); 246cb93a386Sopenharmony_ci 247cb93a386Sopenharmony_ci writer.flush(); 248cb93a386Sopenharmony_ci return stream.detachAsData(); 249cb93a386Sopenharmony_ci} 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_cisk_sp<SkData> Request::getJsonInfo(int n) { 252cb93a386Sopenharmony_ci // drawTo 253cb93a386Sopenharmony_ci sk_sp<SkSurface> surface(this->createCPUSurface()); 254cb93a386Sopenharmony_ci SkCanvas* canvas = surface->getCanvas(); 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci // TODO this is really slow and we should cache the matrix and clip 257cb93a386Sopenharmony_ci fDebugCanvas->drawTo(canvas, n); 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_ci // make some json 260cb93a386Sopenharmony_ci SkDynamicMemoryWStream stream; 261cb93a386Sopenharmony_ci SkJSONWriter writer(&stream, SkJSONWriter::Mode::kFast); 262cb93a386Sopenharmony_ci 263cb93a386Sopenharmony_ci SkM44 vm = fDebugCanvas->getCurrentMatrix(); 264cb93a386Sopenharmony_ci SkIRect clip = fDebugCanvas->getCurrentClip(); 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_ci writer.beginObject(); // root 267cb93a386Sopenharmony_ci writer.appendName("ViewMatrix"); 268cb93a386Sopenharmony_ci DrawCommand::MakeJsonMatrix44(writer, vm); 269cb93a386Sopenharmony_ci writer.appendName("ClipRect"); 270cb93a386Sopenharmony_ci DrawCommand::MakeJsonIRect(writer, clip); 271cb93a386Sopenharmony_ci writer.endObject(); // root 272cb93a386Sopenharmony_ci 273cb93a386Sopenharmony_ci // TODO: Old code explicitly avoided the null terminator in the returned data. Important? 274cb93a386Sopenharmony_ci writer.flush(); 275cb93a386Sopenharmony_ci return stream.detachAsData(); 276cb93a386Sopenharmony_ci} 277cb93a386Sopenharmony_ci 278cb93a386Sopenharmony_ciSkColor Request::getPixel(int x, int y) { 279cb93a386Sopenharmony_ci SkBitmap bmp; 280cb93a386Sopenharmony_ci bmp.allocPixels(this->getCanvas()->imageInfo().makeWH(1, 1)); 281cb93a386Sopenharmony_ci SkAssertResult(this->getCanvas()->readPixels(bmp, x, y)); 282cb93a386Sopenharmony_ci return bmp.getColor(0, 0); 283cb93a386Sopenharmony_ci} 284