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);
/**
* A subclass may implement this factory function to work with the GPU backend.
* If it returns true, then 1 or more fragment processors will have been appended to the
* 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.
* A subclass may implement this factory function to work with the GPU backend. It returns
* a GrFragmentProcessor that implemets the color filter in GPU shader code.
*
* The fragment processor(s) must each return their color as a premul normalized value
* e.g. each component between [0..1] and each color component <= alpha.
* The fragment processor receives a premultiplied input color and produces a premultiplied
* 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*,
SkTDArray<const GrFragmentProcessor*>*) const {
return false;
virtual const GrFragmentProcessor* asFragmentProcessor(GrContext*,
GrProcessorDataManager*) const {
return nullptr;
}
bool affectsTransparentBlack() const {

View File

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

View File

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

View File

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

View File

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

View File

@ -41,12 +41,20 @@ public:
static const GrFragmentProcessor* MulOutputByInputUnpremulColor(const GrFragmentProcessor*);
/**
* Returns a parent fragment processor that adopts the passed fragment processor as a child. The
* parent will ignore its input color and instead feed the passed in color as input to the
* child.
* Returns a parent fragment processor that adopts the passed fragment processor as a child.
* The parent will ignore its input color and instead feed the passed in color as input to the
* child.
*/
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()
: INHERITED()
, fUsesLocalCoords(false)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -48,8 +48,8 @@ public:
SkColorFilter* newComposed(const SkColorFilter* inner) const override;
#if SK_SUPPORT_GPU
bool asFragmentProcessors(GrContext*, GrProcessorDataManager*,
SkTDArray<const GrFragmentProcessor*>*) const override;
const GrFragmentProcessor* asFragmentProcessor(GrContext*,
GrProcessorDataManager*) const override;
#endif
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 {
public:
static GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags);
static const GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags);
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;
desc.fWidth = bitmap.width();
@ -563,31 +564,17 @@ const GrFragmentProcessor* ColorTableEffect::TestCreate(GrProcessorTestData* d)
(flags & (1 << 3)) ? luts[3] : nullptr
));
SkTDArray<const GrFragmentProcessor*> array;
if (filter->asFragmentProcessors(d->fContext, d->fProcDataManager, &array)) {
SkASSERT(1 == array.count()); // TableColorFilter only returns 1
return array[0];
}
return nullptr;
const GrFragmentProcessor* fp = filter->asFragmentProcessor(d->fContext, d->fProcDataManager);
SkASSERT(fp);
return fp;
}
bool SkTable_ColorFilter::asFragmentProcessors(GrContext* context,
GrProcessorDataManager*,
SkTDArray<const GrFragmentProcessor*>* array) const {
const GrFragmentProcessor* SkTable_ColorFilter::asFragmentProcessor(GrContext* context,
GrProcessorDataManager*) const {
SkBitmap bitmap;
this->asComponentTable(&bitmap);
GrFragmentProcessor* frag = ColorTableEffect::Create(context, bitmap, fFlags);
if (frag) {
if (array) {
*array->append() = frag;
} else {
frag->unref();
SkDEBUGCODE(frag = nullptr;)
}
return true;
}
return false;
return ColorTableEffect::Create(context, bitmap, fFlags);
}
#endif // SK_SUPPORT_GPU

View File

@ -10,6 +10,7 @@
#include "GrCoordTransform.h"
#include "gl/GrGLFragmentProcessor.h"
#include "gl/builders/GrGLProgramBuilder.h"
#include "effects/GrConstColorProcessor.h"
#include "effects/GrXfermodeFragmentProcessor.h"
GrFragmentProcessor::~GrFragmentProcessor() {
@ -279,3 +280,96 @@ const GrFragmentProcessor* GrFragmentProcessor::OverrideInput(const GrFragmentPr
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(); }
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) {
grPaint->setColor(SkColorToPremulGrColor(colorFilter->filterColor(skPaint.getColor())));
} else {
SkTDArray<const GrFragmentProcessor*> array;
if (colorFilter->asFragmentProcessors(context, grPaint->getProcessorDataManager(),
&array)) {
for (int i = 0; i < array.count(); ++i) {
grPaint->addColorFragmentProcessor(array[i])->unref();
}
SkAutoTUnref<const GrFragmentProcessor> cfFP(
colorFilter->asFragmentProcessor(context, grPaint->getProcessorDataManager()));
if (cfFP) {
grPaint->addColorFragmentProcessor(cfFP);
} else {
return false;
}

View File

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