Home | History | Annotate | Download | only in skiaserve
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "Request.h"
      9 
     10 #include "SkPictureRecorder.h"
     11 #include "SkPixelSerializer.h"
     12 #include "SkPM4fPriv.h"
     13 #include "picture_utils.h"
     14 #include "sk_tool_utils.h"
     15 
     16 using namespace sk_gpu_test;
     17 
     18 static int kDefaultWidth = 1920;
     19 static int kDefaultHeight = 1080;
     20 static int kMaxWidth = 8192;
     21 static int kMaxHeight = 8192;
     22 
     23 
     24 Request::Request(SkString rootUrl)
     25     : fUploadContext(nullptr)
     26     , fUrlDataManager(rootUrl)
     27     , fGPUEnabled(false)
     28     , fOverdraw(false)
     29     , fColorMode(0) {
     30     // create surface
     31 #if SK_SUPPORT_GPU
     32     GrContextOptions grContextOpts;
     33     fContextFactory = new GrContextFactory(grContextOpts);
     34 #else
     35     fContextFactory = nullptr;
     36 #endif
     37 }
     38 
     39 Request::~Request() {
     40 #if SK_SUPPORT_GPU
     41     if (fContextFactory) {
     42         delete fContextFactory;
     43     }
     44 #endif
     45 }
     46 
     47 SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
     48     SkBitmap* bmp = new SkBitmap();
     49     bmp->setInfo(canvas->imageInfo());
     50     if (!canvas->readPixels(bmp, 0, 0)) {
     51         fprintf(stderr, "Can't read pixels\n");
     52         return nullptr;
     53     }
     54     return bmp;
     55 }
     56 
     57 sk_sp<SkData> Request::writeCanvasToPng(SkCanvas* canvas) {
     58     // capture pixels
     59     std::unique_ptr<SkBitmap> bmp(this->getBitmapFromCanvas(canvas));
     60     SkASSERT(bmp);
     61 
     62     // Convert to format suitable for PNG output
     63     sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bmp);
     64     SkASSERT(encodedBitmap.get());
     65 
     66     // write to an opaque png (black background)
     67     SkDynamicMemoryWStream buffer;
     68     SkDrawCommand::WritePNG(encodedBitmap->bytes(), bmp->width(), bmp->height(),
     69                             buffer, true);
     70     return buffer.detachAsData();
     71 }
     72 
     73 SkCanvas* Request::getCanvas() {
     74 #if SK_SUPPORT_GPU
     75     GrContextFactory* factory = fContextFactory;
     76     GLTestContext* gl = factory->getContextInfo(GrContextFactory::kGL_ContextType,
     77             GrContextFactory::ContextOverrides::kNone).glContext();
     78     if (!gl) {
     79         gl = factory->getContextInfo(GrContextFactory::kGLES_ContextType,
     80                                      GrContextFactory::ContextOverrides::kNone).glContext();
     81     }
     82     if (!gl) {
     83         gl = factory->getContextInfo(GrContextFactory::kMESA_ContextType,
     84                                      GrContextFactory::ContextOverrides::kNone).glContext();
     85     }
     86     if (gl) {
     87         gl->makeCurrent();
     88     }
     89 #endif
     90     SkASSERT(fDebugCanvas);
     91 
     92     // create the appropriate surface if necessary
     93     if (!fSurface) {
     94         this->enableGPU(fGPUEnabled);
     95     }
     96     SkCanvas* target = fSurface->getCanvas();
     97     return target;
     98 }
     99 
    100 void Request::drawToCanvas(int n, int m) {
    101     SkCanvas* target = this->getCanvas();
    102     fDebugCanvas->drawTo(target, n, m);
    103 }
    104 
    105 sk_sp<SkData> Request::drawToPng(int n, int m) {
    106     //fDebugCanvas->setOverdrawViz(true);
    107     this->drawToCanvas(n, m);
    108     //fDebugCanvas->setOverdrawViz(false);
    109     return writeCanvasToPng(this->getCanvas());
    110 }
    111 
    112 sk_sp<SkData> Request::writeOutSkp() {
    113     // Playback into picture recorder
    114     SkIRect bounds = this->getBounds();
    115     SkPictureRecorder recorder;
    116     SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(bounds.width()),
    117                                                SkIntToScalar(bounds.height()));
    118 
    119     fDebugCanvas->draw(canvas);
    120 
    121     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
    122 
    123     SkDynamicMemoryWStream outStream;
    124 
    125     sk_sp<SkPixelSerializer> serializer = sk_tool_utils::MakePixelSerializer();
    126     picture->serialize(&outStream, serializer.get());
    127 
    128     return outStream.detachAsData();
    129 }
    130 
    131 GrContext* Request::getContext() {
    132 #if SK_SUPPORT_GPU
    133     GrContext* result = fContextFactory->get(GrContextFactory::kGL_ContextType,
    134                                              GrContextFactory::ContextOverrides::kNone);
    135     if (!result) {
    136         result = fContextFactory->get(GrContextFactory::kGLES_ContextType,
    137                                       GrContextFactory::ContextOverrides::kNone);
    138     }
    139     if (!result) {
    140         result = fContextFactory->get(GrContextFactory::kMESA_ContextType,
    141                                       GrContextFactory::ContextOverrides::kNone);
    142     }
    143     return result;
    144 #else
    145     return nullptr;
    146 #endif
    147 }
    148 
    149 SkIRect Request::getBounds() {
    150     SkIRect bounds;
    151     if (fPicture) {
    152         bounds = fPicture->cullRect().roundOut();
    153         if (fGPUEnabled) {
    154 #if SK_SUPPORT_GPU
    155             int maxRTSize = this->getContext()->caps()->maxRenderTargetSize();
    156             bounds = SkIRect::MakeWH(SkTMin(bounds.width(), maxRTSize),
    157                                      SkTMin(bounds.height(), maxRTSize));
    158 #endif
    159         }
    160     } else {
    161         bounds = SkIRect::MakeWH(kDefaultWidth, kDefaultHeight);
    162     }
    163 
    164     // We clip to kMaxWidth / kMaxHeight for performance reasons.
    165     // TODO make this configurable
    166     bounds = SkIRect::MakeWH(SkTMin(bounds.width(), kMaxWidth),
    167                              SkTMin(bounds.height(), kMaxHeight));
    168     return bounds;
    169 }
    170 
    171 namespace {
    172 
    173 struct ColorAndProfile {
    174     SkColorType fColorType;
    175     bool fSRGB;
    176 };
    177 
    178 ColorAndProfile ColorModes[] = {
    179     { kN32_SkColorType,      false },
    180     { kN32_SkColorType,       true },
    181     { kRGBA_F16_SkColorType,  true },
    182 };
    183 
    184 }
    185 
    186 SkSurface* Request::createCPUSurface() {
    187     SkIRect bounds = this->getBounds();
    188     ColorAndProfile cap = ColorModes[fColorMode];
    189     auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType
    190                     ? SkColorSpace::MakeSRGBLinear()
    191                     : SkColorSpace::MakeSRGB();
    192     SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
    193                                          kPremul_SkAlphaType, cap.fSRGB ? colorSpace : nullptr);
    194     return SkSurface::MakeRaster(info).release();
    195 }
    196 
    197 SkSurface* Request::createGPUSurface() {
    198     GrContext* context = this->getContext();
    199     SkIRect bounds = this->getBounds();
    200     ColorAndProfile cap = ColorModes[fColorMode];
    201     auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType
    202                     ? SkColorSpace::MakeSRGBLinear()
    203                     : SkColorSpace::MakeSRGB();
    204     SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
    205                                          kPremul_SkAlphaType, cap.fSRGB ? colorSpace: nullptr);
    206     SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info).release();
    207     return surface;
    208 }
    209 
    210 bool Request::setOverdraw(bool enable) {
    211     fOverdraw = enable;
    212     return true;
    213 }
    214 
    215 bool Request::setColorMode(int mode) {
    216     fColorMode = mode;
    217     return enableGPU(fGPUEnabled);
    218 }
    219 
    220 bool Request::enableGPU(bool enable) {
    221     if (enable) {
    222         SkSurface* surface = this->createGPUSurface();
    223         if (surface) {
    224             fSurface.reset(surface);
    225             fGPUEnabled = true;
    226 
    227             // When we switch to GPU, there seems to be some mystery draws in the canvas.  So we
    228             // draw once to flush the pipe
    229             // TODO understand what is actually happening here
    230             if (fDebugCanvas) {
    231                 fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
    232                 this->getCanvas()->flush();
    233             }
    234 
    235             return true;
    236         }
    237         return false;
    238     }
    239     fSurface.reset(this->createCPUSurface());
    240     fGPUEnabled = false;
    241     return true;
    242 }
    243 
    244 bool Request::initPictureFromStream(SkStream* stream) {
    245     // parse picture from stream
    246     fPicture = SkPicture::MakeFromStream(stream);
    247     if (!fPicture) {
    248         fprintf(stderr, "Could not create picture from stream.\n");
    249         return false;
    250     }
    251 
    252     // reinitialize canvas with the new picture dimensions
    253     this->enableGPU(fGPUEnabled);
    254 
    255     // pour picture into debug canvas
    256     SkIRect bounds = this->getBounds();
    257     fDebugCanvas.reset(new SkDebugCanvas(bounds.width(), bounds.height()));
    258     fDebugCanvas->drawPicture(fPicture);
    259 
    260     // for some reason we need to 'flush' the debug canvas by drawing all of the ops
    261     fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
    262     this->getCanvas()->flush();
    263     return true;
    264 }
    265 
    266 sk_sp<SkData> Request::getJsonOps(int n) {
    267     SkCanvas* canvas = this->getCanvas();
    268     Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
    269     root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu");
    270     root["drawGpuOpBounds"] = Json::Value(fDebugCanvas->getDrawGpuOpBounds());
    271     root["colorMode"] = Json::Value(fColorMode);
    272     SkDynamicMemoryWStream stream;
    273     stream.writeText(Json::FastWriter().write(root).c_str());
    274 
    275     return stream.detachAsData();
    276 }
    277 
    278 sk_sp<SkData> Request::getJsonOpList(int n) {
    279     SkCanvas* canvas = this->getCanvas();
    280     SkASSERT(fGPUEnabled);
    281 
    282     Json::Value result = fDebugCanvas->toJSONOpList(n, canvas);
    283 
    284     SkDynamicMemoryWStream stream;
    285     stream.writeText(Json::FastWriter().write(result).c_str());
    286 
    287     return stream.detachAsData();
    288 }
    289 
    290 sk_sp<SkData> Request::getJsonInfo(int n) {
    291     // drawTo
    292     sk_sp<SkSurface> surface(this->createCPUSurface());
    293     SkCanvas* canvas = surface->getCanvas();
    294 
    295     // TODO this is really slow and we should cache the matrix and clip
    296     fDebugCanvas->drawTo(canvas, n);
    297 
    298     // make some json
    299     SkMatrix vm = fDebugCanvas->getCurrentMatrix();
    300     SkIRect clip = fDebugCanvas->getCurrentClip();
    301     Json::Value info(Json::objectValue);
    302     info["ViewMatrix"] = SkDrawCommand::MakeJsonMatrix(vm);
    303     info["ClipRect"] = SkDrawCommand::MakeJsonIRect(clip);
    304 
    305     std::string json = Json::FastWriter().write(info);
    306 
    307     // We don't want the null terminator so strlen is correct
    308     return SkData::MakeWithCopy(json.c_str(), strlen(json.c_str()));
    309 }
    310 
    311 SkColor Request::getPixel(int x, int y) {
    312     SkCanvas* canvas = this->getCanvas();
    313     canvas->flush();
    314     std::unique_ptr<SkBitmap> bitmap(this->getBitmapFromCanvas(canvas));
    315     SkASSERT(bitmap);
    316 
    317     // Convert to format suitable for inspection
    318     sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bitmap);
    319     SkASSERT(encodedBitmap);
    320 
    321     const uint8_t* start = encodedBitmap->bytes() + ((y * bitmap->width() + x) * 4);
    322     SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
    323     return result;
    324 }
    325