aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2017-10-11 15:34:27 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-10-11 20:32:49 +0000
commit0b4d8aa108f2fd14f1ee4de1affacab166d7a357 (patch)
tree1a63c56bd675ebf9400980f25ebc61bb88bfaa56
parentba1c7901a7448a388fd835e487b6b9d223236826 (diff)
Add benchmark for comparing multitexturing to non-multitexturing image draws.
Allows benchmarks to override GrContextOptions. Removes the ability to use the same GrContext for all benchmarks in a config. Change-Id: I5ab9f6e81055451ac912a66537843d1a49f3b479 Reviewed-on: https://skia-review.googlesource.com/34080 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Brian Salomon <bsalomon@google.com>
-rw-r--r--bench/Benchmark.h5
-rw-r--r--bench/GMBench.h4
-rw-r--r--bench/MultitextureImageBench.cpp125
-rw-r--r--bench/nanobench.cpp75
-rw-r--r--bench/nanobench.h3
-rw-r--r--gn/bench.gni1
-rw-r--r--include/gpu/GrCaps.h3
-rw-r--r--include/gpu/GrContextOptions.h6
-rw-r--r--include/gpu/GrShaderCaps.h3
-rw-r--r--src/gpu/GrShaderCaps.cpp7
-rw-r--r--src/gpu/ops/GrTextureOp.cpp4
-rw-r--r--tools/flags/SkCommonFlags.h1
12 files changed, 190 insertions, 47 deletions
diff --git a/bench/Benchmark.h b/bench/Benchmark.h
index 8fc75f8b8e..ddc93870cd 100644
--- a/bench/Benchmark.h
+++ b/bench/Benchmark.h
@@ -27,7 +27,7 @@
* DEF_BENCH(return new MyBenchmark(...))
*/
-
+struct GrContextOptions;
class SkCanvas;
class SkPaint;
@@ -63,6 +63,9 @@ public:
return backend != kNonRendering_Backend;
}
+ // Allows a benchmark to override options used to construct the GrContext.
+ virtual void modifyGrContextOptions(GrContextOptions*) {}
+
virtual int calculateLoops(int defaultLoops) const {
return defaultLoops;
}
diff --git a/bench/GMBench.h b/bench/GMBench.h
index c9ec80c643..5a917ad2a7 100644
--- a/bench/GMBench.h
+++ b/bench/GMBench.h
@@ -20,6 +20,10 @@ public:
GMBench(skiagm::GM* gm);
~GMBench() override;
+ void modifyGrContextOptions(GrContextOptions* options) override {
+ return fGM->modifyGrContextOptions(options);
+ }
+
protected:
const char* onGetName() override;
bool isSuitableFor(Backend backend) override;
diff --git a/bench/MultitextureImageBench.cpp b/bench/MultitextureImageBench.cpp
new file mode 100644
index 0000000000..d001cac774
--- /dev/null
+++ b/bench/MultitextureImageBench.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Benchmark.h"
+#if SK_SUPPORT_GPU
+
+#include "GrContextOptions.h"
+#include "SkCanvas.h"
+#include "SkImage.h"
+#include "SkRandom.h"
+#include "SkSurface.h"
+
+class MultitextureImages : public Benchmark {
+public:
+ MultitextureImages(int imageSize, int dstRectSize, bool disableMultitexturing)
+ : fImageSize(imageSize)
+ , fDstRectSize(dstRectSize)
+ , fDisableMultitexturing(disableMultitexturing) {
+ fName.appendf("multitexture_images_%dx%d_image_%dx%d_rect", imageSize, imageSize,
+ dstRectSize, dstRectSize);
+ if (disableMultitexturing) {
+ fName.append("_disable_multitexturing");
+ }
+ }
+
+ bool isSuitableFor(Backend backend) override { return kGPU_Backend == backend; }
+
+protected:
+ const char* onGetName() override { return fName.c_str(); }
+
+ void onPerCanvasPreDraw(SkCanvas* canvas) override {
+ auto ii = SkImageInfo::Make(fImageSize, fImageSize, kRGBA_8888_SkColorType,
+ kPremul_SkAlphaType, nullptr);
+ SkRandom random;
+ for (int i = 0; i < kNumImages; ++i) {
+ auto surf = canvas->makeSurface(ii);
+ SkColor color = random.nextU();
+ surf->getCanvas()->clear(color);
+ SkPaint paint;
+ paint.setColor(~color);
+ paint.setBlendMode(SkBlendMode::kSrc);
+ surf->getCanvas()->drawRect(SkRect::MakeLTRB(3, 3, fImageSize - 3, fImageSize - 3),
+ paint);
+ fImages[i] = surf->makeImageSnapshot();
+ }
+ }
+
+ void onPerCanvasPostDraw(SkCanvas*) override {
+ for (int i = 0; i < kNumImages; ++i) {
+ fImages[i].reset();
+ }
+ }
+
+ void onDraw(int loops, SkCanvas* canvas) override {
+ SkRect rect = SkRect::MakeWH(fDstRectSize, fDstRectSize);
+ SkPaint paint;
+ paint.setAlpha(0x40);
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ for (int i = 0; i < loops; i++) {
+ for (int j = 0; j < kNumImages; ++j) {
+ SkVector translate = this->translation(i * kNumImages + j);
+ canvas->drawImageRect(fImages[j].get(), rect.makeOffset(translate.fX, translate.fY),
+ &paint);
+ }
+ // Prevent any batching except without multitexturing since we're trying to measure
+ // drawing distinct images and just repeating images here to increase the workload for
+ // timing reasons.
+ canvas->flush();
+ }
+ }
+
+ void modifyGrContextOptions(GrContextOptions* options) override {
+ options->fDisableImageMultitexturing = fDisableMultitexturing;
+ }
+
+private:
+ SkIPoint onGetSize() override {
+ // The rows and columns are spaced by kTranslate, but the images may overlap if they are
+ // larger than kTranslate and extend beyond the last row/column.
+ return SkIPoint::Make(kTranslate * (kNumColumns - 1) + fDstRectSize,
+ kTranslate * (kNumRows - 1) + fDstRectSize);
+ }
+
+ SkVector translation(int i) const {
+ SkVector offset;
+ offset.fX = i % kNumColumns * kTranslate;
+ offset.fY = (i / kNumColumns) % kNumRows * kTranslate;
+ return offset;
+ }
+
+ static const int kTranslate = 200;
+ static const int kNumColumns = 5;
+ static const int kNumRows = 5;
+ static const int kNumImages = 8;
+
+ sk_sp<SkImage> fImages[kNumImages];
+ SkString fName;
+ int fImageSize;
+ int fDstRectSize;
+ bool fDisableMultitexturing;
+
+ typedef Benchmark INHERITED;
+};
+
+DEF_BENCH(return new MultitextureImages(128, 32, false));
+DEF_BENCH(return new MultitextureImages(128, 32, true));
+DEF_BENCH(return new MultitextureImages(128, 128, false));
+DEF_BENCH(return new MultitextureImages(128, 128, true));
+DEF_BENCH(return new MultitextureImages(128, 256, false));
+DEF_BENCH(return new MultitextureImages(128, 256, true));
+
+DEF_BENCH(return new MultitextureImages(512, 32, false));
+DEF_BENCH(return new MultitextureImages(512, 32, true));
+DEF_BENCH(return new MultitextureImages(512, 128, false));
+DEF_BENCH(return new MultitextureImages(512, 128, true));
+DEF_BENCH(return new MultitextureImages(512, 256, false));
+DEF_BENCH(return new MultitextureImages(512, 256, true));
+DEF_BENCH(return new MultitextureImages(512, 512, false));
+DEF_BENCH(return new MultitextureImages(512, 512, true));
+
+#endif
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp
index 5a976e6640..203ed67073 100644
--- a/bench/nanobench.cpp
+++ b/bench/nanobench.cpp
@@ -65,9 +65,10 @@ extern bool gSkForceRasterPipelineBlitter;
#include "GrContextFactory.h"
#include "gl/GrGLUtil.h"
#include "SkGr.h"
+ using sk_gpu_test::ContextInfo;
using sk_gpu_test::GrContextFactory;
using sk_gpu_test::TestContext;
- std::unique_ptr<GrContextFactory> gGrFactory;
+ GrContextOptions grContextOpts;
#endif
struct GrContextOptions;
@@ -124,7 +125,6 @@ DEFINE_bool(lite, false, "Use SkLiteRecorder in recording benchmarks?");
DEFINE_bool(mpd, true, "Use MultiPictureDraw for the SKPs?");
DEFINE_bool(loopSKP, true, "Loop SKPs like we do for micro benches?");
DEFINE_int32(flushEvery, 10, "Flush --outResultsFile every Nth run.");
-DEFINE_bool(resetGpuContext, true, "Reset the GrContext before running each test.");
DEFINE_bool(gpuStats, false, "Print GPU stats after each gpu benchmark?");
DEFINE_bool(gpuStatsDump, false, "Dump GPU states after each benchmark to json");
DEFINE_bool(keepAlive, false, "Print a message every so often so that we don't time out");
@@ -174,44 +174,45 @@ bool Target::capturePixels(SkBitmap* bmp) {
#if SK_SUPPORT_GPU
struct GPUTarget : public Target {
- explicit GPUTarget(const Config& c) : Target(c), context(nullptr) { }
- TestContext* context;
+ explicit GPUTarget(const Config& c) : Target(c) {}
+ ContextInfo contextInfo;
+ std::unique_ptr<GrContextFactory> factory;
void setup() override {
- this->context->makeCurrent();
+ this->contextInfo.testContext()->makeCurrent();
// Make sure we're done with whatever came before.
- this->context->finish();
+ this->contextInfo.testContext()->finish();
}
void endTiming() override {
- if (this->context) {
- this->context->waitOnSyncOrSwap();
+ if (this->contextInfo.testContext()) {
+ this->contextInfo.testContext()->waitOnSyncOrSwap();
}
}
- void fence() override {
- this->context->finish();
- }
+ void fence() override { this->contextInfo.testContext()->finish(); }
bool needsFrameTiming(int* maxFrameLag) const override {
- if (!this->context->getMaxGpuFrameLag(maxFrameLag)) {
+ if (!this->contextInfo.testContext()->getMaxGpuFrameLag(maxFrameLag)) {
// Frame lag is unknown.
*maxFrameLag = FLAGS_gpuFrameLag;
}
return true;
}
bool init(SkImageInfo info, Benchmark* bench) override {
+ GrContextOptions options = grContextOpts;
+ bench->modifyGrContextOptions(&options);
+ this->factory.reset(new GrContextFactory(options));
uint32_t flags = this->config.useDFText ? SkSurfaceProps::kUseDeviceIndependentFonts_Flag :
0;
SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
- this->surface = SkSurface::MakeRenderTarget(gGrFactory->get(this->config.ctxType,
- this->config.ctxOverrides),
- SkBudgeted::kNo, info,
- this->config.samples, &props);
- this->context = gGrFactory->getContextInfo(this->config.ctxType,
- this->config.ctxOverrides).testContext();
+ this->surface = SkSurface::MakeRenderTarget(
+ this->factory->get(this->config.ctxType, this->config.ctxOverrides),
+ SkBudgeted::kNo, info, this->config.samples, &props);
+ this->contextInfo =
+ this->factory->getContextInfo(this->config.ctxType, this->config.ctxOverrides);
if (!this->surface.get()) {
return false;
}
- if (!this->context->fenceSyncSupport()) {
+ if (!this->contextInfo.testContext()->fenceSyncSupport()) {
SkDebugf("WARNING: GL context for config \"%s\" does not support fence sync. "
"Timings might not be accurate.\n", this->config.name.c_str());
}
@@ -219,9 +220,9 @@ struct GPUTarget : public Target {
}
void fillOptions(ResultsWriter* log) override {
const GrGLubyte* version;
- if (this->context->backend() == kOpenGL_GrBackend) {
- const GrGLInterface* gl =
- reinterpret_cast<const GrGLInterface*>(this->context->backendContext());
+ if (this->contextInfo.backend() == kOpenGL_GrBackend) {
+ const GrGLInterface* gl = reinterpret_cast<const GrGLInterface*>(
+ this->contextInfo.testContext()->backendContext());
GR_GL_CALL_RET(gl, version, GetString(GR_GL_VERSION));
log->configOption("GL_VERSION", (const char*)(version));
@@ -235,6 +236,11 @@ struct GPUTarget : public Target {
log->configOption("GL_SHADING_LANGUAGE_VERSION", (const char*) version);
}
}
+
+ void dumpStats() override {
+ this->contextInfo.grContext()->printCacheStats();
+ this->contextInfo.grContext()->printGpuStats();
+ }
};
#endif
@@ -394,7 +400,6 @@ static int setup_gpu_bench(Target* target, Benchmark* bench, int maxGpuFrameLag)
} else {
loops = detect_forever_loops(loops);
}
-
// Pretty much the same deal as the calibration: do some warmup to make
// sure we're timing steady-state pipelined frames.
for (int i = 0; i < maxGpuFrameLag; i++) {
@@ -427,7 +432,8 @@ static void create_config(const SkCommandLineConfig* config, SkTArray<Config>* c
const auto colorType = gpuConfig->getColorType();
auto colorSpace = gpuConfig->getColorSpace();
- if (const GrContext* ctx = gGrFactory->get(ctxType, ctxOverrides)) {
+ GrContextFactory factory(grContextOpts);
+ if (const GrContext* ctx = factory.get(ctxType, ctxOverrides)) {
GrPixelConfig grPixConfig = SkImageInfo2GrPixelConfig(colorType, colorSpace,
*ctx->caps());
int supportedSampleCount = ctx->caps()->getSampleCount(sampleCount, grPixConfig);
@@ -578,14 +584,6 @@ static bool valid_brd_bench(sk_sp<SkData> encoded, SkColorType colorType, uint32
static void cleanup_run(Target* target) {
delete target;
-#if SK_SUPPORT_GPU
- if (FLAGS_abandonGpuContext) {
- gGrFactory->abandonContexts();
- }
- if (FLAGS_resetGpuContext || FLAGS_abandonGpuContext) {
- gGrFactory->destroyContexts();
- }
-#endif
}
static void collect_files(const SkCommandLineFlags::StringArray& paths, const char* ext,
@@ -1141,10 +1139,8 @@ int main(int argc, char** argv) {
SkTaskGroup::Enabler enabled(FLAGS_threads);
#if SK_SUPPORT_GPU
- GrContextOptions grContextOpts;
grContextOpts.fGpuPathRenderers = CollectGpuPathRenderersFromFlags();
grContextOpts.fExecutor = GpuExecutorForTools();
- gGrFactory.reset(new GrContextFactory(grContextOpts));
#endif
if (FLAGS_veryVerbose) {
@@ -1401,10 +1397,7 @@ int main(int argc, char** argv) {
#if SK_SUPPORT_GPU
if (FLAGS_gpuStats && Benchmark::kGPU_Backend == configs[i].backend) {
- GrContext* context = gGrFactory->get(configs[i].ctxType,
- configs[i].ctxOverrides);
- context->printCacheStats();
- context->printGpuStats();
+ target->dumpStats();
}
#endif
@@ -1425,11 +1418,5 @@ int main(int argc, char** argv) {
log->config("meta");
log->metric("max_rss_mb", sk_tools::getMaxResidentSetSizeMB());
-#if SK_SUPPORT_GPU
- // Make sure we clean up the global GrContextFactory here, otherwise we might race with the
- // SkEventTracer destructor
- gGrFactory.reset(nullptr);
-#endif
-
return 0;
}
diff --git a/bench/nanobench.h b/bench/nanobench.h
index ffd6893c4a..45882cc043 100644
--- a/bench/nanobench.h
+++ b/bench/nanobench.h
@@ -79,6 +79,9 @@ struct Target {
/** Writes any config-specific data to the log. */
virtual void fillOptions(ResultsWriter*) { }
+ /** Writes gathered stats using SkDebugf. */
+ virtual void dumpStats() {}
+
SkCanvas* getCanvas() const {
if (!surface.get()) {
return nullptr;
diff --git a/gn/bench.gni b/gn/bench.gni
index 4bd46287db..36569e5613 100644
--- a/gn/bench.gni
+++ b/gn/bench.gni
@@ -78,6 +78,7 @@ bench_sources = [
"$_bench/MergeBench.cpp",
"$_bench/MipMapBench.cpp",
"$_bench/MorphologyBench.cpp",
+ "$_bench/MultitextureImageBench.cpp",
"$_bench/MutexBench.cpp",
"$_bench/pack_int_uint16_t_Bench.cpp",
"$_bench/PatchBench.cpp",
diff --git a/include/gpu/GrCaps.h b/include/gpu/GrCaps.h
index ac4de03ed8..82a4be2c25 100644
--- a/include/gpu/GrCaps.h
+++ b/include/gpu/GrCaps.h
@@ -225,6 +225,9 @@ protected:
// Vulkan doesn't support this (yet) and some drivers have issues, too
bool fCrossContextTextureSupport : 1;
+ // Disables using multiple texture units to batch multiple SkImages at once.
+ bool fDisableImageMultitexturingSupport : 1;
+
InstancedSupport fInstancedSupport;
BlendEquationSupport fBlendEquationSupport;
diff --git a/include/gpu/GrContextOptions.h b/include/gpu/GrContextOptions.h
index 85c8da6e52..61dc8b0457 100644
--- a/include/gpu/GrContextOptions.h
+++ b/include/gpu/GrContextOptions.h
@@ -118,6 +118,12 @@ struct GrContextOptions {
* Include or exclude specific GPU path renderers.
*/
GpuPathRenderers fGpuPathRenderers = GpuPathRenderers::kDefault;
+
+ /**
+ * Disables using multiple texture units to batch multiple images into a single draw on
+ * supported GPUs.
+ */
+ bool fDisableImageMultitexturing = false;
#endif
};
diff --git a/include/gpu/GrShaderCaps.h b/include/gpu/GrShaderCaps.h
index b10ad60b5a..b093f37f28 100644
--- a/include/gpu/GrShaderCaps.h
+++ b/include/gpu/GrShaderCaps.h
@@ -252,6 +252,8 @@ public:
int maxCombinedImageStorages() const { return fMaxCombinedImageStorages; }
+ bool disableImageMultitexturingSupport() const { return fDisableImageMultitexturing; }
+
/**
* Given a texture's config, this determines what swizzle must be appended to accesses to the
* texture in generated shader code. Swizzling may be implemented in texture parameters or a
@@ -306,6 +308,7 @@ private:
bool fExternalTextureSupport : 1;
bool fTexelFetchSupport : 1;
bool fVertexIDSupport : 1;
+ bool fDisableImageMultitexturing : 1;
// Used for specific driver bug work arounds
bool fCanUseMinAndAbsTogether : 1;
diff --git a/src/gpu/GrShaderCaps.cpp b/src/gpu/GrShaderCaps.cpp
index 0ee9339b45..7e44188074 100644
--- a/src/gpu/GrShaderCaps.cpp
+++ b/src/gpu/GrShaderCaps.cpp
@@ -96,6 +96,12 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) {
fMaxFragmentImageStorages = 0;
fMaxCombinedImageStorages = 0;
fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction;
+
+#if GR_TEST_UTILS
+ fDisableImageMultitexturing = options.fDisableImageMultitexturing;
+#else
+ fDisableImageMultitexturing = false;
+#endif
}
void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const {
@@ -175,6 +181,7 @@ void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const {
writer->appendS32("Max Combined Image Storages", fMaxFragmentImageStorages);
writer->appendString("Advanced blend equation interaction",
kAdvBlendEqInteractionStr[fAdvBlendEqInteraction]);
+ writer->appendBool("Disable image multitexturing", fDisableImageMultitexturing);
writer->endObject();
}
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index ab82a9cc87..3606a01096 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -54,7 +54,9 @@ public:
static constexpr int kMaxTextures = 8;
#endif
- static int SupportsMultitexture(const GrShaderCaps& caps) { return caps.integerSupport(); }
+ static int SupportsMultitexture(const GrShaderCaps& caps) {
+ return caps.integerSupport() && !caps.disableImageMultitexturingSupport();
+ }
static sk_sp<GrGeometryProcessor> Make(sk_sp<GrTextureProxy> proxies[], int proxyCnt,
sk_sp<GrColorSpaceXform> csxf,
diff --git a/tools/flags/SkCommonFlags.h b/tools/flags/SkCommonFlags.h
index ef1897b7bc..3d4b33e640 100644
--- a/tools/flags/SkCommonFlags.h
+++ b/tools/flags/SkCommonFlags.h
@@ -20,7 +20,6 @@ DECLARE_string(colorImages);
DECLARE_bool(simpleCodec);
DECLARE_string(match);
DECLARE_bool(quiet);
-DECLARE_bool(resetGpuContext);
DECLARE_bool(preAbandonGpuContext);
DECLARE_bool(abandonGpuContext);
DECLARE_bool(releaseAndAbandonGpuContext);