aboutsummaryrefslogtreecommitdiffhomepage
path: root/dm
diff options
context:
space:
mode:
authorGravatar Brian Osman <brianosman@google.com>2017-08-24 10:36:00 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-08-24 15:22:57 +0000
commit76323bc0615044a5921afef0e19a350f3d04ffe0 (patch)
tree230a9802ad885756532c2c9ec233264b6526985a /dm
parent81da18c427145f48a99093323dcf311e330e676c (diff)
Threaded generation of software paths
All information needed by the thread is captured by the prepare callback object, the lambda captures a pointer to that, and does the mask render. Once it's done, it signals the semaphore (also owned by the callback). The callback defers the semaphore wait even longer (into the ASAP upload), so the odds of waiting for the thread are REALLY low. Also did a bunch of cleanup along the way, and put in some trace markers so we can monitor how well this is working. Traces of a GM that includes GPU and SW path rendering (path-reverse): Original: https://screenshot.googleplex.com/f5BG3901tQg.png Threaded, with wait in the callback (notice pre flush callback blocking): https://screenshot.googleplex.com/htOSZFE2s04.png Current version, with wait deferred to ASAP upload function: https://screenshot.googleplex.com/GHjD0U3C34q.png Bug: skia: Change-Id: I3d5a230bbd68eb35e1f0574b308485c691435790 Reviewed-on: https://skia-review.googlesource.com/36560 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
Diffstat (limited to 'dm')
-rw-r--r--dm/DM.cpp19
-rw-r--r--dm/DMSrcSink.cpp65
-rw-r--r--dm/DMSrcSink.h21
3 files changed, 98 insertions, 7 deletions
diff --git a/dm/DM.cpp b/dm/DM.cpp
index a442e09050..1e02d25b7b 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -18,6 +18,7 @@
#include "SkColorSpacePriv.h"
#include "SkCommonFlags.h"
#include "SkCommonFlagsConfig.h"
+#include "SkCommonFlagsGpuThreads.h"
#include "SkCommonFlagsPathRenderer.h"
#include "SkData.h"
#include "SkDocument.h"
@@ -858,10 +859,19 @@ static Sink* create_sink(const GrContextOptions& grCtxOptions, const SkCommandLi
"GM tests will be skipped.\n", gpuConfig->getTag().c_str());
return nullptr;
}
- return new GPUSink(contextType, contextOverrides, gpuConfig->getSamples(),
- gpuConfig->getUseDIText(), gpuConfig->getColorType(),
- gpuConfig->getAlphaType(), sk_ref_sp(gpuConfig->getColorSpace()),
- FLAGS_gpu_threading, grCtxOptions);
+ if (gpuConfig->getTestThreading()) {
+ return new GPUThreadTestingSink(contextType, contextOverrides,
+ gpuConfig->getSamples(), gpuConfig->getUseDIText(),
+ gpuConfig->getColorType(),
+ gpuConfig->getAlphaType(),
+ sk_ref_sp(gpuConfig->getColorSpace()),
+ FLAGS_gpu_threading, grCtxOptions);
+ } else {
+ return new GPUSink(contextType, contextOverrides, gpuConfig->getSamples(),
+ gpuConfig->getUseDIText(), gpuConfig->getColorType(),
+ gpuConfig->getAlphaType(), sk_ref_sp(gpuConfig->getColorSpace()),
+ FLAGS_gpu_threading, grCtxOptions);
+ }
}
}
#endif
@@ -1320,6 +1330,7 @@ int main(int argc, char** argv) {
GrContextOptions grCtxOptions;
#if SK_SUPPORT_GPU
grCtxOptions.fGpuPathRenderers = CollectGpuPathRenderersFromFlags();
+ grCtxOptions.fExecutor = GpuExecutorForTools();
#endif
JsonWriter::DumpJson(); // It's handy for the bots to assume this is ~never missing.
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index f9e5fd3d21..47b10e42bf 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -20,6 +20,7 @@
#include "SkDebugCanvas.h"
#include "SkDeferredCanvas.h"
#include "SkDocument.h"
+#include "SkExecutor.h"
#include "SkImageGenerator.h"
#include "SkImageGeneratorCG.h"
#include "SkImageGeneratorWIC.h"
@@ -61,6 +62,7 @@
DEFINE_bool(multiPage, false, "For document-type backends, render the source"
" into multiple pages");
DEFINE_bool(RAW_threading, true, "Allow RAW decodes to run on multiple threads?");
+DECLARE_int32(gpuThreads);
using sk_gpu_test::GrContextFactory;
@@ -1315,8 +1317,13 @@ GPUSink::GPUSink(GrContextFactory::ContextType ct,
DEFINE_bool(drawOpClip, false, "Clip each GrDrawOp to its device bounds for testing.");
-Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const {
- GrContextOptions grOptions = fBaseContextOptions;
+Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream* dstStream, SkString* log) const {
+ return this->onDraw(src, dst, dstStream, log, fBaseContextOptions);
+}
+
+Error GPUSink::onDraw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log,
+ const GrContextOptions& baseOptions) const {
+ GrContextOptions grOptions = baseOptions;
src.modifyGrContextOptions(&grOptions);
@@ -1368,6 +1375,58 @@ Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) co
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+GPUThreadTestingSink::GPUThreadTestingSink(GrContextFactory::ContextType ct,
+ GrContextFactory::ContextOverrides overrides,
+ int samples,
+ bool diText,
+ SkColorType colorType,
+ SkAlphaType alphaType,
+ sk_sp<SkColorSpace> colorSpace,
+ bool threaded,
+ const GrContextOptions& grCtxOptions)
+ : INHERITED(ct, overrides, samples, diText, colorType, alphaType, std::move(colorSpace),
+ threaded, grCtxOptions)
+ , fExecutor(SkExecutor::MakeThreadPool(FLAGS_gpuThreads)) {
+ SkASSERT(fExecutor);
+}
+
+Error GPUThreadTestingSink::draw(const Src& src, SkBitmap* dst, SkWStream* wStream,
+ SkString* log) const {
+ // Draw twice, once with worker threads, and once without. Verify that we get the same result.
+ // Also, force us to only use the software path renderer, so we really stress-test the threaded
+ // version of that code.
+ GrContextOptions contextOptions = this->baseContextOptions();
+ contextOptions.fGpuPathRenderers = GrContextOptions::GpuPathRenderers::kNone;
+
+ contextOptions.fExecutor = fExecutor.get();
+ Error err = this->onDraw(src, dst, wStream, log, contextOptions);
+ if (!err.isEmpty() || !dst) {
+ return err;
+ }
+
+ SkBitmap reference;
+ SkString refLog;
+ SkDynamicMemoryWStream refStream;
+ contextOptions.fExecutor = nullptr;
+ Error refErr = this->onDraw(src, &reference, &refStream, &refLog, contextOptions);
+ if (!refErr.isEmpty()) {
+ return refErr;
+ }
+
+ // The dimensions are a property of the Src only, and so should be identical.
+ SkASSERT(reference.getSize() == dst->getSize());
+ if (reference.getSize() != dst->getSize()) {
+ return "Dimensions don't match reference";
+ }
+ // All SkBitmaps in DM are tight, so this comparison is easy.
+ if (0 != memcmp(reference.getPixels(), dst->getPixels(), reference.getSize())) {
+ return "Pixels don't match reference";
+ }
+ return "";
+}
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) {
if (src.size().isEmpty()) {
return "Source has empty dimensions";
@@ -1558,7 +1617,7 @@ static Error check_against_reference(const SkBitmap* bitmap, const Src& src, Sin
if (reference.getSize() != bitmap->getSize()) {
return "Dimensions don't match reference";
}
- // All SkBitmaps in DM are pre-locked and tight, so this comparison is easy.
+ // All SkBitmaps in DM are tight, so this comparison is easy.
if (0 != memcmp(reference.getPixels(), bitmap->getPixels(), reference.getSize())) {
return "Pixels don't match reference";
}
diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h
index 117514995a..8b6ee0e5f4 100644
--- a/dm/DMSrcSink.h
+++ b/dm/DMSrcSink.h
@@ -310,6 +310,9 @@ public:
bool threaded, const GrContextOptions& grCtxOptions);
Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
+ Error onDraw(const Src&, SkBitmap*, SkWStream*, SkString*,
+ const GrContextOptions& baseOptions) const;
+
bool serial() const override { return !fThreaded; }
const char* fileExtension() const override { return "png"; }
SinkFlags flags() const override {
@@ -317,6 +320,8 @@ public:
: SinkFlags::kNotMultisampled;
return SinkFlags{ SinkFlags::kGPU, SinkFlags::kDirect, ms };
}
+ const GrContextOptions& baseContextOptions() const { return fBaseContextOptions; }
+
private:
sk_gpu_test::GrContextFactory::ContextType fContextType;
sk_gpu_test::GrContextFactory::ContextOverrides fContextOverrides;
@@ -329,6 +334,22 @@ private:
GrContextOptions fBaseContextOptions;
};
+class GPUThreadTestingSink : public GPUSink {
+public:
+ GPUThreadTestingSink(sk_gpu_test::GrContextFactory::ContextType,
+ sk_gpu_test::GrContextFactory::ContextOverrides, int samples, bool diText,
+ SkColorType colorType, SkAlphaType alphaType,
+ sk_sp<SkColorSpace> colorSpace, bool threaded,
+ const GrContextOptions& grCtxOptions);
+
+ Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
+
+private:
+ std::unique_ptr<SkExecutor> fExecutor;
+
+ typedef GPUSink INHERITED;
+};
+
class PDFSink : public Sink {
public:
PDFSink(bool pdfa, SkScalar rasterDpi) : fPDFA(pdfa), fRasterDpi(rasterDpi) {}