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 32namespace GrTest { 33void 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 62GrBackendTexture 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 76bool GrSurfaceProxy::isWrapped_ForTesting() const { 77 return SkToBool(fTarget); 78} 79 80bool GrRenderTargetContext::isWrapped_ForTesting() const { 81 return fRenderTargetProxy->isWrapped_ForTesting(); 82} 83 84void GrContext::setTextBlobCacheLimit_ForTesting(size_t bytes) { 85 fTextBlobCache->setBudget(bytes); 86} 87 88void GrContext::setTextContextAtlasSizes_ForTesting(const GrDrawOpAtlasConfig* configs) { 89 fAtlasGlyphCache->setAtlasSizes_ForTesting(configs); 90} 91 92/////////////////////////////////////////////////////////////////////////////// 93 94void GrContext::purgeAllUnlockedResources() { 95 fResourceCache->purgeAllUnlocked(); 96} 97 98void GrContext::resetGpuStats() const { 99#if GR_GPU_STATS 100 fGpu->stats()->reset(); 101#endif 102} 103 104void GrContext::dumpCacheStats(SkString* out) const { 105#if GR_CACHE_STATS 106 fResourceCache->dumpStats(out); 107#endif 108} 109 110void GrContext::dumpCacheStatsKeyValuePairs(SkTArray<SkString>* keys, 111 SkTArray<double>* values) const { 112#if GR_CACHE_STATS 113 fResourceCache->dumpStatsKeyValuePairs(keys, values); 114#endif 115} 116 117void GrContext::printCacheStats() const { 118 SkString out; 119 this->dumpCacheStats(&out); 120 SkDebugf("%s", out.c_str()); 121} 122 123void GrContext::dumpGpuStats(SkString* out) const { 124#if GR_GPU_STATS 125 return fGpu->stats()->dump(out); 126#endif 127} 128 129void 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 136void GrContext::printGpuStats() const { 137 SkString out; 138 this->dumpGpuStats(&out); 139 SkDebugf("%s", out.c_str()); 140} 141 142sk_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 157void 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 167void 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 178void 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 193void 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 213void 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 227void GrResourceCache::changeTimestamp(uint32_t newTimestamp) { fTimestamp = newTimestamp; } 228 229#ifdef SK_DEBUG 230int 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 248uint32_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 263GrRenderTargetFlags GrRenderTargetProxy::testingOnly_getFlags() const { 264 return fRenderTargetFlags; 265} 266 267////////////////////////////////////////////////////////////////////////////// 268 269void GrContextPriv::testingOnly_flushAndRemoveOnFlushCallbackObject(GrOnFlushCallbackObject* cb) { 270 fContext->flush(); 271 fContext->fDrawingManager->testingOnly_removeOnFlushCallbackObject(cb); 272} 273 274void 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 287DRAW_OP_TEST_EXTERN(AAConvexPathOp); 288DRAW_OP_TEST_EXTERN(AAFillRectOp); 289DRAW_OP_TEST_EXTERN(AAFlatteningConvexPathOp); 290DRAW_OP_TEST_EXTERN(AAHairlineOp); 291DRAW_OP_TEST_EXTERN(AAStrokeRectOp); 292DRAW_OP_TEST_EXTERN(CircleOp); 293DRAW_OP_TEST_EXTERN(DashOp); 294DRAW_OP_TEST_EXTERN(DefaultPathOp); 295DRAW_OP_TEST_EXTERN(DIEllipseOp); 296DRAW_OP_TEST_EXTERN(EllipseOp); 297DRAW_OP_TEST_EXTERN(GrAtlasTextOp); 298DRAW_OP_TEST_EXTERN(GrDrawAtlasOp); 299DRAW_OP_TEST_EXTERN(GrDrawVerticesOp); 300DRAW_OP_TEST_EXTERN(NonAAFillRectOp); 301DRAW_OP_TEST_EXTERN(NonAALatticeOp); 302DRAW_OP_TEST_EXTERN(NonAAStrokeRectOp); 303DRAW_OP_TEST_EXTERN(ShadowRRectOp); 304DRAW_OP_TEST_EXTERN(SmallPathOp); 305DRAW_OP_TEST_EXTERN(RegionOp); 306DRAW_OP_TEST_EXTERN(RRectOp); 307DRAW_OP_TEST_EXTERN(TesselatingPathOp); 308 309void 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