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