Home | History | Annotate | Download | only in tests
      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 
     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 
     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