Add support for an inputFP in SkTableColorFilter::asFragmentProcessor.

Additionally, fixed a performance bug which caused the fragment
processor to sample the alpha component from the color-table texture
twice. (This repeated evalation was not optimized away during
compilation.)

Change-Id: Ia2314d7918d849b894043321d6dca5da633cda4a
Bug: skia:10217
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300699
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
This commit is contained in:
John Stiles 2020-07-06 14:45:57 -04:00 committed by Skia Commit-Bot
parent 8d639e1a42
commit 3851be4555

View File

@ -20,48 +20,29 @@
#include "src/core/SkVM.h" #include "src/core/SkVM.h"
#include "src/core/SkWriteBuffer.h" #include "src/core/SkWriteBuffer.h"
static const uint8_t gIdentityTable[] = { static const uint8_t kIdentityTable[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
}; };
class SkTable_ColorFilter : public SkColorFilterBase { class SkTable_ColorFilter : public SkColorFilterBase {
public: public:
SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[], SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[],
const uint8_t tableG[], const uint8_t tableB[]) { const uint8_t tableG[], const uint8_t tableB[]) {
fBitmap = nullptr;
fFlags = 0;
uint8_t* dst = fStorage; uint8_t* dst = fStorage;
if (tableA) { if (tableA) {
memcpy(dst, tableA, 256); memcpy(dst, tableA, 256);
@ -87,8 +68,9 @@ public:
~SkTable_ColorFilter() override { delete fBitmap; } ~SkTable_ColorFilter() override { delete fBitmap; }
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(GrRecordingContext*, bool colorFilterAcceptsInputFP() const override { return true; }
const GrColorInfo&) const override; GrFPResult asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
GrRecordingContext*, const GrColorInfo&) const override;
#endif #endif
enum { enum {
@ -99,10 +81,10 @@ public:
}; };
bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override { bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
const uint8_t *r = gIdentityTable, const uint8_t *r = kIdentityTable,
*g = gIdentityTable, *g = kIdentityTable,
*b = gIdentityTable, *b = kIdentityTable,
*a = gIdentityTable; *a = kIdentityTable;
const uint8_t* ptr = fStorage; const uint8_t* ptr = fStorage;
if (fFlags & kA_Flag) { a = ptr; ptr += 256; } if (fFlags & kA_Flag) { a = ptr; ptr += 256; }
if (fFlags & kR_Flag) { r = ptr; ptr += 256; } if (fFlags & kR_Flag) { r = ptr; ptr += 256; }
@ -163,17 +145,17 @@ private:
void getTableAsBitmap(SkBitmap* table) const; void getTableAsBitmap(SkBitmap* table) const;
mutable const SkBitmap* fBitmap; // lazily allocated mutable const SkBitmap* fBitmap = nullptr; // lazily allocated
uint8_t fStorage[256 * 4]; uint8_t fStorage[256 * 4];
unsigned fFlags; unsigned int fFlags = 0;
friend class SkTableColorFilter; friend class SkTableColorFilter;
typedef SkColorFilter INHERITED; typedef SkColorFilter INHERITED;
}; };
static const uint8_t gCountNibBits[] = { static const uint8_t kCountNibBits[] = {
0, 1, 1, 2, 0, 1, 1, 2,
1, 2, 2, 3, 1, 2, 2, 3,
1, 2, 2, 3, 1, 2, 2, 3,
@ -184,9 +166,8 @@ static const uint8_t gCountNibBits[] = {
void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const { void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
uint8_t storage[5*256]; uint8_t storage[5*256];
int count = gCountNibBits[fFlags & 0xF]; int count = kCountNibBits[fFlags & 0xF];
size_t size = SkPackBits::Pack8(fStorage, count * 256, storage, size_t size = SkPackBits::Pack8(fStorage, count * 256, storage, sizeof(storage));
sizeof(storage));
buffer.write32(fFlags); buffer.write32(fFlags);
buffer.writeByteArray(storage, size); buffer.writeByteArray(storage, size);
@ -194,7 +175,7 @@ void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
sk_sp<SkFlattenable> SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) { sk_sp<SkFlattenable> SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
const int flags = buffer.read32(); const int flags = buffer.read32();
const size_t count = gCountNibBits[flags & 0xF]; const size_t count = kCountNibBits[flags & 0xF];
SkASSERT(count <= 4); SkASSERT(count <= 4);
uint8_t packedStorage[5*256]; uint8_t packedStorage[5*256];
@ -250,7 +231,7 @@ void SkTable_ColorFilter::getTableAsBitmap(SkBitmap* table) const {
for (int x = 0; x < 4; ++x) { for (int x = 0; x < 4; ++x) {
if (!(fFlags & kFlags[x])) { if (!(fFlags & kFlags[x])) {
memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable)); memcpy(bitmapPixels, kIdentityTable, sizeof(kIdentityTable));
} else { } else {
memcpy(bitmapPixels, fStorage + offset, 256); memcpy(bitmapPixels, fStorage + offset, 256);
offset += 256; offset += 256;
@ -277,7 +258,8 @@ void SkTable_ColorFilter::getTableAsBitmap(SkBitmap* table) const {
class ColorTableEffect : public GrFragmentProcessor { class ColorTableEffect : public GrFragmentProcessor {
public: public:
static std::unique_ptr<GrFragmentProcessor> Make(GrRecordingContext* context, static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP,
GrRecordingContext* context,
const SkBitmap& bitmap); const SkBitmap& bitmap);
~ColorTableEffect() override {} ~ColorTableEffect() override {}
@ -288,6 +270,15 @@ public:
return std::unique_ptr<GrFragmentProcessor>(new ColorTableEffect(*this)); return std::unique_ptr<GrFragmentProcessor>(new ColorTableEffect(*this));
} }
bool hasInputFP() const {
// We always have a texture-effect child processor at index 0.
// If we have an input FP, it will be at child index 1.
return this->numChildProcessors() > 1;
}
static constexpr int kTexEffectFPIndex = 0;
static constexpr int kInputFPIndex = 1;
private: private:
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
@ -295,7 +286,7 @@ private:
bool onIsEqual(const GrFragmentProcessor&) const override { return true; } bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
ColorTableEffect(GrSurfaceProxyView view); ColorTableEffect(std::unique_ptr<GrFragmentProcessor> inputFP, GrSurfaceProxyView view);
explicit ColorTableEffect(const ColorTableEffect& that); explicit ColorTableEffect(const ColorTableEffect& that);
@ -304,11 +295,15 @@ private:
typedef GrFragmentProcessor INHERITED; typedef GrFragmentProcessor INHERITED;
}; };
ColorTableEffect::ColorTableEffect(GrSurfaceProxyView view) ColorTableEffect::ColorTableEffect(std::unique_ptr<GrFragmentProcessor> inputFP,
GrSurfaceProxyView view)
// Not bothering with table-specific optimizations. // Not bothering with table-specific optimizations.
: INHERITED(kColorTableEffect_ClassID, kNone_OptimizationFlags) { : INHERITED(kColorTableEffect_ClassID, kNone_OptimizationFlags) {
auto te = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType); this->registerChild(GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType),
this->registerChild(std::move(te), SkSL::SampleUsage::Explicit()); SkSL::SampleUsage::Explicit());
if (inputFP) {
this->registerChild(std::move(inputFP));
}
} }
ColorTableEffect::ColorTableEffect(const ColorTableEffect& that) ColorTableEffect::ColorTableEffect(const ColorTableEffect& that)
@ -320,23 +315,29 @@ GrGLSLFragmentProcessor* ColorTableEffect::onCreateGLSLInstance() const {
class Impl : public GrGLSLFragmentProcessor { class Impl : public GrGLSLFragmentProcessor {
public: public:
void emitCode(EmitArgs& args) override { void emitCode(EmitArgs& args) override {
const ColorTableEffect& proc = args.fFp.cast<ColorTableEffect>();
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
fragBuilder->codeAppendf("\t\thalf4 coord = 255*unpremul(%s) + 0.5;\n", SkString inputColor = proc.hasInputFP()
args.fInputColor); ? this->invokeChild(kInputFPIndex, args.fInputColor, args)
SkString a = this->invokeChild(0, args, "half2(coord.a, 0.5)"); : SkString(args.fInputColor);
SkString r = this->invokeChild(0, args, "half2(coord.r, 1.5)"); SkString a = this->invokeChild(kTexEffectFPIndex, args, "half2(coord.a, 0.5)");
SkString g = this->invokeChild(0, args, "half2(coord.g, 2.5)"); SkString r = this->invokeChild(kTexEffectFPIndex, args, "half2(coord.r, 1.5)");
SkString b = this->invokeChild(0, args, "half2(coord.b, 3.5)"); SkString g = this->invokeChild(kTexEffectFPIndex, args, "half2(coord.g, 2.5)");
fragBuilder->codeAppendf("%s = half4(half3(%s.a, %s.a, %s.a) * %s.a, %s.a);", SkString b = this->invokeChild(kTexEffectFPIndex, args, "half2(coord.b, 3.5)");
args.fOutputColor, r.c_str(), g.c_str(), b.c_str(), a.c_str(), fragBuilder->codeAppendf("half4 coord = 255 * unpremul(%s) + 0.5;\n"
a.c_str()); "%s = half4(%s.a, %s.a, %s.a, 1);\n"
"%s *= %s.a;\n",
inputColor.c_str(),
args.fOutputColor, r.c_str(), g.c_str(), b.c_str(),
args.fOutputColor, a.c_str());
} }
}; };
return new Impl; return new Impl;
} }
std::unique_ptr<GrFragmentProcessor> ColorTableEffect::Make(GrRecordingContext* context, std::unique_ptr<GrFragmentProcessor> ColorTableEffect::Make(
const SkBitmap& bitmap) { std::unique_ptr<GrFragmentProcessor> inputFP,
GrRecordingContext* context, const SkBitmap& bitmap) {
SkASSERT(kPremul_SkAlphaType == bitmap.alphaType()); SkASSERT(kPremul_SkAlphaType == bitmap.alphaType());
SkASSERT(bitmap.isImmutable()); SkASSERT(bitmap.isImmutable());
@ -345,7 +346,8 @@ std::unique_ptr<GrFragmentProcessor> ColorTableEffect::Make(GrRecordingContext*
return nullptr; return nullptr;
} }
return std::unique_ptr<GrFragmentProcessor>(new ColorTableEffect(std::move(view))); return std::unique_ptr<GrFragmentProcessor>(
new ColorTableEffect(std::move(inputFP), std::move(view)));
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -378,20 +380,21 @@ std::unique_ptr<GrFragmentProcessor> ColorTableEffect::TestCreate(GrProcessorTes
(flags & (1 << 3)) ? luts[3] : nullptr (flags & (1 << 3)) ? luts[3] : nullptr
)); ));
sk_sp<SkColorSpace> colorSpace = GrTest::TestColorSpace(d->fRandom); sk_sp<SkColorSpace> colorSpace = GrTest::TestColorSpace(d->fRandom);
auto fp = as_CFB(filter)->asFragmentProcessor( auto [success, fp] = as_CFB(filter)->asFragmentProcessor(
d->context(), /*inputFP=*/nullptr, d->context(),
GrColorInfo(GrColorType::kRGBA_8888, kUnknown_SkAlphaType, std::move(colorSpace))); GrColorInfo(GrColorType::kRGBA_8888, kUnknown_SkAlphaType, std::move(colorSpace)));
SkASSERT(fp); SkASSERT(success);
return fp; return std::move(fp);
} }
#endif #endif
std::unique_ptr<GrFragmentProcessor> SkTable_ColorFilter::asFragmentProcessor( GrFPResult SkTable_ColorFilter::asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
GrRecordingContext* context, const GrColorInfo&) const { GrRecordingContext* context,
const GrColorInfo&) const {
SkBitmap bitmap; SkBitmap bitmap;
this->getTableAsBitmap(&bitmap); this->getTableAsBitmap(&bitmap);
return ColorTableEffect::Make(context, bitmap); return GrFPSuccess(ColorTableEffect::Make(std::move(inputFP), context, bitmap));
} }
#endif // SK_SUPPORT_GPU #endif // SK_SUPPORT_GPU