Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2016 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 #if SK_SUPPORT_GPU
     11 #include "GrContext.h"
     12 #include "GrRenderTargetContext.h"
     13 
     14 #include "SkCanvas.h"
     15 #include "SkSurface.h"
     16 
     17 static bool check_rect(GrRenderTargetContext* rtc, const SkIRect& rect, uint32_t expectedValue,
     18                        uint32_t* actualValue, int* failX, int* failY) {
     19     int w = rect.width();
     20     int h = rect.height();
     21     std::unique_ptr<uint32_t[]> pixels(new uint32_t[w * h]);
     22     memset(pixels.get(), ~expectedValue, sizeof(uint32_t) * w * h);
     23 
     24     SkImageInfo dstInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
     25 
     26     if (!rtc->readPixels(dstInfo, pixels.get(), 0, rect.fLeft, rect.fTop)) {
     27         return false;
     28     }
     29 
     30     for (int y = 0; y < h; ++y) {
     31         for (int x = 0; x < w; ++x) {
     32             uint32_t pixel = pixels.get()[y * w + x];
     33             if (pixel != expectedValue) {
     34                 *actualValue = pixel;
     35                 *failX = x + rect.fLeft;
     36                 *failY = y + rect.fTop;
     37                 return false;
     38             }
     39         }
     40     }
     41     return true;
     42 }
     43 
     44 sk_sp<GrRenderTargetContext> newRTC(GrContext* context, int w, int h) {
     45     return context->makeDeferredRenderTargetContext(SkBackingFit::kExact, w, h,
     46                                                     kRGBA_8888_GrPixelConfig, nullptr);
     47 }
     48 
     49 static void clear_op_test(skiatest::Reporter* reporter, GrContext* context) {
     50     static const int kW = 10;
     51     static const int kH = 10;
     52 
     53     SkIRect fullRect = SkIRect::MakeWH(kW, kH);
     54     sk_sp<GrRenderTargetContext> rtContext;
     55 
     56     // A rectangle that is inset by one on all sides and the 1-pixel wide rectangles that surround
     57     // it.
     58     SkIRect mid1Rect = SkIRect::MakeXYWH(1, 1, kW-2, kH-2);
     59     SkIRect outerLeftEdge = SkIRect::MakeXYWH(0, 0, 1, kH);
     60     SkIRect outerTopEdge = SkIRect::MakeXYWH(0, 0, kW, 1);
     61     SkIRect outerRightEdge = SkIRect::MakeXYWH(kW-1, 0, 1, kH);
     62     SkIRect outerBottomEdge = SkIRect::MakeXYWH(0, kH-1, kW, 1);
     63 
     64     // A rectangle that is inset by two on all sides and the 1-pixel wide rectangles that surround
     65     // it.
     66     SkIRect mid2Rect = SkIRect::MakeXYWH(2, 2, kW-4, kH-4);
     67     SkIRect innerLeftEdge = SkIRect::MakeXYWH(1, 1, 1, kH-2);
     68     SkIRect innerTopEdge = SkIRect::MakeXYWH(1, 1, kW-2, 1);
     69     SkIRect innerRightEdge = SkIRect::MakeXYWH(kW-2, 1, 1, kH-2);
     70     SkIRect innerBottomEdge = SkIRect::MakeXYWH(1, kH-2, kW-2, 1);
     71 
     72     uint32_t actualValue;
     73     int failX, failY;
     74 
     75     static const GrColor kColor1 = 0xABCDEF01;
     76     static const GrColor kColor2 = ~kColor1;
     77 
     78     rtContext = newRTC(context, kW, kH);
     79     SkASSERT(rtContext);
     80 
     81     // Check a full clear
     82     rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
     83     if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
     84         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
     85                failX, failY);
     86     }
     87 
     88     rtContext = newRTC(context, kW, kH);
     89     SkASSERT(rtContext);
     90 
     91     // Check two full clears, same color
     92     rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
     93     rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
     94     if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
     95         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
     96                failX, failY);
     97     }
     98 
     99     rtContext = newRTC(context, kW, kH);
    100     SkASSERT(rtContext);
    101 
    102     // Check two full clears, different colors
    103     rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
    104     rtContext->clear(&fullRect, kColor2, GrRenderTargetContext::CanClearFullscreen::kNo);
    105     if (!check_rect(rtContext.get(), fullRect, kColor2, &actualValue, &failX, &failY)) {
    106         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
    107                failX, failY);
    108     }
    109 
    110     rtContext = newRTC(context, kW, kH);
    111     SkASSERT(rtContext);
    112 
    113     // Test a full clear followed by a same color inset clear
    114     rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
    115     rtContext->clear(&mid1Rect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
    116     if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
    117         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
    118                failX, failY);
    119     }
    120 
    121     rtContext = newRTC(context, kW, kH);
    122     SkASSERT(rtContext);
    123 
    124     // Test a inset clear followed by same color full clear
    125     rtContext->clear(&mid1Rect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
    126     rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
    127     if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
    128         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
    129                failX, failY);
    130     }
    131 
    132     rtContext = newRTC(context, kW, kH);
    133     SkASSERT(rtContext);
    134 
    135     // Test a full clear followed by a different color inset clear
    136     rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
    137     rtContext->clear(&mid1Rect, kColor2, GrRenderTargetContext::CanClearFullscreen::kNo);
    138     if (!check_rect(rtContext.get(), mid1Rect, kColor2, &actualValue, &failX, &failY)) {
    139         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
    140                failX, failY);
    141     }
    142     if (!check_rect(rtContext.get(), outerLeftEdge, kColor1, &actualValue, &failX, &failY) ||
    143         !check_rect(rtContext.get(), outerTopEdge, kColor1, &actualValue, &failX, &failY) ||
    144         !check_rect(rtContext.get(), outerRightEdge, kColor1, &actualValue, &failX, &failY) ||
    145         !check_rect(rtContext.get(), outerBottomEdge, kColor1, &actualValue, &failX, &failY)) {
    146         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
    147                failX, failY);
    148     }
    149 
    150     rtContext = newRTC(context, kW, kH);
    151     SkASSERT(rtContext);
    152 
    153     // Test a inset clear followed by a different full clear
    154     rtContext->clear(&mid1Rect, kColor2, GrRenderTargetContext::CanClearFullscreen::kNo);
    155     rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
    156     if (!check_rect(rtContext.get(), fullRect, kColor1, &actualValue, &failX, &failY)) {
    157         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
    158                failX, failY);
    159     }
    160 
    161     rtContext = newRTC(context, kW, kH);
    162     SkASSERT(rtContext);
    163 
    164     // Check three nested clears from largest to smallest where outermost and innermost are same
    165     // color.
    166     rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
    167     rtContext->clear(&mid1Rect, kColor2, GrRenderTargetContext::CanClearFullscreen::kNo);
    168     rtContext->clear(&mid2Rect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
    169     if (!check_rect(rtContext.get(), mid2Rect, kColor1, &actualValue, &failX, &failY)) {
    170         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
    171                failX, failY);
    172     }
    173     if (!check_rect(rtContext.get(), innerLeftEdge, kColor2, &actualValue, &failX, &failY) ||
    174         !check_rect(rtContext.get(), innerTopEdge, kColor2, &actualValue, &failX, &failY) ||
    175         !check_rect(rtContext.get(), innerRightEdge, kColor2, &actualValue, &failX, &failY) ||
    176         !check_rect(rtContext.get(), innerBottomEdge, kColor2, &actualValue, &failX, &failY)) {
    177         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
    178                failX, failY);
    179     }
    180     if (!check_rect(rtContext.get(), outerLeftEdge, kColor1, &actualValue, &failX, &failY) ||
    181         !check_rect(rtContext.get(), outerTopEdge, kColor1, &actualValue, &failX, &failY) ||
    182         !check_rect(rtContext.get(), outerRightEdge, kColor1, &actualValue, &failX, &failY) ||
    183         !check_rect(rtContext.get(), outerBottomEdge, kColor1, &actualValue, &failX, &failY)) {
    184         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
    185                failX, failY);
    186     }
    187 
    188     rtContext = newRTC(context, kW, kH);
    189     SkASSERT(rtContext);
    190 
    191     // Swap the order of the second two clears in the above test.
    192     rtContext->clear(&fullRect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
    193     rtContext->clear(&mid2Rect, kColor1, GrRenderTargetContext::CanClearFullscreen::kNo);
    194     rtContext->clear(&mid1Rect, kColor2, GrRenderTargetContext::CanClearFullscreen::kNo);
    195     if (!check_rect(rtContext.get(), mid1Rect, kColor2, &actualValue, &failX, &failY)) {
    196         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue,
    197                failX, failY);
    198     }
    199     if (!check_rect(rtContext.get(), outerLeftEdge, kColor1, &actualValue, &failX, &failY) ||
    200         !check_rect(rtContext.get(), outerTopEdge, kColor1, &actualValue, &failX, &failY) ||
    201         !check_rect(rtContext.get(), outerRightEdge, kColor1, &actualValue, &failX, &failY) ||
    202         !check_rect(rtContext.get(), outerBottomEdge, kColor1, &actualValue, &failX, &failY)) {
    203         ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue,
    204                failX, failY);
    205     }
    206 }
    207 
    208 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ClearOp, reporter, ctxInfo) {
    209     clear_op_test(reporter, ctxInfo.grContext());
    210     if (ctxInfo.backend() == kOpenGL_GrBackend) {
    211         GrContextOptions options(ctxInfo.options());
    212         options.fUseDrawInsteadOfGLClear = GrContextOptions::Enable::kYes;
    213         sk_gpu_test::GrContextFactory workaroundFactory(options);
    214         clear_op_test(reporter, workaroundFactory.get(ctxInfo.type()));
    215     }
    216 }
    217 
    218 void fullscreen_clear_with_layer_test(skiatest::Reporter* reporter, GrContext* context) {
    219     const SkImageInfo ii = SkImageInfo::Make(400, 77, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
    220 
    221     sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, ii);
    222     SkCanvas* canvas = surf->getCanvas();
    223 
    224     SkPaint paints[2];
    225     paints[0].setColor(SK_ColorGREEN);
    226     paints[1].setColor(SK_ColorGRAY);
    227 
    228     static const int kLeftX = 158;
    229     static const int kMidX = 258;
    230     static const int kRightX = 383;
    231     static const int kTopY = 26;
    232     static const int kBotY = 51;
    233 
    234     const SkRect rects[2] = {
    235         { kLeftX, kTopY, kMidX, kBotY },
    236         { kMidX, kTopY, kRightX, kBotY },
    237     };
    238 
    239     for (int i = 0; i < 2; ++i) {
    240         // the bounds parameter is required to cause a full screen clear
    241         canvas->saveLayer(&rects[i], nullptr);
    242             canvas->drawRect(rects[i], paints[i]);
    243         canvas->restore();
    244     }
    245 
    246     SkBitmap bm;
    247     bm.allocPixels(ii, 0);
    248 
    249     SkAssertResult(surf->readPixels(bm, 0, 0));
    250 
    251     bool isCorrect = true;
    252     for (int y = kTopY; isCorrect && y < kBotY; ++y) {
    253         const uint32_t* sl = bm.getAddr32(0, y);
    254 
    255         for (int x = kLeftX; x < kMidX; ++x) {
    256             if (SK_ColorGREEN != sl[x]) {
    257                 isCorrect = false;
    258                 break;
    259             }
    260         }
    261 
    262         for (int x = kMidX; x < kRightX; ++x) {
    263             if (SK_ColorGRAY != sl[x]) {
    264                 isCorrect = false;
    265                 break;
    266             }
    267         }
    268     }
    269 
    270     REPORTER_ASSERT(reporter, isCorrect);
    271 }
    272 // From crbug.com/768134
    273 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(FullScreenClearWithLayers, reporter, ctxInfo) {
    274     fullscreen_clear_with_layer_test(reporter, ctxInfo.grContext());
    275     if (ctxInfo.backend() == kOpenGL_GrBackend) {
    276         GrContextOptions options(ctxInfo.options());
    277         options.fUseDrawInsteadOfGLClear = GrContextOptions::Enable::kYes;
    278         sk_gpu_test::GrContextFactory workaroundFactory(options);
    279         fullscreen_clear_with_layer_test(reporter, workaroundFactory.get(ctxInfo.type()));
    280     }
    281 }
    282 
    283 #endif
    284