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