blob: 9c697b41cb7b949659005234949b323772f64d89 [file] [log] [blame]
Ethan Nicholas839872c2017-10-05 12:36:59 -04001@header {
2 #include "GrClip.h"
3 #include "GrContext.h"
4 #include "GrRenderTargetContext.h"
5}
6
7@class {
8 enum PMConversion {
9 kToPremul_PMConversion = 0,
10 kToUnpremul_PMConversion = 1,
11 kPMConversionCnt = 2
12 };
13
14 static bool TestForPreservingPMConversions(GrContext* context) {
15 static constexpr int kSize = 256;
16 static constexpr GrPixelConfig kConfig = kRGBA_8888_GrPixelConfig;
17 SkAutoTMalloc<uint32_t> data(kSize * kSize * 3);
18 uint32_t* srcData = data.get();
19 uint32_t* firstRead = data.get() + kSize * kSize;
20 uint32_t* secondRead = data.get() + 2 * kSize * kSize;
21
22 // Fill with every possible premultiplied A, color channel value. There will be 256-y
23 // duplicate values in row y. We set r, g, and b to the same value since they are handled
24 // identically.
25 for (int y = 0; y < kSize; ++y) {
26 for (int x = 0; x < kSize; ++x) {
27 uint8_t* color = reinterpret_cast<uint8_t*>(&srcData[kSize*y + x]);
28 color[3] = y;
29 color[2] = SkTMin(x, y);
30 color[1] = SkTMin(x, y);
31 color[0] = SkTMin(x, y);
32 }
33 }
34
35 const SkImageInfo ii = SkImageInfo::Make(kSize, kSize,
36 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
37
38 sk_sp<GrRenderTargetContext> readRTC(context->makeDeferredRenderTargetContext(
39 SkBackingFit::kExact,
40 kSize, kSize,
41 kConfig, nullptr));
42 sk_sp<GrRenderTargetContext> tempRTC(context->makeDeferredRenderTargetContext(
43 SkBackingFit::kExact,
44 kSize, kSize,
45 kConfig, nullptr));
46 if (!readRTC || !readRTC->asTextureProxy() || !tempRTC) {
47 return false;
48 }
49 GrSurfaceDesc desc;
50 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
51 desc.fWidth = kSize;
52 desc.fHeight = kSize;
53 desc.fConfig = kConfig;
54
55 sk_sp<GrTextureProxy> dataProxy = GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
56 desc,
57 SkBudgeted::kYes, data, 0);
58 if (!dataProxy) {
59 return false;
60 }
61
62 static const SkRect kRect = SkRect::MakeIWH(kSize, kSize);
63
64 // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
65 // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
66 // We then verify that two reads produced the same values.
67
68 GrPaint paint1;
69 GrPaint paint2;
70 GrPaint paint3;
71 std::unique_ptr<GrFragmentProcessor> pmToUPM(
72 new GrConfigConversionEffect(kToUnpremul_PMConversion));
73 std::unique_ptr<GrFragmentProcessor> upmToPM(
74 new GrConfigConversionEffect(kToPremul_PMConversion));
75
76 paint1.addColorTextureProcessor(dataProxy, nullptr, SkMatrix::I());
77 paint1.addColorFragmentProcessor(pmToUPM->clone());
78 paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
79
80 readRTC->fillRectToRect(GrNoClip(), std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect,
81 kRect);
82 if (!readRTC->readPixels(ii, firstRead, 0, 0, 0)) {
83 return false;
84 }
85
86 paint2.addColorTextureProcessor(readRTC->asTextureProxyRef(), nullptr,
87 SkMatrix::I());
88 paint2.addColorFragmentProcessor(std::move(upmToPM));
89 paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
90
91 tempRTC->fillRectToRect(GrNoClip(), std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect,
92 kRect);
93
94 paint3.addColorTextureProcessor(tempRTC->asTextureProxyRef(), nullptr,
95 SkMatrix::I());
96 paint3.addColorFragmentProcessor(std::move(pmToUPM));
97 paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
98
99 readRTC->fillRectToRect(GrNoClip(), std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect,
100 kRect);
101
102 if (!readRTC->readPixels(ii, secondRead, 0, 0, 0)) {
103 return false;
104 }
105
106 for (int y = 0; y < kSize; ++y) {
107 for (int x = 0; x <= y; ++x) {
108 if (firstRead[kSize * y + x] != secondRead[kSize * y + x]) {
109 return false;
110 }
111 }
112 }
113
114 return true;
115 }
116}
117
118@make {
119 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
120 PMConversion pmConversion) {
121 if (!fp) {
122 return nullptr;
123 }
124 std::unique_ptr<GrFragmentProcessor> ccFP(new GrConfigConversionEffect(pmConversion));
125 std::unique_ptr<GrFragmentProcessor> fpPipeline[] = { std::move(fp), std::move(ccFP) };
126 return GrFragmentProcessor::RunInSeries(fpPipeline, 2);
127 }
128}
129
130layout(key) in int pmConversion;
131
132@emitCode {
133 fragBuilder->forceHighPrecision();
134}
135
136void main() {
137 // Aggressively round to the nearest exact (N / 255) floating point value. This lets us find a
138 // round-trip preserving pair on some GPUs that do odd byte to float conversion.
139 sk_OutColor = floor(sk_InColor * 255 + 0.5) / 255;
140
141 @switch (pmConversion) {
142 case 0 /* kToPremul_PMConversion */:
143 sk_OutColor.rgb = floor(sk_OutColor.rgb * sk_OutColor.a * 255 + 0.5) / 255;
144 break;
145
146 case 1 /* kToUnpremul_PMConversion */:
147 sk_OutColor.rgb = sk_OutColor.a <= 0.0 ?
148 half3(0) :
149 floor(sk_OutColor.rgb / sk_OutColor.a * 255 + 0.5) / 255;
150 break;
151 }
152}
153
154@test(data) {
155 PMConversion pmConv = static_cast<PMConversion>(data->fRandom->nextULessThan(kPMConversionCnt));
156 return std::unique_ptr<GrFragmentProcessor>(new GrConfigConversionEffect(pmConv));
157}