aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--bench/nanobench.cpp59
-rw-r--r--bench/nanobench.h2
-rw-r--r--dm/DM.cpp12
-rw-r--r--dm/DMGpuSupport.h8
-rw-r--r--dm/DMSrcSink.cpp30
-rw-r--r--dm/DMSrcSink.h16
-rwxr-xr-xsrc/gpu/GrContextFactory.cpp19
-rw-r--r--src/gpu/GrContextFactory.h45
-rwxr-xr-xtests/GLInterfaceValidationTest.cpp39
-rw-r--r--tests/GrContextFactoryTest.cpp18
-rw-r--r--tools/PictureRenderer.h707
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
};
diff --git a/dm/DM.cpp b/dm/DM.cpp
index 7497161369..6549af5a0f 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -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