converted GrConfigConversionEffect to SkSL
Bug: skia:
Change-Id: If17cf0fc8b857d22f33a462a39a02bcddd15deda
Reviewed-on: https://skia-review.googlesource.com/55741
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
diff --git a/gn/sksl.gni b/gn/sksl.gni
index 65913e3..55e8bd2 100644
--- a/gn/sksl.gni
+++ b/gn/sksl.gni
@@ -29,6 +29,7 @@
"$_src/effects/GrCircleBlurFragmentProcessor.fp",
"$_src/gpu/effects/GrBlurredEdgeFragmentProcessor.fp",
"$_src/gpu/effects/GrCircleEffect.fp",
+ "$_src/gpu/effects/GrConfigConversionEffect.fp",
"$_src/gpu/effects/GrDitherEffect.fp",
"$_src/gpu/effects/GrEllipseEffect.fp",
"$_src/gpu/effects/GrSimpleTextureEffect.fp",
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index e1ecc7f..2c12c7e 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -1,212 +1,71 @@
/*
- * Copyright 2012 Google Inc.
+ * Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
+/*
+ * This file was autogenerated from GrConfigConversionEffect.fp; do not modify.
+ */
#include "GrConfigConversionEffect.h"
-#include "../private/GrGLSL.h"
-#include "GrClip.h"
-#include "GrContext.h"
-#include "GrRenderTargetContext.h"
-#include "SkMatrix.h"
+#if SK_SUPPORT_GPU
+#include "glsl/GrGLSLColorSpaceXformHelper.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
-
-class GrGLConfigConversionEffect : public GrGLSLFragmentProcessor {
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLConfigConversionEffect : public GrGLSLFragmentProcessor {
public:
+ GrGLSLConfigConversionEffect() {}
void emitCode(EmitArgs& args) override {
- const GrConfigConversionEffect& cce = args.fFp.cast<GrConfigConversionEffect>();
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+ const GrConfigConversionEffect& _outer = args.fFp.cast<GrConfigConversionEffect>();
+ (void)_outer;
- // Use highp throughout the shader to avoid some precision issues on specific GPUs.
fragBuilder->forceHighPrecision();
-
- if (nullptr == args.fInputColor) {
- // could optimize this case, but we aren't for now.
- args.fInputColor = "half4(1)";
- }
-
- // Aggressively round to the nearest exact (N / 255) floating point value. This lets us
- // find a round-trip preserving pair on some GPUs that do odd byte to float conversion.
- fragBuilder->codeAppendf("half4 color = floor(%s * 255.0 + 0.5) / 255.0;", args.fInputColor);
-
- switch (cce.pmConversion()) {
- case GrConfigConversionEffect::kToPremul_PMConversion:
- fragBuilder->codeAppend(
- "color.rgb = floor(color.rgb * color.a * 255.0 + 0.5) / 255.0;");
- break;
-
- case GrConfigConversionEffect::kToUnpremul_PMConversion:
- fragBuilder->codeAppend(
- "color.rgb = color.a <= 0.0 ? half3(0,0,0) : floor(color.rgb / color.a * 255.0 + 0.5) / 255.0;");
- break;
-
- default:
- SK_ABORT("Unknown conversion op.");
- break;
- }
- fragBuilder->codeAppendf("%s = color;", args.fOutputColor);
- }
-
- static inline void GenKey(const GrProcessor& processor, const GrShaderCaps&,
- GrProcessorKeyBuilder* b) {
- const GrConfigConversionEffect& cce = processor.cast<GrConfigConversionEffect>();
- uint32_t key = cce.pmConversion();
- b->add32(key);
+ fragBuilder->codeAppendf(
+ "%s = half4(floor(float4(float4(%s * 255.0) + 0.5)) / 255.0);\n@switch (%d) {\n "
+ "case 0:\n %s.xyz = half3(floor(float3(float3((%s.xyz * %s.w) * 255.0) + "
+ "0.5)) / 255.0);\n break;\n case 1:\n %s.xyz = float(%s.w) <= 0.0 "
+ "? half3(0.0) : half3(floor(float3(float3((%s.xyz / %s.w) * 255.0) + 0.5)) / "
+ "255.0);\n break;\n}\n",
+ args.fOutputColor, args.fInputColor ? args.fInputColor : "half4(1)",
+ _outer.pmConversion(), args.fOutputColor, args.fOutputColor, args.fOutputColor,
+ args.fOutputColor, args.fOutputColor, args.fOutputColor, args.fOutputColor);
}
private:
- typedef GrGLSLFragmentProcessor INHERITED;
-
+ void onSetData(const GrGLSLProgramDataManager& pdman,
+ const GrFragmentProcessor& _proc) override {}
};
-
-///////////////////////////////////////////////////////////////////////////////
-
-GrConfigConversionEffect::GrConfigConversionEffect(PMConversion pmConversion)
- : INHERITED(kNone_OptimizationFlags)
- , fPMConversion(pmConversion) {
+GrGLSLFragmentProcessor* GrConfigConversionEffect::onCreateGLSLInstance() const {
+ return new GrGLSLConfigConversionEffect();
+}
+void GrConfigConversionEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+ GrProcessorKeyBuilder* b) const {
+ b->add32(fPmConversion);
+}
+bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& other) const {
+ const GrConfigConversionEffect& that = other.cast<GrConfigConversionEffect>();
+ (void)that;
+ if (fPmConversion != that.fPmConversion) return false;
+ return true;
+}
+GrConfigConversionEffect::GrConfigConversionEffect(const GrConfigConversionEffect& src)
+ : INHERITED(src.optimizationFlags()), fPmConversion(src.fPmConversion) {
this->initClassID<GrConfigConversionEffect>();
}
-
std::unique_ptr<GrFragmentProcessor> GrConfigConversionEffect::clone() const {
- return std::unique_ptr<GrFragmentProcessor>(new GrConfigConversionEffect(fPMConversion));
+ return std::unique_ptr<GrFragmentProcessor>(new GrConfigConversionEffect(*this));
}
-
-bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& s) const {
- const GrConfigConversionEffect& other = s.cast<GrConfigConversionEffect>();
- return other.fPMConversion == fPMConversion;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConfigConversionEffect);
-
#if GR_TEST_UTILS
-std::unique_ptr<GrFragmentProcessor> GrConfigConversionEffect::TestCreate(GrProcessorTestData* d) {
- PMConversion pmConv = static_cast<PMConversion>(d->fRandom->nextULessThan(kPMConversionCnt));
+std::unique_ptr<GrFragmentProcessor> GrConfigConversionEffect::TestCreate(
+ GrProcessorTestData* data) {
+ PMConversion pmConv = static_cast<PMConversion>(data->fRandom->nextULessThan(kPMConversionCnt));
return std::unique_ptr<GrFragmentProcessor>(new GrConfigConversionEffect(pmConv));
}
#endif
-
-///////////////////////////////////////////////////////////////////////////////
-
-void GrConfigConversionEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const {
- GrGLConfigConversionEffect::GenKey(*this, caps, b);
-}
-
-GrGLSLFragmentProcessor* GrConfigConversionEffect::onCreateGLSLInstance() const {
- return new GrGLConfigConversionEffect();
-}
-
-
-bool GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context) {
- static constexpr int kSize = 256;
- static constexpr GrPixelConfig kConfig = kRGBA_8888_GrPixelConfig;
- SkAutoTMalloc<uint32_t> data(kSize * kSize * 3);
- uint32_t* srcData = data.get();
- uint32_t* firstRead = data.get() + kSize * kSize;
- uint32_t* secondRead = data.get() + 2 * kSize * kSize;
-
- // Fill with every possible premultiplied A, color channel value. There will be 256-y duplicate
- // values in row y. We set r,g, and b to the same value since they are handled identically.
- for (int y = 0; y < kSize; ++y) {
- for (int x = 0; x < kSize; ++x) {
- uint8_t* color = reinterpret_cast<uint8_t*>(&srcData[kSize*y + x]);
- color[3] = y;
- color[2] = SkTMin(x, y);
- color[1] = SkTMin(x, y);
- color[0] = SkTMin(x, y);
- }
- }
-
- const SkImageInfo ii = SkImageInfo::Make(kSize, kSize,
- kRGBA_8888_SkColorType, kPremul_SkAlphaType);
-
- sk_sp<GrRenderTargetContext> readRTC(context->makeDeferredRenderTargetContext(
- SkBackingFit::kExact,
- kSize, kSize,
- kConfig, nullptr));
- sk_sp<GrRenderTargetContext> tempRTC(context->makeDeferredRenderTargetContext(
- SkBackingFit::kExact,
- kSize, kSize,
- kConfig, nullptr));
- if (!readRTC || !readRTC->asTextureProxy() || !tempRTC) {
- return false;
- }
- GrSurfaceDesc desc;
- desc.fOrigin = kTopLeft_GrSurfaceOrigin;
- desc.fWidth = kSize;
- desc.fHeight = kSize;
- desc.fConfig = kConfig;
-
- sk_sp<GrTextureProxy> dataProxy = GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
- desc,
- SkBudgeted::kYes, data, 0);
- if (!dataProxy) {
- return false;
- }
-
- static const SkRect kRect = SkRect::MakeIWH(kSize, kSize);
-
- // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
- // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
- // We then verify that two reads produced the same values.
-
- GrPaint paint1;
- GrPaint paint2;
- GrPaint paint3;
- std::unique_ptr<GrFragmentProcessor> pmToUPM(
- new GrConfigConversionEffect(kToUnpremul_PMConversion));
- std::unique_ptr<GrFragmentProcessor> upmToPM(
- new GrConfigConversionEffect(kToPremul_PMConversion));
-
- paint1.addColorTextureProcessor(dataProxy, nullptr, SkMatrix::I());
- paint1.addColorFragmentProcessor(pmToUPM->clone());
- paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
-
- readRTC->fillRectToRect(GrNoClip(), std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect, kRect);
- if (!readRTC->readPixels(ii, firstRead, 0, 0, 0)) {
- return false;
- }
-
- paint2.addColorTextureProcessor(readRTC->asTextureProxyRef(), nullptr,
- SkMatrix::I());
- paint2.addColorFragmentProcessor(std::move(upmToPM));
- paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
-
- tempRTC->fillRectToRect(GrNoClip(), std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect, kRect);
-
- paint3.addColorTextureProcessor(tempRTC->asTextureProxyRef(), nullptr,
- SkMatrix::I());
- paint3.addColorFragmentProcessor(std::move(pmToUPM));
- paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
-
- readRTC->fillRectToRect(GrNoClip(), std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect, kRect);
-
- if (!readRTC->readPixels(ii, secondRead, 0, 0, 0)) {
- return false;
- }
-
- for (int y = 0; y < kSize; ++y) {
- for (int x = 0; x <= y; ++x) {
- if (firstRead[kSize * y + x] != secondRead[kSize * y + x]) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-std::unique_ptr<GrFragmentProcessor> GrConfigConversionEffect::Make(
- std::unique_ptr<GrFragmentProcessor> fp, PMConversion pmConversion) {
- if (!fp) {
- return nullptr;
- }
- std::unique_ptr<GrFragmentProcessor> ccFP(new GrConfigConversionEffect(pmConversion));
- std::unique_ptr<GrFragmentProcessor> fpPipeline[] = { std::move(fp), std::move(ccFP) };
- return GrFragmentProcessor::RunInSeries(fpPipeline, 2);
-}
+#endif
diff --git a/src/gpu/effects/GrConfigConversionEffect.fp b/src/gpu/effects/GrConfigConversionEffect.fp
new file mode 100644
index 0000000..9c697b4
--- /dev/null
+++ b/src/gpu/effects/GrConfigConversionEffect.fp
@@ -0,0 +1,157 @@
+@header {
+ #include "GrClip.h"
+ #include "GrContext.h"
+ #include "GrRenderTargetContext.h"
+}
+
+@class {
+ enum PMConversion {
+ kToPremul_PMConversion = 0,
+ kToUnpremul_PMConversion = 1,
+ kPMConversionCnt = 2
+ };
+
+ static bool TestForPreservingPMConversions(GrContext* context) {
+ static constexpr int kSize = 256;
+ static constexpr GrPixelConfig kConfig = kRGBA_8888_GrPixelConfig;
+ SkAutoTMalloc<uint32_t> data(kSize * kSize * 3);
+ uint32_t* srcData = data.get();
+ uint32_t* firstRead = data.get() + kSize * kSize;
+ uint32_t* secondRead = data.get() + 2 * kSize * kSize;
+
+ // Fill with every possible premultiplied A, color channel value. There will be 256-y
+ // duplicate values in row y. We set r, g, and b to the same value since they are handled
+ // identically.
+ for (int y = 0; y < kSize; ++y) {
+ for (int x = 0; x < kSize; ++x) {
+ uint8_t* color = reinterpret_cast<uint8_t*>(&srcData[kSize*y + x]);
+ color[3] = y;
+ color[2] = SkTMin(x, y);
+ color[1] = SkTMin(x, y);
+ color[0] = SkTMin(x, y);
+ }
+ }
+
+ const SkImageInfo ii = SkImageInfo::Make(kSize, kSize,
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+
+ sk_sp<GrRenderTargetContext> readRTC(context->makeDeferredRenderTargetContext(
+ SkBackingFit::kExact,
+ kSize, kSize,
+ kConfig, nullptr));
+ sk_sp<GrRenderTargetContext> tempRTC(context->makeDeferredRenderTargetContext(
+ SkBackingFit::kExact,
+ kSize, kSize,
+ kConfig, nullptr));
+ if (!readRTC || !readRTC->asTextureProxy() || !tempRTC) {
+ return false;
+ }
+ GrSurfaceDesc desc;
+ desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+ desc.fWidth = kSize;
+ desc.fHeight = kSize;
+ desc.fConfig = kConfig;
+
+ sk_sp<GrTextureProxy> dataProxy = GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
+ desc,
+ SkBudgeted::kYes, data, 0);
+ if (!dataProxy) {
+ return false;
+ }
+
+ static const SkRect kRect = SkRect::MakeIWH(kSize, kSize);
+
+ // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
+ // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
+ // We then verify that two reads produced the same values.
+
+ GrPaint paint1;
+ GrPaint paint2;
+ GrPaint paint3;
+ std::unique_ptr<GrFragmentProcessor> pmToUPM(
+ new GrConfigConversionEffect(kToUnpremul_PMConversion));
+ std::unique_ptr<GrFragmentProcessor> upmToPM(
+ new GrConfigConversionEffect(kToPremul_PMConversion));
+
+ paint1.addColorTextureProcessor(dataProxy, nullptr, SkMatrix::I());
+ paint1.addColorFragmentProcessor(pmToUPM->clone());
+ paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
+
+ readRTC->fillRectToRect(GrNoClip(), std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect,
+ kRect);
+ if (!readRTC->readPixels(ii, firstRead, 0, 0, 0)) {
+ return false;
+ }
+
+ paint2.addColorTextureProcessor(readRTC->asTextureProxyRef(), nullptr,
+ SkMatrix::I());
+ paint2.addColorFragmentProcessor(std::move(upmToPM));
+ paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
+
+ tempRTC->fillRectToRect(GrNoClip(), std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect,
+ kRect);
+
+ paint3.addColorTextureProcessor(tempRTC->asTextureProxyRef(), nullptr,
+ SkMatrix::I());
+ paint3.addColorFragmentProcessor(std::move(pmToUPM));
+ paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
+
+ readRTC->fillRectToRect(GrNoClip(), std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect,
+ kRect);
+
+ if (!readRTC->readPixels(ii, secondRead, 0, 0, 0)) {
+ return false;
+ }
+
+ for (int y = 0; y < kSize; ++y) {
+ for (int x = 0; x <= y; ++x) {
+ if (firstRead[kSize * y + x] != secondRead[kSize * y + x]) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+}
+
+@make {
+ static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
+ PMConversion pmConversion) {
+ if (!fp) {
+ return nullptr;
+ }
+ std::unique_ptr<GrFragmentProcessor> ccFP(new GrConfigConversionEffect(pmConversion));
+ std::unique_ptr<GrFragmentProcessor> fpPipeline[] = { std::move(fp), std::move(ccFP) };
+ return GrFragmentProcessor::RunInSeries(fpPipeline, 2);
+ }
+}
+
+layout(key) in int pmConversion;
+
+@emitCode {
+ fragBuilder->forceHighPrecision();
+}
+
+void main() {
+ // Aggressively round to the nearest exact (N / 255) floating point value. This lets us find a
+ // round-trip preserving pair on some GPUs that do odd byte to float conversion.
+ sk_OutColor = floor(sk_InColor * 255 + 0.5) / 255;
+
+ @switch (pmConversion) {
+ case 0 /* kToPremul_PMConversion */:
+ sk_OutColor.rgb = floor(sk_OutColor.rgb * sk_OutColor.a * 255 + 0.5) / 255;
+ break;
+
+ case 1 /* kToUnpremul_PMConversion */:
+ sk_OutColor.rgb = sk_OutColor.a <= 0.0 ?
+ half3(0) :
+ floor(sk_OutColor.rgb / sk_OutColor.a * 255 + 0.5) / 255;
+ break;
+ }
+}
+
+@test(data) {
+ PMConversion pmConv = static_cast<PMConversion>(data->fRandom->nextULessThan(kPMConversionCnt));
+ return std::unique_ptr<GrFragmentProcessor>(new GrConfigConversionEffect(pmConv));
+}
diff --git a/src/gpu/effects/GrConfigConversionEffect.h b/src/gpu/effects/GrConfigConversionEffect.h
index 690fbd5..f17b32f 100644
--- a/src/gpu/effects/GrConfigConversionEffect.h
+++ b/src/gpu/effects/GrConfigConversionEffect.h
@@ -1,64 +1,153 @@
/*
- * Copyright 2012 Google Inc.
+ * Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
+/*
+ * This file was autogenerated from GrConfigConversionEffect.fp; do not modify.
+ */
#ifndef GrConfigConversionEffect_DEFINED
#define GrConfigConversionEffect_DEFINED
+#include "SkTypes.h"
+#if SK_SUPPORT_GPU
+#include "GrClip.h"
+#include "GrContext.h"
+#include "GrRenderTargetContext.h"
#include "GrFragmentProcessor.h"
-
-/**
- * This class is used to perform config conversions. Clients may want to read/write data that is
- * unpremultiplied.
- */
+#include "GrCoordTransform.h"
+#include "GrColorSpaceXform.h"
class GrConfigConversionEffect : public GrFragmentProcessor {
public:
- /**
- * The PM->UPM or UPM->PM conversions to apply.
- */
enum PMConversion {
kToPremul_PMConversion = 0,
- kToUnpremul_PMConversion,
- kPMConversionCnt
+ kToUnpremul_PMConversion = 1,
+ kPMConversionCnt = 2
};
- /**
- * Returns a fragment processor that calls the passed in fragment processor, and then performs
- * the requested premul or unpremul conversion.
- */
- static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor>,
- PMConversion);
+ static bool TestForPreservingPMConversions(GrContext* context) {
+ static constexpr int kSize = 256;
+ static constexpr GrPixelConfig kConfig = kRGBA_8888_GrPixelConfig;
+ SkAutoTMalloc<uint32_t> data(kSize * kSize * 3);
+ uint32_t* srcData = data.get();
+ uint32_t* firstRead = data.get() + kSize * kSize;
+ uint32_t* secondRead = data.get() + 2 * kSize * kSize;
- const char* name() const override { return "Config Conversion"; }
+ // Fill with every possible premultiplied A, color channel value. There will be 256-y
+ // duplicate values in row y. We set r, g, and b to the same value since they are handled
+ // identically.
+ for (int y = 0; y < kSize; ++y) {
+ for (int x = 0; x < kSize; ++x) {
+ uint8_t* color = reinterpret_cast<uint8_t*>(&srcData[kSize * y + x]);
+ color[3] = y;
+ color[2] = SkTMin(x, y);
+ color[1] = SkTMin(x, y);
+ color[0] = SkTMin(x, y);
+ }
+ }
+ const SkImageInfo ii =
+ SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+
+ sk_sp<GrRenderTargetContext> readRTC(context->makeDeferredRenderTargetContext(
+ SkBackingFit::kExact, kSize, kSize, kConfig, nullptr));
+ sk_sp<GrRenderTargetContext> tempRTC(context->makeDeferredRenderTargetContext(
+ SkBackingFit::kExact, kSize, kSize, kConfig, nullptr));
+ if (!readRTC || !readRTC->asTextureProxy() || !tempRTC) {
+ return false;
+ }
+ GrSurfaceDesc desc;
+ desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+ desc.fWidth = kSize;
+ desc.fHeight = kSize;
+ desc.fConfig = kConfig;
+
+ sk_sp<GrTextureProxy> dataProxy = GrSurfaceProxy::MakeDeferred(
+ context->resourceProvider(), desc, SkBudgeted::kYes, data, 0);
+ if (!dataProxy) {
+ return false;
+ }
+
+ static const SkRect kRect = SkRect::MakeIWH(kSize, kSize);
+
+ // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
+ // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
+ // We then verify that two reads produced the same values.
+
+ GrPaint paint1;
+ GrPaint paint2;
+ GrPaint paint3;
+ std::unique_ptr<GrFragmentProcessor> pmToUPM(
+ new GrConfigConversionEffect(kToUnpremul_PMConversion));
+ std::unique_ptr<GrFragmentProcessor> upmToPM(
+ new GrConfigConversionEffect(kToPremul_PMConversion));
+
+ paint1.addColorTextureProcessor(dataProxy, nullptr, SkMatrix::I());
+ paint1.addColorFragmentProcessor(pmToUPM->clone());
+ paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
+
+ readRTC->fillRectToRect(GrNoClip(), std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect,
+ kRect);
+ if (!readRTC->readPixels(ii, firstRead, 0, 0, 0)) {
+ return false;
+ }
+
+ paint2.addColorTextureProcessor(readRTC->asTextureProxyRef(), nullptr, SkMatrix::I());
+ paint2.addColorFragmentProcessor(std::move(upmToPM));
+ paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
+
+ tempRTC->fillRectToRect(GrNoClip(), std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect,
+ kRect);
+
+ paint3.addColorTextureProcessor(tempRTC->asTextureProxyRef(), nullptr, SkMatrix::I());
+ paint3.addColorFragmentProcessor(std::move(pmToUPM));
+ paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
+
+ readRTC->fillRectToRect(GrNoClip(), std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect,
+ kRect);
+
+ if (!readRTC->readPixels(ii, secondRead, 0, 0, 0)) {
+ return false;
+ }
+
+ for (int y = 0; y < kSize; ++y) {
+ for (int x = 0; x <= y; ++x) {
+ if (firstRead[kSize * y + x] != secondRead[kSize * y + x]) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+ int pmConversion() const { return fPmConversion; }
+
+ static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
+ PMConversion pmConversion) {
+ if (!fp) {
+ return nullptr;
+ }
+ std::unique_ptr<GrFragmentProcessor> ccFP(new GrConfigConversionEffect(pmConversion));
+ std::unique_ptr<GrFragmentProcessor> fpPipeline[] = {std::move(fp), std::move(ccFP)};
+ return GrFragmentProcessor::RunInSeries(fpPipeline, 2);
+ }
+ GrConfigConversionEffect(const GrConfigConversionEffect& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
-
- PMConversion pmConversion() const { return fPMConversion; }
-
- // This function determines whether it is possible to choose PM->UPM and UPM->PM conversions
- // for which in any PM->UPM->PM->UPM sequence the two UPM values are the same. This means that
- // if pixels are read back to a UPM buffer, written back to PM to the GPU, and read back again
- // both reads will produce the same result. This test is quite expensive and should not be run
- // multiple times for a given context.
- static bool TestForPreservingPMConversions(GrContext* context);
+ const char* name() const override { return "ConfigConversionEffect"; }
private:
- GrConfigConversionEffect(PMConversion);
-
+ GrConfigConversionEffect(int pmConversion)
+ : INHERITED(kNone_OptimizationFlags), fPmConversion(pmConversion) {
+ this->initClassID<GrConfigConversionEffect>();
+ }
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
-
bool onIsEqual(const GrFragmentProcessor&) const override;
-
- PMConversion fPMConversion;
-
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
-
+ int fPmConversion;
typedef GrFragmentProcessor INHERITED;
};
-
+#endif
#endif