diff options
-rw-r--r-- | bench/nanobench.cpp | 59 | ||||
-rw-r--r-- | bench/nanobench.h | 2 | ||||
-rw-r--r-- | dm/DM.cpp | 12 | ||||
-rw-r--r-- | dm/DMGpuSupport.h | 8 | ||||
-rw-r--r-- | dm/DMSrcSink.cpp | 30 | ||||
-rw-r--r-- | dm/DMSrcSink.h | 16 | ||||
-rwxr-xr-x | src/gpu/GrContextFactory.cpp | 19 | ||||
-rw-r--r-- | src/gpu/GrContextFactory.h | 45 | ||||
-rwxr-xr-x | tests/GLInterfaceValidationTest.cpp | 39 | ||||
-rw-r--r-- | tests/GrContextFactoryTest.cpp | 18 | ||||
-rw-r--r-- | tools/PictureRenderer.h | 707 |
11 files changed, 863 insertions, 92 deletions
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp index 99483ebd99..6c42097f18 100644 --- a/bench/nanobench.cpp +++ b/bench/nanobench.cpp @@ -169,10 +169,13 @@ struct GPUTarget : public Target { uint32_t flags = this->config.useDFText ? SkSurfaceProps::kUseDeviceIndependentFonts_Flag : 0; SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType); - this->surface.reset(SkSurface::NewRenderTarget(gGrFactory->get(this->config.ctxType), + this->surface.reset(SkSurface::NewRenderTarget(gGrFactory->get(this->config.ctxType, + kNone_GrGLStandard, + this->config.ctxOptions), SkSurface::kNo_Budgeted, info, this->config.samples, &props)); - this->gl = gGrFactory->getContextInfo(this->config.ctxType)->fGLContext; + this->gl = gGrFactory->getContextInfo(this->config.ctxType, kNone_GrGLStandard, + this->config.ctxOptions)->fGLContext; if (!this->surface.get()) { return false; } @@ -384,11 +387,12 @@ static bool is_cpu_config_allowed(const char* name) { #if SK_SUPPORT_GPU static bool is_gpu_config_allowed(const char* name, GrContextFactory::GLContextType ctxType, + GrContextFactory::GLContextOptions ctxOptions, int sampleCnt) { if (!is_cpu_config_allowed(name)) { return false; } - if (const GrContext* ctx = gGrFactory->get(ctxType)) { + if (const GrContext* ctx = gGrFactory->get(ctxType, kNone_GrGLStandard, ctxOptions)) { return sampleCnt <= ctx->caps()->maxSampleCount(); } return false; @@ -397,17 +401,20 @@ static bool is_gpu_config_allowed(const char* name, GrContextFactory::GLContextT #if SK_SUPPORT_GPU #define kBogusGLContextType GrContextFactory::kNative_GLContextType +#define kBogusGLContextOptions GrContextFactory::kNone_GLContextOptions #else #define kBogusGLContextType 0 +#define kBogusGLContextOptions 0 #endif // Append all configs that are enabled and supported. static void create_configs(SkTDArray<Config>* configs) { - #define CPU_CONFIG(name, backend, color, alpha) \ - if (is_cpu_config_allowed(#name)) { \ - Config config = { #name, Benchmark::backend, color, alpha, 0, \ - kBogusGLContextType, false }; \ - configs->push(config); \ + #define CPU_CONFIG(name, backend, color, alpha) \ + if (is_cpu_config_allowed(#name)) { \ + Config config = { #name, Benchmark::backend, color, alpha, 0, \ + kBogusGLContextType, kBogusGLContextOptions, \ + false }; \ + configs->push(config); \ } if (FLAGS_cpu) { @@ -417,8 +424,9 @@ static void create_configs(SkTDArray<Config>* configs) { } #if SK_SUPPORT_GPU - #define GPU_CONFIG(name, ctxType, samples, useDFText) \ - if (is_gpu_config_allowed(#name, GrContextFactory::ctxType, samples)) { \ + #define GPU_CONFIG(name, ctxType, ctxOptions, samples, useDFText) \ + if (is_gpu_config_allowed(#name, GrContextFactory::ctxType, \ + GrContextFactory::ctxOptions, samples)) { \ Config config = { \ #name, \ Benchmark::kGPU_Backend, \ @@ -426,28 +434,29 @@ static void create_configs(SkTDArray<Config>* configs) { kPremul_SkAlphaType, \ samples, \ GrContextFactory::ctxType, \ + GrContextFactory::ctxOptions, \ useDFText }; \ configs->push(config); \ } if (FLAGS_gpu) { - GPU_CONFIG(gpu, kNative_GLContextType, 0, false) - GPU_CONFIG(msaa4, kNative_GLContextType, 4, false) - GPU_CONFIG(msaa16, kNative_GLContextType, 16, false) - GPU_CONFIG(nvprmsaa4, kNVPR_GLContextType, 4, false) - GPU_CONFIG(nvprmsaa16, kNVPR_GLContextType, 16, false) - GPU_CONFIG(gpudft, kNative_GLContextType, 0, true) - GPU_CONFIG(debug, kDebug_GLContextType, 0, false) - GPU_CONFIG(nullgpu, kNull_GLContextType, 0, false) + GPU_CONFIG(gpu, kNative_GLContextType, kNone_GLContextOptions, 0, false) + GPU_CONFIG(msaa4, kNative_GLContextType, kNone_GLContextOptions, 4, false) + GPU_CONFIG(msaa16, kNative_GLContextType, kNone_GLContextOptions, 16, false) + GPU_CONFIG(nvprmsaa4, kNative_GLContextType, kEnableNVPR_GLContextOptions, 4, false) + GPU_CONFIG(nvprmsaa16, kNative_GLContextType, kEnableNVPR_GLContextOptions, 16, false) + GPU_CONFIG(gpudft, kNative_GLContextType, kNone_GLContextOptions, 0, true) + GPU_CONFIG(debug, kDebug_GLContextType, kNone_GLContextOptions, 0, false) + GPU_CONFIG(nullgpu, kNull_GLContextType, kNone_GLContextOptions, 0, false) #ifdef SK_ANGLE - GPU_CONFIG(angle, kANGLE_GLContextType, 0, false) - GPU_CONFIG(angle-gl, kANGLE_GL_GLContextType, 0, false) + GPU_CONFIG(angle, kANGLE_GLContextType, kNone_GLContextOptions, 0, false) + GPU_CONFIG(angle-gl, kANGLE_GL_GLContextType, kNone_GLContextOptions, 0, false) #endif #ifdef SK_COMMAND_BUFFER - GPU_CONFIG(commandbuffer, kCommandBuffer_GLContextType, 0, false) + GPU_CONFIG(commandbuffer, kCommandBuffer_GLContextType, kNone_GLContextOptions, 0, false) #endif #if SK_MESA - GPU_CONFIG(mesa, kMESA_GLContextType, 0, false) + GPU_CONFIG(mesa, kMESA_GLContextType, kNone_GLContextOptions, 0, false) #endif } #endif @@ -1243,8 +1252,10 @@ int nanobench_main() { #if SK_SUPPORT_GPU if (FLAGS_gpuStats && Benchmark::kGPU_Backend == configs[i].backend) { - gGrFactory->get(configs[i].ctxType)->printCacheStats(); - gGrFactory->get(configs[i].ctxType)->printGpuStats(); + GrContext* context = gGrFactory->get(configs[i].ctxType, + kNone_GrGLStandard, configs[i].ctxOptions); + context->printCacheStats(); + context->printGpuStats(); } #endif if (FLAGS_verbose) { diff --git a/bench/nanobench.h b/bench/nanobench.h index 36f5ad5b75..2dac30a927 100644 --- a/bench/nanobench.h +++ b/bench/nanobench.h @@ -29,9 +29,11 @@ struct Config { int samples; #if SK_SUPPORT_GPU GrContextFactory::GLContextType ctxType; + GrContextFactory::GLContextOptions ctxOptions; bool useDFText; #else int bogusInt; + int bogusIntOption; bool bogusBool; #endif }; @@ -609,8 +609,8 @@ static Sink* create_sink(const char* tag) { SINK("gpudft", GPUSink, Gr::kNative_GLContextType, api, 0, true, FLAGS_gpu_threading); SINK("msaa4", GPUSink, Gr::kNative_GLContextType, api, 4, false, FLAGS_gpu_threading); SINK("msaa16", GPUSink, Gr::kNative_GLContextType, api, 16, false, FLAGS_gpu_threading); - SINK("nvprmsaa4", GPUSink, Gr::kNVPR_GLContextType, api, 4, true, FLAGS_gpu_threading); - SINK("nvprmsaa16", GPUSink, Gr::kNVPR_GLContextType, api, 16, true, FLAGS_gpu_threading); + SINK("nvprmsaa4", GPUSink, Gr::kNative_GLContextType, Gr::kEnableNVPR_GLContextOptions, api, 4, true, FLAGS_gpu_threading); + SINK("nvprmsaa16", GPUSink, Gr::kNative_GLContextType, Gr::kEnableNVPR_GLContextOptions, api, 16, true, FLAGS_gpu_threading); #if SK_ANGLE SINK("angle", GPUSink, Gr::kANGLE_GLContextType, api, 0, false, FLAGS_gpu_threading); SINK("angle-gl", GPUSink, Gr::kANGLE_GL_GLContextType, api, 0, false, FLAGS_gpu_threading); @@ -1171,6 +1171,7 @@ template<typename T> void RunWithGPUTestContexts(T test, GPUTestContexts testContexts, Reporter* reporter, GrContextFactory* factory) { #if SK_SUPPORT_GPU + const GrGLStandard api = get_gpu_api(); for (int i = 0; i < GrContextFactory::kGLContextTypeCnt; ++i) { GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i; int contextSelector = kNone_GPUTestContexts; @@ -1186,7 +1187,12 @@ void RunWithGPUTestContexts(T test, GPUTestContexts testContexts, Reporter* repo if ((testContexts & contextSelector) == 0) { continue; } - if (GrContextFactory::ContextInfo* context = factory->getContextInfo(glCtxType)) { + if (GrContextFactory::ContextInfo* context = factory->getContextInfo(glCtxType, api)) { + call_test(test, reporter, context); + } + if (GrContextFactory::ContextInfo* context = + factory->getContextInfo(glCtxType, api, + GrContextFactory::kEnableNVPR_GLContextOptions)) { call_test(test, reporter, context); } } diff --git a/dm/DMGpuSupport.h b/dm/DMGpuSupport.h index 9f20dd51da..6a59558f55 100644 --- a/dm/DMGpuSupport.h +++ b/dm/DMGpuSupport.h @@ -26,13 +26,14 @@ static const bool kGPUDisabled = false; static inline SkSurface* NewGpuSurface(GrContextFactory* grFactory, GrContextFactory::GLContextType type, + GrContextFactory::GLContextOptions options, GrGLStandard gpuAPI, SkImageInfo info, int samples, bool useDIText) { uint32_t flags = useDIText ? SkSurfaceProps::kUseDeviceIndependentFonts_Flag : 0; SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType); - return SkSurface::NewRenderTarget(grFactory->get(type, gpuAPI), SkSurface::kNo_Budgeted, + return SkSurface::NewRenderTarget(grFactory->get(type, gpuAPI, options), SkSurface::kNo_Budgeted, info, samples, &props); } @@ -76,6 +77,10 @@ public: kNative_GLContextType = 0, kNull_GLContextType = 0; static const int kGLContextTypeCnt = 1; + enum GLContextOptions { + kNone_GLContextOptions = 0, + kEnableNVPR_GLContextOptions = 0x1, + }; void destroyContexts() {} void abandonContexts() {} @@ -87,6 +92,7 @@ static const bool kGPUDisabled = true; static inline SkSurface* NewGpuSurface(GrContextFactory*, GrContextFactory::GLContextType, + GrContextFactory::GLContextOptions, GrGLStandard, SkImageInfo, int, diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp index 2861ae8ea2..365ebc267f 100644 --- a/dm/DMSrcSink.cpp +++ b/dm/DMSrcSink.cpp @@ -789,12 +789,26 @@ Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const { DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?"); GPUSink::GPUSink(GrContextFactory::GLContextType ct, - GrGLStandard api, + GrGLStandard gpuAPI, int samples, bool diText, bool threaded) : fContextType(ct) - , fGpuAPI(api) + , fContextOptions(GrContextFactory::kNone_GLContextOptions) + , fGpuAPI(gpuAPI) + , fSampleCount(samples) + , fUseDIText(diText) + , fThreaded(threaded) {} + +GPUSink::GPUSink(GrContextFactory::GLContextType ct, + GrContextFactory::GLContextOptions options, + GrGLStandard gpuAPI, + int samples, + bool diText, + bool threaded) + : fContextType(ct) + , fContextOptions(options) + , fGpuAPI(gpuAPI) , fSampleCount(samples) , fUseDIText(diText) , fThreaded(threaded) {} @@ -809,21 +823,21 @@ DEFINE_bool(imm, false, "Run gpu configs in immediate mode."); DEFINE_bool(batchClip, false, "Clip each GrBatch to its device bounds for testing."); Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const { - GrContextOptions options; + GrContextOptions grOptions; if (FLAGS_imm) { - options.fImmediateMode = true; + grOptions.fImmediateMode = true; } if (FLAGS_batchClip) { - options.fClipBatchToBounds = true; + grOptions.fClipBatchToBounds = true; } - src.modifyGrContextOptions(&options); + src.modifyGrContextOptions(&grOptions); - GrContextFactory factory(options); + GrContextFactory factory(grOptions); const SkISize size = src.size(); const SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), kN32_SkColorType, kPremul_SkAlphaType); SkAutoTUnref<SkSurface> surface( - NewGpuSurface(&factory, fContextType, fGpuAPI, info, fSampleCount, fUseDIText)); + NewGpuSurface(&factory, fContextType, fContextOptions, fGpuAPI, info, fSampleCount, fUseDIText)); if (!surface) { return "Could not create a surface."; } diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h index e155508ac2..63d6717e78 100644 --- a/dm/DMSrcSink.h +++ b/dm/DMSrcSink.h @@ -214,18 +214,22 @@ public: class GPUSink : public Sink { public: - GPUSink(GrContextFactory::GLContextType, GrGLStandard, int samples, bool diText, bool threaded); + GPUSink(GrContextFactory::GLContextType, GrGLStandard, int samples, + bool diText, bool threaded); + GPUSink(GrContextFactory::GLContextType, GrContextFactory::GLContextOptions, + GrGLStandard, int samples, bool diText, bool threaded); Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; int enclave() const override; const char* fileExtension() const override { return "png"; } SinkFlags flags() const override { return SinkFlags{ SinkFlags::kGPU, SinkFlags::kDirect }; } private: - GrContextFactory::GLContextType fContextType; - GrGLStandard fGpuAPI; - int fSampleCount; - bool fUseDIText; - bool fThreaded; + GrContextFactory::GLContextType fContextType; + GrContextFactory::GLContextOptions fContextOptions; + GrGLStandard fGpuAPI; + int fSampleCount; + bool fUseDIText; + bool fThreaded; }; class PDFSink : public Sink { diff --git a/src/gpu/GrContextFactory.cpp b/src/gpu/GrContextFactory.cpp index 424b3fda3a..19382ee112 100755 --- a/src/gpu/GrContextFactory.cpp +++ b/src/gpu/GrContextFactory.cpp @@ -24,21 +24,21 @@ #include "GrCaps.h" GrContextFactory::ContextInfo* GrContextFactory::getContextInfo(GLContextType type, - GrGLStandard forcedGpuAPI) { + GrGLStandard forcedGpuAPI, + GLContextOptions options) { for (int i = 0; i < fContexts.count(); ++i) { - if (forcedGpuAPI != kNone_GrGLStandard && - forcedGpuAPI != fContexts[i]->fGLContext->gl()->fStandard) - continue; - - if (fContexts[i]->fType == type) { + if (fContexts[i]->fType == type && + fContexts[i]->fOptions == options && + (forcedGpuAPI == kNone_GrGLStandard || + forcedGpuAPI == fContexts[i]->fGLContext->gl()->fStandard)) { fContexts[i]->fGLContext->makeCurrent(); return fContexts[i]; } } + SkAutoTUnref<SkGLContext> glCtx; SkAutoTUnref<GrContext> grCtx; switch (type) { - case kNVPR_GLContextType: // fallthru case kNative_GLContextType: glCtx.reset(SkCreatePlatformGLContext(forcedGpuAPI)); break; @@ -75,7 +75,7 @@ GrContextFactory::ContextInfo* GrContextFactory::getContextInfo(GLContextType ty // Block NVPR from non-NVPR types. SkAutoTUnref<const GrGLInterface> glInterface(SkRef(glCtx->gl())); - if (kNVPR_GLContextType != type) { + if (!(kEnableNVPR_GLContextOptions & options)) { glInterface.reset(GrGLInterfaceRemoveNVPR(glInterface)); if (!glInterface) { return nullptr; @@ -97,7 +97,7 @@ GrContextFactory::ContextInfo* GrContextFactory::getContextInfo(GLContextType ty return nullptr; } // Warn if path rendering support is not available for the NVPR type. - if (kNVPR_GLContextType == type) { + if (kEnableNVPR_GLContextOptions & options) { if (!grCtx->caps()->shaderCaps()->pathRenderingSupport()) { GrGpu* gpu = grCtx->getGpu(); const GrGLContext* ctx = gpu->glContextForTesting(); @@ -119,5 +119,6 @@ GrContextFactory::ContextInfo* GrContextFactory::getContextInfo(GLContextType ty ctx->fGLContext = SkRef(glCtx.get()); ctx->fGrContext = SkRef(grCtx.get()); ctx->fType = type; + ctx->fOptions = options; return ctx; } diff --git a/src/gpu/GrContextFactory.h b/src/gpu/GrContextFactory.h index c837e74a25..3a71d80a0a 100644 --- a/src/gpu/GrContextFactory.h +++ b/src/gpu/GrContextFactory.h @@ -23,35 +23,34 @@ */ class GrContextFactory : SkNoncopyable { public: - /** - * Types of GL contexts supported. For historical and testing reasons the native GrContext will - * not use "GL_NV_path_rendering" even when the driver supports it. There is a separate context - * type that does not remove NVPR support and which will fail when the driver does not support - * the extension. - */ enum GLContextType { - kNative_GLContextType, + kNative_GLContextType, #if SK_ANGLE - kANGLE_GLContextType, - kANGLE_GL_GLContextType, + kANGLE_GLContextType, + kANGLE_GL_GLContextType, #endif #if SK_COMMAND_BUFFER - kCommandBuffer_GLContextType, + kCommandBuffer_GLContextType, #endif #if SK_MESA - kMESA_GLContextType, + kMESA_GLContextType, #endif - /** Similar to kNative but does not filter NVPR. It will fail if the GL driver does not - support NVPR */ - kNVPR_GLContextType, - kNull_GLContextType, - kDebug_GLContextType, - - kLastGLContextType = kDebug_GLContextType + kNull_GLContextType, + kDebug_GLContextType, + kLastGLContextType = kDebug_GLContextType }; static const int kGLContextTypeCnt = kLastGLContextType + 1; + /** + * Options for GL context creation. For historical and testing reasons the options will default + * to not using GL_NV_path_rendering extension even when the driver supports it. + */ + enum GLContextOptions { + kNone_GLContextOptions = 0, + kEnableNVPR_GLContextOptions = 0x1, + }; + static bool IsRenderingGLContext(GLContextType type) { switch (type) { case kNull_GLContextType: @@ -82,8 +81,6 @@ public: case kMESA_GLContextType: return "mesa"; #endif - case kNVPR_GLContextType: - return "nvpr"; case kDebug_GLContextType: return "debug"; default: @@ -119,6 +116,7 @@ public: struct ContextInfo { GLContextType fType; + GLContextOptions fOptions; SkGLContext* fGLContext; GrContext* fGrContext; }; @@ -126,13 +124,14 @@ public: * Get a context initialized with a type of GL context. It also makes the GL context current. * Pointer is valid until destroyContexts() is called. */ - ContextInfo* getContextInfo(GLContextType type, GrGLStandard forcedGpuAPI = kNone_GrGLStandard); + ContextInfo* getContextInfo(GLContextType type, GrGLStandard forcedGpuAPI = kNone_GrGLStandard, GLContextOptions options = kNone_GLContextOptions); /** * Get a GrContext initialized with a type of GL context. It also makes the GL context current. */ - GrContext* get(GLContextType type, GrGLStandard forcedGpuAPI = kNone_GrGLStandard) { - if (ContextInfo* info = this->getContextInfo(type, forcedGpuAPI)) { + GrContext* get(GLContextType type, GrGLStandard forcedGpuAPI = kNone_GrGLStandard, + GLContextOptions options = kNone_GLContextOptions) { + if (ContextInfo* info = this->getContextInfo(type, forcedGpuAPI, options)) { return info->fGrContext; } return nullptr; diff --git a/tests/GLInterfaceValidationTest.cpp b/tests/GLInterfaceValidationTest.cpp index 5736e2d2d6..b890b44e5f 100755 --- a/tests/GLInterfaceValidationTest.cpp +++ b/tests/GLInterfaceValidationTest.cpp @@ -12,28 +12,33 @@ #include "GrContextFactory.h" -DEF_GPUTEST(GLInterfaceValidation, reporter, factory) { - for (int i = 0; i <= GrContextFactory::kLastGLContextType; ++i) { - GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType)i; - // this forces the factory to make the context if it hasn't yet - GrContextFactory::ContextInfo* contextInfo = factory->getContextInfo(glCtxType); - SkGLContext* glCtx = contextInfo ? contextInfo->fGLContext : nullptr; - - // We're supposed to fail the NVPR context type when we the native context that does not - // support the NVPR extension. - if (GrContextFactory::kNVPR_GLContextType == glCtxType && - factory->getContextInfo(GrContextFactory::kNative_GLContextType) && - !factory->getContextInfo(GrContextFactory::kNative_GLContextType)->fGLContext->gl()->hasExtension("GL_NV_path_rendering")) { - REPORTER_ASSERT(reporter, nullptr == glCtx); +DEF_GPUTEST(GLInterfaceValidation, reporter, /*factory*/) { + GrContextFactory testFactory; + + // Test that if we do not have NV_path_rendering -related GL extensions, + // GrContextFactory::get(.., kEnableNVPR_GLContextOptions) always returns nullptr. + for (int i = 0; i < GrContextFactory::kGLContextTypeCnt; ++i) { + GrContextFactory::GLContextType glCtxType = static_cast<GrContextFactory::GLContextType>(i); + GrContextFactory::ContextInfo* context = + testFactory.getContextInfo(glCtxType, kNone_GrGLStandard, + GrContextFactory::kNone_GLContextOptions); + if (!context) { continue; } - REPORTER_ASSERT(reporter, glCtx); - if (glCtx) { - const GrGLInterface* interface = glCtx->gl(); - REPORTER_ASSERT(reporter, interface->validate()); + SkGLContext* glContext = context->fGLContext; + REPORTER_ASSERT(reporter, glContext->gl()->validate()); + + if (!(glContext->gl()->hasExtension("GL_NV_path_rendering") || + glContext->gl()->hasExtension("GL_CHROMIUM_path_rendering"))) { + REPORTER_ASSERT(reporter, + nullptr == testFactory.getContextInfo( + glCtxType, + kNone_GrGLStandard, + GrContextFactory::kEnableNVPR_GLContextOptions)); } } + } #endif diff --git a/tests/GrContextFactoryTest.cpp b/tests/GrContextFactoryTest.cpp index 79209c719f..ad83a344d8 100644 --- a/tests/GrContextFactoryTest.cpp +++ b/tests/GrContextFactoryTest.cpp @@ -10,8 +10,24 @@ #if SK_SUPPORT_GPU #include "GrContextFactory.h" +#include "GrCaps.h" #include "Test.h" -// TODO: test GrContextFactory. +DEF_GPUTEST(GrContextFactoryNVPRContextOptions, reporter, /*factory*/) { + GrContextFactory testFactory; + // Test that if NVPR is possible, caps are in sync. + for (int i = 0; i < GrContextFactory::kGLContextTypeCnt; ++i) { + GrContextFactory::GLContextType glCtxType = static_cast<GrContextFactory::GLContextType>(i); + GrContext* context = testFactory.get(glCtxType, + kNone_GrGLStandard, + GrContextFactory::kEnableNVPR_GLContextOptions); + if (!context) { + continue; + } + REPORTER_ASSERT( + reporter, + context->caps()->shaderCaps()->pathRenderingSupport()); + } +} #endif diff --git a/tools/PictureRenderer.h b/tools/PictureRenderer.h new file mode 100644 index 0000000000..63043a030b --- /dev/null +++ b/tools/PictureRenderer.h @@ -0,0 +1,707 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef PictureRenderer_DEFINED +#define PictureRenderer_DEFINED + +#include "SkCanvas.h" +#include "SkDrawFilter.h" +#include "SkJSONCPP.h" +#include "SkMath.h" +#include "SkPaint.h" +#include "SkPicture.h" +#include "SkPictureRecorder.h" +#include "SkRect.h" +#include "SkRefCnt.h" +#include "SkString.h" +#include "SkTDArray.h" +#include "SkTypes.h" + +#if SK_SUPPORT_GPU +#include "GrContextFactory.h" +#include "GrContext.h" +#endif + +struct GrContextOptions; +class SkBitmap; +class SkCanvas; +class SkGLContext; +class SkThread; + +namespace sk_tools { + +class TiledPictureRenderer; + +class PictureRenderer : public SkRefCnt { + +public: + enum SkDeviceTypes { +#if SK_ANGLE + kAngle_DeviceType, +#endif +#if SK_COMMAND_BUFFER + kCommandBuffer_DeviceType, +#endif +#if SK_MESA + kMesa_DeviceType, +#endif + kBitmap_DeviceType, +#if SK_SUPPORT_GPU + kGPU_DeviceType, + kNVPR_DeviceType, +#endif + }; + + enum BBoxHierarchyType { + kNone_BBoxHierarchyType = 0, + kRTree_BBoxHierarchyType, + + kLast_BBoxHierarchyType = kRTree_BBoxHierarchyType, + }; + + // this uses SkPaint::Flags as a base and adds additional flags + enum DrawFilterFlags { + kNone_DrawFilterFlag = 0, + kHinting_DrawFilterFlag = 0x10000, // toggles between no hinting and normal hinting + kSlightHinting_DrawFilterFlag = 0x20000, // toggles between slight and normal hinting + kAAClip_DrawFilterFlag = 0x40000, // toggles between soft and hard clip + kMaskFilter_DrawFilterFlag = 0x80000, // toggles on/off mask filters (e.g., blurs) + }; + + static_assert(!(kMaskFilter_DrawFilterFlag & SkPaint::kAllFlags), + "maskfilter_flag_must_be_greater"); + static_assert(!(kHinting_DrawFilterFlag & SkPaint::kAllFlags), + "hinting_flag_must_be_greater"); + static_assert(!(kSlightHinting_DrawFilterFlag & SkPaint::kAllFlags), + "slight_hinting_flag_must_be_greater"); + + /** + * Called with each new SkPicture to render. + * + * @param pict The SkPicture to render. + * @param writePath The output directory within which this renderer should write all images, + * or nullptr if this renderer should not write all images. + * @param mismatchPath The output directory within which this renderer should write any images + * which do not match expectations, or nullptr if this renderer should not write mismatches. + * @param inputFilename The name of the input file we are rendering. + * @param useChecksumBasedFilenames Whether to use checksum-based filenames when writing + * bitmap images to disk. + * @param useMultiPictureDraw true if MultiPictureDraw should be used for rendering + */ + virtual void init(const SkPicture* pict, + const SkString* writePath, + const SkString* mismatchPath, + const SkString* inputFilename, + bool useChecksumBasedFilenames, + bool useMultiPictureDraw); + + /** + * Set the viewport so that only the portion listed gets drawn. + */ + void setViewport(SkISize size) { fViewport = size; } + + /** + * Set the scale factor at which draw the picture. + */ + void setScaleFactor(SkScalar scale) { fScaleFactor = scale; } + + /** + * Perform any setup that should done prior to each iteration of render() which should not be + * timed. + */ + virtual void setup() {} + + /** + * Perform the work. If this is being called within the context of bench_pictures, + * this is the step that will be timed. + * + * Typically "the work" is rendering an SkPicture into a bitmap, but in some subclasses + * it is recording the source SkPicture into another SkPicture. + * + * If fWritePath has been specified, the result of the work will be written to that dir. + * If fMismatchPath has been specified, and the actual image result differs from its + * expectation, the result of the work will be written to that dir. + * + * @param out If non-null, the implementing subclass MAY allocate an SkBitmap, copy the + * output image into it, and return it here. (Some subclasses ignore this parameter) + * @return bool True if rendering succeeded and, if fWritePath had been specified, the output + * was successfully written to a file. + */ + virtual bool render(SkBitmap** out = nullptr) = 0; + + /** + * Called once finished with a particular SkPicture, before calling init again, and before + * being done with this Renderer. + */ + virtual void end(); + + /** + * If this PictureRenderer is actually a TiledPictureRender, return a pointer to this as a + * TiledPictureRender so its methods can be called. + */ + virtual TiledPictureRenderer* getTiledRenderer() { return nullptr; } + + /** + * Resets the GPU's state. Does nothing if the backing is raster. For a GPU renderer, calls + * flush, swapBuffers and, if callFinish is true, finish. + * @param callFinish Whether to call finish. + */ + void resetState(bool callFinish); + + /** + * Remove all decoded textures from the CPU caches and all uploaded textures + * from the GPU. + */ + void purgeTextures(); + + /** + * Set the backend type. Returns true on success and false on failure. + */ +#if SK_SUPPORT_GPU + bool setDeviceType(SkDeviceTypes deviceType, GrGLStandard gpuAPI = kNone_GrGLStandard) { +#else + bool setDeviceType(SkDeviceTypes deviceType) { +#endif + fDeviceType = deviceType; +#if SK_SUPPORT_GPU + // In case this function is called more than once + fGrContext.reset(); + fGLContext.reset(); + + // Set to Native so it will have an initial value. + GrContextFactory::GLContextType glContextType = GrContextFactory::kNative_GLContextType; + GrContextFactory::GLContextType glContextOptions = GrContextFactory::kNone_GLContextOptions; +#endif + switch(deviceType) { + case kBitmap_DeviceType: + return true; +#if SK_SUPPORT_GPU + case kGPU_DeviceType: + // Already set to GrContextFactory::kNative_GLContextType, above. + break; + case kNVPR_DeviceType: + // Already set to GrContextFactory::kNative_GLContextType, above. + glContextOptions = GrContextFactory::kEnableNVPR_GLContextOptions; + break; +#if SK_ANGLE + case kAngle_DeviceType: + glContextType = GrContextFactory::kANGLE_GLContextType; + break; +#endif +#if SK_COMMAND_BUFFER + case kCommandBuffer_DeviceType: + glContextType = GrContextFactory::kCommandBuffer_GLContextType; + break; +#endif +#if SK_MESA + case kMesa_DeviceType: + glContextType = GrContextFactory::kMESA_GLContextType; + break; +#endif +#endif + default: + // Invalid device type. + return false; + } +#if SK_SUPPORT_GPU + GrContextFactory::ContextInfo* contextInfo = fGrContextFactory.getContextInfo(glContextType, gpuAPI, glContextOptions); + if (contextInfo) { + fGrContext.reset(SkRef(contextInfo->fGrContext)); + fGLContext.reset(SkRef(contextInfo->fGLContext)); + return true; + } + return false; +#endif + } + +#if SK_SUPPORT_GPU + void setSampleCount(int sampleCount) { + fSampleCount = sampleCount; + } + + void setUseDFText(bool useDFText) { + fUseDFText = useDFText; + } +#endif + + void setDrawFilters(DrawFilterFlags const * const filters, const SkString& configName) { + fHasDrawFilters = false; + fDrawFiltersConfig = configName; + + for (size_t i = 0; i < SK_ARRAY_COUNT(fDrawFilters); ++i) { + fDrawFilters[i] = filters[i]; + fHasDrawFilters |= SkToBool(filters[i]); + } + } + + void setBBoxHierarchyType(BBoxHierarchyType bbhType) { + fBBoxHierarchyType = bbhType; + } + + BBoxHierarchyType getBBoxHierarchyType() { return fBBoxHierarchyType; } + + bool isUsingBitmapDevice() { + return kBitmap_DeviceType == fDeviceType; + } + + virtual SkString getPerIterTimeFormat() { return SkString("%.2f"); } + + virtual SkString getNormalTimeFormat() { return SkString("%6.2f"); } + + /** + * Reports the configuration of this PictureRenderer. + */ + SkString getConfigName() { + SkString config = this->getConfigNameInternal(); + if (!fViewport.isEmpty()) { + config.appendf("_viewport_%ix%i", fViewport.width(), fViewport.height()); + } + if (fScaleFactor != SK_Scalar1) { + config.appendf("_scalar_%f", SkScalarToFloat(fScaleFactor)); + } + if (kRTree_BBoxHierarchyType == fBBoxHierarchyType) { + config.append("_rtree"); + } +#if SK_SUPPORT_GPU + switch (fDeviceType) { + case kGPU_DeviceType: + if (fSampleCount) { + config.appendf("_msaa%d", fSampleCount); + } else if (fUseDFText) { + config.append("_gpudft"); + } else { + config.append("_gpu"); + } + break; + case kNVPR_DeviceType: + config.appendf("_nvprmsaa%d", fSampleCount); + break; +#if SK_ANGLE + case kAngle_DeviceType: + config.append("_angle"); + break; +#endif +#if SK_COMMAND_BUFFER + case kCommandBuffer_DeviceType: + config.append("_commandbuffer"); + break; +#endif +#if SK_MESA + case kMesa_DeviceType: + config.append("_mesa"); + break; +#endif + default: + // Assume that no extra info means bitmap. + break; + } +#endif + config.append(fDrawFiltersConfig.c_str()); + return config; + } + + Json::Value getJSONConfig() { + Json::Value result; + + result["mode"] = this->getConfigNameInternal().c_str(); + result["scale"] = 1.0f; + if (SK_Scalar1 != fScaleFactor) { + result["scale"] = SkScalarToFloat(fScaleFactor); + } + if (kRTree_BBoxHierarchyType == fBBoxHierarchyType) { + result["bbh"] = "rtree"; + } +#if SK_SUPPORT_GPU + SkString tmp; + switch (fDeviceType) { + case kGPU_DeviceType: + if (0 != fSampleCount) { + tmp = "msaa"; + tmp.appendS32(fSampleCount); + result["config"] = tmp.c_str(); + } else if (fUseDFText) { + result["config"] = "gpudft"; + } else { + result["config"] = "gpu"; + } + break; + case kNVPR_DeviceType: + tmp = "nvprmsaa"; + tmp.appendS32(fSampleCount); + result["config"] = tmp.c_str(); + break; +#if SK_ANGLE + case kAngle_DeviceType: + result["config"] = "angle"; + break; +#endif +#if SK_COMMAND_BUFFER + case kCommandBuffer_DeviceType: + result["config"] = "commandbuffer"; + break; +#endif +#if SK_MESA + case kMesa_DeviceType: + result["config"] = "mesa"; + break; +#endif + default: + // Assume that no extra info means bitmap. + break; + } +#endif + return result; + } + +#if SK_SUPPORT_GPU + bool isUsingGpuDevice() { + switch (fDeviceType) { + case kGPU_DeviceType: + case kNVPR_DeviceType: + // fall through +#if SK_ANGLE + case kAngle_DeviceType: + // fall through +#endif +#if SK_COMMAND_BUFFER + case kCommandBuffer_DeviceType: + // fall through +#endif +#if SK_MESA + case kMesa_DeviceType: +#endif + return true; + default: + return false; + } + } + + SkGLContext* getGLContext() { + return fGLContext; + } + + GrContext* getGrContext() { + return fGrContext; + } + + const GrContextOptions& getGrContextOptions() { + return fGrContextFactory.getGlobalOptions(); + } +#endif + + SkCanvas* getCanvas() { + return fCanvas; + } + + const SkPicture* getPicture() { + return fPicture; + } + +#if SK_SUPPORT_GPU + explicit PictureRenderer(const GrContextOptions &opts) +#else + PictureRenderer() +#endif + : fDeviceType(kBitmap_DeviceType) + , fBBoxHierarchyType(kNone_BBoxHierarchyType) + , fHasDrawFilters(false) + , fScaleFactor(SK_Scalar1) +#if SK_SUPPORT_GPU + , fGrContextFactory(opts) + , fSampleCount(0) + , fUseDFText(false) +#endif + { + sk_bzero(fDrawFilters, sizeof(fDrawFilters)); + fViewport.set(0, 0); + } + +protected: + SkAutoTUnref<SkCanvas> fCanvas; + SkAutoTUnref<const SkPicture> fPicture; + bool fUseChecksumBasedFilenames; + bool fUseMultiPictureDraw; + SkDeviceTypes fDeviceType; + BBoxHierarchyType fBBoxHierarchyType; + bool fHasDrawFilters; + DrawFilterFlags fDrawFilters[SkDrawFilter::kTypeCount]; + SkString fDrawFiltersConfig; + SkString fWritePath; + SkString fMismatchPath; + SkString fInputFilename; + + void buildBBoxHierarchy(); + + /** + * Return the total width that should be drawn. If the viewport width has been set greater than + * 0, this will be the minimum of the current SkPicture's width and the viewport's width. + */ + int getViewWidth(); + + /** + * Return the total height that should be drawn. If the viewport height has been set greater + * than 0, this will be the minimum of the current SkPicture's height and the viewport's height. + */ + int getViewHeight(); + + /** + * Scales the provided canvas to the scale factor set by setScaleFactor. + */ + void scaleToScaleFactor(SkCanvas*); + + SkBBHFactory* getFactory(); + uint32_t recordFlags() const { return 0; } + SkCanvas* setupCanvas(); + virtual SkCanvas* setupCanvas(int width, int height); + + /** + * Copy src to dest; if src==nullptr, set dest to empty string. + */ + static void CopyString(SkString* dest, const SkString* src); + +private: + SkISize fViewport; + SkScalar fScaleFactor; +#if SK_SUPPORT_GPU + GrContextFactory fGrContextFactory; + SkAutoTUnref<GrContext> fGrContext; + SkAutoTUnref<SkGLContext> fGLContext; + int fSampleCount; + bool fUseDFText; +#endif + + virtual SkString getConfigNameInternal() = 0; + + typedef SkRefCnt INHERITED; +}; + +/** + * This class does not do any rendering, but its render function executes recording, which we want + * to time. + */ +class RecordPictureRenderer : public PictureRenderer { +public: +#if SK_SUPPORT_GPU + RecordPictureRenderer(const GrContextOptions &opts) : INHERITED(opts) { } +#endif + + bool render(SkBitmap** out = nullptr) override; + + SkString getPerIterTimeFormat() override { return SkString("%.4f"); } + + SkString getNormalTimeFormat() override { return SkString("%6.4f"); } + +protected: + SkCanvas* setupCanvas(int width, int height) override; + +private: + SkString getConfigNameInternal() override; + + typedef PictureRenderer INHERITED; +}; + +class PipePictureRenderer : public PictureRenderer { +public: +#if SK_SUPPORT_GPU + PipePictureRenderer(const GrContextOptions &opts) : INHERITED(opts) { } +#endif + + bool render(SkBitmap** out = nullptr) override; + +private: + SkString getConfigNameInternal() override; + + typedef PictureRenderer INHERITED; +}; + +class SimplePictureRenderer : public PictureRenderer { +public: +#if SK_SUPPORT_GPU + SimplePictureRenderer(const GrContextOptions &opts) : INHERITED(opts) { } +#endif + + virtual void init(const SkPicture* pict, + const SkString* writePath, + const SkString* mismatchPath, + const SkString* inputFilename, + bool useChecksumBasedFilenames, + bool useMultiPictureDraw) override; + + bool render(SkBitmap** out = nullptr) override; + +private: + SkString getConfigNameInternal() override; + + typedef PictureRenderer INHERITED; +}; + +class TiledPictureRenderer : public PictureRenderer { +public: +#if SK_SUPPORT_GPU + TiledPictureRenderer(const GrContextOptions &opts); +#else + TiledPictureRenderer(); +#endif + + virtual void init(const SkPicture* pict, + const SkString* writePath, + const SkString* mismatchPath, + const SkString* inputFilename, + bool useChecksumBasedFilenames, + bool useMultiPictureDraw) override; + + /** + * Renders to tiles, rather than a single canvas. + * If fWritePath was provided, a separate file is + * created for each tile, named "path0.png", "path1.png", etc. + */ + bool render(SkBitmap** out = nullptr) override; + + void end() override; + + void setTileWidth(int width) { + fTileWidth = width; + } + + int getTileWidth() const { + return fTileWidth; + } + + void setTileHeight(int height) { + fTileHeight = height; + } + + int getTileHeight() const { + return fTileHeight; + } + + void setTileWidthPercentage(double percentage) { + fTileWidthPercentage = percentage; + } + + double getTileWidthPercentage() const { + return fTileWidthPercentage; + } + + void setTileHeightPercentage(double percentage) { + fTileHeightPercentage = percentage; + } + + double getTileHeightPercentage() const { + return fTileHeightPercentage; + } + + void setTileMinPowerOf2Width(int width) { + SkASSERT(SkIsPow2(width) && width > 0); + if (!SkIsPow2(width) || width <= 0) { + return; + } + + fTileMinPowerOf2Width = width; + } + + int getTileMinPowerOf2Width() const { + return fTileMinPowerOf2Width; + } + + TiledPictureRenderer* getTiledRenderer() override { return this; } + + virtual bool supportsTimingIndividualTiles() { return true; } + + /** + * Report the number of tiles in the x and y directions. Must not be called before init. + * @param x Output parameter identifying the number of tiles in the x direction. + * @param y Output parameter identifying the number of tiles in the y direction. + * @return True if the tiles have been set up, and x and y are meaningful. If false, x and y are + * unmodified. + */ + bool tileDimensions(int& x, int&y); + + /** + * Move to the next tile and return its indices. Must be called before calling drawCurrentTile + * for the first time. + * @param i Output parameter identifying the column of the next tile to be drawn on the next + * call to drawNextTile. + * @param j Output parameter identifying the row of the next tile to be drawn on the next call + * to drawNextTile. + * @param True if the tiles have been created and the next tile to be drawn by drawCurrentTile + * is within the range of tiles. If false, i and j are unmodified. + */ + bool nextTile(int& i, int& j); + + /** + * Render one tile. This will draw the same tile each time it is called until nextTile is + * called. The tile rendered will depend on how many calls have been made to nextTile. + * It is an error to call this without first calling nextTile, or if nextTile returns false. + */ + void drawCurrentTile(); + +protected: + SkTDArray<SkIRect> fTileRects; + + SkCanvas* setupCanvas(int width, int height) override; + SkString getConfigNameInternal() override; + +private: + int fTileWidth; + int fTileHeight; + double fTileWidthPercentage; + double fTileHeightPercentage; + int fTileMinPowerOf2Width; + + // These variables are only used for timing individual tiles. + // Next tile to draw in fTileRects. + int fCurrentTileOffset; + // Number of tiles in the x direction. + int fTilesX; + // Number of tiles in the y direction. + int fTilesY; + + void setupTiles(); + void setupPowerOf2Tiles(); + bool postRender(SkCanvas*, const SkIRect& tileRect, + SkBitmap* tempBM, SkBitmap** out, + int tileNumber); + + typedef PictureRenderer INHERITED; +}; + +/** + * This class does not do any rendering, but its render function executes turning an SkPictureRecord + * into an SkPicturePlayback, which we want to time. + */ +class PlaybackCreationRenderer : public PictureRenderer { +public: +#if SK_SUPPORT_GPU + PlaybackCreationRenderer(const GrContextOptions &opts) : INHERITED(opts) { } +#endif + + void setup() override; + + bool render(SkBitmap** out = nullptr) override; + + SkString getPerIterTimeFormat() override { return SkString("%.4f"); } + + SkString getNormalTimeFormat() override { return SkString("%6.4f"); } + +private: + SkAutoTDelete<SkPictureRecorder> fRecorder; + + SkString getConfigNameInternal() override; + + typedef PictureRenderer INHERITED; +}; + +#if SK_SUPPORT_GPU +extern PictureRenderer* CreateGatherPixelRefsRenderer(const GrContextOptions& opts); +#else +extern PictureRenderer* CreateGatherPixelRefsRenderer(); +#endif + +} + +#endif // PictureRenderer_DEFINED |