• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 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 // This test is specific to the GPU backend.
11 #if SK_SUPPORT_GPU
12 
13 #include "GrContext.h"
14 #include "GrContextPriv.h"
15 #include "GrResourceProvider.h"
16 #include "GrSurfaceContext.h"
17 #include "GrSurfaceProxy.h"
18 #include "GrTextureProxy.h"
19 #include "SkCanvas.h"
20 #include "SkSurface.h"
21 
22 // This was made indivisible by 4 to ensure we test setting GL_PACK_ALIGNMENT properly.
23 static const int X_SIZE = 13;
24 static const int Y_SIZE = 13;
25 
validate_alpha_data(skiatest::Reporter * reporter,int w,int h,const uint8_t * actual,size_t actualRowBytes,const uint8_t * expected,SkString extraMsg)26 static void validate_alpha_data(skiatest::Reporter* reporter, int w, int h, const uint8_t* actual,
27                                 size_t actualRowBytes, const uint8_t* expected, SkString extraMsg) {
28     for (int y = 0; y < h; ++y) {
29         for (int x = 0; x < w; ++x) {
30             uint8_t a = actual[y * actualRowBytes + x];
31             uint8_t e = expected[y * w + x];
32             if (e != a) {
33                 ERRORF(reporter,
34                        "Failed alpha readback. Expected: 0x%02x, Got: 0x%02x at (%d,%d), %s",
35                        e, a, x, y, extraMsg.c_str());
36                 return;
37             }
38         }
39     }
40 }
41 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadWriteAlpha,reporter,ctxInfo)42 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadWriteAlpha, reporter, ctxInfo) {
43     GrContext* context = ctxInfo.grContext();
44     unsigned char alphaData[X_SIZE * Y_SIZE];
45 
46     static const int kClearValue = 0x2;
47 
48     bool match;
49     static const size_t kRowBytes[] = {0, X_SIZE, X_SIZE + 1, 2 * X_SIZE - 1};
50     {
51         GrSurfaceDesc desc;
52         desc.fFlags     = kNone_GrSurfaceFlags;
53         desc.fConfig    = kAlpha_8_GrPixelConfig;    // it is a single channel texture
54         desc.fWidth     = X_SIZE;
55         desc.fHeight    = Y_SIZE;
56 
57         // We are initializing the texture with zeros here
58         memset(alphaData, 0, X_SIZE * Y_SIZE);
59 
60         sk_sp<GrTextureProxy> proxy(GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
61                                                                  desc,
62                                                                  SkBudgeted::kNo,
63                                                                  alphaData, 0));
64         if (!proxy) {
65             ERRORF(reporter, "Could not create alpha texture.");
66             return;
67         }
68         sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeWrappedSurfaceContext(
69                                                                   std::move(proxy), nullptr));
70 
71         const SkImageInfo ii = SkImageInfo::MakeA8(X_SIZE, Y_SIZE);
72         sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii));
73 
74         // create a distinctive texture
75         for (int y = 0; y < Y_SIZE; ++y) {
76             for (int x = 0; x < X_SIZE; ++x) {
77                 alphaData[y * X_SIZE + x] = y*X_SIZE+x;
78             }
79         }
80 
81         for (auto rowBytes : kRowBytes) {
82 
83             // upload the texture (do per-rowbytes iteration because we may overwrite below).
84             bool result = sContext->writePixels(ii, alphaData, 0, 0, 0);
85             REPORTER_ASSERT_MESSAGE(reporter, result, "Initial A8 writePixels failed");
86 
87             size_t nonZeroRowBytes = rowBytes ? rowBytes : X_SIZE;
88             std::unique_ptr<uint8_t[]> readback(new uint8_t[nonZeroRowBytes * Y_SIZE]);
89             // clear readback to something non-zero so we can detect readback failures
90             memset(readback.get(), kClearValue, nonZeroRowBytes * Y_SIZE);
91 
92             // read the texture back
93             result = sContext->readPixels(ii, readback.get(), rowBytes, 0, 0);
94             REPORTER_ASSERT_MESSAGE(reporter, result, "Initial A8 readPixels failed");
95 
96             // make sure the original & read back versions match
97             SkString msg;
98             msg.printf("rb:%d A8", SkToU32(rowBytes));
99             validate_alpha_data(reporter, X_SIZE, Y_SIZE, readback.get(), nonZeroRowBytes,
100                                 alphaData, msg);
101 
102             // Now try writing to a single channel surface (if we could create one).
103             if (surf) {
104                 SkCanvas* canvas = surf->getCanvas();
105 
106                 SkPaint paint;
107 
108                 const SkRect rect = SkRect::MakeLTRB(-10, -10, X_SIZE + 10, Y_SIZE + 10);
109 
110                 paint.setColor(SK_ColorWHITE);
111 
112                 canvas->drawRect(rect, paint);
113 
114                 memset(readback.get(), kClearValue, nonZeroRowBytes * Y_SIZE);
115                 result = surf->readPixels(ii, readback.get(), nonZeroRowBytes, 0, 0);
116                 REPORTER_ASSERT_MESSAGE(reporter, result, "A8 readPixels after clear failed");
117 
118                 match = true;
119                 for (int y = 0; y < Y_SIZE && match; ++y) {
120                     for (int x = 0; x < X_SIZE && match; ++x) {
121                         uint8_t rbValue = readback.get()[y * nonZeroRowBytes + x];
122                         if (0xFF != rbValue) {
123                             ERRORF(reporter,
124                                    "Failed alpha readback after clear. Expected: 0xFF, Got: 0x%02x"
125                                    " at (%d,%d), rb:%d", rbValue, x, y, SkToU32(rowBytes));
126                             match = false;
127                         }
128                     }
129                 }
130             }
131         }
132     }
133 
134     static const GrPixelConfig kRGBAConfigs[] {
135         kRGBA_8888_GrPixelConfig,
136         kBGRA_8888_GrPixelConfig,
137         kSRGBA_8888_GrPixelConfig
138     };
139 
140     for (int y = 0; y < Y_SIZE; ++y) {
141         for (int x = 0; x < X_SIZE; ++x) {
142             alphaData[y * X_SIZE + x] = y*X_SIZE+x;
143         }
144     }
145 
146     const SkImageInfo dstInfo = SkImageInfo::Make(X_SIZE, Y_SIZE,
147                                                   kAlpha_8_SkColorType,
148                                                   kPremul_SkAlphaType);
149 
150     // Attempt to read back just alpha from a RGBA/BGRA texture. Once with a texture-only src and
151     // once with a render target.
152     for (auto config : kRGBAConfigs) {
153         for (int rt = 0; rt < 2; ++rt) {
154             GrSurfaceDesc desc;
155             desc.fFlags     = rt ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
156             desc.fConfig    = config;
157             desc.fWidth     = X_SIZE;
158             desc.fHeight    = Y_SIZE;
159 
160             uint32_t rgbaData[X_SIZE * Y_SIZE];
161             // Make the alpha channel of the rgba texture come from alphaData.
162             for (int y = 0; y < Y_SIZE; ++y) {
163                 for (int x = 0; x < X_SIZE; ++x) {
164                     rgbaData[y * X_SIZE + x] = GrColorPackRGBA(6, 7, 8, alphaData[y * X_SIZE + x]);
165                 }
166             }
167             sk_sp<GrTextureProxy> proxy =
168                 GrSurfaceProxy::MakeDeferred(context->resourceProvider(), desc, SkBudgeted::kNo,
169                                              rgbaData, 0);
170             if (!proxy) {
171                 // We always expect to be able to create a RGBA texture
172                 if (!rt  && kRGBA_8888_GrPixelConfig == desc.fConfig) {
173                     ERRORF(reporter, "Failed to create RGBA texture.");
174                 }
175                 continue;
176             }
177 
178             sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeWrappedSurfaceContext(
179                                                                        std::move(proxy), nullptr);
180 
181             for (auto rowBytes : kRowBytes) {
182                 size_t nonZeroRowBytes = rowBytes ? rowBytes : X_SIZE;
183 
184                 std::unique_ptr<uint8_t[]> readback(new uint8_t[nonZeroRowBytes * Y_SIZE]);
185                 // Clear so we don't accidentally see values from previous iteration.
186                 memset(readback.get(), kClearValue, nonZeroRowBytes * Y_SIZE);
187 
188                 // read the texture back
189                 bool result = sContext->readPixels(dstInfo, readback.get(), rowBytes, 0, 0);
190                 REPORTER_ASSERT_MESSAGE(reporter, result, "8888 readPixels failed");
191 
192                 // make sure the original & read back versions match
193                 SkString msg;
194                 msg.printf("rt:%d, rb:%d 8888", rt, SkToU32(rowBytes));
195                 validate_alpha_data(reporter, X_SIZE, Y_SIZE, readback.get(), nonZeroRowBytes,
196                                     alphaData, msg);
197             }
198         }
199     }
200 }
201 
202 #endif
203