int main(int argc, char** argv) { #if SK_SUPPORT_GPU SkCommandLineFlags::SetUsage("Reports on an skp file's suitability for GPU rasterization"); SkCommandLineFlags::Parse(argc, argv); if (FLAGS_readFile.count() != 1) { if (!FLAGS_quiet) { SkDebugf("Missing input file\n"); } return kError; } SkFILEStream inputStream(FLAGS_readFile[0]); if (!inputStream.isValid()) { if (!FLAGS_quiet) { SkDebugf("Couldn't open file\n"); } return kError; } sk_sp<SkPicture> picture(SkPicture::MakeFromStream(&inputStream)); if (nullptr == picture) { if (!FLAGS_quiet) { SkDebugf("Could not read the SkPicture\n"); } return kError; } // The SkPicture tracking information is only generated during recording // an isn't serialized. Replay the picture to regenerated the tracking data. SkPictureRecorder recorder; picture->playback(recorder.beginRecording(picture->cullRect().width(), picture->cullRect().height(), nullptr, 0)); sk_sp<SkPicture> recorded(recorder.finishRecordingAsPicture()); if (SkPictureGpuAnalyzer(recorded).suitableForGpuRasterization(nullptr)) { SkDebugf("suitable\n"); } else { SkDebugf("unsuitable\n"); } return kSuccess; #else SkDebugf("gpuveto is only useful when GPU rendering is enabled\n"); return kError; #endif }
static void test_gpu_veto(skiatest::Reporter* reporter) { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(100, 100); { SkPath path; path.moveTo(0, 0); path.lineTo(50, 50); SkScalar intervals[] = { 1.0f, 1.0f }; sk_sp<SkPathEffect> dash(SkDashPathEffect::Make(intervals, 2, 0)); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setPathEffect(dash); for (int i = 0; i < 50; ++i) { canvas->drawPath(path, paint); } } sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); // path effects currently render an SkPicture undesireable for GPU rendering const char *reason = nullptr; REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization(&reason)); REPORTER_ASSERT(reporter, reason); canvas = recorder.beginRecording(100, 100); { SkPath path; path.moveTo(0, 0); path.lineTo(0, 50); path.lineTo(25, 25); path.lineTo(50, 50); path.lineTo(50, 0); path.close(); REPORTER_ASSERT(reporter, !path.isConvex()); SkPaint paint; paint.setAntiAlias(true); for (int i = 0; i < 50; ++i) { canvas->drawPath(path, paint); } } picture = recorder.finishRecordingAsPicture(); // A lot of small AA concave paths should be fine for GPU rendering REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization()); canvas = recorder.beginRecording(100, 100); { SkPath path; path.moveTo(0, 0); path.lineTo(0, 100); path.lineTo(50, 50); path.lineTo(100, 100); path.lineTo(100, 0); path.close(); REPORTER_ASSERT(reporter, !path.isConvex()); SkPaint paint; paint.setAntiAlias(true); for (int i = 0; i < 50; ++i) { canvas->drawPath(path, paint); } } picture = recorder.finishRecordingAsPicture(); // A lot of large AA concave paths currently render an SkPicture undesireable for GPU rendering REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization()); canvas = recorder.beginRecording(100, 100); { SkPath path; path.moveTo(0, 0); path.lineTo(0, 50); path.lineTo(25, 25); path.lineTo(50, 50); path.lineTo(50, 0); path.close(); REPORTER_ASSERT(reporter, !path.isConvex()); SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(0); for (int i = 0; i < 50; ++i) { canvas->drawPath(path, paint); } } picture = recorder.finishRecordingAsPicture(); // hairline stroked AA concave paths are fine for GPU rendering REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization()); canvas = recorder.beginRecording(100, 100); { SkPaint paint; SkScalar intervals [] = { 10, 20 }; paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25)); SkPoint points [2] = { { 0, 0 }, { 100, 0 } }; for (int i = 0; i < 50; ++i) { canvas->drawPoints(SkCanvas::kLines_PointMode, 2, points, paint); } } picture = recorder.finishRecordingAsPicture(); // fast-path dashed effects are fine for GPU rendering ... REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization()); canvas = recorder.beginRecording(100, 100); { SkPaint paint; SkScalar intervals [] = { 10, 20 }; paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25)); for (int i = 0; i < 50; ++i) { canvas->drawRect(SkRect::MakeWH(10, 10), paint); } } picture = recorder.finishRecordingAsPicture(); // ... but only when applied to drawPoint() calls REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization()); canvas = recorder.beginRecording(100, 100); { const SkPath convexClip = make_convex_path(); const SkPath concaveClip = make_concave_path(); for (int i = 0; i < 50; ++i) { canvas->clipPath(convexClip); canvas->clipPath(concaveClip); canvas->clipPath(convexClip, SkRegion::kIntersect_Op, true); canvas->drawRect(SkRect::MakeWH(100, 100), SkPaint()); } } picture = recorder.finishRecordingAsPicture(); // Convex clips and non-AA concave clips are fine on the GPU. REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization()); canvas = recorder.beginRecording(100, 100); { const SkPath concaveClip = make_concave_path(); for (int i = 0; i < 50; ++i) { canvas->clipPath(concaveClip, SkRegion::kIntersect_Op, true); canvas->drawRect(SkRect::MakeWH(100, 100), SkPaint()); } } picture = recorder.finishRecordingAsPicture(); // ... but AA concave clips are not. REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization()); // Nest the previous picture inside a new one. canvas = recorder.beginRecording(100, 100); { canvas->drawPicture(picture); } picture = recorder.finishRecordingAsPicture(); REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization()); }