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