1 | /* |
2 | * Copyright 2018 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 | /************************************************************************************************** |
9 | *** This file was autogenerated from GrConfigConversionEffect.fp; do not modify. |
10 | **************************************************************************************************/ |
11 | #include "GrConfigConversionEffect.h" |
12 | |
13 | #include "src/core/SkUtils.h" |
14 | #include "src/gpu/GrTexture.h" |
15 | #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" |
16 | #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
17 | #include "src/gpu/glsl/GrGLSLProgramBuilder.h" |
18 | #include "src/sksl/SkSLCPP.h" |
19 | #include "src/sksl/SkSLUtil.h" |
20 | class GrGLSLConfigConversionEffect : public GrGLSLFragmentProcessor { |
21 | public: |
22 | GrGLSLConfigConversionEffect() {} |
23 | void emitCode(EmitArgs& args) override { |
24 | GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; |
25 | const GrConfigConversionEffect& _outer = args.fFp.cast<GrConfigConversionEffect>(); |
26 | (void)_outer; |
27 | auto pmConversion = _outer.pmConversion; |
28 | (void)pmConversion; |
29 | |
30 | fragBuilder->forceHighPrecision(); |
31 | SkString _sample5773 = this->invokeChild(0, args); |
32 | fragBuilder->codeAppendf( |
33 | R"SkSL(%s = floor(%s * 255.0 + 0.5) / 255.0; |
34 | @switch (%d) { |
35 | case 0: |
36 | %s.xyz = floor((%s.xyz * %s.w) * 255.0 + 0.5) / 255.0; |
37 | break; |
38 | case 1: |
39 | %s.xyz = %s.w <= 0.0 ? half3(0.0) : floor((%s.xyz / %s.w) * 255.0 + 0.5) / 255.0; |
40 | break; |
41 | } |
42 | )SkSL" , |
43 | args.fOutputColor, _sample5773.c_str(), (int)_outer.pmConversion, args.fOutputColor, |
44 | args.fOutputColor, args.fOutputColor, args.fOutputColor, args.fOutputColor, |
45 | args.fOutputColor, args.fOutputColor); |
46 | } |
47 | |
48 | private: |
49 | void onSetData(const GrGLSLProgramDataManager& pdman, |
50 | const GrFragmentProcessor& _proc) override {} |
51 | }; |
52 | GrGLSLFragmentProcessor* GrConfigConversionEffect::onCreateGLSLInstance() const { |
53 | return new GrGLSLConfigConversionEffect(); |
54 | } |
55 | void GrConfigConversionEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, |
56 | GrProcessorKeyBuilder* b) const { |
57 | b->add32((uint32_t)pmConversion); |
58 | } |
59 | bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& other) const { |
60 | const GrConfigConversionEffect& that = other.cast<GrConfigConversionEffect>(); |
61 | (void)that; |
62 | if (pmConversion != that.pmConversion) return false; |
63 | return true; |
64 | } |
65 | GrConfigConversionEffect::GrConfigConversionEffect(const GrConfigConversionEffect& src) |
66 | : INHERITED(kGrConfigConversionEffect_ClassID, src.optimizationFlags()) |
67 | , pmConversion(src.pmConversion) { |
68 | this->cloneAndRegisterAllChildProcessors(src); |
69 | } |
70 | std::unique_ptr<GrFragmentProcessor> GrConfigConversionEffect::clone() const { |
71 | return std::make_unique<GrConfigConversionEffect>(*this); |
72 | } |
73 | #if GR_TEST_UTILS |
74 | SkString GrConfigConversionEffect::onDumpInfo() const { |
75 | return SkStringPrintf("(pmConversion=%d)" , (int)pmConversion); |
76 | } |
77 | #endif |
78 | GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConfigConversionEffect); |
79 | #if GR_TEST_UTILS |
80 | std::unique_ptr<GrFragmentProcessor> GrConfigConversionEffect::TestCreate( |
81 | GrProcessorTestData* data) { |
82 | PMConversion pmConv = static_cast<PMConversion>( |
83 | data->fRandom->nextULessThan((int)PMConversion::kPMConversionCnt)); |
84 | return std::unique_ptr<GrFragmentProcessor>( |
85 | new GrConfigConversionEffect(GrProcessorUnitTest::MakeChildFP(data), pmConv)); |
86 | } |
87 | #endif |
88 | |
89 | bool GrConfigConversionEffect::TestForPreservingPMConversions(GrDirectContext* dContext) { |
90 | static constexpr int kSize = 256; |
91 | static constexpr GrColorType kColorType = GrColorType::kRGBA_8888; |
92 | SkAutoTMalloc<uint32_t> data(kSize * kSize * 3); |
93 | uint32_t* srcData = data.get(); |
94 | uint32_t* firstRead = data.get() + kSize * kSize; |
95 | uint32_t* secondRead = data.get() + 2 * kSize * kSize; |
96 | |
97 | // Fill with every possible premultiplied A, color channel value. There will be 256-y |
98 | // duplicate values in row y. We set r, g, and b to the same value since they are handled |
99 | // identically. |
100 | for (int y = 0; y < kSize; ++y) { |
101 | for (int x = 0; x < kSize; ++x) { |
102 | uint8_t* color = reinterpret_cast<uint8_t*>(&srcData[kSize * y + x]); |
103 | color[3] = y; |
104 | color[2] = std::min(x, y); |
105 | color[1] = std::min(x, y); |
106 | color[0] = std::min(x, y); |
107 | } |
108 | } |
109 | memset(firstRead, 0, kSize * kSize * sizeof(uint32_t)); |
110 | memset(secondRead, 0, kSize * kSize * sizeof(uint32_t)); |
111 | |
112 | const SkImageInfo ii = |
113 | SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType); |
114 | |
115 | auto readRTC = GrRenderTargetContext::Make(dContext, kColorType, nullptr, SkBackingFit::kExact, |
116 | {kSize, kSize}); |
117 | auto tempRTC = GrRenderTargetContext::Make(dContext, kColorType, nullptr, SkBackingFit::kExact, |
118 | {kSize, kSize}); |
119 | if (!readRTC || !readRTC->asTextureProxy() || !tempRTC) { |
120 | return false; |
121 | } |
122 | // Adding discard to appease vulkan validation warning about loading uninitialized data on |
123 | // draw |
124 | readRTC->discard(); |
125 | |
126 | // This function is only ever called if we are in a GrContext that has a GrGpu since we are |
127 | // calling read pixels here. Thus the pixel data will be uploaded immediately and we don't |
128 | // need to keep the pixel data alive in the proxy. Therefore the ReleaseProc is nullptr. |
129 | SkBitmap bitmap; |
130 | bitmap.installPixels(ii, srcData, 4 * kSize); |
131 | bitmap.setImmutable(); |
132 | |
133 | GrBitmapTextureMaker maker(dContext, bitmap, GrImageTexGenPolicy::kNew_Uncached_Budgeted); |
134 | auto dataView = maker.view(GrMipmapped::kNo); |
135 | if (!dataView) { |
136 | return false; |
137 | } |
138 | |
139 | static const SkRect kRect = SkRect::MakeIWH(kSize, kSize); |
140 | |
141 | // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw |
142 | // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data. |
143 | // We then verify that two reads produced the same values. |
144 | |
145 | GrPaint paint1; |
146 | paint1.setColorFragmentProcessor(GrConfigConversionEffect::Make( |
147 | GrTextureEffect::Make(std::move(dataView), kPremul_SkAlphaType), |
148 | PMConversion::kToUnpremul)); |
149 | paint1.setPorterDuffXPFactory(SkBlendMode::kSrc); |
150 | |
151 | readRTC->fillRectToRect(nullptr, std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect, kRect); |
152 | if (!readRTC->readPixels(dContext, ii, firstRead, 0, {0, 0})) { |
153 | return false; |
154 | } |
155 | |
156 | // Adding discard to appease vulkan validation warning about loading uninitialized data on |
157 | // draw |
158 | tempRTC->discard(); |
159 | |
160 | GrPaint paint2; |
161 | paint2.setColorFragmentProcessor(GrConfigConversionEffect::Make( |
162 | GrTextureEffect::Make(readRTC->readSurfaceView(), kUnpremul_SkAlphaType), |
163 | PMConversion::kToPremul)); |
164 | paint2.setPorterDuffXPFactory(SkBlendMode::kSrc); |
165 | |
166 | tempRTC->fillRectToRect(nullptr, std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect, kRect); |
167 | |
168 | GrPaint paint3; |
169 | paint3.setColorFragmentProcessor(GrConfigConversionEffect::Make( |
170 | GrTextureEffect::Make(tempRTC->readSurfaceView(), kPremul_SkAlphaType), |
171 | PMConversion::kToUnpremul)); |
172 | paint3.setPorterDuffXPFactory(SkBlendMode::kSrc); |
173 | |
174 | readRTC->fillRectToRect(nullptr, std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect, kRect); |
175 | |
176 | if (!readRTC->readPixels(dContext, ii, secondRead, 0, {0, 0})) { |
177 | return false; |
178 | } |
179 | |
180 | for (int y = 0; y < kSize; ++y) { |
181 | for (int x = 0; x <= y; ++x) { |
182 | if (firstRead[kSize * y + x] != secondRead[kSize * y + x]) { |
183 | return false; |
184 | } |
185 | } |
186 | } |
187 | |
188 | return true; |
189 | } |
190 | |