Use child processors to implement compose color filter.

Review URL: https://codereview.chromium.org/1368423003
This commit is contained in:
bsalomon 2015-09-29 06:38:55 -07:00 committed by Commit bot
parent c56c6ef3ce
commit e25eea4b36
16 changed files with 196 additions and 139 deletions

View File

@ -124,20 +124,17 @@ public:
static SkColorFilter* CreateComposeFilter(SkColorFilter* outer, SkColorFilter* inner); static SkColorFilter* CreateComposeFilter(SkColorFilter* outer, SkColorFilter* inner);
/** /**
* A subclass may implement this factory function to work with the GPU backend. * A subclass may implement this factory function to work with the GPU backend. It returns
* If it returns true, then 1 or more fragment processors will have been appended to the * a GrFragmentProcessor that implemets the color filter in GPU shader code.
* array, each of which has been ref'd, so that the caller is responsible for calling unref()
* on them when they are finished. If more than one processor is appended, they will be
* applied in FIFO order.
* *
* The fragment processor(s) must each return their color as a premul normalized value * The fragment processor receives a premultiplied input color and produces a premultiplied
* e.g. each component between [0..1] and each color component <= alpha. * output color.
* *
* If the subclass returns false, then it should not modify the array at all. * A null return indicates that the color filter isn't implemented for the GPU backend.
*/ */
virtual bool asFragmentProcessors(GrContext*, GrProcessorDataManager*, virtual const GrFragmentProcessor* asFragmentProcessor(GrContext*,
SkTDArray<const GrFragmentProcessor*>*) const { GrProcessorDataManager*) const {
return false; return nullptr;
} }
bool affectsTransparentBlack() const { bool affectsTransparentBlack() const {

View File

@ -25,8 +25,8 @@ public:
uint32_t getFlags() const override; uint32_t getFlags() const override;
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
bool asFragmentProcessors(GrContext*, GrProcessorDataManager*, const GrFragmentProcessor* asFragmentProcessor(GrContext*,
SkTDArray<const GrFragmentProcessor*>*) const override; GrProcessorDataManager*) const override;
#endif #endif
SK_TO_STRING_OVERRIDE() SK_TO_STRING_OVERRIDE()

View File

@ -26,8 +26,8 @@ public:
SkColorFilter* newComposed(const SkColorFilter*) const override; SkColorFilter* newComposed(const SkColorFilter*) const override;
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
bool asFragmentProcessors(GrContext*, GrProcessorDataManager*, const GrFragmentProcessor* asFragmentProcessor(GrContext*,
SkTDArray<const GrFragmentProcessor*>*) const override; GrProcessorDataManager*) const override;
#endif #endif
struct State { struct State {

View File

@ -28,8 +28,8 @@ public:
void filterSpan(const SkPMColor src[], int count, SkPMColor[]) const override; void filterSpan(const SkPMColor src[], int count, SkPMColor[]) const override;
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
bool asFragmentProcessors(GrContext*, GrProcessorDataManager*, const GrFragmentProcessor* asFragmentProcessor(GrContext*,
SkTDArray<const GrFragmentProcessor*>*) const override; GrProcessorDataManager*) const override;
#endif #endif
SK_TO_STRING_OVERRIDE() SK_TO_STRING_OVERRIDE()

View File

@ -39,8 +39,8 @@ public:
#endif #endif
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
bool asFragmentProcessors(GrContext*, GrProcessorDataManager*, const GrFragmentProcessor* asFragmentProcessor(GrContext*,
SkTDArray<const GrFragmentProcessor*>*) const override; GrProcessorDataManager*) const override;
#endif #endif
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkModeColorFilter) SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkModeColorFilter)

View File

@ -41,12 +41,20 @@ public:
static const GrFragmentProcessor* MulOutputByInputUnpremulColor(const GrFragmentProcessor*); static const GrFragmentProcessor* MulOutputByInputUnpremulColor(const GrFragmentProcessor*);
/** /**
* Returns a parent fragment processor that adopts the passed fragment processor as a child. The * Returns a parent fragment processor that adopts the passed fragment processor as a child.
* parent will ignore its input color and instead feed the passed in color as input to the * The parent will ignore its input color and instead feed the passed in color as input to the
* child. * child.
*/ */
static const GrFragmentProcessor* OverrideInput(const GrFragmentProcessor*, GrColor); static const GrFragmentProcessor* OverrideInput(const GrFragmentProcessor*, GrColor);
/**
* Returns a fragment processor that runs the passed in array of fragment processors in a
* series. The original input is passed to the first, the first's output is passed to the
* second, etc. The output of the returned processor is the output of the last processor of the
* series.
*/
static const GrFragmentProcessor* RunInSeries(const GrFragmentProcessor*[], int cnt);
GrFragmentProcessor() GrFragmentProcessor()
: INHERITED() : INHERITED()
, fUsesLocalCoords(false) , fUsesLocalCoords(false)

View File

@ -13,7 +13,9 @@
#include "SkUnPreMultiply.h" #include "SkUnPreMultiply.h"
#include "SkWriteBuffer.h" #include "SkWriteBuffer.h"
class GrFragmentProcessor; #if SK_SUPPORT_GPU
#include "GrFragmentProcessor.h"
#endif
bool SkColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) const { bool SkColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) const {
return false; return false;
@ -67,11 +69,15 @@ public:
#endif #endif
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
bool asFragmentProcessors(GrContext* context, GrProcessorDataManager* procDataManager, const GrFragmentProcessor* asFragmentProcessor(GrContext* context,
SkTDArray<const GrFragmentProcessor*>* array) const override { GrProcessorDataManager* pdm) const override {
bool hasFrags = fInner->asFragmentProcessors(context, procDataManager, array); SkAutoTUnref<const GrFragmentProcessor> innerFP(fInner->asFragmentProcessor(context, pdm));
hasFrags |= fOuter->asFragmentProcessors(context, procDataManager, array); SkAutoTUnref<const GrFragmentProcessor> outerFP(fOuter->asFragmentProcessor(context, pdm));
return hasFrags; if (!innerFP || !outerFP) {
return nullptr;
}
const GrFragmentProcessor* series[] = { innerFP, outerFP };
return GrFragmentProcessor::RunInSeries(series, 2);
} }
#endif #endif

View File

@ -160,7 +160,7 @@ void SkColorCubeFilter::toString(SkString* str) const {
class GrColorCubeEffect : public GrFragmentProcessor { class GrColorCubeEffect : public GrFragmentProcessor {
public: public:
static GrFragmentProcessor* Create(GrTexture* colorCube) { static const GrFragmentProcessor* Create(GrTexture* colorCube) {
return (nullptr != colorCube) ? new GrColorCubeEffect(colorCube) : nullptr; return (nullptr != colorCube) ? new GrColorCubeEffect(colorCube) : nullptr;
} }
@ -303,8 +303,8 @@ void GrColorCubeEffect::GLProcessor::GenKey(const GrProcessor& proc,
const GrGLSLCaps&, GrProcessorKeyBuilder* b) { const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
} }
bool SkColorCubeFilter::asFragmentProcessors(GrContext* context, GrProcessorDataManager*, const GrFragmentProcessor* SkColorCubeFilter::asFragmentProcessor(GrContext* context,
SkTDArray<const GrFragmentProcessor*>* array) const { GrProcessorDataManager*) const {
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey key; GrUniqueKey key;
GrUniqueKey::Builder builder(&key, kDomain, 2); GrUniqueKey::Builder builder(&key, kDomain, 2);
@ -324,19 +324,11 @@ bool SkColorCubeFilter::asFragmentProcessors(GrContext* context, GrProcessorData
desc, true, fCubeData->data(), 0)); desc, true, fCubeData->data(), 0));
if (textureCube) { if (textureCube) {
context->textureProvider()->assignUniqueKeyToTexture(key, textureCube); context->textureProvider()->assignUniqueKeyToTexture(key, textureCube);
} else {
return nullptr;
} }
} }
GrFragmentProcessor* frag = textureCube ? GrColorCubeEffect::Create(textureCube) : nullptr; return GrColorCubeEffect::Create(textureCube);
if (frag) {
if (array) {
*array->append() = frag;
} else {
frag->unref();
SkDEBUGCODE(frag = nullptr;)
}
return true;
}
return false;
} }
#endif #endif

View File

@ -70,15 +70,20 @@ SkFlattenable* SkModeColorFilter::CreateProc(SkReadBuffer& buffer) {
#include "effects/GrConstColorProcessor.h" #include "effects/GrConstColorProcessor.h"
#include "SkGr.h" #include "SkGr.h"
bool SkModeColorFilter::asFragmentProcessors(GrContext*, GrProcessorDataManager*, const GrFragmentProcessor* SkModeColorFilter::asFragmentProcessor(GrContext*,
SkTDArray<const GrFragmentProcessor*>* array) const { GrProcessorDataManager*) const {
if (SkXfermode::kDst_Mode != fMode) { if (SkXfermode::kDst_Mode == fMode) {
return nullptr;
}
SkAutoTUnref<const GrFragmentProcessor> constFP( SkAutoTUnref<const GrFragmentProcessor> constFP(
GrConstColorProcessor::Create(SkColorToPremulGrColor(fColor), GrConstColorProcessor::Create(SkColorToPremulGrColor(fColor),
GrConstColorProcessor::kIgnore_InputMode)); GrConstColorProcessor::kIgnore_InputMode));
const GrFragmentProcessor* fp = const GrFragmentProcessor* fp =
GrXfermodeFragmentProcessor::CreateFromSrcProcessor(constFP, fMode); GrXfermodeFragmentProcessor::CreateFromSrcProcessor(constFP, fMode);
if (fp) { if (!fp) {
return nullptr;
}
#ifdef SK_DEBUG #ifdef SK_DEBUG
// With a solid color input this should always be able to compute the blended color // With a solid color input this should always be able to compute the blended color
// (at least for coeff modes) // (at least for coeff modes)
@ -90,16 +95,7 @@ bool SkModeColorFilter::asFragmentProcessors(GrContext*, GrProcessorDataManager*
SkASSERT(io.validFlags() == kRGBA_GrColorComponentFlags); SkASSERT(io.validFlags() == kRGBA_GrColorComponentFlags);
} }
#endif #endif
if (array) { return fp;
*array->append() = fp;
} else {
fp->unref();
SkDEBUGCODE(fp = nullptr;)
}
return true;
}
}
return false;
} }
#endif #endif

View File

@ -390,7 +390,7 @@ SkColorFilter* SkColorMatrixFilter::newComposed(const SkColorFilter* innerFilter
class ColorMatrixEffect : public GrFragmentProcessor { class ColorMatrixEffect : public GrFragmentProcessor {
public: public:
static GrFragmentProcessor* Create(const SkColorMatrix& matrix) { static const GrFragmentProcessor* Create(const SkColorMatrix& matrix) {
return new ColorMatrixEffect(matrix); return new ColorMatrixEffect(matrix);
} }
@ -536,19 +536,9 @@ const GrFragmentProcessor* ColorMatrixEffect::TestCreate(GrProcessorTestData* d)
return ColorMatrixEffect::Create(colorMatrix); return ColorMatrixEffect::Create(colorMatrix);
} }
bool SkColorMatrixFilter::asFragmentProcessors(GrContext*, GrProcessorDataManager*, const GrFragmentProcessor* SkColorMatrixFilter::asFragmentProcessor(GrContext*,
SkTDArray<const GrFragmentProcessor*>* array) const { GrProcessorDataManager*) const {
GrFragmentProcessor* frag = ColorMatrixEffect::Create(fMatrix); return ColorMatrixEffect::Create(fMatrix);
if (frag) {
if (array) {
*array->append() = frag;
} else {
frag->unref();
SkDEBUGCODE(frag = nullptr;)
}
return true;
}
return false;
} }
#endif #endif

View File

@ -54,7 +54,7 @@ void SkLumaColorFilter::toString(SkString* str) const {
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
class LumaColorFilterEffect : public GrFragmentProcessor { class LumaColorFilterEffect : public GrFragmentProcessor {
public: public:
static GrFragmentProcessor* Create() { static const GrFragmentProcessor* Create() {
static LumaColorFilterEffect gLumaEffect; static LumaColorFilterEffect gLumaEffect;
return SkRef(&gLumaEffect); return SkRef(&gLumaEffect);
} }
@ -108,19 +108,9 @@ private:
} }
}; };
bool SkLumaColorFilter::asFragmentProcessors(GrContext*, GrProcessorDataManager*, const GrFragmentProcessor* SkLumaColorFilter::asFragmentProcessor(GrContext*,
SkTDArray<const GrFragmentProcessor*>* array) const { GrProcessorDataManager*) const {
GrFragmentProcessor* frag = LumaColorFilterEffect::Create(); return LumaColorFilterEffect::Create();
if (frag) {
if (array) {
*array->append() = frag;
} else {
frag->unref();
SkDEBUGCODE(frag = nullptr;)
}
return true;
}
return false;
} }
#endif #endif

View File

@ -48,8 +48,8 @@ public:
SkColorFilter* newComposed(const SkColorFilter* inner) const override; SkColorFilter* newComposed(const SkColorFilter* inner) const override;
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
bool asFragmentProcessors(GrContext*, GrProcessorDataManager*, const GrFragmentProcessor* asFragmentProcessor(GrContext*,
SkTDArray<const GrFragmentProcessor*>*) const override; GrProcessorDataManager*) const override;
#endif #endif
void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override; void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override;
@ -340,7 +340,7 @@ SkColorFilter* SkTable_ColorFilter::newComposed(const SkColorFilter* innerFilter
class ColorTableEffect : public GrFragmentProcessor { class ColorTableEffect : public GrFragmentProcessor {
public: public:
static GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags); static const GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags);
virtual ~ColorTableEffect(); virtual ~ColorTableEffect();
@ -461,7 +461,8 @@ void GLColorTableEffect::emitCode(EmitArgs& args) {
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap bitmap, unsigned flags) { const GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap bitmap,
unsigned flags) {
GrTextureStripAtlas::Desc desc; GrTextureStripAtlas::Desc desc;
desc.fWidth = bitmap.width(); desc.fWidth = bitmap.width();
@ -563,31 +564,17 @@ const GrFragmentProcessor* ColorTableEffect::TestCreate(GrProcessorTestData* d)
(flags & (1 << 3)) ? luts[3] : nullptr (flags & (1 << 3)) ? luts[3] : nullptr
)); ));
SkTDArray<const GrFragmentProcessor*> array; const GrFragmentProcessor* fp = filter->asFragmentProcessor(d->fContext, d->fProcDataManager);
if (filter->asFragmentProcessors(d->fContext, d->fProcDataManager, &array)) { SkASSERT(fp);
SkASSERT(1 == array.count()); // TableColorFilter only returns 1 return fp;
return array[0];
}
return nullptr;
} }
bool SkTable_ColorFilter::asFragmentProcessors(GrContext* context, const GrFragmentProcessor* SkTable_ColorFilter::asFragmentProcessor(GrContext* context,
GrProcessorDataManager*, GrProcessorDataManager*) const {
SkTDArray<const GrFragmentProcessor*>* array) const {
SkBitmap bitmap; SkBitmap bitmap;
this->asComponentTable(&bitmap); this->asComponentTable(&bitmap);
GrFragmentProcessor* frag = ColorTableEffect::Create(context, bitmap, fFlags); return ColorTableEffect::Create(context, bitmap, fFlags);
if (frag) {
if (array) {
*array->append() = frag;
} else {
frag->unref();
SkDEBUGCODE(frag = nullptr;)
}
return true;
}
return false;
} }
#endif // SK_SUPPORT_GPU #endif // SK_SUPPORT_GPU

View File

@ -10,6 +10,7 @@
#include "GrCoordTransform.h" #include "GrCoordTransform.h"
#include "gl/GrGLFragmentProcessor.h" #include "gl/GrGLFragmentProcessor.h"
#include "gl/builders/GrGLProgramBuilder.h" #include "gl/builders/GrGLProgramBuilder.h"
#include "effects/GrConstColorProcessor.h"
#include "effects/GrXfermodeFragmentProcessor.h" #include "effects/GrXfermodeFragmentProcessor.h"
GrFragmentProcessor::~GrFragmentProcessor() { GrFragmentProcessor::~GrFragmentProcessor() {
@ -279,3 +280,96 @@ const GrFragmentProcessor* GrFragmentProcessor::OverrideInput(const GrFragmentPr
return SkRef(fp); return SkRef(fp);
} }
} }
const GrFragmentProcessor* GrFragmentProcessor::RunInSeries(const GrFragmentProcessor* series[],
int cnt) {
class SeriesFragmentProcessor : public GrFragmentProcessor {
public:
SeriesFragmentProcessor(const GrFragmentProcessor* children[], int cnt){
SkASSERT(cnt > 1);
this->initClassID<SeriesFragmentProcessor>();
for (int i = 0; i < cnt; ++i) {
this->registerChildProcessor(children[i]);
}
}
const char* name() const override { return "Series"; }
GrGLFragmentProcessor* onCreateGLInstance() const override {
class GLFP : public GrGLFragmentProcessor {
public:
GLFP() {}
void emitCode(EmitArgs& args) override {
SkString input(args.fInputColor);
for (int i = 0; i < this->numChildProcessors() - 1; ++i) {
SkString temp;
temp.printf("out%d", i);
this->emitChild(i, input.c_str(), &temp, args);
input = temp;
}
// Last guy writes to our output variable.
this->emitChild(this->numChildProcessors() - 1, input.c_str(), args);
}
};
return new GLFP;
}
private:
void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override {}
bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
GrProcOptInfo info;
SkTDArray<const GrFragmentProcessor*> children;
children.setCount(this->numChildProcessors());
for (int i = 0; i < children.count(); ++i) {
children[i] = &this->childProcessor(i);
}
info.calcWithInitialValues(children.begin(), children.count(), inout->color(),
inout->validFlags(), false, false);
for (int i = 0; i < this->numChildProcessors(); ++i) {
this->childProcessor(i).computeInvariantOutput(inout);
}
}
};
if (!cnt) {
return nullptr;
}
// Run the through the series, do the invariant output processing, and look for eliminations.
SkTDArray<const GrFragmentProcessor*> replacementSeries;
SkAutoTUnref<const GrFragmentProcessor> colorFP;
GrProcOptInfo info;
info.calcWithInitialValues(series, cnt, 0x0, kNone_GrColorComponentFlags, false, false);
if (kRGBA_GrColorComponentFlags == info.validFlags()) {
return GrConstColorProcessor::Create(info.color(),
GrConstColorProcessor::kIgnore_InputMode);
} else {
int firstIdx = info.firstEffectiveProcessorIndex();
cnt -= firstIdx;
if (firstIdx > 0 && info.inputColorIsUsed()) {
colorFP.reset(GrConstColorProcessor::Create(info.inputColorToFirstEffectiveProccesor(),
GrConstColorProcessor::kIgnore_InputMode));
cnt += 1;
replacementSeries.setCount(cnt);
replacementSeries[0] = colorFP;
for (int i = 0; i < cnt - 1; ++i) {
replacementSeries[i + 1] = series[firstIdx + i];
}
series = replacementSeries.begin();
} else {
series += firstIdx;
cnt -= firstIdx;
}
}
if (1 == cnt) {
return SkRef(series[0]);
} else {
return new SeriesFragmentProcessor(series, cnt);
}
}

View File

@ -50,7 +50,7 @@ public:
GrColor color() const { return fInOut.color(); } GrColor color() const { return fInOut.color(); }
GrColorComponentFlags validFlags() const { GrColorComponentFlags validFlags() const {
return static_cast<GrColorComponentFlags>(fInOut.validFlags()); return fInOut.validFlags();
} }
/** /**

View File

@ -812,12 +812,10 @@ static inline bool skpaint_to_grpaint_impl(GrContext* context,
if (applyColorFilterToPaintColor) { if (applyColorFilterToPaintColor) {
grPaint->setColor(SkColorToPremulGrColor(colorFilter->filterColor(skPaint.getColor()))); grPaint->setColor(SkColorToPremulGrColor(colorFilter->filterColor(skPaint.getColor())));
} else { } else {
SkTDArray<const GrFragmentProcessor*> array; SkAutoTUnref<const GrFragmentProcessor> cfFP(
if (colorFilter->asFragmentProcessors(context, grPaint->getProcessorDataManager(), colorFilter->asFragmentProcessor(context, grPaint->getProcessorDataManager()));
&array)) { if (cfFP) {
for (int i = 0; i < array.count(); ++i) { grPaint->addColorFragmentProcessor(cfFP);
grPaint->addColorFragmentProcessor(array[i])->unref();
}
} else { } else {
return false; return false;
} }

View File

@ -100,19 +100,18 @@ static void test_getConstantColorComponents(skiatest::Reporter* reporter, GrCont
GrPaint paint; GrPaint paint;
for (size_t i = 0; i < SK_ARRAY_COUNT(filterTests); ++i) { for (size_t i = 0; i < SK_ARRAY_COUNT(filterTests); ++i) {
const GetConstantComponentTestCase& test = filterTests[i]; const GetConstantComponentTestCase& test = filterTests[i];
SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(test.filterColor, test.filterMode)); SkAutoTUnref<SkColorFilter> cf(
SkTDArray<const GrFragmentProcessor*> array; SkColorFilter::CreateModeFilter(test.filterColor, test.filterMode));
bool hasFrag = cf->asFragmentProcessors(grContext, paint.getProcessorDataManager(), &array); SkAutoTUnref<const GrFragmentProcessor> fp(
REPORTER_ASSERT(reporter, hasFrag); cf->asFragmentProcessor(grContext, paint.getProcessorDataManager()));
REPORTER_ASSERT(reporter, 1 == array.count()); REPORTER_ASSERT(reporter, fp);
GrInvariantOutput inout(test.inputColor, GrInvariantOutput inout(test.inputColor,
static_cast<GrColorComponentFlags>(test.inputComponents), static_cast<GrColorComponentFlags>(test.inputComponents),
false); false);
array[0]->computeInvariantOutput(&inout); fp->computeInvariantOutput(&inout);
REPORTER_ASSERT(reporter, filterColor(inout.color(), inout.validFlags()) ==
REPORTER_ASSERT(reporter, filterColor(inout.color(), inout.validFlags()) == test.outputColor); test.outputColor);
REPORTER_ASSERT(reporter, test.outputComponents == inout.validFlags()); REPORTER_ASSERT(reporter, test.outputComponents == inout.validFlags());
array[0]->unref();
} }
} }