• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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