• 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 #include "GrContext.h"
12 #include "GrContextPriv.h"
13 #include "GrProxyProvider.h"
14 #include "GrResourceProvider.h"
15 #include "GrSurfaceContext.h"
16 #include "GrSurfaceProxy.h"
17 #include "GrTextureProxy.h"
18 #include "ProxyUtils.h"
19 #include "SkCanvas.h"
20 #include "SkSurface.h"
21 #include "SkTo.h"
22 
23 // This was made indivisible by 4 to ensure we test setting GL_PACK_ALIGNMENT properly.
24 static const int X_SIZE = 13;
25 static const int Y_SIZE = 13;
26 
validate_alpha_data(skiatest::Reporter * reporter,int w,int h,const uint8_t * actual,size_t actualRowBytes,const uint8_t * expected,SkString extraMsg,GrColorType colorType)27 static void validate_alpha_data(skiatest::Reporter* reporter, int w, int h, const uint8_t* actual,
28                                 size_t actualRowBytes, const uint8_t* expected, SkString extraMsg,
29                                 GrColorType colorType) {
30     for (int y = 0; y < h; ++y) {
31         for (int x = 0; x < w; ++x) {
32             uint8_t a = actual[y * actualRowBytes + x];
33             uint8_t e = expected[y * w + x];
34             if (GrColorType::kRGBA_1010102 == colorType) {
35                 // This config only preserves two bits of alpha
36                 a >>= 6;
37                 e >>= 6;
38             }
39             if (e != a) {
40                 ERRORF(reporter,
41                        "Failed alpha readback. Expected: 0x%02x, Got: 0x%02x at (%d,%d), %s",
42                        e, a, x, y, extraMsg.c_str());
43                 return;
44             }
45         }
46     }
47 }
48 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadWriteAlpha,reporter,ctxInfo)49 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadWriteAlpha, reporter, ctxInfo) {
50     GrContext* context = ctxInfo.grContext();
51     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
52 
53     unsigned char alphaData[X_SIZE * Y_SIZE];
54 
55     static const int kClearValue = 0x2;
56 
57     bool match;
58     static const size_t kRowBytes[] = {0, X_SIZE, X_SIZE + 1, 2 * X_SIZE - 1};
59     {
60         GrSurfaceDesc desc;
61         desc.fFlags     = kNone_GrSurfaceFlags;
62         desc.fConfig    = kAlpha_8_GrPixelConfig;    // it is a single channel texture
63         desc.fWidth     = X_SIZE;
64         desc.fHeight    = Y_SIZE;
65 
66         // We are initializing the texture with zeros here
67         memset(alphaData, 0, X_SIZE * Y_SIZE);
68 
69         const SkImageInfo ii = SkImageInfo::MakeA8(X_SIZE, Y_SIZE);
70 
71         SkPixmap pixmap(ii, alphaData, ii.minRowBytes());
72         sk_sp<SkImage> alphaImg = SkImage::MakeRasterCopy(pixmap);
73         sk_sp<GrTextureProxy> proxy =
74             proxyProvider->createTextureProxy(alphaImg, kNone_GrSurfaceFlags, 1,
75                                               SkBudgeted::kNo, SkBackingFit::kExact);
76         if (!proxy) {
77             ERRORF(reporter, "Could not create alpha texture.");
78             return;
79         }
80         sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeWrappedSurfaceContext(
81                                                                   std::move(proxy)));
82 
83         sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii));
84 
85         // create a distinctive texture
86         for (int y = 0; y < Y_SIZE; ++y) {
87             for (int x = 0; x < X_SIZE; ++x) {
88                 alphaData[y * X_SIZE + x] = y*X_SIZE+x;
89             }
90         }
91 
92         for (auto rowBytes : kRowBytes) {
93 
94             // upload the texture (do per-rowbytes iteration because we may overwrite below).
95             bool result = sContext->writePixels(ii, alphaData, 0, 0, 0);
96             REPORTER_ASSERT(reporter, result, "Initial A8 writePixels failed");
97 
98             size_t nonZeroRowBytes = rowBytes ? rowBytes : X_SIZE;
99             size_t bufLen = nonZeroRowBytes * Y_SIZE;
100             std::unique_ptr<uint8_t[]> readback(new uint8_t[bufLen]);
101             // clear readback to something non-zero so we can detect readback failures
102             memset(readback.get(), kClearValue, bufLen);
103 
104             // read the texture back
105             result = sContext->readPixels(ii, readback.get(), rowBytes, 0, 0);
106             // We don't require reading from kAlpha_8 to be supported. TODO: At least make this work
107             // when kAlpha_8 is renderable.
108             if (!result) {
109                 continue;
110             }
111             REPORTER_ASSERT(reporter, result, "Initial A8 readPixels failed");
112 
113             // make sure the original & read back versions match
114             SkString msg;
115             msg.printf("rb:%d A8", SkToU32(rowBytes));
116             validate_alpha_data(reporter, X_SIZE, Y_SIZE, readback.get(), nonZeroRowBytes,
117                                 alphaData, msg, GrColorType::kAlpha_8);
118 
119             // Now try writing to a single channel surface (if we could create one).
120             if (surf) {
121                 SkCanvas* canvas = surf->getCanvas();
122 
123                 SkPaint paint;
124 
125                 const SkRect rect = SkRect::MakeLTRB(-10, -10, X_SIZE + 10, Y_SIZE + 10);
126 
127                 paint.setColor(SK_ColorWHITE);
128 
129                 canvas->drawRect(rect, paint);
130 
131                 // Workaround for a bug in old GCC/glibc used in our Chromecast toolchain:
132                 // error: call to '__warn_memset_zero_len' declared with attribute warning:
133                 //        memset used with constant zero length parameter; this could be due
134                 //        to transposed parameters
135                 // See also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61294
136                 if (bufLen > 0) {
137                     memset(readback.get(), kClearValue, bufLen);
138                 }
139                 result = surf->readPixels(ii, readback.get(), nonZeroRowBytes, 0, 0);
140                 REPORTER_ASSERT(reporter, result, "A8 readPixels after clear failed");
141 
142                 match = true;
143                 for (int y = 0; y < Y_SIZE && match; ++y) {
144                     for (int x = 0; x < X_SIZE && match; ++x) {
145                         uint8_t rbValue = readback.get()[y * nonZeroRowBytes + x];
146                         if (0xFF != rbValue) {
147                             ERRORF(reporter,
148                                    "Failed alpha readback after clear. Expected: 0xFF, Got: 0x%02x"
149                                    " at (%d,%d), rb:%d", rbValue, x, y, SkToU32(rowBytes));
150                             match = false;
151                         }
152                     }
153                 }
154             }
155         }
156     }
157 
158     static constexpr struct {
159         GrColorType fColorType;
160         GrSRGBEncoded fSRGBEncoded;
161     } kInfos[] = {
162             {GrColorType::kRGBA_8888, GrSRGBEncoded::kNo},
163             {GrColorType::kBGRA_8888, GrSRGBEncoded::kNo},
164             {GrColorType::kRGBA_8888, GrSRGBEncoded::kYes},
165             {GrColorType::kRGBA_1010102, GrSRGBEncoded::kNo},
166     };
167 
168     for (int y = 0; y < Y_SIZE; ++y) {
169         for (int x = 0; x < X_SIZE; ++x) {
170             alphaData[y * X_SIZE + x] = y*X_SIZE+x;
171         }
172     }
173 
174     const SkImageInfo dstInfo = SkImageInfo::Make(X_SIZE, Y_SIZE,
175                                                   kAlpha_8_SkColorType,
176                                                   kPremul_SkAlphaType);
177 
178     // Attempt to read back just alpha from a RGBA/BGRA texture. Once with a texture-only src and
179     // once with a render target.
180     for (auto info : kInfos) {
181         for (int rt = 0; rt < 2; ++rt) {
182             uint32_t rgbaData[X_SIZE * Y_SIZE];
183             // Make the alpha channel of the rgba texture come from alphaData.
184             for (int y = 0; y < Y_SIZE; ++y) {
185                 for (int x = 0; x < X_SIZE; ++x) {
186                     rgbaData[y * X_SIZE + x] = GrColorPackRGBA(6, 7, 8, alphaData[y * X_SIZE + x]);
187                 }
188             }
189 
190             auto origin = rt ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
191             auto proxy = sk_gpu_test::MakeTextureProxyFromData(context, rt, X_SIZE, Y_SIZE,
192                                                                info.fColorType, info.fSRGBEncoded,
193                                                                origin, rgbaData, 0);
194             if (!proxy) {
195                 continue;
196             }
197 
198             sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeWrappedSurfaceContext(
199                     std::move(proxy));
200 
201             for (auto rowBytes : kRowBytes) {
202                 size_t nonZeroRowBytes = rowBytes ? rowBytes : X_SIZE;
203 
204                 std::unique_ptr<uint8_t[]> readback(new uint8_t[nonZeroRowBytes * Y_SIZE]);
205                 // Clear so we don't accidentally see values from previous iteration.
206                 memset(readback.get(), kClearValue, nonZeroRowBytes * Y_SIZE);
207 
208                 // read the texture back
209                 bool result = sContext->readPixels(dstInfo, readback.get(), rowBytes, 0, 0);
210                 REPORTER_ASSERT(reporter, result, "8888 readPixels failed");
211 
212                 // make sure the original & read back versions match
213                 SkString msg;
214                 msg.printf("rt:%d, rb:%d 8888", rt, SkToU32(rowBytes));
215                 validate_alpha_data(reporter, X_SIZE, Y_SIZE, readback.get(), nonZeroRowBytes,
216                                     alphaData, msg, info.fColorType);
217             }
218         }
219     }
220 }
221