diff options
-rw-r--r-- | gn/sksl.gni | 1 | ||||
-rw-r--r-- | src/gpu/effects/GrConfigConversionEffect.cpp | 229 | ||||
-rw-r--r-- | src/gpu/effects/GrConfigConversionEffect.fp | 157 | ||||
-rw-r--r-- | src/gpu/effects/GrConfigConversionEffect.h | 165 |
4 files changed, 329 insertions, 223 deletions
diff --git a/gn/sksl.gni b/gn/sksl.gni index 65913e3417..55e8bd270b 100644 --- a/gn/sksl.gni +++ b/gn/sksl.gni @@ -29,6 +29,7 @@ skia_gpu_processor_sources = [ "$_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 e1ecc7f864..2c12c7e8dc 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)); -} - -bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& s) const { - const GrConfigConversionEffect& other = s.cast<GrConfigConversionEffect>(); - return other.fPMConversion == fPMConversion; + return std::unique_ptr<GrFragmentProcessor>(new GrConfigConversionEffect(*this)); } - -/////////////////////////////////////////////////////////////////////////////// - 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 0000000000..9c697b41cb --- /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 690fbd5ff7..f17b32fa0e 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); - - const char* name() const override { return "Config Conversion"; } - + 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; + } + 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 |