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 "GrDrawContext.h" 13 #include "GrGpu.h" 14 #include "GrRenderTarget.h" 15 #include "GrTexture.h" 16 #include "GrTextureProvider.h" 17 18 static bool check_rect(GrDrawContext* dc, const SkIRect& rect, uint32_t expectedValue, 19 uint32_t* actualValue, int* failX, int* failY) { 20 GrRenderTarget* rt = dc->accessRenderTarget(); 21 int w = rect.width(); 22 int h = rect.height(); 23 SkAutoTDeleteArray<uint32_t> pixels(new uint32_t[w * h]); 24 memset(pixels.get(), ~expectedValue, sizeof(uint32_t) * w * h); 25 rt->readPixels(rect.fLeft, rect.fTop, w, h, kRGBA_8888_GrPixelConfig, pixels.get()); 26 for (int y = 0; y < h; ++y) { 27 for (int x = 0; x < w; ++x) { 28 uint32_t pixel = pixels.get()[y * w + x]; 29 if (pixel != expectedValue) { 30 *actualValue = pixel; 31 *failX = x + rect.fLeft; 32 *failY = y + rect.fTop; 33 return false; 34 } 35 } 36 } 37 return true; 38 } 39 40 // We only really need the DC, but currently the DC doesn't own the RT so we also ref it, but that 41 // could be dropped when DC is a proper owner of its RT. 42 static bool reset_dc(SkAutoTUnref<GrDrawContext>* dc, SkAutoTUnref<GrSurface>* rtKeepAlive, 43 GrContext* context, int w, int h) { 44 SkDEBUGCODE(uint32_t oldID = 0;) 45 if (*dc) { 46 SkDEBUGCODE(oldID = (*dc)->accessRenderTarget()->getUniqueID();) 47 rtKeepAlive->reset(nullptr); 48 dc->reset(nullptr); 49 } 50 context->freeGpuResources(); 51 52 GrTextureDesc desc; 53 desc.fWidth = w; 54 desc.fHeight = h; 55 desc.fConfig = kRGBA_8888_GrPixelConfig; 56 desc.fFlags = kRenderTarget_GrSurfaceFlag; 57 58 rtKeepAlive->reset(context->textureProvider()->createTexture(desc, SkBudgeted::kYes)); 59 if (!(*rtKeepAlive)) { 60 return false; 61 } 62 GrRenderTarget* rt = (*rtKeepAlive)->asRenderTarget(); 63 SkASSERT(rt->getUniqueID() != oldID); 64 dc->reset(context->drawContext(rt)); 65 return SkToBool(*dc); 66 } 67 68 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ClearBatch, reporter, context) { 69 static const int kW = 10; 70 static const int kH = 10; 71 72 SkIRect fullRect = SkIRect::MakeWH(kW, kH); 73 SkAutoTUnref<GrDrawContext> drawContext; 74 SkAutoTUnref<GrSurface> rtKeepAlive; 75 76 // A rectangle that is inset by one on all sides and the 1-pixel wide rectangles that surround 77 // it. 78 SkIRect mid1Rect = SkIRect::MakeXYWH(1, 1, kW-2, kH-2); 79 SkIRect outerLeftEdge = SkIRect::MakeXYWH(0, 0, 1, kH); 80 SkIRect outerTopEdge = SkIRect::MakeXYWH(0, 0, kW, 1); 81 SkIRect outerRightEdge = SkIRect::MakeXYWH(kW-1, 0, 1, kH); 82 SkIRect outerBottomEdge = SkIRect::MakeXYWH(0, kH-1, kW, 1); 83 84 // A rectangle that is inset by two on all sides and the 1-pixel wide rectangles that surround 85 // it. 86 SkIRect mid2Rect = SkIRect::MakeXYWH(2, 2, kW-4, kH-4); 87 SkIRect innerLeftEdge = SkIRect::MakeXYWH(1, 1, 1, kH-2); 88 SkIRect innerTopEdge = SkIRect::MakeXYWH(1, 1, kW-2, 1); 89 SkIRect innerRightEdge = SkIRect::MakeXYWH(kW-2, 1, 1, kH-2); 90 SkIRect innerBottomEdge = SkIRect::MakeXYWH(1, kH-2, kW-2, 1); 91 92 uint32_t actualValue; 93 int failX, failY; 94 95 static const GrColor kColor1 = 0xABCDEF01; 96 static const GrColor kColor2 = ~kColor1; 97 98 if (!reset_dc(&drawContext, &rtKeepAlive, context, kW, kH)) { 99 ERRORF(reporter, "Could not create draw context."); 100 return; 101 } 102 // Check a full clear 103 drawContext->clear(&fullRect, kColor1, false); 104 if (!check_rect(drawContext, fullRect, kColor1, &actualValue, &failX, &failY)) { 105 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue, 106 failX, failY); 107 } 108 109 if (!reset_dc(&drawContext, &rtKeepAlive, context, kW, kH)) { 110 ERRORF(reporter, "Could not create draw context."); 111 return; 112 } 113 // Check two full clears, same color 114 drawContext->clear(&fullRect, kColor1, false); 115 drawContext->clear(&fullRect, kColor1, false); 116 if (!check_rect(drawContext, 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 if (!reset_dc(&drawContext, &rtKeepAlive, context, kW, kH)) { 122 ERRORF(reporter, "Could not create draw context."); 123 return; 124 } 125 // Check two full clears, different colors 126 drawContext->clear(&fullRect, kColor1, false); 127 drawContext->clear(&fullRect, kColor2, false); 128 if (!check_rect(drawContext, fullRect, kColor2, &actualValue, &failX, &failY)) { 129 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue, 130 failX, failY); 131 } 132 133 if (!reset_dc(&drawContext, &rtKeepAlive, context, kW, kH)) { 134 ERRORF(reporter, "Could not create draw context."); 135 return; 136 } 137 // Test a full clear followed by a same color inset clear 138 drawContext->clear(&fullRect, kColor1, false); 139 drawContext->clear(&mid1Rect, kColor1, false); 140 if (!check_rect(drawContext, fullRect, kColor1, &actualValue, &failX, &failY)) { 141 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue, 142 failX, failY); 143 } 144 145 if (!reset_dc(&drawContext, &rtKeepAlive, context, kW, kH)) { 146 ERRORF(reporter, "Could not create draw context."); 147 return; 148 } 149 // Test a inset clear followed by same color full clear 150 drawContext->clear(&mid1Rect, kColor1, false); 151 drawContext->clear(&fullRect, kColor1, false); 152 if (!check_rect(drawContext, fullRect, kColor1, &actualValue, &failX, &failY)) { 153 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue, 154 failX, failY); 155 } 156 157 if (!reset_dc(&drawContext, &rtKeepAlive, context, kW, kH)) { 158 ERRORF(reporter, "Could not create draw context."); 159 return; 160 } 161 // Test a full clear followed by a different color inset clear 162 drawContext->clear(&fullRect, kColor1, false); 163 drawContext->clear(&mid1Rect, kColor2, false); 164 if (!check_rect(drawContext, mid1Rect, kColor2, &actualValue, &failX, &failY)) { 165 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue, 166 failX, failY); 167 } 168 if (!check_rect(drawContext, outerLeftEdge, kColor1, &actualValue, &failX, &failY) || 169 !check_rect(drawContext, outerTopEdge, kColor1, &actualValue, &failX, &failY) || 170 !check_rect(drawContext, outerRightEdge, kColor1, &actualValue, &failX, &failY) || 171 !check_rect(drawContext, outerBottomEdge, kColor1, &actualValue, &failX, &failY)) { 172 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue, 173 failX, failY); 174 } 175 176 if (!reset_dc(&drawContext, &rtKeepAlive, context, kW, kH)) { 177 ERRORF(reporter, "Could not create draw context."); 178 return; 179 } 180 // Test a inset clear followed by a different full clear 181 drawContext->clear(&mid1Rect, kColor2, false); 182 drawContext->clear(&fullRect, kColor1, false); 183 if (!check_rect(drawContext, fullRect, 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 if (!reset_dc(&drawContext, &rtKeepAlive, context, kW, kH)) { 189 ERRORF(reporter, "Could not create draw context."); 190 return; 191 } 192 // Check three nested clears from largest to smallest where outermost and innermost are same 193 // color. 194 drawContext->clear(&fullRect, kColor1, false); 195 drawContext->clear(&mid1Rect, kColor2, false); 196 drawContext->clear(&mid2Rect, kColor1, false); 197 if (!check_rect(drawContext, mid2Rect, kColor1, &actualValue, &failX, &failY)) { 198 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue, 199 failX, failY); 200 } 201 if (!check_rect(drawContext, innerLeftEdge, kColor2, &actualValue, &failX, &failY) || 202 !check_rect(drawContext, innerTopEdge, kColor2, &actualValue, &failX, &failY) || 203 !check_rect(drawContext, innerRightEdge, kColor2, &actualValue, &failX, &failY) || 204 !check_rect(drawContext, innerBottomEdge, kColor2, &actualValue, &failX, &failY)) { 205 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue, 206 failX, failY); 207 } 208 if (!check_rect(drawContext, outerLeftEdge, kColor1, &actualValue, &failX, &failY) || 209 !check_rect(drawContext, outerTopEdge, kColor1, &actualValue, &failX, &failY) || 210 !check_rect(drawContext, outerRightEdge, kColor1, &actualValue, &failX, &failY) || 211 !check_rect(drawContext, outerBottomEdge, kColor1, &actualValue, &failX, &failY)) { 212 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue, 213 failX, failY); 214 } 215 216 if (!reset_dc(&drawContext, &rtKeepAlive, context, kW, kH)) { 217 ERRORF(reporter, "Could not create draw context."); 218 return; 219 } 220 // Swap the order of the second two clears in the above test. 221 drawContext->clear(&fullRect, kColor1, false); 222 drawContext->clear(&mid2Rect, kColor1, false); 223 drawContext->clear(&mid1Rect, kColor2, false); 224 if (!check_rect(drawContext, mid1Rect, kColor2, &actualValue, &failX, &failY)) { 225 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor2, actualValue, 226 failX, failY); 227 } 228 if (!check_rect(drawContext, outerLeftEdge, kColor1, &actualValue, &failX, &failY) || 229 !check_rect(drawContext, outerTopEdge, kColor1, &actualValue, &failX, &failY) || 230 !check_rect(drawContext, outerRightEdge, kColor1, &actualValue, &failX, &failY) || 231 !check_rect(drawContext, outerBottomEdge, kColor1, &actualValue, &failX, &failY)) { 232 ERRORF(reporter, "Expected 0x%08x but got 0x%08x at (%d, %d).", kColor1, actualValue, 233 failX, failY); 234 } 235 } 236 #endif 237