blob: d83e82d8d9aafb413fe1182a983d18c1931792f5 [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 }
Brian Osman9f903e42017-04-10 13:42:48 -040030
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.
Brian Osman28804f32017-04-20 10:24:36 -040033 fragBuilder->codeAppendf("vec4 color = floor(%s * 255.0 + 0.5) / 255.0;", args.fInputColor);
changjun.yangcecc91c2014-08-19 18:24:30 -070034
Brian Osmanee805322017-04-05 10:09:00 -040035 switch (cce.pmConversion()) {
Brian Osman28804f32017-04-20 10:24:36 -040036 case GrConfigConversionEffect::kToPremul_PMConversion:
Brian Osman9f903e42017-04-10 13:42:48 -040037 fragBuilder->codeAppend(
38 "color.rgb = floor(color.rgb * color.a * 255.0 + 0.5) / 255.0;");
39 break;
40
Brian Osman28804f32017-04-20 10:24:36 -040041 case GrConfigConversionEffect::kToUnpremul_PMConversion:
Brian Osman9f903e42017-04-10 13:42:48 -040042 fragBuilder->codeAppend(
43 "color.rgb = color.a <= 0.0 ? vec3(0,0,0) : floor(color.rgb / color.a * 255.0 + 0.5) / 255.0;");
44 break;
45
Brian Osmance425512017-03-22 14:37:50 -040046 default:
47 SkFAIL("Unknown conversion op.");
48 break;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000049 }
Brian Osmanee805322017-04-05 10:09:00 -040050 fragBuilder->codeAppendf("%s = color;", args.fOutputColor);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000051 }
52
Brian Salomon94efbf52016-11-29 13:43:05 -050053 static inline void GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -070054 GrProcessorKeyBuilder* b) {
bsalomon6c9cd552016-01-22 07:17:34 -080055 const GrConfigConversionEffect& cce = processor.cast<GrConfigConversionEffect>();
Brian Osmance425512017-03-22 14:37:50 -040056 uint32_t key = cce.pmConversion();
bsalomon63e99f72014-07-21 08:03:14 -070057 b->add32(key);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000058 }
59
60private:
egdaniel64c47282015-11-13 06:54:19 -080061 typedef GrGLSLFragmentProcessor INHERITED;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000062
63};
64
65///////////////////////////////////////////////////////////////////////////////
Brian Osmanee805322017-04-05 10:09:00 -040066
67GrConfigConversionEffect::GrConfigConversionEffect(PMConversion pmConversion)
68 : INHERITED(kNone_OptimizationFlags)
Brian Osman31f96a62017-03-24 18:27:56 +000069 , fPMConversion(pmConversion) {
70 this->initClassID<GrConfigConversionEffect>();
Robert Phillips757914d2017-01-25 15:48:30 -050071}
72
Brian Salomonfcc527b2017-07-26 12:21:21 -040073sk_sp<GrFragmentProcessor> GrConfigConversionEffect::clone() const {
74 return sk_sp<GrFragmentProcessor>(new GrConfigConversionEffect(fPMConversion));
75}
76
bsalomon0e08fc12014-10-15 08:19:04 -070077bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& s) const {
joshualitt49586be2014-09-16 08:21:41 -070078 const GrConfigConversionEffect& other = s.cast<GrConfigConversionEffect>();
Brian Osmance425512017-03-22 14:37:50 -040079 return other.fPMConversion == fPMConversion;
bsalomon@google.com68b58c92013-01-17 16:50:08 +000080}
81
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000082///////////////////////////////////////////////////////////////////////////////
83
joshualittb0a8a372014-09-23 09:50:21 -070084GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConfigConversionEffect);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000085
Hal Canary6f6961e2017-01-31 13:50:44 -050086#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -070087sk_sp<GrFragmentProcessor> GrConfigConversionEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -070088 PMConversion pmConv = static_cast<PMConversion>(d->fRandom->nextULessThan(kPMConversionCnt));
Brian Osmanee805322017-04-05 10:09:00 -040089 return sk_sp<GrFragmentProcessor>(new GrConfigConversionEffect(pmConv));
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000090}
Hal Canary6f6961e2017-01-31 13:50:44 -050091#endif
bsalomon@google.coma04e8e82012-08-27 12:53:13 +000092
93///////////////////////////////////////////////////////////////////////////////
joshualitteb2a6762014-12-04 11:35:33 -080094
Brian Salomon94efbf52016-11-29 13:43:05 -050095void GrConfigConversionEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -080096 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -080097 GrGLConfigConversionEffect::GenKey(*this, caps, b);
98}
99
egdaniel57d3b032015-11-13 11:57:27 -0800100GrGLSLFragmentProcessor* GrConfigConversionEffect::onCreateGLSLInstance() const {
bsalomon6c9cd552016-01-22 07:17:34 -0800101 return new GrGLConfigConversionEffect();
joshualitteb2a6762014-12-04 11:35:33 -0800102}
103
robertphillipse85a32d2015-02-10 08:16:55 -0800104
Brian Osman28804f32017-04-20 10:24:36 -0400105bool GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context) {
bsalomon49b264c2016-07-19 08:38:09 -0700106 static constexpr int kSize = 256;
107 static constexpr GrPixelConfig kConfig = kRGBA_8888_GrPixelConfig;
108 SkAutoTMalloc<uint32_t> data(kSize * kSize * 3);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000109 uint32_t* srcData = data.get();
bsalomon49b264c2016-07-19 08:38:09 -0700110 uint32_t* firstRead = data.get() + kSize * kSize;
111 uint32_t* secondRead = data.get() + 2 * kSize * kSize;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000112
113 // Fill with every possible premultiplied A, color channel value. There will be 256-y duplicate
114 // 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 -0700115 for (int y = 0; y < kSize; ++y) {
116 for (int x = 0; x < kSize; ++x) {
117 uint8_t* color = reinterpret_cast<uint8_t*>(&srcData[kSize*y + x]);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000118 color[3] = y;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000119 color[2] = SkTMin(x, y);
120 color[1] = SkTMin(x, y);
121 color[0] = SkTMin(x, y);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000122 }
123 }
124
Robert Phillipsc949ce92017-01-19 16:59:04 -0500125 const SkImageInfo ii = SkImageInfo::Make(kSize, kSize,
126 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
127
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400128 sk_sp<GrRenderTargetContext> readRTC(context->makeDeferredRenderTargetContext(
129 SkBackingFit::kExact,
Brian Osman693a5402016-10-27 15:13:22 -0400130 kSize, kSize,
131 kConfig, nullptr));
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400132 sk_sp<GrRenderTargetContext> tempRTC(context->makeDeferredRenderTargetContext(
133 SkBackingFit::kExact,
Brian Osman693a5402016-10-27 15:13:22 -0400134 kSize, kSize,
135 kConfig, nullptr));
Brian Osman28804f32017-04-20 10:24:36 -0400136 if (!readRTC || !readRTC->asTextureProxy() || !tempRTC) {
137 return false;
bsalomon49b264c2016-07-19 08:38:09 -0700138 }
bsalomonf2703d82014-10-28 14:33:06 -0700139 GrSurfaceDesc desc;
Robert Phillipsc686ce32017-07-21 14:12:29 -0400140 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
bsalomon49b264c2016-07-19 08:38:09 -0700141 desc.fWidth = kSize;
142 desc.fHeight = kSize;
143 desc.fConfig = kConfig;
Robert Phillips757914d2017-01-25 15:48:30 -0500144
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400145 sk_sp<GrTextureProxy> dataProxy = GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
146 desc,
Brian Osmance425512017-03-22 14:37:50 -0400147 SkBudgeted::kYes, data, 0);
Robert Phillips2f493142017-03-02 18:18:38 -0500148 if (!dataProxy) {
Brian Osman28804f32017-04-20 10:24:36 -0400149 return false;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000150 }
151
Brian Osman28804f32017-04-20 10:24:36 -0400152 static const SkRect kRect = SkRect::MakeIWH(kSize, kSize);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000153
Brian Osman28804f32017-04-20 10:24:36 -0400154 // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
155 // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
156 // We then verify that two reads produced the same values.
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000157
Brian Osman28804f32017-04-20 10:24:36 -0400158 GrPaint paint1;
159 GrPaint paint2;
160 GrPaint paint3;
161 sk_sp<GrFragmentProcessor> pmToUPM(new GrConfigConversionEffect(kToUnpremul_PMConversion));
162 sk_sp<GrFragmentProcessor> upmToPM(new GrConfigConversionEffect(kToPremul_PMConversion));
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000163
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400164 paint1.addColorTextureProcessor(dataProxy, nullptr, SkMatrix::I());
Brian Osman28804f32017-04-20 10:24:36 -0400165 paint1.addColorFragmentProcessor(pmToUPM);
166 paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000167
Brian Osman28804f32017-04-20 10:24:36 -0400168 readRTC->fillRectToRect(GrNoClip(), std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect, kRect);
169 if (!readRTC->readPixels(ii, firstRead, 0, 0, 0)) {
170 return false;
171 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000172
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400173 paint2.addColorTextureProcessor(readRTC->asTextureProxyRef(), nullptr,
Brian Osman28804f32017-04-20 10:24:36 -0400174 SkMatrix::I());
175 paint2.addColorFragmentProcessor(std::move(upmToPM));
176 paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700177
Brian Osman28804f32017-04-20 10:24:36 -0400178 tempRTC->fillRectToRect(GrNoClip(), std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect, kRect);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700179
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400180 paint3.addColorTextureProcessor(tempRTC->asTextureProxyRef(), nullptr,
Brian Osman28804f32017-04-20 10:24:36 -0400181 SkMatrix::I());
182 paint3.addColorFragmentProcessor(std::move(pmToUPM));
183 paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000184
Brian Osman28804f32017-04-20 10:24:36 -0400185 readRTC->fillRectToRect(GrNoClip(), std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect, kRect);
robertphillipsff0ca5e2015-07-22 11:54:44 -0700186
Brian Osman28804f32017-04-20 10:24:36 -0400187 if (!readRTC->readPixels(ii, secondRead, 0, 0, 0)) {
188 return false;
189 }
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000190
Brian Osman28804f32017-04-20 10:24:36 -0400191 for (int y = 0; y < kSize; ++y) {
192 for (int x = 0; x <= y; ++x) {
193 if (firstRead[kSize * y + x] != secondRead[kSize * y + x]) {
194 return false;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000195 }
196 }
197 }
Brian Osman28804f32017-04-20 10:24:36 -0400198
199 return true;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000200}
201
Brian Osmanee805322017-04-05 10:09:00 -0400202sk_sp<GrFragmentProcessor> GrConfigConversionEffect::Make(sk_sp<GrFragmentProcessor> fp,
203 PMConversion pmConversion) {
204 if (!fp) {
Brian Osman31f96a62017-03-24 18:27:56 +0000205 return nullptr;
206 }
Brian Osmanee805322017-04-05 10:09:00 -0400207 sk_sp<GrFragmentProcessor> ccFP(new GrConfigConversionEffect(pmConversion));
208 sk_sp<GrFragmentProcessor> fpPipeline[] = { fp, ccFP };
209 return GrFragmentProcessor::RunInSeries(fpPipeline, 2);
Robert Phillips757914d2017-01-25 15:48:30 -0500210}