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