/* * 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 "SkOverdrawColorFilter.h" void SkOverdrawColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const { for (int x = 0; x < count; x++) { uint8_t alpha = SkGetPackedA32(src[x]); if (alpha >= kNumColors) { alpha = kNumColors - 1; } dst[x] = fColors[alpha]; } } void SkOverdrawColorFilter::toString(SkString* str) const { str->append("SkOverdrawColorFilter ("); for (int i = 0; i < kNumColors; i++) { str->appendf("%d: %x\n", i, fColors[i]); } str->append(")"); } void SkOverdrawColorFilter::flatten(SkWriteBuffer& buffer) const { buffer.writeByteArray(fColors, kNumColors * sizeof(SkPMColor)); } sk_sp SkOverdrawColorFilter::CreateProc(SkReadBuffer& buffer) { SkPMColor colors[kNumColors]; size_t size = buffer.getArrayCount(); if (!buffer.validate(size == sizeof(colors))) { return nullptr; } if (!buffer.readByteArray(colors, sizeof(colors))) { return nullptr; } return SkOverdrawColorFilter::Make(colors); } SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkOverdrawColorFilter) SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkOverdrawColorFilter) SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END #if SK_SUPPORT_GPU #include "GrFragmentProcessor.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" class OverdrawFragmentProcessor : public GrFragmentProcessor { public: static sk_sp Make(const SkPMColor* colors); const char* name() const override { return "Overdraw"; } private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} bool onIsEqual(const GrFragmentProcessor&) const override; OverdrawFragmentProcessor(const GrColor4f* colors); GrColor4f fColors[SkOverdrawColorFilter::kNumColors]; typedef GrFragmentProcessor INHERITED; }; class GLOverdrawFragmentProcessor : public GrGLSLFragmentProcessor { public: GLOverdrawFragmentProcessor(const GrColor4f* colors); void emitCode(EmitArgs&) override; protected: void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override {} private: GrColor4f fColors[SkOverdrawColorFilter::kNumColors]; typedef GrGLSLFragmentProcessor INHERITED; }; sk_sp SkOverdrawColorFilter::asFragmentProcessor(GrContext*, SkColorSpace*) const { return OverdrawFragmentProcessor::Make(fColors); } sk_sp OverdrawFragmentProcessor::Make(const SkPMColor* colors) { GrColor4f grColors[SkOverdrawColorFilter::kNumColors]; for (int i = 0; i < SkOverdrawColorFilter::kNumColors; i++) { grColors[i] = GrColor4f::FromGrColor(GrColorPackRGBA(SkGetPackedR32(colors[i]), SkGetPackedG32(colors[i]), SkGetPackedB32(colors[i]), SkGetPackedA32(colors[i]))); } return sk_sp(new OverdrawFragmentProcessor(grColors)); } // This could implement the constant input -> constant output optimization, but we don't really // care given how this is used. OverdrawFragmentProcessor::OverdrawFragmentProcessor(const GrColor4f* colors) : INHERITED(kNone_OptimizationFlags) { this->initClassID(); memcpy(fColors, colors, SkOverdrawColorFilter::kNumColors * sizeof(GrColor4f)); } GrGLSLFragmentProcessor* OverdrawFragmentProcessor::onCreateGLSLInstance() const { return new GLOverdrawFragmentProcessor(fColors); } bool OverdrawFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const { const OverdrawFragmentProcessor& that = other.cast(); return 0 == memcmp(fColors, that.fColors, sizeof(GrColor4f) * SkOverdrawColorFilter::kNumColors); } GLOverdrawFragmentProcessor::GLOverdrawFragmentProcessor(const GrColor4f* colors) { memcpy(fColors, colors, SkOverdrawColorFilter::kNumColors * sizeof(GrColor4f)); } void GLOverdrawFragmentProcessor::emitCode(EmitArgs& args) { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; if (nullptr == args.fInputColor) { fragBuilder->codeAppendf("%s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, fColors[5].fRGBA[0], fColors[5].fRGBA[1], fColors[5].fRGBA[2], fColors[5].fRGBA[3]); } else { fragBuilder->codeAppendf("float alpha = 255.0 * %s.a;", args.fInputColor); fragBuilder->codeAppendf("if (alpha < 0.5) {"); fragBuilder->codeAppendf(" %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, fColors[0].fRGBA[0], fColors[0].fRGBA[1], fColors[0].fRGBA[2], fColors[0].fRGBA[3]); fragBuilder->codeAppendf("} else if (alpha < 1.5) {"); fragBuilder->codeAppendf(" %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, fColors[1].fRGBA[0], fColors[1].fRGBA[1], fColors[1].fRGBA[2], fColors[1].fRGBA[3]); fragBuilder->codeAppendf("} else if (alpha < 2.5) {"); fragBuilder->codeAppendf(" %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, fColors[2].fRGBA[0], fColors[2].fRGBA[1], fColors[2].fRGBA[2], fColors[2].fRGBA[3]); fragBuilder->codeAppendf("} else if (alpha < 3.5) {"); fragBuilder->codeAppendf(" %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, fColors[3].fRGBA[0], fColors[3].fRGBA[1], fColors[3].fRGBA[2], fColors[3].fRGBA[3]); fragBuilder->codeAppendf("} else if (alpha < 4.5) {"); fragBuilder->codeAppendf(" %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, fColors[4].fRGBA[0], fColors[4].fRGBA[1], fColors[4].fRGBA[2], fColors[4].fRGBA[3]); fragBuilder->codeAppendf("} else {"); fragBuilder->codeAppendf(" %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor, fColors[5].fRGBA[0], fColors[5].fRGBA[1], fColors[5].fRGBA[2], fColors[5].fRGBA[3]); fragBuilder->codeAppendf("}"); } } #endif