1 /* 2 * Copyright 2013 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 "GrTest.h" 9 #include <algorithm> 10 #include "GrBackendSurface.h" 11 #include "GrContextOptions.h" 12 #include "GrContextPriv.h" 13 #include "GrDrawOpAtlas.h" 14 #include "GrDrawingManager.h" 15 #include "GrGpu.h" 16 #include "GrGpuResourceCacheAccess.h" 17 #include "GrRenderTargetContext.h" 18 #include "GrRenderTargetContextPriv.h" 19 #include "GrRenderTargetProxy.h" 20 #include "GrResourceCache.h" 21 #include "GrSemaphore.h" 22 #include "GrSurfaceContextPriv.h" 23 #include "GrTexture.h" 24 #include "SkGr.h" 25 #include "SkImage_Gpu.h" 26 #include "SkMathPriv.h" 27 #include "SkString.h" 28 #include "ops/GrMeshDrawOp.h" 29 #include "text/GrAtlasGlyphCache.h" 30 #include "text/GrTextBlobCache.h" 31 32 namespace GrTest { 33 void SetupAlwaysEvictAtlas(GrContext* context) { 34 // These sizes were selected because they allow each atlas to hold a single plot and will thus 35 // stress the atlas 36 int dim = GrDrawOpAtlas::kGlyphMaxDim; 37 GrDrawOpAtlasConfig configs[3]; 38 configs[kA8_GrMaskFormat].fWidth = dim; 39 configs[kA8_GrMaskFormat].fHeight = dim; 40 configs[kA8_GrMaskFormat].fLog2Width = SkNextLog2(dim); 41 configs[kA8_GrMaskFormat].fLog2Height = SkNextLog2(dim); 42 configs[kA8_GrMaskFormat].fPlotWidth = dim; 43 configs[kA8_GrMaskFormat].fPlotHeight = dim; 44 45 configs[kA565_GrMaskFormat].fWidth = dim; 46 configs[kA565_GrMaskFormat].fHeight = dim; 47 configs[kA565_GrMaskFormat].fLog2Width = SkNextLog2(dim); 48 configs[kA565_GrMaskFormat].fLog2Height = SkNextLog2(dim); 49 configs[kA565_GrMaskFormat].fPlotWidth = dim; 50 configs[kA565_GrMaskFormat].fPlotHeight = dim; 51 52 configs[kARGB_GrMaskFormat].fWidth = dim; 53 configs[kARGB_GrMaskFormat].fHeight = dim; 54 configs[kARGB_GrMaskFormat].fLog2Width = SkNextLog2(dim); 55 configs[kARGB_GrMaskFormat].fLog2Height = SkNextLog2(dim); 56 configs[kARGB_GrMaskFormat].fPlotWidth = dim; 57 configs[kARGB_GrMaskFormat].fPlotHeight = dim; 58 59 context->setTextContextAtlasSizes_ForTesting(configs); 60 } 61 62 GrBackendTexture CreateBackendTexture(GrBackend backend, int width, int height, 63 GrPixelConfig config, GrBackendObject handle) { 64 #ifdef SK_VULKAN 65 if (kVulkan_GrBackend == backend) { 66 GrVkImageInfo* vkInfo = (GrVkImageInfo*)(handle); 67 return GrBackendTexture(width, height, *vkInfo); 68 } 69 #endif 70 SkASSERT(kOpenGL_GrBackend == backend); 71 GrGLTextureInfo* glInfo = (GrGLTextureInfo*)(handle); 72 return GrBackendTexture(width, height, config, *glInfo); 73 } 74 }; 75 76 bool GrSurfaceProxy::isWrapped_ForTesting() const { 77 return SkToBool(fTarget); 78 } 79 80 bool GrRenderTargetContext::isWrapped_ForTesting() const { 81 return fRenderTargetProxy->isWrapped_ForTesting(); 82 } 83 84 void GrContext::setTextBlobCacheLimit_ForTesting(size_t bytes) { 85 fTextBlobCache->setBudget(bytes); 86 } 87 88 void GrContext::setTextContextAtlasSizes_ForTesting(const GrDrawOpAtlasConfig* configs) { 89 fAtlasGlyphCache->setAtlasSizes_ForTesting(configs); 90 } 91 92 /////////////////////////////////////////////////////////////////////////////// 93 94 void GrContext::purgeAllUnlockedResources() { 95 fResourceCache->purgeAllUnlocked(); 96 } 97 98 void GrContext::resetGpuStats() const { 99 #if GR_GPU_STATS 100 fGpu->stats()->reset(); 101 #endif 102 } 103 104 void GrContext::dumpCacheStats(SkString* out) const { 105 #if GR_CACHE_STATS 106 fResourceCache->dumpStats(out); 107 #endif 108 } 109 110 void GrContext::dumpCacheStatsKeyValuePairs(SkTArray<SkString>* keys, 111 SkTArray<double>* values) const { 112 #if GR_CACHE_STATS 113 fResourceCache->dumpStatsKeyValuePairs(keys, values); 114 #endif 115 } 116 117 void GrContext::printCacheStats() const { 118 SkString out; 119 this->dumpCacheStats(&out); 120 SkDebugf("%s", out.c_str()); 121 } 122 123 void GrContext::dumpGpuStats(SkString* out) const { 124 #if GR_GPU_STATS 125 return fGpu->stats()->dump(out); 126 #endif 127 } 128 129 void GrContext::dumpGpuStatsKeyValuePairs(SkTArray<SkString>* keys, 130 SkTArray<double>* values) const { 131 #if GR_GPU_STATS 132 return fGpu->stats()->dumpKeyValuePairs(keys, values); 133 #endif 134 } 135 136 void GrContext::printGpuStats() const { 137 SkString out; 138 this->dumpGpuStats(&out); 139 SkDebugf("%s", out.c_str()); 140 } 141 142 sk_sp<SkImage> GrContext::getFontAtlasImage_ForTesting(GrMaskFormat format) { 143 GrAtlasGlyphCache* cache = this->getAtlasGlyphCache(); 144 145 sk_sp<GrTextureProxy> proxy = cache->getProxy(format); 146 if (!proxy) { 147 return nullptr; 148 } 149 150 SkASSERT(proxy->priv().isExact()); 151 sk_sp<SkImage> image(new SkImage_Gpu(this, kNeedNewImageUniqueID, kPremul_SkAlphaType, 152 std::move(proxy), nullptr, SkBudgeted::kNo)); 153 return image; 154 } 155 156 #if GR_GPU_STATS 157 void GrGpu::Stats::dump(SkString* out) { 158 out->appendf("Render Target Binds: %d\n", fRenderTargetBinds); 159 out->appendf("Shader Compilations: %d\n", fShaderCompilations); 160 out->appendf("Textures Created: %d\n", fTextureCreates); 161 out->appendf("Texture Uploads: %d\n", fTextureUploads); 162 out->appendf("Transfers to Texture: %d\n", fTransfersToTexture); 163 out->appendf("Stencil Buffer Creates: %d\n", fStencilAttachmentCreates); 164 out->appendf("Number of draws: %d\n", fNumDraws); 165 } 166 167 void GrGpu::Stats::dumpKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* values) { 168 keys->push_back(SkString("render_target_binds")); values->push_back(fRenderTargetBinds); 169 keys->push_back(SkString("shader_compilations")); values->push_back(fShaderCompilations); 170 keys->push_back(SkString("texture_uploads")); values->push_back(fTextureUploads); 171 keys->push_back(SkString("number_of_draws")); values->push_back(fNumDraws); 172 keys->push_back(SkString("number_of_failed_draws")); values->push_back(fNumFailedDraws); 173 } 174 175 #endif 176 177 #if GR_CACHE_STATS 178 void GrResourceCache::getStats(Stats* stats) const { 179 stats->reset(); 180 181 stats->fTotal = this->getResourceCount(); 182 stats->fNumNonPurgeable = fNonpurgeableResources.count(); 183 stats->fNumPurgeable = fPurgeableQueue.count(); 184 185 for (int i = 0; i < fNonpurgeableResources.count(); ++i) { 186 stats->update(fNonpurgeableResources[i]); 187 } 188 for (int i = 0; i < fPurgeableQueue.count(); ++i) { 189 stats->update(fPurgeableQueue.at(i)); 190 } 191 } 192 193 void GrResourceCache::dumpStats(SkString* out) const { 194 this->validate(); 195 196 Stats stats; 197 198 this->getStats(&stats); 199 200 float countUtilization = (100.f * fBudgetedCount) / fMaxCount; 201 float byteUtilization = (100.f * fBudgetedBytes) / fMaxBytes; 202 203 out->appendf("Budget: %d items %d bytes\n", fMaxCount, (int)fMaxBytes); 204 out->appendf("\t\tEntry Count: current %d" 205 " (%d budgeted, %d wrapped, %d locked, %d scratch %.2g%% full), high %d\n", 206 stats.fTotal, fBudgetedCount, stats.fWrapped, stats.fNumNonPurgeable, 207 stats.fScratch, countUtilization, fHighWaterCount); 208 out->appendf("\t\tEntry Bytes: current %d (budgeted %d, %.2g%% full, %d unbudgeted) high %d\n", 209 SkToInt(fBytes), SkToInt(fBudgetedBytes), byteUtilization, 210 SkToInt(stats.fUnbudgetedSize), SkToInt(fHighWaterBytes)); 211 } 212 213 void GrResourceCache::dumpStatsKeyValuePairs(SkTArray<SkString>* keys, 214 SkTArray<double>* values) const { 215 this->validate(); 216 217 Stats stats; 218 this->getStats(&stats); 219 220 keys->push_back(SkString("gpu_cache_purgable_entries")); values->push_back(stats.fNumPurgeable); 221 } 222 223 #endif 224 225 /////////////////////////////////////////////////////////////////////////////// 226 227 void GrResourceCache::changeTimestamp(uint32_t newTimestamp) { fTimestamp = newTimestamp; } 228 229 #ifdef SK_DEBUG 230 int GrResourceCache::countUniqueKeysWithTag(const char* tag) const { 231 int count = 0; 232 UniqueHash::ConstIter iter(&fUniqueHash); 233 while (!iter.done()) { 234 if (0 == strcmp(tag, (*iter).getUniqueKey().tag())) { 235 ++count; 236 } 237 ++iter; 238 } 239 return count; 240 } 241 #endif 242 243 /////////////////////////////////////////////////////////////////////////////// 244 245 #define ASSERT_SINGLE_OWNER \ 246 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());) 247 248 uint32_t GrRenderTargetContextPriv::testingOnly_addDrawOp(std::unique_ptr<GrDrawOp> op) { 249 ASSERT_SINGLE_OWNER 250 if (fRenderTargetContext->drawingManager()->wasAbandoned()) { 251 return SK_InvalidUniqueID; 252 } 253 SkDEBUGCODE(fRenderTargetContext->validate()); 254 GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail, 255 "GrRenderTargetContext::testingOnly_addDrawOp"); 256 return fRenderTargetContext->addDrawOp(GrNoClip(), std::move(op)); 257 } 258 259 #undef ASSERT_SINGLE_OWNER 260 261 /////////////////////////////////////////////////////////////////////////////// 262 263 GrRenderTargetFlags GrRenderTargetProxy::testingOnly_getFlags() const { 264 return fRenderTargetFlags; 265 } 266 267 ////////////////////////////////////////////////////////////////////////////// 268 269 void GrContextPriv::testingOnly_flushAndRemoveOnFlushCallbackObject(GrOnFlushCallbackObject* cb) { 270 fContext->flush(); 271 fContext->fDrawingManager->testingOnly_removeOnFlushCallbackObject(cb); 272 } 273 274 void GrDrawingManager::testingOnly_removeOnFlushCallbackObject(GrOnFlushCallbackObject* cb) { 275 int n = std::find(fOnFlushCBObjects.begin(), fOnFlushCBObjects.end(), cb) - 276 fOnFlushCBObjects.begin(); 277 SkASSERT(n < fOnFlushCBObjects.count()); 278 fOnFlushCBObjects.removeShuffle(n); 279 } 280 281 ////////////////////////////////////////////////////////////////////////////// 282 283 #define DRAW_OP_TEST_EXTERN(Op) \ 284 extern std::unique_ptr<GrDrawOp> Op##__Test(GrPaint&&, SkRandom*, GrContext*, GrFSAAType) 285 #define DRAW_OP_TEST_ENTRY(Op) Op##__Test 286 287 DRAW_OP_TEST_EXTERN(AAConvexPathOp); 288 DRAW_OP_TEST_EXTERN(AAFillRectOp); 289 DRAW_OP_TEST_EXTERN(AAFlatteningConvexPathOp); 290 DRAW_OP_TEST_EXTERN(AAHairlineOp); 291 DRAW_OP_TEST_EXTERN(AAStrokeRectOp); 292 DRAW_OP_TEST_EXTERN(CircleOp); 293 DRAW_OP_TEST_EXTERN(DashOp); 294 DRAW_OP_TEST_EXTERN(DefaultPathOp); 295 DRAW_OP_TEST_EXTERN(DIEllipseOp); 296 DRAW_OP_TEST_EXTERN(EllipseOp); 297 DRAW_OP_TEST_EXTERN(GrAtlasTextOp); 298 DRAW_OP_TEST_EXTERN(GrDrawAtlasOp); 299 DRAW_OP_TEST_EXTERN(GrDrawVerticesOp); 300 DRAW_OP_TEST_EXTERN(NonAAFillRectOp); 301 DRAW_OP_TEST_EXTERN(NonAALatticeOp); 302 DRAW_OP_TEST_EXTERN(NonAAStrokeRectOp); 303 DRAW_OP_TEST_EXTERN(ShadowRRectOp); 304 DRAW_OP_TEST_EXTERN(SmallPathOp); 305 DRAW_OP_TEST_EXTERN(RegionOp); 306 DRAW_OP_TEST_EXTERN(RRectOp); 307 DRAW_OP_TEST_EXTERN(TesselatingPathOp); 308 309 void GrDrawRandomOp(SkRandom* random, GrRenderTargetContext* renderTargetContext, GrPaint&& paint) { 310 GrContext* context = renderTargetContext->surfPriv().getContext(); 311 using MakeDrawOpFn = std::unique_ptr<GrDrawOp>(GrPaint&&, SkRandom*, GrContext*, GrFSAAType); 312 static constexpr MakeDrawOpFn* gFactories[] = { 313 DRAW_OP_TEST_ENTRY(AAConvexPathOp), 314 DRAW_OP_TEST_ENTRY(AAFillRectOp), 315 DRAW_OP_TEST_ENTRY(AAFlatteningConvexPathOp), 316 DRAW_OP_TEST_ENTRY(AAHairlineOp), 317 DRAW_OP_TEST_ENTRY(AAStrokeRectOp), 318 DRAW_OP_TEST_ENTRY(CircleOp), 319 DRAW_OP_TEST_ENTRY(DashOp), 320 DRAW_OP_TEST_ENTRY(DefaultPathOp), 321 DRAW_OP_TEST_ENTRY(DIEllipseOp), 322 DRAW_OP_TEST_ENTRY(EllipseOp), 323 DRAW_OP_TEST_ENTRY(GrAtlasTextOp), 324 DRAW_OP_TEST_ENTRY(GrDrawAtlasOp), 325 DRAW_OP_TEST_ENTRY(GrDrawVerticesOp), 326 DRAW_OP_TEST_ENTRY(NonAAFillRectOp), 327 DRAW_OP_TEST_ENTRY(NonAALatticeOp), 328 DRAW_OP_TEST_ENTRY(NonAAStrokeRectOp), 329 DRAW_OP_TEST_ENTRY(ShadowRRectOp), 330 DRAW_OP_TEST_ENTRY(SmallPathOp), 331 DRAW_OP_TEST_ENTRY(RegionOp), 332 DRAW_OP_TEST_ENTRY(RRectOp), 333 DRAW_OP_TEST_ENTRY(TesselatingPathOp), 334 }; 335 336 static constexpr size_t kTotal = SK_ARRAY_COUNT(gFactories); 337 uint32_t index = random->nextULessThan(static_cast<uint32_t>(kTotal)); 338 auto op = gFactories[index]( 339 std::move(paint), random, context, renderTargetContext->fsaaType()); 340 SkASSERT(op); 341 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op)); 342 } 343