LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/effects - GrConfigConversionEffect.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 134 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2012 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "GrConfigConversionEffect.h"
       9             : #include "../private/GrGLSL.h"
      10             : #include "GrClip.h"
      11             : #include "GrContext.h"
      12             : #include "GrRenderTargetContext.h"
      13             : #include "SkMatrix.h"
      14             : #include "glsl/GrGLSLFragmentProcessor.h"
      15             : #include "glsl/GrGLSLFragmentShaderBuilder.h"
      16             : 
      17           0 : class GrGLConfigConversionEffect : public GrGLSLFragmentProcessor {
      18             : public:
      19           0 :     void emitCode(EmitArgs& args) override {
      20           0 :         const GrConfigConversionEffect& cce = args.fFp.cast<GrConfigConversionEffect>();
      21           0 :         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
      22             : 
      23             :         // Use highp throughout the shader to avoid some precision issues on specific GPUs.
      24           0 :         fragBuilder->elevateDefaultPrecision(kHigh_GrSLPrecision);
      25             : 
      26           0 :         if (nullptr == args.fInputColor) {
      27             :             // could optimize this case, but we aren't for now.
      28           0 :             args.fInputColor = "vec4(1)";
      29             :         }
      30             : 
      31             :         // Aggressively round to the nearest exact (N / 255) floating point value. This lets us
      32             :         // find a round-trip preserving pair on some GPUs that do odd byte to float conversion.
      33           0 :         fragBuilder->codeAppendf("vec4 color = floor(%s * 255.0 + 0.5) / 255.0;",
      34           0 :                                 args.fInputColor);
      35             : 
      36           0 :         switch (cce.pmConversion()) {
      37             :             case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion:
      38           0 :                 fragBuilder->codeAppend(
      39           0 :                     "color.rgb = ceil(color.rgb * color.a * 255.0) / 255.0;");
      40           0 :                 break;
      41             :             case GrConfigConversionEffect::kMulByAlpha_RoundDown_PMConversion:
      42             :                 // Add a compensation(0.001) here to avoid the side effect of the floor operation.
      43             :                 // In Intel GPUs, the integer value converted from floor(%s.r * 255.0) / 255.0
      44             :                 // is less than the integer value converted from  %s.r by 1 when the %s.r is
      45             :                 // converted from the integer value 2^n, such as 1, 2, 4, 8, etc.
      46           0 :                 fragBuilder->codeAppend(
      47           0 :                     "color.rgb = floor(color.rgb * color.a * 255.0 + 0.001) / 255.0;");
      48           0 :                 break;
      49             :             case GrConfigConversionEffect::kMulByAlpha_RoundNearest_PMConversion:
      50           0 :                 fragBuilder->codeAppend(
      51           0 :                     "color.rgb = floor(color.rgb * color.a * 255.0 + 0.5) / 255.0;");
      52           0 :                 break;
      53             : 
      54             :             case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion:
      55           0 :                 fragBuilder->codeAppend(
      56           0 :                     "color.rgb = color.a <= 0.0 ? vec3(0,0,0) : ceil(color.rgb / color.a * 255.0) / 255.0;");
      57           0 :                 break;
      58             :             case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion:
      59           0 :                 fragBuilder->codeAppend(
      60           0 :                     "color.rgb = color.a <= 0.0 ? vec3(0,0,0) : floor(color.rgb / color.a * 255.0) / 255.0;");
      61           0 :                 break;
      62             :             case GrConfigConversionEffect::kDivByAlpha_RoundNearest_PMConversion:
      63           0 :                 fragBuilder->codeAppend(
      64           0 :                     "color.rgb = color.a <= 0.0 ? vec3(0,0,0) : floor(color.rgb / color.a * 255.0 + 0.5) / 255.0;");
      65           0 :                 break;
      66             : 
      67             :             default:
      68           0 :                 SkFAIL("Unknown conversion op.");
      69           0 :                 break;
      70             :         }
      71           0 :         fragBuilder->codeAppendf("%s = color;", args.fOutputColor);
      72           0 :     }
      73             : 
      74           0 :     static inline void GenKey(const GrProcessor& processor, const GrShaderCaps&,
      75             :                               GrProcessorKeyBuilder* b) {
      76           0 :         const GrConfigConversionEffect& cce = processor.cast<GrConfigConversionEffect>();
      77           0 :         uint32_t key = cce.pmConversion();
      78           0 :         b->add32(key);
      79           0 :     }
      80             : 
      81             : private:
      82             :     typedef GrGLSLFragmentProcessor INHERITED;
      83             : 
      84             : };
      85             : 
      86             : ///////////////////////////////////////////////////////////////////////////////
      87             : 
      88           0 : GrConfigConversionEffect::GrConfigConversionEffect(PMConversion pmConversion)
      89             :         : INHERITED(kNone_OptimizationFlags)
      90           0 :         , fPMConversion(pmConversion) {
      91           0 :     this->initClassID<GrConfigConversionEffect>();
      92           0 : }
      93             : 
      94           0 : bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& s) const {
      95           0 :     const GrConfigConversionEffect& other = s.cast<GrConfigConversionEffect>();
      96           0 :     return other.fPMConversion == fPMConversion;
      97             : }
      98             : 
      99             : ///////////////////////////////////////////////////////////////////////////////
     100             : 
     101             : GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConfigConversionEffect);
     102             : 
     103             : #if GR_TEST_UTILS
     104           0 : sk_sp<GrFragmentProcessor> GrConfigConversionEffect::TestCreate(GrProcessorTestData* d) {
     105           0 :     PMConversion pmConv = static_cast<PMConversion>(d->fRandom->nextULessThan(kPMConversionCnt));
     106           0 :     return sk_sp<GrFragmentProcessor>(new GrConfigConversionEffect(pmConv));
     107             : }
     108             : #endif
     109             : 
     110             : ///////////////////////////////////////////////////////////////////////////////
     111             : 
     112           0 : void GrConfigConversionEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
     113             :                                                      GrProcessorKeyBuilder* b) const {
     114           0 :     GrGLConfigConversionEffect::GenKey(*this, caps, b);
     115           0 : }
     116             : 
     117           0 : GrGLSLFragmentProcessor* GrConfigConversionEffect::onCreateGLSLInstance() const {
     118           0 :     return new GrGLConfigConversionEffect();
     119             : }
     120             : 
     121             : 
     122             : 
     123           0 : void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context,
     124             :                                                               PMConversion* pmToUPMRule,
     125             :                                                               PMConversion* upmToPMRule) {
     126           0 :     *pmToUPMRule = kPMConversionCnt;
     127           0 :     *upmToPMRule = kPMConversionCnt;
     128             :     static constexpr int kSize = 256;
     129             :     static constexpr GrPixelConfig kConfig = kRGBA_8888_GrPixelConfig;
     130           0 :     SkAutoTMalloc<uint32_t> data(kSize * kSize * 3);
     131           0 :     uint32_t* srcData = data.get();
     132           0 :     uint32_t* firstRead = data.get() + kSize * kSize;
     133           0 :     uint32_t* secondRead = data.get() + 2 * kSize * kSize;
     134             : 
     135             :     // Fill with every possible premultiplied A, color channel value. There will be 256-y duplicate
     136             :     // values in row y. We set r,g, and b to the same value since they are handled identically.
     137           0 :     for (int y = 0; y < kSize; ++y) {
     138           0 :         for (int x = 0; x < kSize; ++x) {
     139           0 :             uint8_t* color = reinterpret_cast<uint8_t*>(&srcData[kSize*y + x]);
     140           0 :             color[3] = y;
     141           0 :             color[2] = SkTMin(x, y);
     142           0 :             color[1] = SkTMin(x, y);
     143           0 :             color[0] = SkTMin(x, y);
     144             :         }
     145             :     }
     146             : 
     147             :     const SkImageInfo ii = SkImageInfo::Make(kSize, kSize,
     148           0 :                                              kRGBA_8888_SkColorType, kPremul_SkAlphaType);
     149             : 
     150             :     sk_sp<GrRenderTargetContext> readRTC(context->makeRenderTargetContext(SkBackingFit::kExact,
     151             :                                                                           kSize, kSize,
     152           0 :                                                                           kConfig, nullptr));
     153             :     sk_sp<GrRenderTargetContext> tempRTC(context->makeRenderTargetContext(SkBackingFit::kExact,
     154             :                                                                           kSize, kSize,
     155           0 :                                                                           kConfig, nullptr));
     156           0 :     if (!readRTC || !tempRTC) {
     157           0 :         return;
     158             :     }
     159           0 :     GrSurfaceDesc desc;
     160           0 :     desc.fWidth = kSize;
     161           0 :     desc.fHeight = kSize;
     162           0 :     desc.fConfig = kConfig;
     163             : 
     164           0 :     GrResourceProvider* resourceProvider = context->resourceProvider();
     165             :     sk_sp<GrTextureProxy> dataProxy = GrSurfaceProxy::MakeDeferred(resourceProvider, desc,
     166           0 :                                                                    SkBudgeted::kYes, data, 0);
     167           0 :     if (!dataProxy) {
     168           0 :         return;
     169             :     }
     170             : 
     171             :     static const PMConversion kConversionRules[][2] = {
     172             :         {kDivByAlpha_RoundNearest_PMConversion, kMulByAlpha_RoundNearest_PMConversion},
     173             :         {kDivByAlpha_RoundDown_PMConversion, kMulByAlpha_RoundUp_PMConversion},
     174             :         {kDivByAlpha_RoundUp_PMConversion, kMulByAlpha_RoundDown_PMConversion},
     175             :     };
     176             : 
     177           0 :     uint32_t bestFailCount = 0xFFFFFFFF;
     178           0 :     size_t bestRule = 0;
     179             : 
     180           0 :     for (size_t i = 0; i < SK_ARRAY_COUNT(kConversionRules) && bestFailCount; ++i) {
     181           0 :         *pmToUPMRule = kConversionRules[i][0];
     182           0 :         *upmToPMRule = kConversionRules[i][1];
     183             : 
     184           0 :         static const SkRect kDstRect = SkRect::MakeIWH(kSize, kSize);
     185           0 :         static const SkRect kSrcRect = SkRect::MakeIWH(kSize, kSize);
     186             :         // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
     187             :         // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
     188             :         // We then verify that two reads produced the same values.
     189             : 
     190           0 :         if (!readRTC->asTextureProxy()) {
     191           0 :             continue;
     192             :         }
     193           0 :         GrPaint paint1;
     194           0 :         GrPaint paint2;
     195           0 :         GrPaint paint3;
     196           0 :         sk_sp<GrFragmentProcessor> pmToUPM(new GrConfigConversionEffect(*pmToUPMRule));
     197           0 :         sk_sp<GrFragmentProcessor> upmToPM(new GrConfigConversionEffect(*upmToPMRule));
     198             : 
     199           0 :         paint1.addColorTextureProcessor(resourceProvider, dataProxy, nullptr, SkMatrix::I());
     200           0 :         paint1.addColorFragmentProcessor(pmToUPM);
     201           0 :         paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
     202             : 
     203           0 :         readRTC->fillRectToRect(GrNoClip(), std::move(paint1), GrAA::kNo, SkMatrix::I(), kDstRect,
     204           0 :                                 kSrcRect);
     205             : 
     206           0 :         if (!readRTC->readPixels(ii, firstRead, 0, 0, 0)) {
     207           0 :             continue;
     208             :         }
     209             : 
     210           0 :         paint2.addColorTextureProcessor(resourceProvider, readRTC->asTextureProxyRef(), nullptr,
     211           0 :                                         SkMatrix::I());
     212           0 :         paint2.addColorFragmentProcessor(std::move(upmToPM));
     213           0 :         paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
     214             : 
     215           0 :         tempRTC->fillRectToRect(GrNoClip(), std::move(paint2), GrAA::kNo, SkMatrix::I(), kDstRect,
     216           0 :                                 kSrcRect);
     217             : 
     218           0 :         paint3.addColorTextureProcessor(resourceProvider, tempRTC->asTextureProxyRef(), nullptr,
     219           0 :                                         SkMatrix::I());
     220           0 :         paint3.addColorFragmentProcessor(std::move(pmToUPM));
     221           0 :         paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
     222             : 
     223           0 :         readRTC->fillRectToRect(GrNoClip(), std::move(paint3), GrAA::kNo, SkMatrix::I(), kDstRect,
     224           0 :                                 kSrcRect);
     225             : 
     226           0 :         if (!readRTC->readPixels(ii, secondRead, 0, 0, 0)) {
     227           0 :             continue;
     228             :         }
     229             : 
     230           0 :         uint32_t failCount = 0;
     231           0 :         for (int y = 0; y < kSize; ++y) {
     232           0 :             for (int x = 0; x <= y; ++x) {
     233           0 :                 if (firstRead[kSize * y + x] != secondRead[kSize * y + x]) {
     234           0 :                     if (++failCount >= bestFailCount) {
     235           0 :                         break;
     236             :                     }
     237             :                 }
     238             :             }
     239             :         }
     240           0 :         if (failCount < bestFailCount) {
     241           0 :             bestFailCount = failCount;
     242           0 :             bestRule = i;
     243             :         }
     244             :     }
     245           0 :     if (bestFailCount > 0) {
     246           0 :         *pmToUPMRule = kPMConversionCnt;
     247           0 :         *upmToPMRule = kPMConversionCnt;
     248             :     } else {
     249           0 :         *pmToUPMRule = kConversionRules[bestRule][0];
     250           0 :         *upmToPMRule = kConversionRules[bestRule][1];
     251             :     }
     252             : }
     253             : 
     254           0 : sk_sp<GrFragmentProcessor> GrConfigConversionEffect::Make(sk_sp<GrFragmentProcessor> fp,
     255             :                                                           PMConversion pmConversion) {
     256           0 :     if (!fp) {
     257           0 :         return nullptr;
     258             :     }
     259           0 :     sk_sp<GrFragmentProcessor> ccFP(new GrConfigConversionEffect(pmConversion));
     260           0 :     sk_sp<GrFragmentProcessor> fpPipeline[] = { fp, ccFP };
     261           0 :     return GrFragmentProcessor::RunInSeries(fpPipeline, 2);
     262             : }

Generated by: LCOV version 1.13