Add the ability to enable/disable GPU path renderers
authorcsmartdalton <csmartdalton@google.com>
Wed, 22 Feb 2017 19:00:42 +0000 (12:00 -0700)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Wed, 22 Feb 2017 20:29:56 +0000 (20:29 +0000)
Adds a bitfield to GrContextOptions that masks out path renderers.
Adds commandline flags support to set this bitfield in tools apps.
Removes GrGLInterfaceRemoveNVPR since we can now accomplish the same
thing in the context options.

BUG=skia:

Change-Id: Icf2a4df36374b3ba2f69ebf0db56e8aedd6cf65f
Reviewed-on: https://skia-review.googlesource.com/8786
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>

19 files changed:
bench/nanobench.cpp
dm/DM.cpp
example/SkiaSDLExample.cpp
gm/pathmaskcache.cpp
include/gpu/GrContextOptions.h
include/gpu/gl/GrGLInterface.h
samplecode/SampleApp.cpp
samplecode/SampleApp.h
src/gpu/GrContext.cpp
src/gpu/GrPathRendererChain.cpp
src/gpu/GrPathRendererChain.h
src/gpu/gl/GrGLCaps.cpp
src/gpu/gl/GrGLInterface.cpp
tools/flags/SkCommonFlagsPathRenderer.h [new file with mode: 0644]
tools/gpu/GrContextFactory.cpp
tools/skpbench/skpbench.cpp
tools/viewer/Viewer.cpp
tools/viewer/sk_app/GLWindowContext.cpp
tools/viewer/sk_app/VulkanWindowContext.cpp

index e97e9a0bf30102670879056179871dfdc8037bb5..f73ae464cc5132034f4c9f55acb763269d35da1c 100644 (file)
@@ -33,6 +33,7 @@
 #include "SkCodec.h"
 #include "SkCommonFlags.h"
 #include "SkCommonFlagsConfig.h"
+#include "SkCommonFlagsPathRenderer.h"
 #include "SkData.h"
 #include "SkGraphics.h"
 #include "SkLeanWindows.h"
@@ -128,6 +129,10 @@ DEFINE_string(sourceType, "",
 DEFINE_string(benchType,  "",
         "Apply usual --match rules to bench type: micro, recording, piping, playback, skcodec, etc.");
 
+#if SK_SUPPORT_GPU
+DEFINE_pathrenderer_flag;
+#endif
+
 static double now_ms() { return SkTime::GetNSecs() * 1e-6; }
 
 static SkString humanize(double ms) {
@@ -1106,6 +1111,7 @@ int main(int argc, char** argv) {
 
 #if SK_SUPPORT_GPU
     GrContextOptions grContextOpts;
+    grContextOpts.fGpuPathRenderers = CollectGpuPathRenderersFromFlags();
     gGrFactory.reset(new GrContextFactory(grContextOpts));
 #endif
 
index c25076ff0600764f26e71a8eca86a9e92c8bb7b5..5e3185bb3028266aa58bb1c8b0c7f1b0aec34737 100644 (file)
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -16,6 +16,7 @@
 #include "SkColorSpace.h"
 #include "SkCommonFlags.h"
 #include "SkCommonFlagsConfig.h"
+#include "SkCommonFlagsPathRenderer.h"
 #include "SkData.h"
 #include "SkFontMgr.h"
 #include "SkGraphics.h"
@@ -77,6 +78,10 @@ DEFINE_int32(shard,  0, "Which shard do I run?");
 
 DEFINE_string(mskps, "", "Directory to read mskps from, or a single mskp file.");
 
+#if SK_SUPPORT_GPU
+DEFINE_pathrenderer_flag;
+#endif
+
 using namespace DM;
 using sk_gpu_test::GrContextFactory;
 using sk_gpu_test::GLTestContext;
@@ -838,13 +843,13 @@ static bool gpu_supported() {
 #endif
 }
 
-static Sink* create_sink(const SkCommandLineConfig* config) {
+static Sink* create_sink(const GrContextOptions& grCtxOptions, const SkCommandLineConfig* config) {
 #if SK_SUPPORT_GPU
     if (gpu_supported()) {
         if (const SkCommandLineConfigGpu* gpuConfig = config->asConfigGpu()) {
             GrContextFactory::ContextType contextType = gpuConfig->getContextType();
             GrContextFactory::ContextOverrides contextOverrides = gpuConfig->getContextOverrides();
-            GrContextFactory testFactory;
+            GrContextFactory testFactory(grCtxOptions);
             if (!testFactory.get(contextType, contextOverrides)) {
                 info("WARNING: can not create GPU context for config '%s'. "
                      "GM tests will be skipped.\n", gpuConfig->getTag().c_str());
@@ -911,12 +916,12 @@ static Sink* create_via(const SkString& tag, Sink* wrapped) {
     return nullptr;
 }
 
-static bool gather_sinks() {
+static bool gather_sinks(const GrContextOptions& grCtxOptions) {
     SkCommandLineConfigArray configs;
     ParseConfigs(FLAGS_config, &configs);
     for (int i = 0; i < configs.count(); i++) {
         const SkCommandLineConfig& config = *configs[i];
-        Sink* sink = create_sink(&config);
+        Sink* sink = create_sink(grCtxOptions, &config);
         if (sink == nullptr) {
             info("Skipping config %s: Don't understand '%s'.\n", config.getTag().c_str(),
                  config.getTag().c_str());
@@ -1233,7 +1238,7 @@ static void gather_tests() {
     }
 }
 
-static void run_test(skiatest::Test test) {
+static void run_test(skiatest::Test test, const GrContextOptions& grCtxOptions) {
     struct : public skiatest::Reporter {
         void reportFailed(const skiatest::Failure& failure) override {
             fail(failure.toString());
@@ -1247,7 +1252,7 @@ static void run_test(skiatest::Test test) {
 
     if (!FLAGS_dryRun && !is_blacklisted("_", "tests", "_", test.name)) {
         start("unit", "test", "", test.name);
-        GrContextFactory factory;
+        GrContextFactory factory(grCtxOptions);
         test.proc(&reporter, &factory);
     }
     done("unit", "test", "", test.name);
@@ -1307,6 +1312,11 @@ int main(int argc, char** argv) {
         gVLog = fopen(SkOSPath::Join(FLAGS_writePath[0], "verbose.log").c_str(), "w");
     }
 
+    GrContextOptions grCtxOptions;
+#if SK_SUPPORT_GPU
+    grCtxOptions.fGpuPathRenderers = CollectGpuPathRenderersFromFlags();
+#endif
+
     JsonWriter::DumpJson();  // It's handy for the bots to assume this is ~never missing.
     SkAutoGraphics ag;
     SkTaskGroup::Enabler enabled(FLAGS_threads);
@@ -1325,7 +1335,7 @@ int main(int argc, char** argv) {
     if (!gather_srcs()) {
         return 1;
     }
-    if (!gather_sinks()) {
+    if (!gather_sinks(grCtxOptions)) {
         return 1;
     }
     gather_tests();
@@ -1356,12 +1366,12 @@ int main(int argc, char** argv) {
         }
     }
     for (auto test : gParallelTests) {
-        parallel.add([test] { run_test(test); });
+        parallel.add([test, grCtxOptions] { run_test(test, grCtxOptions); });
     }
 
     // With the parallel work running, run serial tasks and tests here on main thread.
     for (auto task : serial) { Task::Run(task); }
-    for (auto test : gSerialTests) { run_test(test); }
+    for (auto test : gSerialTests) { run_test(test, grCtxOptions); }
 
     // Wait for any remaining parallel work to complete (including any spun off of serial tasks).
     parallel.wait();
index 3aa42b3518bb703ea57bfb838f104cfb423e6f17..abd198afe98d03ef7a34ebac2ea14f476cc4f852 100644 (file)
@@ -185,10 +185,6 @@ int main(int argc, char** argv) {
     // setup GrContext
     sk_sp<const GrGLInterface> interface(GrGLCreateNativeInterface());
 
-    // To use NVPR, comment this out
-    interface.reset(GrGLInterfaceRemoveNVPR(interface));
-    SkASSERT(interface);
-
     // setup contexts
     sk_sp<GrContext> grContext(GrContext::Create(kOpenGL_GrBackend,
                                                  (GrBackendContext)interface.get()));
index 21397f077d9cc970003592cbcbf0207becedfa32..5e3232b6bdcba2f1d30913cddf10ea23dc0b7c83 100644 (file)
@@ -104,7 +104,7 @@ protected:
     }
 
     void modifyGrContextOptions(GrContextOptions* options) override {
-        options->fForceSWPathMasks = true;
+        options->fGpuPathRenderers = GrContextOptions::GpuPathRenderers::kNone;
         options->fAllowPathMaskCaching = true;
     }
 
index a2e4288c66cd3e3c92858a24cdad48ab2de2bec8..6c42ec66add1ab64f958c5c1465479960d6364b5 100644 (file)
@@ -9,6 +9,7 @@
 #define GrContextOptions_DEFINED
 
 #include "SkTypes.h"
+#include "GrTypes.h"
 
 struct GrContextOptions {
     GrContextOptions() {}
@@ -61,23 +62,12 @@ struct GrContextOptions {
         Instanced rendering is still experimental at this point and disabled by default. */
     bool fEnableInstancedRendering = false;
 
-    /** Disables distance field rendering for paths. Distance field computation can be expensive
-        and yields no benefit if a path is not rendered multiple times with different transforms */
-    bool fDisableDistanceFieldPaths = false;
-
     /**
      * If true this allows path mask textures to be cached. This is only really useful if paths
      * are commonly rendered at the same scale and fractional translation.
      */
     bool fAllowPathMaskCaching = false;
 
-    /**
-     * Force all path draws to go through through the sw-rasterize-to-texture code path (assuming
-     * the path is not recognized as a simpler shape (e.g. a rrect). This is intended for testing
-     * purposes.
-     */
-    bool fForceSWPathMasks = false;
-
     /**
      * If true, sRGB support will not be enabled unless sRGB decoding can be disabled (via an
      * extension). If mixed use of "legacy" mode and sRGB/color-correct mode is not required, this
@@ -91,6 +81,34 @@ struct GrContextOptions {
      * textures from codec-backed images.
      */
     bool fDisableGpuYUVConversion = false;
+
+    /**
+     * If true, the caps will never report driver support for path rendering.
+     */
+    bool fSuppressPathRendering = false;
+
+    /**
+     * Allows the client to include or exclude specific GPU path renderers.
+     */
+    enum class GpuPathRenderers {
+        kNone              = 0, // Always use sofware masks.
+        kDashLine          = 1 << 0,
+        kStencilAndCover   = 1 << 1,
+        kMSAA              = 1 << 2,
+        kAAHairline        = 1 << 3,
+        kAAConvex          = 1 << 4,
+        kAALinearizing     = 1 << 5,
+        kPLS               = 1 << 6,
+        kDistanceField     = 1 << 7,
+        kTesselating       = 1 << 8,
+        kDefault           = 1 << 9,
+
+        kAll               = kDefault | (kDefault - 1)
+    };
+
+    GpuPathRenderers fGpuPathRenderers = GpuPathRenderers::kAll;
 };
 
+GR_MAKE_BITFIELD_CLASS_OPS(GrContextOptions::GpuPathRenderers)
+
 #endif
index 3afa6be9fd7cd5ef258ed9ac19a8c00660bf519c..cce1cb546bb02eb2dce98e1694bd0479d1b230db 100644 (file)
@@ -55,10 +55,6 @@ typedef intptr_t GrGLInterfaceCallbackData;
  */
 const SK_API GrGLInterface* GrGLCreateNullInterface(bool enableNVPR = false);
 
-/** Function that returns a new interface identical to "interface" but without support for
-    GL_NV_path_rendering. */
-const GrGLInterface* GrGLInterfaceRemoveNVPR(const GrGLInterface*);
-
 /** Function that returns a new interface identical to "interface" but with support for
     test version of GL_EXT_debug_marker. */
 const GrGLInterface* GrGLInterfaceAddTestDebugMarker(const GrGLInterface*,
index 8b5e07417343ebc65b064c1887233cf8f3e8837a..1aac794ddd17d25f7959e909331d8ff250438ff6 100644 (file)
@@ -14,6 +14,7 @@
 #include "SkCanvas.h"
 #include "SkColorSpace_XYZ.h"
 #include "SkCommandLineFlags.h"
+#include "SkCommonFlagsPathRenderer.h"
 #include "SkData.h"
 #include "SkDocument.h"
 #include "SkGraphics.h"
@@ -208,7 +209,7 @@ public:
 #endif
     }
 
-    void setUpBackend(SampleWindow* win, int msaaSampleCount, bool deepColor) override {
+    void setUpBackend(SampleWindow* win, const BackendOptions& backendOptions) override {
         SkASSERT(kNone_BackEndType == fBackend);
 
         fBackend = kNone_BackEndType;
@@ -231,27 +232,27 @@ public:
                 break;
         }
         AttachmentInfo attachmentInfo;
-        bool result = win->attach(fBackend, msaaSampleCount, deepColor, &attachmentInfo);
+        bool result = win->attach(fBackend, backendOptions.fMSAASampleCount,
+                                  backendOptions.fDeepColor, &attachmentInfo);
         if (!result) {
             SkDebugf("Failed to initialize GL");
             return;
         }
-        fMSAASampleCount = msaaSampleCount;
-        fDeepColor = deepColor;
+        fMSAASampleCount = backendOptions.fMSAASampleCount;
+        fDeepColor = backendOptions.fDeepColor;
         // Assume that we have at least 24-bit output, for backends that don't supply this data
         fActualColorBits = SkTMax(attachmentInfo.fColorBits, 24);
 
         SkASSERT(nullptr == fCurIntf);
-        sk_sp<const GrGLInterface> glInterface;
         switch (win->getDeviceType()) {
             case kRaster_DeviceType:    // fallthrough
             case kGPU_DeviceType:
                 // all these guys use the native interface
-                glInterface.reset(GrGLCreateNativeInterface());
+                fCurIntf = GrGLCreateNativeInterface();
                 break;
 #if SK_ANGLE
             case kANGLE_DeviceType:
-                glInterface.reset(sk_gpu_test::CreateANGLEGLInterface());
+                fCurIntf = sk_gpu_test::CreateANGLEGLInterface();
                 break;
 #endif // SK_ANGLE
             default:
@@ -259,12 +260,9 @@ public:
                 break;
         }
 
-        // Currently SampleApp does not use NVPR. TODO: Provide an NVPR device type that is skipped
-        // when the driver doesn't support NVPR.
-        fCurIntf = GrGLInterfaceRemoveNVPR(glInterface.get());
-
         SkASSERT(nullptr == fCurContext);
-        fCurContext = GrContext::Create(kOpenGL_GrBackend, (GrBackendContext) fCurIntf);
+        fCurContext = GrContext::Create(kOpenGL_GrBackend, (GrBackendContext) fCurIntf,
+                                        backendOptions.fGrContextOptions);
 
         if (nullptr == fCurContext || nullptr == fCurIntf) {
             // We need some context and interface to see results
@@ -723,8 +721,6 @@ static void restrict_samples(SkTDArray<const SkViewFactory*>& factories, const S
 }
 
 DEFINE_string(slide, "", "Start on this sample.");
-DEFINE_int32(msaa, 0, "Request multisampling with this count.");
-DEFINE_bool(deepColor, false, "Request deep color (10-bit/channel or more) display buffer.");
 DEFINE_string(pictureDir, "", "Read pictures from here.");
 DEFINE_string(picture, "", "Path to single picture.");
 DEFINE_string(svg, "", "Path to single SVG file.");
@@ -737,6 +733,11 @@ DEFINE_bool(redraw, false, "Force continuous redrawing, for profiling or debuggi
 #ifdef SAMPLE_PDF_FILE_VIEWER
 DEFINE_string(pdfPath, "", "Path to direcotry of pdf files.");
 #endif
+#if SK_SUPPORT_GPU
+DEFINE_pathrenderer_flag;
+DEFINE_int32(msaa, 0, "Request multisampling with this count.");
+DEFINE_bool(deepColor, false, "Request deep color (10-bit/channel or more) display buffer.");
+#endif
 
 #include "SkTaskGroup.h"
 
@@ -826,8 +827,11 @@ SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* dev
         }
     }
 
-    fMSAASampleCount = FLAGS_msaa;
-    fDeepColor = FLAGS_deepColor;
+#if SK_SUPPORT_GPU
+    fBackendOptions.fGrContextOptions.fGpuPathRenderers = CollectGpuPathRenderersFromFlags();
+    fBackendOptions.fMSAASampleCount = FLAGS_msaa;
+    fBackendOptions.fDeepColor = FLAGS_deepColor;
+#endif
     fColorConfigIndex = 0;
 
     if (FLAGS_list) {
@@ -996,7 +1000,7 @@ SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* dev
         devManager->ref();
         fDevManager = devManager;
     }
-    fDevManager->setUpBackend(this, fMSAASampleCount, fDeepColor);
+    fDevManager->setUpBackend(this, fBackendOptions);
 
     // If another constructor set our dimensions, ensure that our
     // onSizeChange gets called.
@@ -1916,7 +1920,7 @@ void SampleWindow::setDeviceType(DeviceType type) {
 
     fDevManager->tearDownBackend(this);
     fDeviceType = type;
-    fDevManager->setUpBackend(this, fMSAASampleCount, fDeepColor);
+    fDevManager->setUpBackend(this, fBackendOptions);
 
     this->updateTitle();
     this->inval(nullptr);
@@ -1926,7 +1930,7 @@ void SampleWindow::setDeviceColorType(SkColorType ct, sk_sp<SkColorSpace> cs) {
     this->setColorType(ct, std::move(cs));
 
     fDevManager->tearDownBackend(this);
-    fDevManager->setUpBackend(this, fMSAASampleCount, fDeepColor);
+    fDevManager->setUpBackend(this, fBackendOptions);
 
     this->updateTitle();
     this->inval(nullptr);
@@ -1953,7 +1957,7 @@ void SampleWindow::toggleFPS() {
 void SampleWindow::toggleDistanceFieldFonts() {
     // reset backend
     fDevManager->tearDownBackend(this);
-    fDevManager->setUpBackend(this, fMSAASampleCount, fDeepColor);
+    fDevManager->setUpBackend(this, fBackendOptions);
 
     SkSurfaceProps props = this->getSurfaceProps();
     uint32_t flags = props.flags() ^ SkSurfaceProps::kUseDeviceIndependentFonts_Flag;
@@ -1966,7 +1970,7 @@ void SampleWindow::toggleDistanceFieldFonts() {
 void SampleWindow::setPixelGeometry(int pixelGeometryIndex) {
     // reset backend
     fDevManager->tearDownBackend(this);
-    fDevManager->setUpBackend(this, fMSAASampleCount, fDeepColor);
+    fDevManager->setUpBackend(this, fBackendOptions);
 
     const SkSurfaceProps& oldProps = this->getSurfaceProps();
     SkSurfaceProps newProps(oldProps.flags(), SkSurfaceProps::kLegacyFontHost_InitType);
index c52541d4093790c61484abe5b2e6f2ecb27b6a5c..7b0dbf4942754154a6cdf8f8f23a234f0bdb2d94 100644 (file)
 
 #include "SkPipe.h"
 
+#if SK_SUPPORT_GPU
+#include "GrContextOptions.h"
+#endif
+
 class GrContext;
 class GrRenderTarget;
 
@@ -70,9 +74,15 @@ public:
      */
     class DeviceManager : public SkRefCnt {
     public:
+        struct BackendOptions {
+#if SK_SUPPORT_GPU
+            GrContextOptions   fGrContextOptions;
+            int                fMSAASampleCount;
+            bool               fDeepColor;
+#endif
+        };
 
-
-        virtual void setUpBackend(SampleWindow* win, int msaaSampleCount, bool deepColor) = 0;
+        virtual void setUpBackend(SampleWindow* win, const BackendOptions&) = 0;
 
         virtual void tearDownBackend(SampleWindow* win) = 0;
 
@@ -219,8 +229,8 @@ private:
     int fFilterQualityIndex;
     unsigned   fFlipAxis;
 
-    int fMSAASampleCount;
-    bool fDeepColor;
+    DeviceManager::BackendOptions fBackendOptions;
+
     int fColorConfigIndex;
 
     SkScalar fZoomCenterX, fZoomCenterY;
index 8460702a44b8a4baa0d338b207fcdb63a65e25f1..4b1324e33eb84871cac6a04e996491ec8eda8a80 100644 (file)
@@ -99,9 +99,8 @@ void GrContext::initCommon(const GrContextOptions& options) {
     rtOpListOptions.fMaxOpCombineLookback = options.fMaxOpCombineLookback;
     rtOpListOptions.fMaxOpCombineLookahead = options.fMaxOpCombineLookahead;
     GrPathRendererChain::Options prcOptions;
-    prcOptions.fDisableDistanceFieldRenderer = options.fDisableDistanceFieldPaths;
     prcOptions.fAllowPathMaskCaching = options.fAllowPathMaskCaching;
-    prcOptions.fDisableAllPathRenderers = options.fForceSWPathMasks;
+    prcOptions.fGpuPathRenderers = options.fGpuPathRenderers;
     fDrawingManager.reset(new GrDrawingManager(this, rtOpListOptions, prcOptions,
                                                options.fImmediateMode, &fSingleOwner));
 
index c0cac80dff0a9300d969c5c62547b58dd3bfd588..4b4ae26d6a38b1b556819c18818522f48ce9b957 100644 (file)
 #include "ops/GrTessellatingPathRenderer.h"
 
 GrPathRendererChain::GrPathRendererChain(GrContext* context, const Options& options) {
-    if (!options.fDisableAllPathRenderers) {
-        const GrCaps& caps = *context->caps();
-        this->addPathRenderer(new GrDashLinePathRenderer)->unref();
-
-        if (GrPathRenderer* pr = GrStencilAndCoverPathRenderer::Create(context->resourceProvider(),
-                                                                       caps)) {
-            this->addPathRenderer(pr)->unref();
+    using GpuPathRenderers = GrContextOptions::GpuPathRenderers;
+    const GrCaps& caps = *context->caps();
+    if (options.fGpuPathRenderers & GpuPathRenderers::kDashLine) {
+        fChain.push_back(sk_make_sp<GrDashLinePathRenderer>());
+    }
+    if (options.fGpuPathRenderers & GpuPathRenderers::kStencilAndCover) {
+        sk_sp<GrPathRenderer> pr(
+            GrStencilAndCoverPathRenderer::Create(context->resourceProvider(), caps));
+        if (pr) {
+            fChain.push_back(std::move(pr));
         }
-    #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    }
+#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    if (options.fGpuPathRenderers & GpuPathRenderers::kMSAA) {
         if (caps.sampleShadingSupport()) {
-            this->addPathRenderer(new GrMSAAPathRenderer)->unref();
+            fChain.push_back(sk_make_sp<GrMSAAPathRenderer>());
         }
-    #endif
-        this->addPathRenderer(new GrAAHairLinePathRenderer)->unref();
-        this->addPathRenderer(new GrAAConvexPathRenderer)->unref();
-        this->addPathRenderer(new GrAALinearizingConvexPathRenderer)->unref();
+    }
+#endif
+    if (options.fGpuPathRenderers & GpuPathRenderers::kAAHairline) {
+        fChain.push_back(sk_make_sp<GrAAHairLinePathRenderer>());
+    }
+    if (options.fGpuPathRenderers & GpuPathRenderers::kAAConvex) {
+        fChain.push_back(sk_make_sp<GrAAConvexPathRenderer>());
+    }
+    if (options.fGpuPathRenderers & GpuPathRenderers::kAALinearizing) {
+        fChain.push_back(sk_make_sp<GrAALinearizingConvexPathRenderer>());
+    }
+    if (options.fGpuPathRenderers & GpuPathRenderers::kPLS) {
         if (caps.shaderCaps()->plsPathRenderingSupport()) {
-            this->addPathRenderer(new GrPLSPathRenderer)->unref();
-        }
-        if (!options.fDisableDistanceFieldRenderer) {
-            this->addPathRenderer(new GrAADistanceFieldPathRenderer)->unref();
+            fChain.push_back(sk_make_sp<GrPLSPathRenderer>());
         }
-        this->addPathRenderer(new GrTessellatingPathRenderer)->unref();
-        this->addPathRenderer(new GrDefaultPathRenderer(caps.twoSidedStencilSupport(),
-                                                        caps.stencilWrapOpsSupport()))->unref();
     }
-}
-
-GrPathRendererChain::~GrPathRendererChain() {
-    for (int i = 0; i < fChain.count(); ++i) {
-        fChain[i]->unref();
+    if (options.fGpuPathRenderers & GpuPathRenderers::kDistanceField) {
+        fChain.push_back(sk_make_sp<GrAADistanceFieldPathRenderer>());
+    }
+    if (options.fGpuPathRenderers & GpuPathRenderers::kTesselating) {
+        fChain.push_back(sk_make_sp<GrTessellatingPathRenderer>());
+    }
+    if (options.fGpuPathRenderers & GpuPathRenderers::kDefault) {
+        fChain.push_back(sk_make_sp<GrDefaultPathRenderer>(caps.twoSidedStencilSupport(),
+                                                           caps.stencilWrapOpsSupport()));
     }
-}
-
-GrPathRenderer* GrPathRendererChain::addPathRenderer(GrPathRenderer* pr) {
-    fChain.push_back() = pr;
-    pr->ref();
-    return pr;
 }
 
 GrPathRenderer* GrPathRendererChain::getPathRenderer(
@@ -99,7 +104,7 @@ GrPathRenderer* GrPathRendererChain::getPathRenderer(
                     *stencilSupport = support;
                 }
             }
-            return fChain[i];
+            return fChain[i].get();
         }
     }
     return nullptr;
index 9a1a8fe108d4ecc7b83a39e22a78ced79495f181..c0a0ee39f56809066385ea701e52df2dd51ae5d5 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "GrPathRenderer.h"
 
+#include "GrContextOptions.h"
 #include "SkTypes.h"
 #include "SkTArray.h"
 
@@ -24,14 +25,12 @@ class GrContext;
 class GrPathRendererChain : public SkNoncopyable {
 public:
     struct Options {
-        bool fDisableDistanceFieldRenderer = false;
+        using GpuPathRenderers = GrContextOptions::GpuPathRenderers;
         bool fAllowPathMaskCaching = false;
-        bool fDisableAllPathRenderers = false;
+        GpuPathRenderers fGpuPathRenderers = GpuPathRenderers::kAll;
     };
     GrPathRendererChain(GrContext* context, const Options&);
 
-    ~GrPathRendererChain();
-
     /** Documents how the caller plans to use a GrPathRenderer to draw a path. It affects the PR
         returned by getPathRenderer */
     enum class DrawType {
@@ -49,13 +48,10 @@ public:
                                     GrPathRenderer::StencilSupport* stencilSupport);
 
 private:
-    // takes a ref and unrefs in destructor
-    GrPathRenderer* addPathRenderer(GrPathRenderer* pr);
-
     enum {
         kPreAllocCount = 8,
     };
-    SkSTArray<kPreAllocCount, GrPathRenderer*, true>    fChain;
+    SkSTArray<kPreAllocCount, sk_sp<GrPathRenderer>>    fChain;
 };
 
 #endif
index 4c252215a95a2c3c3605a8545cffab5cbdd6966a..370fb0713bedca526d1836d5a9d85eca950a47d0 100644 (file)
@@ -258,7 +258,9 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
     this->initGLSL(ctxInfo);
     GrShaderCaps* shaderCaps = fShaderCaps.get();
 
-    shaderCaps->fPathRenderingSupport = this->hasPathRenderingSupport(ctxInfo, gli);
+    if (!contextOptions.fSuppressPathRendering) {
+        shaderCaps->fPathRenderingSupport = this->hasPathRenderingSupport(ctxInfo, gli);
+    }
 
     // For now these two are equivalent but we could have dst read in shader via some other method.
     // Before setting this, initGLSL() must have been called.
index 45d84add8dfdc15e3313694a5719176f82abe2b1..3714dcb86e08fb109b2026805313128f95c363e9 100644 (file)
@@ -29,37 +29,6 @@ const GrGLInterface* GrGLInterfaceAddTestDebugMarker(const GrGLInterface* interf
     return newInterface;
 }
 
-const GrGLInterface* GrGLInterfaceRemoveNVPR(const GrGLInterface* interface) {
-    GrGLInterface* newInterface = GrGLInterface::NewClone(interface);
-
-    newInterface->fExtensions.remove("GL_NV_path_rendering");
-    newInterface->fExtensions.remove("GL_CHROMIUM_path_rendering");
-    newInterface->fFunctions.fMatrixLoadf = nullptr;
-    newInterface->fFunctions.fMatrixLoadIdentity = nullptr;
-    newInterface->fFunctions.fPathCommands = nullptr;
-    newInterface->fFunctions.fPathParameteri = nullptr;
-    newInterface->fFunctions.fPathParameterf = nullptr;
-    newInterface->fFunctions.fGenPaths = nullptr;
-    newInterface->fFunctions.fDeletePaths = nullptr;
-    newInterface->fFunctions.fIsPath = nullptr;
-    newInterface->fFunctions.fPathStencilFunc = nullptr;
-    newInterface->fFunctions.fStencilFillPath = nullptr;
-    newInterface->fFunctions.fStencilStrokePath = nullptr;
-    newInterface->fFunctions.fStencilFillPathInstanced = nullptr;
-    newInterface->fFunctions.fStencilStrokePathInstanced = nullptr;
-    newInterface->fFunctions.fCoverFillPath = nullptr;
-    newInterface->fFunctions.fCoverStrokePath = nullptr;
-    newInterface->fFunctions.fCoverFillPathInstanced = nullptr;
-    newInterface->fFunctions.fCoverStrokePathInstanced = nullptr;
-    newInterface->fFunctions.fStencilThenCoverFillPath = nullptr;
-    newInterface->fFunctions.fStencilThenCoverStrokePath = nullptr;
-    newInterface->fFunctions.fStencilThenCoverFillPathInstanced = nullptr;
-    newInterface->fFunctions.fStencilThenCoverStrokePathInstanced = nullptr;
-    newInterface->fFunctions.fProgramPathFragmentInputGen = nullptr;
-    newInterface->fFunctions.fBindFragmentInputLocation = nullptr;
-    return newInterface;
-}
-
 GrGLInterface::GrGLInterface() {
     fStandard = kNone_GrGLStandard;
 }
diff --git a/tools/flags/SkCommonFlagsPathRenderer.h b/tools/flags/SkCommonFlagsPathRenderer.h
new file mode 100644 (file)
index 0000000..d3b80f5
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SK_COMMON_FLAGS_PATH_RENDERER_H
+#define SK_COMMON_FLAGS_PATH_RENDERER_H
+
+#if SK_SUPPORT_GPU
+
+#include "GrContextFactory.h"
+#include "SkCommandLineFlags.h"
+#include "SkTypes.h"
+
+DECLARE_string(pr);
+
+#define DEFINE_pathrenderer_flag \
+    DEFINE_string(pr, "all", \
+                  "Set of enabled gpu path renderers. Defined as a list of: " \
+                    "[[~]all [~]dashline [~]nvpr [~]msaa [~]aahairline [~]aaconvex " \
+                    "[~]aalinearizing [~]pls [~]sdf [~]tess [~]grdefault]")
+
+inline GrContextOptions::GpuPathRenderers get_named_pathrenderers_flags(const char* name) {
+    using GpuPathRenderers = GrContextOptions::GpuPathRenderers;
+    if (!strcmp(name, "all")) {
+        return GpuPathRenderers::kAll;
+    } else if (!strcmp(name, "dashline")) {
+        return GpuPathRenderers::kDashLine;
+    } else if (!strcmp(name, "nvpr")) {
+        return GpuPathRenderers::kStencilAndCover;
+    } else if (!strcmp(name, "msaa")) {
+        return GpuPathRenderers::kMSAA;
+    } else if (!strcmp(name, "aahairline")) {
+        return GpuPathRenderers::kAAHairline;
+    } else if (!strcmp(name, "aaconvex")) {
+        return GpuPathRenderers::kAAConvex;
+    } else if (!strcmp(name, "aalinearizing")) {
+        return GpuPathRenderers::kAALinearizing;
+    } else if (!strcmp(name, "pls")) {
+        return GpuPathRenderers::kPLS;
+    } else if (!strcmp(name, "sdf")) {
+        return GpuPathRenderers::kDistanceField;
+    } else if (!strcmp(name, "tess")) {
+        return GpuPathRenderers::kTesselating;
+    } else if (!strcmp(name, "grdefault")) {
+        return GpuPathRenderers::kDefault;
+    }
+    SK_ABORT(SkStringPrintf("error: unknown named path renderer \"%s\"\n", name).c_str());
+    return GpuPathRenderers::kNone;
+}
+
+inline GrContextOptions::GpuPathRenderers CollectGpuPathRenderersFromFlags() {
+    using GpuPathRenderers = GrContextOptions::GpuPathRenderers;
+    if (FLAGS_pr.isEmpty()) {
+        return GpuPathRenderers::kAll;
+    }
+    GpuPathRenderers gpuPathRenderers = '~' == FLAGS_pr[0][0] ?
+                                        GpuPathRenderers::kAll : GpuPathRenderers::kNone;
+    for (int i = 0; i < FLAGS_pr.count(); ++i) {
+        const char* name = FLAGS_pr[i];
+        if (name[0] == '~') {
+            gpuPathRenderers &= ~get_named_pathrenderers_flags(&name[1]);
+        } else {
+            gpuPathRenderers |= get_named_pathrenderers_flags(name);
+        }
+    }
+    return gpuPathRenderers;
+}
+
+#endif // SK_SUPPORT_GPU
+
+#endif
index 965e646e59752b14295c11e82c0a52595fb7af64..637c569f898f6149c1645f82a18607268e4cb6be 100644 (file)
@@ -196,12 +196,6 @@ ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOverrides
             }
             testCtx.reset(glCtx);
             glInterface.reset(SkRef(glCtx->gl()));
-            if (ContextOverrides::kDisableNVPR & overrides) {
-                glInterface.reset(GrGLInterfaceRemoveNVPR(glInterface.get()));
-                if (!glInterface) {
-                    return ContextInfo();
-                }
-            }
             backendContext = reinterpret_cast<GrBackendContext>(glInterface.get());
             break;
         }
@@ -238,6 +232,9 @@ ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOverrides
     testCtx->makeCurrent();
     SkASSERT(testCtx && testCtx->backend() == backend);
     GrContextOptions grOptions = fGlobalOptions;
+    if (ContextOverrides::kDisableNVPR & overrides) {
+        grOptions.fSuppressPathRendering = true;
+    }
     if (ContextOverrides::kUseInstanced & overrides) {
         grOptions.fEnableInstancedRendering = true;
     }
index 3887c5ea88fce047b34e90ed89619863fe8dd4f6..569c204a72a4be2509dd189a7bd6d4f6449b77cc 100644 (file)
@@ -8,6 +8,7 @@
 #include "GpuTimer.h"
 #include "GrContextFactory.h"
 #include "SkCanvas.h"
+#include "SkCommonFlagsPathRenderer.h"
 #include "SkOSFile.h"
 #include "SkOSPath.h"
 #include "SkPerlinNoiseShader.h"
@@ -46,6 +47,7 @@ DEFINE_string(skp, "", "path to a single .skp file, or 'warmup' for a builtin wa
 DEFINE_string(png, "", "if set, save a .png proof to disk at this file location");
 DEFINE_int32(verbosity, 4, "level of verbosity (0=none to 5=debug)");
 DEFINE_bool(suppressHeader, false, "don't print a header row before the results");
+DEFINE_pathrenderer_flag;
 
 static const char* header =
 "   accum    median       max       min   stddev  samples  sample_ms  clock  metric  config    bench";
@@ -271,7 +273,9 @@ int main(int argc, char** argv) {
     }
 
     // Create a context.
-    sk_gpu_test::GrContextFactory factory;
+    GrContextOptions ctxOptions;
+    ctxOptions.fGpuPathRenderers = CollectGpuPathRenderersFromFlags();
+    sk_gpu_test::GrContextFactory factory(ctxOptions);
     sk_gpu_test::ContextInfo ctxInfo =
         factory.getContextInfo(config->getContextType(), config->getContextOverrides());
     GrContext* ctx = ctxInfo.grContext();
index 57185d2c3b6ce9873e9f5cd684e599eb041b0c8d..092910a724b04ed8de624c0c5b2c923a3b5e753f 100644 (file)
@@ -16,6 +16,7 @@
 #include "SkATrace.h"
 #include "SkCanvas.h"
 #include "SkCommandLineFlags.h"
+#include "SkCommonFlagsPathRenderer.h"
 #include "SkDashPathEffect.h"
 #include "SkGraphics.h"
 #include "SkImagePriv.h"
@@ -134,6 +135,8 @@ static DEFINE_string2(backend, b, "sw", "Backend to use. Allowed values are " BA
 
 static DEFINE_bool(atrace, false, "Enable support for using ATrace. ATrace is only supported on Android.");
 
+DEFINE_pathrenderer_flag;
+
 const char *kBackendTypeStrings[sk_app::Window::kBackendTypeCount] = {
     " [OpenGL]",
 #ifdef SK_VULKAN
index 501f272a3ebc0725988a6332f9b40f82d3f19834..fac0c328c4e288da7b9b9e1c47de35d37024ef05 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include "GrContext.h"
+#include "SkCommonFlagsPathRenderer.h"
 #include "SkSurface.h"
 #include "GLWindowContext.h"
 
@@ -30,12 +31,13 @@ GLWindowContext::GLWindowContext(const DisplayParams& params)
 
 void GLWindowContext::initializeContext() {
     this->onInitializeContext();
-    sk_sp<const GrGLInterface> glInterface;
-    glInterface.reset(GrGLCreateNativeInterface());
-    fBackendContext.reset(GrGLInterfaceRemoveNVPR(glInterface.get()));
-
     SkASSERT(nullptr == fContext);
-    fContext = GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)fBackendContext.get());
+
+    GrContextOptions ctxOptions;
+    ctxOptions.fGpuPathRenderers = CollectGpuPathRenderersFromFlags();
+    fBackendContext.reset(GrGLCreateNativeInterface());
+    fContext = GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)fBackendContext.get(),
+                                 ctxOptions);
 
     // We may not have real sRGB support (ANGLE, in particular), so check for
     // that, and fall back to L32:
index b4e6676335d236c42bd51c6463649d55f6a1d738..65273b05d097cee486e4412057863d213011fac6 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "GrContext.h"
 #include "GrRenderTarget.h"
+#include "SkCommonFlagsPathRenderer.h"
 #include "SkAutoMalloc.h"
 #include "SkSurface.h"
 #include "VulkanWindowContext.h"
@@ -61,7 +62,10 @@ VulkanWindowContext::VulkanWindowContext(const DisplayParams& params,
     GET_DEV_PROC(AcquireNextImageKHR);
     GET_DEV_PROC(QueuePresentKHR);
 
-    fContext = GrContext::Create(kVulkan_GrBackend, (GrBackendContext) fBackendContext.get());
+    GrContextOptions ctxOptions;
+    ctxOptions.fGpuPathRenderers = CollectGpuPathRenderersFromFlags();
+    fContext = GrContext::Create(kVulkan_GrBackend, (GrBackendContext) fBackendContext.get(),
+                                 ctxOptions);
 
     fSurface = createVkSurface(instance);
     if (VK_NULL_HANDLE == fSurface) {