1 /*
2 * Copyright 2016 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 "Test.h"
9
10 #if SK_SUPPORT_GPU
11 #include "GrClip.h"
12 #include "GrContext.h"
13 #include "GrContextPriv.h"
14 #include "GrProxyProvider.h"
15 #include "GrRenderTargetContext.h"
16 #include "GrResourceProvider.h"
17 #include "GrTexture.h"
18 #include "effects/GrSimpleTextureEffect.h"
19
20 template <typename I>
21 static SK_WHEN(std::is_integral<I>::value && 4 == sizeof(I), void)
check_pixels(skiatest::Reporter * reporter,int w,int h,const I exepctedData[],const I actualData[],const char * testName)22 check_pixels(skiatest::Reporter* reporter, int w, int h, const I exepctedData[],
23 const I actualData[], const char* testName) {
24 for (int j = 0; j < h; ++j) {
25 for (int i = 0; i < w; ++i) {
26 I expected = exepctedData[j * w + i];
27 I actual = actualData[j * w + i];
28 if (expected != actual) {
29 ERRORF(reporter, "[%s] Expected 0x08%x, got 0x%08x at %d, %d.", testName, expected,
30 actual, i, j);
31 return;
32 }
33 }
34 }
35 }
36
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(IntTexture,reporter,ctxInfo)37 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(IntTexture, reporter, ctxInfo) {
38 GrContext* context = ctxInfo.grContext();
39 if (!context->caps()->isConfigTexturable(kRGBA_8888_sint_GrPixelConfig)) {
40 return;
41 }
42
43 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
44 auto resourceProvider = context->contextPriv().resourceProvider();
45
46 static const int kS = UINT8_MAX + 1;
47 static const size_t kRowBytes = kS * sizeof(int32_t);
48
49 GrSurfaceDesc desc;
50 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
51 desc.fConfig = kRGBA_8888_sint_GrPixelConfig;
52 desc.fWidth = kS;
53 desc.fHeight = kS;
54
55 std::unique_ptr<int32_t[]> testData(new int32_t[kS * kS]);
56 for (int j = 0; j < kS; ++j) {
57 for (int i = 0; i < kS; ++i) {
58 uint32_t r = i - INT8_MIN;
59 uint32_t g = j - INT8_MIN;
60 uint32_t b = INT8_MAX - r;
61 uint32_t a = INT8_MAX - g;
62 testData.get()[j * kS + i] = (a << 24) | (b << 16) | (g << 8) | r;
63 }
64 }
65
66 // Test that attempting to create a integer texture with multiple MIP levels fails.
67 {
68 GrMipLevel levels[2];
69 levels[0].fPixels = testData.get();
70 levels[0].fRowBytes = kRowBytes;
71 levels[1].fPixels = testData.get();
72 levels[1].fRowBytes = (kS / 2) * sizeof(int32_t);
73
74 sk_sp<GrTextureProxy> temp = proxyProvider->createMipMapProxy(
75 desc, SkBudgeted::kYes, levels, 2);
76 REPORTER_ASSERT(reporter, !temp);
77 }
78
79 sk_sp<GrSurfaceContext> sContext;
80 // Test that we can create a non-mipmapped integer texture.
81 {
82 sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(desc, SkBudgeted::kYes,
83 testData.get(), kRowBytes);
84 REPORTER_ASSERT(reporter, proxy);
85 if (!proxy) {
86 return;
87 }
88
89 sContext = context->contextPriv().makeWrappedSurfaceContext(std::move(proxy));
90 if (!sContext) {
91 return;
92 }
93 }
94
95 std::unique_ptr<int32_t[]> readData(new int32_t[kS * kS]);
96 // Test that reading to a non-integer config fails.
97 {
98 bool success = context->contextPriv().readSurfacePixels(sContext.get(),
99 0, 0, kS, kS,
100 kRGBA_8888_GrPixelConfig,
101 nullptr, readData.get());
102 REPORTER_ASSERT(reporter, !success);
103 }
104 {
105 std::unique_ptr<uint16_t[]> halfData(new uint16_t[4 * kS * kS]);
106 bool success = context->contextPriv().readSurfacePixels(sContext.get(),
107 0, 0, kS, kS,
108 kRGBA_half_GrPixelConfig,
109 nullptr, halfData.get());
110 REPORTER_ASSERT(reporter, !success);
111 }
112 {
113 // Can read back as ints. (ES only requires being able to read back into 32bit ints which
114 // we don't support. Right now this test is counting on GR_RGBA_INTEGER/GL_BYTE being the
115 // implementation-dependent second format).
116 sk_bzero(readData.get(), sizeof(int32_t) * kS * kS);
117 bool success = context->contextPriv().readSurfacePixels(sContext.get(),
118 0, 0, kS, kS,
119 kRGBA_8888_sint_GrPixelConfig,
120 nullptr, readData.get());
121 REPORTER_ASSERT(reporter, success);
122 if (success) {
123 check_pixels(reporter, kS, kS, testData.get(), readData.get(), "readPixels");
124 }
125 }
126 {
127 // readPixels should fail if we attempt to use the unpremul flag with an integer texture.
128 bool success = context->contextPriv().readSurfacePixels(
129 sContext.get(),
130 0, 0, kS, kS,
131 kRGBA_8888_sint_GrPixelConfig,
132 nullptr, readData.get(), 0,
133 GrContextPriv::kUnpremul_PixelOpsFlag);
134 REPORTER_ASSERT(reporter, !success);
135 }
136
137 // Test that copying from one integer texture to another succeeds.
138 {
139 sk_sp<GrSurfaceContext> dstContext(GrSurfaceProxy::TestCopy(context, desc,
140 sContext->asSurfaceProxy()));
141 REPORTER_ASSERT(reporter, dstContext);
142 if (!dstContext || !dstContext->asTextureProxy()) {
143 return;
144 }
145
146 sk_bzero(readData.get(), sizeof(int32_t) * kS * kS);
147 bool success = context->contextPriv().readSurfacePixels(dstContext.get(), 0, 0, kS, kS,
148 kRGBA_8888_sint_GrPixelConfig,
149 nullptr, readData.get());
150 REPORTER_ASSERT(reporter, success);
151 if (success) {
152 check_pixels(reporter, kS, kS, testData.get(), readData.get(), "copyIntegerToInteger");
153 }
154 }
155
156
157 // Test that copying to a non-integer (8888) texture fails.
158 {
159 GrSurfaceDesc nonIntDesc = desc;
160 nonIntDesc.fConfig = kRGBA_8888_GrPixelConfig;
161
162 sk_sp<GrSurfaceContext> dstContext(GrSurfaceProxy::TestCopy(context, nonIntDesc,
163 sContext->asSurfaceProxy()));
164 REPORTER_ASSERT(reporter, !dstContext);
165 }
166
167 // Test that copying to a non-integer (RGBA_half) texture fails.
168 if (context->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig)) {
169 GrSurfaceDesc nonIntDesc = desc;
170 nonIntDesc.fConfig = kRGBA_half_GrPixelConfig;
171
172 sk_sp<GrSurfaceContext> dstContext(GrSurfaceProxy::TestCopy(context, nonIntDesc,
173 sContext->asSurfaceProxy()));
174 REPORTER_ASSERT(reporter, !dstContext);
175 }
176
177 // We overwrite the top left quarter of the texture with the bottom right quarter of the
178 // original data.
179 const void* bottomRightQuarter = testData.get() + kS / 2 * kS + kS / 2;
180
181 {
182 // Can't write pixels from a non-int config.
183 bool success = context->contextPriv().writeSurfacePixels(sContext.get(),
184 0, 0, kS/2, kS/2,
185 kRGBA_8888_GrPixelConfig, nullptr,
186 bottomRightQuarter, kRowBytes);
187 REPORTER_ASSERT(reporter, !success);
188 }
189 {
190 // Can't use unpremul flag.
191 bool success = context->contextPriv().writeSurfacePixels(
192 sContext.get(),
193 0, 0, kS/2, kS/2,
194 kRGBA_8888_sint_GrPixelConfig,
195 nullptr,
196 bottomRightQuarter, kRowBytes,
197 GrContextPriv::kUnpremul_PixelOpsFlag);
198 REPORTER_ASSERT(reporter, !success);
199 }
200 {
201 bool success = context->contextPriv().writeSurfacePixels(sContext.get(),
202 0, 0, kS/2, kS/2,
203 kRGBA_8888_sint_GrPixelConfig,
204 nullptr,
205 bottomRightQuarter, kRowBytes);
206 REPORTER_ASSERT(reporter, success);
207 if (!success) {
208 return;
209 }
210
211 sk_bzero(readData.get(), sizeof(int32_t) * kS * kS);
212 success = context->contextPriv().readSurfacePixels(sContext.get(),
213 0, 0, kS, kS,
214 kRGBA_8888_sint_GrPixelConfig,
215 nullptr, readData.get(), 0);
216 REPORTER_ASSERT(reporter, success);
217 if (!success) {
218 return;
219 }
220 std::unique_ptr<int32_t[]> overwrittenTestData(new int32_t[kS * kS]);
221 memcpy(overwrittenTestData.get(), testData.get(), sizeof(int32_t) * kS * kS);
222 char* dst = (char*)overwrittenTestData.get();
223 char* src = (char*)(testData.get() + kS/2 * kS + kS/2);
224 for (int i = 0; i < kS/2; ++i) {
225 memcpy(dst, src, sizeof(int32_t) * kS/2);
226 dst += kRowBytes;
227 src += kRowBytes;
228 }
229 check_pixels(reporter, kS, kS, overwrittenTestData.get(), readData.get(), "overwrite");
230 }
231
232 // Test drawing from the integer texture to a fixed point texture. To avoid any premul issues
233 // we init the int texture with 0s and 1s and make alpha always be 1. We expect that 1s turn
234 // into 0xffs and zeros stay zero.
235 std::unique_ptr<uint32_t[]> expectedData(new uint32_t[kS * kS]);
236 std::unique_ptr<uint32_t[]> actualData(new uint32_t[kS * kS]);
237 for (int i = 0; i < kS*kS; ++i) {
238 int32_t a = 0x1;
239 int32_t b = ((i & 0x1) ? 1 : 0);
240 int32_t g = ((i & 0x1) ? 0 : 1);
241 int32_t r = ((i & 0x2) ? 1 : 0);
242 testData.get()[i] = (a << 24) | (b << 16) | (g << 8) | r;
243 expectedData.get()[i] = ((0xFF * a) << 24) | ((0xFF * b) << 16) |
244 ((0xFF * g) << 8) | (0xFF * r);
245 }
246 context->contextPriv().writeSurfacePixels(sContext.get(),
247 0, 0, kS, kS,
248 kRGBA_8888_sint_GrPixelConfig, nullptr,
249 testData.get(), 0);
250
251 sk_sp<GrRenderTargetContext> rtContext = context->makeDeferredRenderTargetContext(
252 SkBackingFit::kExact, kS, kS, kRGBA_8888_GrPixelConfig, nullptr);
253
254 struct {
255 GrSamplerState::Filter fMode;
256 const char* fName;
257 } kNamedFilters[] = {{GrSamplerState::Filter::kNearest, "filter-none"},
258 {GrSamplerState::Filter::kBilerp, "filter-bilerp"},
259 {GrSamplerState::Filter::kMipMap, "filter-mipmap"}};
260
261 for (auto filter : kNamedFilters) {
262 auto fp = GrSimpleTextureEffect::Make(sContext->asTextureProxyRef(), SkMatrix::I(),
263 filter.fMode);
264 REPORTER_ASSERT(reporter, fp);
265 if (!fp) {
266 return;
267 }
268 rtContext->clear(nullptr, 0xDDAABBCC, GrRenderTargetContext::CanClearFullscreen::kYes);
269 GrPaint paint;
270 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
271 paint.addColorFragmentProcessor(std::move(fp));
272 rtContext->drawPaint(GrNoClip(), std::move(paint), SkMatrix::I());
273 SkImageInfo readInfo = SkImageInfo::Make(kS, kS, kRGBA_8888_SkColorType,
274 kPremul_SkAlphaType);
275 rtContext->readPixels(readInfo, actualData.get(), 0, 0, 0);
276 check_pixels(reporter, kS, kS, expectedData.get(), actualData.get(), filter.fName);
277 }
278
279 {
280 // No rendering to integer textures.
281 GrSurfaceDesc intRTDesc = desc;
282 intRTDesc.fFlags = kRenderTarget_GrSurfaceFlag;
283 sk_sp<GrTexture> temp(resourceProvider->createTexture(intRTDesc, SkBudgeted::kYes));
284 REPORTER_ASSERT(reporter, !temp);
285 }
286 }
287
288 #endif
289