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 17static 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 44sk_sp<GrRenderTargetContext> newRTC(GrContext* context, int w, int h) { 45 return context->makeDeferredRenderTargetContext(SkBackingFit::kExact, w, h, 46 kRGBA_8888_GrPixelConfig, nullptr); 47} 48 49static 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 208DEF_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 218void 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 273DEF_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