blob: 07225f1fc627424c055fa4ca4a197eebe43638e1 [file] [log] [blame]
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001/*
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"
Brian Salomonc65aec92017-03-09 09:03:58 -05009#include "../private/GrGLSL.h"
10#include "GrClip.h"
bsalomon@google.comb1456d72012-11-02 18:23:45 +000011#include "GrContext.h"
Brian Osman11052242016-10-27 14:47:55 -040012#include "GrRenderTargetContext.h"
joshualitteb2a6762014-12-04 11:35:33 -080013#include "SkMatrix.h"
egdaniel64c47282015-11-13 06:54:19 -080014#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -080015#include "glsl/GrGLSLFragmentShaderBuilder.h"
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000016
egdaniel64c47282015-11-13 06:54:19 -080017class GrGLConfigConversionEffect : public GrGLSLFragmentProcessor {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000018public:
robertphillips9cdb9922016-02-03 12:25:40 -080019 void emitCode(EmitArgs& args) override {
bsalomon6c9cd552016-01-22 07:17:34 -080020 const GrConfigConversionEffect& cce = args.fFp.cast<GrConfigConversionEffect>();
cdalton85285412016-02-18 12:37:07 -080021 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
joshualitt30ba4362014-08-21 20:18:45 -070022
Brian Osmanee805322017-04-05 10:09:00 -040023 // Use highp throughout the shader to avoid some precision issues on specific GPUs.
24 fragBuilder->elevateDefaultPrecision(kHigh_GrSLPrecision);
joshualitt30ba4362014-08-21 20:18:45 -070025
Brian Osmanee805322017-04-05 10:09:00 -040026 if (nullptr == args.fInputColor) {
27 // could optimize this case, but we aren't for now.
28 args.fInputColor = "vec4(1)";
29 }
30 fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor);
changjun.yangcecc91c2014-08-19 18:24:30 -070031
Brian Osmanee805322017-04-05 10:09:00 -040032 switch (cce.pmConversion()) {
Brian Osmance425512017-03-22 14:37:50 -040033 case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion:
Brian Osmanee805322017-04-05 10:09:00 -040034 fragBuilder->codeAppend(
35 "color.rgb = ceil(color.rgb * color.a * 255.0) / 255.0;");
Brian Osmance425512017-03-22 14:37:50 -040036 break;
37 case GrConfigConversionEffect::kMulByAlpha_RoundDown_PMConversion:
38 // Add a compensation(0.001) here to avoid the side effect of the floor operation.
39 // In Intel GPUs, the integer value converted from floor(%s.r * 255.0) / 255.0
40 // is less than the integer value converted from %s.r by 1 when the %s.r is
41 // converted from the integer value 2^n, such as 1, 2, 4, 8, etc.
Brian Osmanee805322017-04-05 10:09:00 -040042 fragBuilder->codeAppend(
43 "color.rgb = floor(color.rgb * color.a * 255.0 + 0.001) / 255.0;");
Brian Osmance425512017-03-22 14:37:50 -040044 break;
45 case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion:
Brian Osmanee805322017-04-05 10:09:00 -040046 fragBuilder->codeAppend(
47 "color.rgb = color.a <= 0.0 ? vec3(0,0,0) : ceil(color.rgb / color.a * 255.0) / 255.0;");
Brian Osmance425512017-03-22 14:37:50 -040048 break;
49 case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion:
Brian Osmanee805322017-04-05 10:09:00 -040050 fragBuilder->codeAppend(
51 "color.rgb = color.a <= 0.0 ? vec3(0,0,0) : floor(color.rgb / color.a * 255.0) / 255.0;");
Brian Osmance425512017-03-22 14:37:50 -040052 break;
53 default:
54 SkFAIL("Unknown conversion op.");
55 break;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000056 }
Brian Osmanee805322017-04-05 10:09:00 -040057 fragBuilder->codeAppendf("%s = color;", args.fOutputColor);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000058 }
59
Brian Salomon94efbf52016-11-29 13:43:05 -050060 static inline void GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -070061 GrProcessorKeyBuilder* b) {
bsalomon6c9cd552016-01-22 07:17:34 -080062 const GrConfigConversionEffect& cce = processor.cast<GrConfigConversionEffect>();
Brian Osmance425512017-03-22 14:37:50 -040063 uint32_t key = cce.pmConversion();
bsalomon63e99f72014-07-21 08:03:14 -070064 b->add32(key);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000065 }
66
67private:
egdaniel64c47282015-11-13 06:54:19 -080068 typedef GrGLSLFragmentProcessor INHERITED;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000069
70};
71
72///////////////////////////////////////////////////////////////////////////////
Brian Osmanee805322017-04-05 10:09:00 -040073
74GrConfigConversionEffect::GrConfigConversionEffect(PMConversion pmConversion)
75 : INHERITED(kNone_OptimizationFlags)
Brian Osman31f96a62017-03-24 18:27:56 +000076 , fPMConversion(pmConversion) {
77 this->initClassID<GrConfigConversionEffect>();
Robert Phillips757914d2017-01-25 15:48:30 -050078}
79
bsalomon0e08fc12014-10-15 08:19:04 -070080bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& s) const {
joshualitt49586be2014-09-16 08:21:41 -070081 const GrConfigConversionEffect& other = s.cast<GrConfigConversionEffect>();
Brian Osmance425512017-03-22 14:37:50 -040082 return other.fPMConversion == fPMConversion;
bsalomon@google.com68b58c92013-01-17 16:50:08 +000083}
84
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000085///////////////////////////////////////////////////////////////////////////////
86
joshualittb0a8a372014-09-23 09:50:21 -070087GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConfigConversionEffect);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000088
Hal Canary6f6961e2017-01-31 13:50:44 -050089#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -070090sk_sp<GrFragmentProcessor> GrConfigConversionEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -070091 PMConversion pmConv = static_cast<PMConversion>(d->fRandom->nextULessThan(kPMConversionCnt));
Brian Osmanee805322017-04-05 10:09:00 -040092 return sk_sp<GrFragmentProcessor>(new GrConfigConversionEffect(pmConv));
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000093}
Hal Canary6f6961e2017-01-31 13:50:44 -050094#endif
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000095
96///////////////////////////////////////////////////////////////////////////////
joshualitteb2a6762014-12-04 11:35:33 -080097
Brian Salomon94efbf52016-11-29 13:43:05 -050098void GrConfigConversionEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -080099 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -0800100 GrGLConfigConversionEffect::GenKey(*this, caps, b);
101}
102
egdaniel57d3b032015-11-13 11:57:27 -0800103GrGLSLFragmentProcessor* GrConfigConversionEffect::onCreateGLSLInstance() const {
bsalomon6c9cd552016-01-22 07:17:34 -0800104 return new GrGLConfigConversionEffect();
joshualitteb2a6762014-12-04 11:35:33 -0800105}
106
robertphillipse85a32d2015-02-10 08:16:55 -0800107
108
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000109void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context,
110 PMConversion* pmToUPMRule,
111 PMConversion* upmToPMRule) {
Brian Osmance425512017-03-22 14:37:50 -0400112 *pmToUPMRule = kPMConversionCnt;
113 *upmToPMRule = kPMConversionCnt;
bsalomon49b264c2016-07-19 08:38:09 -0700114 static constexpr int kSize = 256;
115 static constexpr GrPixelConfig kConfig = kRGBA_8888_GrPixelConfig;
116 SkAutoTMalloc<uint32_t> data(kSize * kSize * 3);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000117 uint32_t* srcData = data.get();
bsalomon49b264c2016-07-19 08:38:09 -0700118 uint32_t* firstRead = data.get() + kSize * kSize;
119 uint32_t* secondRead = data.get() + 2 * kSize * kSize;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000120
121 // Fill with every possible premultiplied A, color channel value. There will be 256-y duplicate
122 // values in row y. We set r,g, and b to the same value since they are handled identically.
bsalomon49b264c2016-07-19 08:38:09 -0700123 for (int y = 0; y < kSize; ++y) {
124 for (int x = 0; x < kSize; ++x) {
125 uint8_t* color = reinterpret_cast<uint8_t*>(&srcData[kSize*y + x]);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000126 color[3] = y;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000127 color[2] = SkTMin(x, y);
128 color[1] = SkTMin(x, y);
129 color[0] = SkTMin(x, y);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000130 }
131 }
132
Robert Phillipsc949ce92017-01-19 16:59:04 -0500133 const SkImageInfo ii = SkImageInfo::Make(kSize, kSize,
134 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
135
Brian Osman693a5402016-10-27 15:13:22 -0400136 sk_sp<GrRenderTargetContext> readRTC(context->makeRenderTargetContext(SkBackingFit::kExact,
137 kSize, kSize,
138 kConfig, nullptr));
139 sk_sp<GrRenderTargetContext> tempRTC(context->makeRenderTargetContext(SkBackingFit::kExact,
140 kSize, kSize,
141 kConfig, nullptr));
142 if (!readRTC || !tempRTC) {
bsalomon49b264c2016-07-19 08:38:09 -0700143 return;
144 }
bsalomonf2703d82014-10-28 14:33:06 -0700145 GrSurfaceDesc desc;
bsalomon49b264c2016-07-19 08:38:09 -0700146 desc.fWidth = kSize;
147 desc.fHeight = kSize;
148 desc.fConfig = kConfig;
Robert Phillips757914d2017-01-25 15:48:30 -0500149
Brian Osmance425512017-03-22 14:37:50 -0400150 GrResourceProvider* resourceProvider = context->resourceProvider();
151 sk_sp<GrTextureProxy> dataProxy = GrSurfaceProxy::MakeDeferred(resourceProvider, desc,
152 SkBudgeted::kYes, data, 0);
Robert Phillips2f493142017-03-02 18:18:38 -0500153 if (!dataProxy) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000154 return;
155 }
156
157 static const PMConversion kConversionRules[][2] = {
158 {kDivByAlpha_RoundDown_PMConversion, kMulByAlpha_RoundUp_PMConversion},
159 {kDivByAlpha_RoundUp_PMConversion, kMulByAlpha_RoundDown_PMConversion},
160 };
161
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000162 bool failed = true;
163
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000164 for (size_t i = 0; i < SK_ARRAY_COUNT(kConversionRules) && failed; ++i) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000165 *pmToUPMRule = kConversionRules[i][0];
166 *upmToPMRule = kConversionRules[i][1];
167
bsalomon49b264c2016-07-19 08:38:09 -0700168 static const SkRect kDstRect = SkRect::MakeIWH(kSize, kSize);
Robert Phillips67c18d62017-01-20 12:44:06 -0500169 static const SkRect kSrcRect = SkRect::MakeIWH(kSize, kSize);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000170 // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
171 // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
172 // We then verify that two reads produced the same values.
173
Robert Phillips301431d2017-03-29 12:08:49 -0400174 if (!readRTC->asTextureProxy()) {
Robert Phillips833dcf42016-11-18 08:44:13 -0500175 continue;
176 }
joshualitt5f10b5c2015-07-09 10:24:35 -0700177 GrPaint paint1;
178 GrPaint paint2;
179 GrPaint paint3;
Brian Osmanee805322017-04-05 10:09:00 -0400180 sk_sp<GrFragmentProcessor> pmToUPM(new GrConfigConversionEffect(*pmToUPMRule));
181 sk_sp<GrFragmentProcessor> upmToPM(new GrConfigConversionEffect(*upmToPMRule));
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000182
Brian Osmanee805322017-04-05 10:09:00 -0400183 paint1.addColorTextureProcessor(resourceProvider, dataProxy, nullptr, SkMatrix::I());
184 paint1.addColorFragmentProcessor(pmToUPM);
reed374772b2016-10-05 17:33:02 -0700185 paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700186
Brian Salomon82f44312017-01-11 13:42:54 -0500187 readRTC->fillRectToRect(GrNoClip(), std::move(paint1), GrAA::kNo, SkMatrix::I(), kDstRect,
188 kSrcRect);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700189
Robert Phillipsc949ce92017-01-19 16:59:04 -0500190 if (!readRTC->readPixels(ii, firstRead, 0, 0, 0)) {
191 continue;
192 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000193
Brian Osmanee805322017-04-05 10:09:00 -0400194 paint2.addColorTextureProcessor(resourceProvider, readRTC->asTextureProxyRef(), nullptr,
195 SkMatrix::I());
bungeman06ca8ec2016-06-09 08:01:03 -0700196 paint2.addColorFragmentProcessor(std::move(upmToPM));
reed374772b2016-10-05 17:33:02 -0700197 paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700198
Brian Salomon82f44312017-01-11 13:42:54 -0500199 tempRTC->fillRectToRect(GrNoClip(), std::move(paint2), GrAA::kNo, SkMatrix::I(), kDstRect,
200 kSrcRect);
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000201
Brian Osmanee805322017-04-05 10:09:00 -0400202 paint3.addColorTextureProcessor(resourceProvider, tempRTC->asTextureProxyRef(), nullptr,
203 SkMatrix::I());
204 paint3.addColorFragmentProcessor(std::move(pmToUPM));
reed374772b2016-10-05 17:33:02 -0700205 paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700206
Brian Salomon82f44312017-01-11 13:42:54 -0500207 readRTC->fillRectToRect(GrNoClip(), std::move(paint3), GrAA::kNo, SkMatrix::I(), kDstRect,
208 kSrcRect);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700209
Robert Phillipsc949ce92017-01-19 16:59:04 -0500210 if (!readRTC->readPixels(ii, secondRead, 0, 0, 0)) {
211 continue;
212 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000213
214 failed = false;
bsalomon49b264c2016-07-19 08:38:09 -0700215 for (int y = 0; y < kSize && !failed; ++y) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000216 for (int x = 0; x <= y; ++x) {
bsalomon49b264c2016-07-19 08:38:09 -0700217 if (firstRead[kSize * y + x] != secondRead[kSize * y + x]) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000218 failed = true;
219 break;
220 }
221 }
222 }
223 }
224 if (failed) {
Brian Osmance425512017-03-22 14:37:50 -0400225 *pmToUPMRule = kPMConversionCnt;
226 *upmToPMRule = kPMConversionCnt;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000227 }
228}
229
Brian Osmanee805322017-04-05 10:09:00 -0400230sk_sp<GrFragmentProcessor> GrConfigConversionEffect::Make(sk_sp<GrFragmentProcessor> fp,
231 PMConversion pmConversion) {
232 if (!fp) {
Brian Osman31f96a62017-03-24 18:27:56 +0000233 return nullptr;
234 }
Brian Osmanee805322017-04-05 10:09:00 -0400235 sk_sp<GrFragmentProcessor> ccFP(new GrConfigConversionEffect(pmConversion));
236 sk_sp<GrFragmentProcessor> fpPipeline[] = { fp, ccFP };
237 return GrFragmentProcessor::RunInSeries(fpPipeline, 2);
Robert Phillips757914d2017-01-25 15:48:30 -0500238}