Index: src/utils/debugger/SkOverdrawMode.cpp |
diff --git a/src/utils/debugger/SkOverdrawMode.cpp b/src/utils/debugger/SkOverdrawMode.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9dd62db363828af0a31f6cddf42df54175b0fa90 |
--- /dev/null |
+++ b/src/utils/debugger/SkOverdrawMode.cpp |
@@ -0,0 +1,331 @@ |
+/* |
+ * Copyright 2016 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#include "SkOverdrawMode.h" |
+#include "SkXfermode.h" |
+ |
+#if SK_SUPPORT_GPU |
+#include "GrFragmentProcessor.h" |
+#include "GrInvariantOutput.h" |
+#include "GrXferProcessor.h" |
+#include "glsl/GrGLSLFragmentProcessor.h" |
+#include "glsl/GrGLSLFragmentShaderBuilder.h" |
+#include "glsl/GrGLSLXferProcessor.h" |
+ |
+ /////////////////////////////////////////////////////////////////////////////// |
+ // Fragment Processor |
+ /////////////////////////////////////////////////////////////////////////////// |
+ |
+class GLOverdrawFP; |
+ |
+class GrOverdrawFP : public GrFragmentProcessor { |
+public: |
+ static const GrFragmentProcessor* Create(const GrFragmentProcessor* dst) { |
+ return new GrOverdrawFP(dst); |
+ } |
+ |
+ ~GrOverdrawFP() override { } |
+ |
+ const char* name() const override { return "Overdraw"; } |
+ |
+ SkString dumpInfo() const override { |
+ SkString str; |
+ return str; |
+ } |
+ |
+private: |
+ GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; |
+ |
+ void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder* b) const override; |
+ |
+ bool onIsEqual(const GrFragmentProcessor&) const override { return true; } |
+ |
+ void onComputeInvariantOutput(GrInvariantOutput* inout) const override { |
+ inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); |
+ } |
+ |
+ GrOverdrawFP(const GrFragmentProcessor* dst) { |
+ this->initClassID<GrOverdrawFP>(); |
+ |
+ SkASSERT(dst); |
+ SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst); |
+ SkASSERT(0 == dstIndex); |
+ } |
+ |
+ GR_DECLARE_FRAGMENT_PROCESSOR_TEST; |
+ typedef GrFragmentProcessor INHERITED; |
+}; |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+static void add_overdraw_code(GrGLSLFragmentBuilder* fragBuilder, |
+ const char* dstColor, |
+ const char* outputColor) { |
+ |
+ fragBuilder->codeAppend("vec4 gTable[11] = vec4[11]("); |
+ fragBuilder->codeAppend("vec4(0, 0, 0, 0.0),"); |
+ fragBuilder->codeAppend("vec4(0.5, 0.617, 1.0, 1.0),"); |
+ fragBuilder->codeAppend("vec4(0.664, 0.723, 0.83, 1.0),"); |
+ fragBuilder->codeAppend("vec4(0.832, 0.762, 0.664, 1.0),"); |
+ fragBuilder->codeAppend("vec4(1, 0.75, 0.496, 1.0),"); |
+ fragBuilder->codeAppend("vec4(1, 0.723, 0.332, 1.0),"); |
+ fragBuilder->codeAppend("vec4(1, 0.645, 0.164, 1.0),"); |
+ fragBuilder->codeAppend("vec4(1, 0.527, 0, 1.0),"); |
+ fragBuilder->codeAppend("vec4(1, 0.371, 0, 1.0),"); |
+ fragBuilder->codeAppend("vec4(1, 0.195, 0, 1.0),"); |
+ fragBuilder->codeAppend("vec4(1, 0, 0, 1.0)"); |
+ fragBuilder->codeAppend(");"); |
+ |
+ fragBuilder->codeAppend("int idx;"); |
+ fragBuilder->codeAppendf("vec4 dst = %s;", dstColor); |
+ fragBuilder->codeAppend("if (dst.r < 0.25) { idx = 0; }"); |
+ // cap 'idx' at 9 for upcoming increment |
+ fragBuilder->codeAppend("else if (dst.g < 0.0977) { idx = 9; }"); |
+ fragBuilder->codeAppend("else if (dst.b > 0.08) { idx = 7 - int(6 * dst.b + 0.5); }"); |
+ fragBuilder->codeAppend("else { idx = 10 - int(5.7 * dst.g + 0.5); }"); |
+ fragBuilder->codeAppend("idx++;"); |
+ fragBuilder->codeAppendf("%s = gTable[idx];", outputColor); |
+} |
+ |
+class GLOverdrawFP : public GrGLSLFragmentProcessor { |
+public: |
+ GLOverdrawFP(const GrOverdrawFP&) {} |
+ |
+ ~GLOverdrawFP() override {} |
+ |
+ void emitCode(EmitArgs& args) override { |
+ GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; |
+ SkString dstColor("dstColor"); |
+ this->emitChild(0, nullptr, &dstColor, args); |
+ |
+ add_overdraw_code(fragBuilder, dstColor.c_str(), args.fOutputColor); |
+ } |
+ |
+ static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*) { } |
+ |
+private: |
+ typedef GrGLSLFragmentProcessor INHERITED; |
+}; |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+GrGLSLFragmentProcessor* GrOverdrawFP::onCreateGLSLInstance() const { |
+ return new GLOverdrawFP(*this); |
+} |
+ |
+void GrOverdrawFP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { |
+ GLOverdrawFP::GenKey(*this, caps, b); |
+} |
+ |
+const GrFragmentProcessor* GrOverdrawFP::TestCreate(GrProcessorTestData* d) { |
+ SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChildFP(d)); |
+ return new GrOverdrawFP(dst); |
+} |
+ |
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrOverdrawFP); |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+// Xfer Processor |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+class OverdrawXP : public GrXferProcessor { |
+public: |
+ OverdrawXP(const DstTexture* dstTexture, bool hasMixedSamples) |
+ : INHERITED(dstTexture, true, hasMixedSamples) { |
+ this->initClassID<OverdrawXP>(); |
+ } |
+ |
+ const char* name() const override { return "Overdraw"; } |
+ |
+ GrGLSLXferProcessor* createGLSLInstance() const override; |
+ |
+private: |
+ GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations, |
+ bool doesStencilWrite, |
+ GrColor* overrideColor, |
+ const GrCaps& caps) const override { |
+ return GrXferProcessor::kNone_OptFlags; |
egdaniel
2016/01/20 14:28:34
I think this can return ignore color right?
robertphillips
2016/01/20 15:45:10
Done.
|
+ } |
+ |
+ void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; |
+ |
+ bool onIsEqual(const GrXferProcessor&) const override { return true; } |
+ |
+ typedef GrXferProcessor INHERITED; |
+}; |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+class GLOverdrawXP : public GrGLSLXferProcessor { |
+public: |
+ GLOverdrawXP(const OverdrawXP&) { } |
+ |
+ ~GLOverdrawXP() override {} |
+ |
+ static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*) { } |
+ |
+private: |
+ void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder, |
+ GrGLSLUniformHandler* uniformHandler, |
+ const char* srcColor, |
+ const char* srcCoverage, |
+ const char* dstColor, |
+ const char* outColor, |
+ const char* outColorSecondary, |
+ const GrXferProcessor& proc) override { |
+ add_overdraw_code(fragBuilder, dstColor, outColor); |
+ |
+ // Apply coverage. |
+ if (proc.dstReadUsesMixedSamples()) { |
egdaniel
2016/01/20 14:28:34
Instead of copying and pasting this code into almo
robertphillips
2016/01/20 15:45:10
Done.
|
+ if (srcCoverage) { |
+ fragBuilder->codeAppendf("%s *= %s;", outColor, srcCoverage); |
+ fragBuilder->codeAppendf("%s = %s;", outColorSecondary, srcCoverage); |
+ } else { |
+ fragBuilder->codeAppendf("%s = vec4(1.0);", outColorSecondary); |
+ } |
+ } else if (srcCoverage) { |
+ fragBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;", |
+ outColor, srcCoverage, outColor, srcCoverage, dstColor); |
+ } |
+ } |
+ |
+ void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override { }; |
+ |
+ typedef GrGLSLXferProcessor INHERITED; |
+}; |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+void OverdrawXP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const { |
+ GLOverdrawXP::GenKey(*this, caps, b); |
+} |
+ |
+GrGLSLXferProcessor* OverdrawXP::createGLSLInstance() const { return new GLOverdrawXP(*this); } |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+class GrOverdrawXPFactory : public GrXPFactory { |
+public: |
+ static GrXPFactory* Create() { return new GrOverdrawXPFactory(); } |
+ |
+ void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, |
+ GrXPFactory::InvariantBlendedColor* blendedColor) const override { |
+ blendedColor->fWillBlendWithDst = true; |
+ blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags; |
+ } |
+ |
+private: |
+ GrOverdrawXPFactory() { |
+ this->initClassID<GrOverdrawXPFactory>(); |
+ } |
+ |
+ GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, |
+ const GrPipelineOptimizations& optimizations, |
+ bool hasMixedSamples, |
+ const DstTexture* dstTexture) const override { |
+ return new OverdrawXP(dstTexture, hasMixedSamples); |
+ } |
+ |
+ bool willReadDstColor(const GrCaps& caps, |
+ const GrPipelineOptimizations& optimizations, |
+ bool hasMixedSamples) const override { |
+ return true; |
+ } |
+ |
+ bool onIsEqual(const GrXPFactory& xpfBase) const override { return true; } |
+ |
+ GR_DECLARE_XP_FACTORY_TEST; |
+ |
+ typedef GrXPFactory INHERITED; |
+}; |
+ |
+GR_DEFINE_XP_FACTORY_TEST(GrOverdrawXPFactory); |
+ |
+const GrXPFactory* GrOverdrawXPFactory::TestCreate(GrProcessorTestData* d) { |
+ return GrOverdrawXPFactory::Create(); |
+} |
+#endif |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+class SkOverdrawXfermode : public SkXfermode { |
+public: |
+ static SkXfermode* Create() { |
+ return new SkOverdrawXfermode; |
+ } |
+ |
+ SkPMColor xferColor(SkPMColor src, SkPMColor dst) const override { |
+ // This table encodes the color progression of the overdraw visualization |
+ static const SkPMColor gTable[] = { |
+ SkPackARGB32(0x00, 0x00, 0x00, 0x00), |
+ SkPackARGB32(0xFF, 128, 158, 255), |
+ SkPackARGB32(0xFF, 170, 185, 212), |
+ SkPackARGB32(0xFF, 213, 195, 170), |
+ SkPackARGB32(0xFF, 255, 192, 127), |
+ SkPackARGB32(0xFF, 255, 185, 85), |
+ SkPackARGB32(0xFF, 255, 165, 42), |
+ SkPackARGB32(0xFF, 255, 135, 0), |
+ SkPackARGB32(0xFF, 255, 95, 0), |
+ SkPackARGB32(0xFF, 255, 50, 0), |
+ SkPackARGB32(0xFF, 255, 0, 0) |
+ }; |
+ |
+ |
+ int idx; |
+ if (SkColorGetR(dst) < 64) { // 0 |
+ idx = 0; |
+ } else if (SkColorGetG(dst) < 25) { // 10 |
+ idx = 9; // cap at 9 for upcoming increment |
+ } else if ((SkColorGetB(dst)+21)/42 > 0) { // 1-6 |
+ idx = 7 - (SkColorGetB(dst)+21)/42; |
+ } else { // 7-9 |
+ idx = 10 - (SkColorGetG(dst)+22)/45; |
+ } |
+ ++idx; |
egdaniel
2016/01/20 14:28:34
Why is this +1 here? Why not either get right of t
robertphillips
2016/01/20 15:45:10
Done. Here and in the gpu implementation.
|
+ SkASSERT(idx < (int)SK_ARRAY_COUNT(gTable)); |
+ |
+ return gTable[idx]; |
+ } |
+ |
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkOverdrawXfermode) |
+ |
+#if SK_SUPPORT_GPU |
+ bool asFragmentProcessor(const GrFragmentProcessor** output, |
+ const GrFragmentProcessor* dst) const override { |
+ if (output) { |
+ *output = GrOverdrawFP::Create(dst); |
+ } |
+ return true; |
+ } |
+ |
+ bool asXPFactory(GrXPFactory** xpf) const override { |
+ if (xpf) { |
+ *xpf = GrOverdrawXPFactory::Create(); |
+ } |
+ return true; |
+ } |
+#endif |
+ |
+#ifndef SK_IGNORE_TO_STRING |
+ void toString(SkString* str) const override { str->set("SkOverdrawXfermode"); } |
+#endif |
+ |
+private: |
+ friend class SkOverdrawMode; |
+ |
+ void flatten(SkWriteBuffer& buffer) const override { } |
+ |
+ typedef SkXfermode INHERITED; |
+}; |
+ |
+SkFlattenable* SkOverdrawXfermode::CreateProc(SkReadBuffer& buffer) { |
+ return Create(); |
+} |
+ |
+SkXfermode* SkOverdrawMode::Create() { return new SkOverdrawXfermode; } |
+ |
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkOverdrawMode) |
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkOverdrawXfermode) |
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |