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 if (!bmp->tryAllocPixels(canvas->imageInfo()) || !canvas->readPixels(*bmp, 0, 0)) { 50 fprintf(stderr, "Can't read pixels\n"); 51 delete bmp; 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