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 10#include "GrContextOptions.h" 11#include "GrDrawOpAtlas.h" 12#include "GrDrawingManager.h" 13#include "GrGpuResourceCacheAccess.h" 14#include "GrPipelineBuilder.h" 15#include "GrRenderTargetContextPriv.h" 16#include "GrRenderTargetProxy.h" 17#include "GrResourceCache.h" 18#include "GrSemaphore.h" 19 20#include "SkGr.h" 21#include "SkImage_Gpu.h" 22#include "SkMathPriv.h" 23#include "SkString.h" 24 25#include "text/GrAtlasGlyphCache.h" 26#include "text/GrTextBlobCache.h" 27 28namespace GrTest { 29void SetupAlwaysEvictAtlas(GrContext* context) { 30 // These sizes were selected because they allow each atlas to hold a single plot and will thus 31 // stress the atlas 32 int dim = GrDrawOpAtlas::kGlyphMaxDim; 33 GrDrawOpAtlasConfig configs[3]; 34 configs[kA8_GrMaskFormat].fWidth = dim; 35 configs[kA8_GrMaskFormat].fHeight = dim; 36 configs[kA8_GrMaskFormat].fLog2Width = SkNextLog2(dim); 37 configs[kA8_GrMaskFormat].fLog2Height = SkNextLog2(dim); 38 configs[kA8_GrMaskFormat].fPlotWidth = dim; 39 configs[kA8_GrMaskFormat].fPlotHeight = dim; 40 41 configs[kA565_GrMaskFormat].fWidth = dim; 42 configs[kA565_GrMaskFormat].fHeight = dim; 43 configs[kA565_GrMaskFormat].fLog2Width = SkNextLog2(dim); 44 configs[kA565_GrMaskFormat].fLog2Height = SkNextLog2(dim); 45 configs[kA565_GrMaskFormat].fPlotWidth = dim; 46 configs[kA565_GrMaskFormat].fPlotHeight = dim; 47 48 configs[kARGB_GrMaskFormat].fWidth = dim; 49 configs[kARGB_GrMaskFormat].fHeight = dim; 50 configs[kARGB_GrMaskFormat].fLog2Width = SkNextLog2(dim); 51 configs[kARGB_GrMaskFormat].fLog2Height = SkNextLog2(dim); 52 configs[kARGB_GrMaskFormat].fPlotWidth = dim; 53 configs[kARGB_GrMaskFormat].fPlotHeight = dim; 54 55 context->setTextContextAtlasSizes_ForTesting(configs); 56} 57}; 58 59bool GrSurfaceProxy::isWrapped_ForTesting() const { 60 return SkToBool(fTarget); 61} 62 63bool GrRenderTargetContext::isWrapped_ForTesting() const { 64 return fRenderTargetProxy->isWrapped_ForTesting(); 65} 66 67void GrContext::setTextBlobCacheLimit_ForTesting(size_t bytes) { 68 fTextBlobCache->setBudget(bytes); 69} 70 71void GrContext::setTextContextAtlasSizes_ForTesting(const GrDrawOpAtlasConfig* configs) { 72 fAtlasGlyphCache->setAtlasSizes_ForTesting(configs); 73} 74 75/////////////////////////////////////////////////////////////////////////////// 76 77void GrContext::purgeAllUnlockedResources() { 78 fResourceCache->purgeAllUnlocked(); 79} 80 81void GrContext::resetGpuStats() const { 82#if GR_GPU_STATS 83 fGpu->stats()->reset(); 84#endif 85} 86 87void GrContext::dumpCacheStats(SkString* out) const { 88#if GR_CACHE_STATS 89 fResourceCache->dumpStats(out); 90#endif 91} 92 93void GrContext::dumpCacheStatsKeyValuePairs(SkTArray<SkString>* keys, 94 SkTArray<double>* values) const { 95#if GR_CACHE_STATS 96 fResourceCache->dumpStatsKeyValuePairs(keys, values); 97#endif 98} 99 100void GrContext::printCacheStats() const { 101 SkString out; 102 this->dumpCacheStats(&out); 103 SkDebugf("%s", out.c_str()); 104} 105 106void GrContext::dumpGpuStats(SkString* out) const { 107#if GR_GPU_STATS 108 return fGpu->stats()->dump(out); 109#endif 110} 111 112void GrContext::dumpGpuStatsKeyValuePairs(SkTArray<SkString>* keys, 113 SkTArray<double>* values) const { 114#if GR_GPU_STATS 115 return fGpu->stats()->dumpKeyValuePairs(keys, values); 116#endif 117} 118 119void GrContext::printGpuStats() const { 120 SkString out; 121 this->dumpGpuStats(&out); 122 SkDebugf("%s", out.c_str()); 123} 124 125sk_sp<SkImage> GrContext::getFontAtlasImage_ForTesting(GrMaskFormat format) { 126 GrAtlasGlyphCache* cache = this->getAtlasGlyphCache(); 127 128 sk_sp<GrTextureProxy> proxy = cache->getProxy(format); 129 if (!proxy) { 130 return nullptr; 131 } 132 133 SkASSERT(proxy->priv().isExact()); 134 sk_sp<SkImage> image(new SkImage_Gpu(this, kNeedNewImageUniqueID, kPremul_SkAlphaType, 135 std::move(proxy), nullptr, SkBudgeted::kNo)); 136 return image; 137} 138 139#if GR_GPU_STATS 140void GrGpu::Stats::dump(SkString* out) { 141 out->appendf("Render Target Binds: %d\n", fRenderTargetBinds); 142 out->appendf("Shader Compilations: %d\n", fShaderCompilations); 143 out->appendf("Textures Created: %d\n", fTextureCreates); 144 out->appendf("Texture Uploads: %d\n", fTextureUploads); 145 out->appendf("Transfers to Texture: %d\n", fTransfersToTexture); 146 out->appendf("Stencil Buffer Creates: %d\n", fStencilAttachmentCreates); 147 out->appendf("Number of draws: %d\n", fNumDraws); 148} 149 150void GrGpu::Stats::dumpKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* values) { 151 keys->push_back(SkString("render_target_binds")); values->push_back(fRenderTargetBinds); 152 keys->push_back(SkString("shader_compilations")); values->push_back(fShaderCompilations); 153 keys->push_back(SkString("texture_uploads")); values->push_back(fTextureUploads); 154 keys->push_back(SkString("number_of_draws")); values->push_back(fNumDraws); 155 keys->push_back(SkString("number_of_failed_draws")); values->push_back(fNumFailedDraws); 156} 157 158#endif 159 160#if GR_CACHE_STATS 161void GrResourceCache::getStats(Stats* stats) const { 162 stats->reset(); 163 164 stats->fTotal = this->getResourceCount(); 165 stats->fNumNonPurgeable = fNonpurgeableResources.count(); 166 stats->fNumPurgeable = fPurgeableQueue.count(); 167 168 for (int i = 0; i < fNonpurgeableResources.count(); ++i) { 169 stats->update(fNonpurgeableResources[i]); 170 } 171 for (int i = 0; i < fPurgeableQueue.count(); ++i) { 172 stats->update(fPurgeableQueue.at(i)); 173 } 174} 175 176void GrResourceCache::dumpStats(SkString* out) const { 177 this->validate(); 178 179 Stats stats; 180 181 this->getStats(&stats); 182 183 float countUtilization = (100.f * fBudgetedCount) / fMaxCount; 184 float byteUtilization = (100.f * fBudgetedBytes) / fMaxBytes; 185 186 out->appendf("Budget: %d items %d bytes\n", fMaxCount, (int)fMaxBytes); 187 out->appendf("\t\tEntry Count: current %d" 188 " (%d budgeted, %d wrapped, %d locked, %d scratch %.2g%% full), high %d\n", 189 stats.fTotal, fBudgetedCount, stats.fWrapped, stats.fNumNonPurgeable, 190 stats.fScratch, countUtilization, fHighWaterCount); 191 out->appendf("\t\tEntry Bytes: current %d (budgeted %d, %.2g%% full, %d unbudgeted) high %d\n", 192 SkToInt(fBytes), SkToInt(fBudgetedBytes), byteUtilization, 193 SkToInt(stats.fUnbudgetedSize), SkToInt(fHighWaterBytes)); 194} 195 196void GrResourceCache::dumpStatsKeyValuePairs(SkTArray<SkString>* keys, 197 SkTArray<double>* values) const { 198 this->validate(); 199 200 Stats stats; 201 this->getStats(&stats); 202 203 keys->push_back(SkString("gpu_cache_purgable_entries")); values->push_back(stats.fNumPurgeable); 204} 205 206#endif 207 208/////////////////////////////////////////////////////////////////////////////// 209 210void GrResourceCache::changeTimestamp(uint32_t newTimestamp) { fTimestamp = newTimestamp; } 211 212#ifdef SK_DEBUG 213int GrResourceCache::countUniqueKeysWithTag(const char* tag) const { 214 int count = 0; 215 UniqueHash::ConstIter iter(&fUniqueHash); 216 while (!iter.done()) { 217 if (0 == strcmp(tag, (*iter).getUniqueKey().tag())) { 218 ++count; 219 } 220 ++iter; 221 } 222 return count; 223} 224#endif 225 226/////////////////////////////////////////////////////////////////////////////// 227 228#define ASSERT_SINGLE_OWNER \ 229 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->fSingleOwner);) 230 231uint32_t GrRenderTargetContextPriv::testingOnly_addMeshDrawOp(GrPaint&& paint, 232 GrAAType aaType, 233 std::unique_ptr<GrMeshDrawOp> op, 234 const GrUserStencilSettings* uss, 235 bool snapToCenters) { 236 ASSERT_SINGLE_OWNER 237 if (fRenderTargetContext->drawingManager()->wasAbandoned()) { 238 return SK_InvalidUniqueID; 239 } 240 SkDEBUGCODE(fRenderTargetContext->validate();) 241 GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail, 242 "GrRenderTargetContext::testingOnly_addMeshDrawOp"); 243 244 GrPipelineBuilder pipelineBuilder(std::move(paint), aaType); 245 if (uss) { 246 pipelineBuilder.setUserStencil(uss); 247 } 248 pipelineBuilder.setSnapVerticesToPixelCenters(snapToCenters); 249 250 return fRenderTargetContext->addMeshDrawOp(pipelineBuilder, GrNoClip(), std::move(op)); 251} 252 253#undef ASSERT_SINGLE_OWNER 254 255/////////////////////////////////////////////////////////////////////////////// 256 257GrRenderTarget::Flags GrRenderTargetProxy::testingOnly_getFlags() const { 258 return fRenderTargetFlags; 259} 260 261/////////////////////////////////////////////////////////////////////////////// 262// Code for the mock context. It's built on a mock GrGpu class that does nothing. 263//// 264 265#include "GrGpu.h" 266 267class GrPipeline; 268 269class MockCaps : public GrCaps { 270public: 271 explicit MockCaps(const GrContextOptions& options) : INHERITED(options) {} 272 bool isConfigTexturable(GrPixelConfig config) const override { return false; } 273 bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override { return false; } 274 bool canConfigBeImageStorage(GrPixelConfig) const override { return false; } 275 bool initDescForDstCopy(const GrRenderTarget* src, GrSurfaceDesc* desc) const override { 276 return false; 277 } 278 279private: 280 typedef GrCaps INHERITED; 281}; 282 283class MockGpu : public GrGpu { 284public: 285 MockGpu(GrContext* context, const GrContextOptions& options) : INHERITED(context) { 286 fCaps.reset(new MockCaps(options)); 287 } 288 ~MockGpu() override {} 289 290 bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes, 291 GrPixelConfig readConfig, DrawPreference*, 292 ReadPixelTempDrawInfo*) override { return false; } 293 294 bool onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height, 295 GrPixelConfig srcConfig, DrawPreference*, 296 WritePixelTempDrawInfo*) override { return false; } 297 298 bool onCopySurface(GrSurface* dst, 299 GrSurface* src, 300 const SkIRect& srcRect, 301 const SkIPoint& dstPoint) override { return false; } 302 303 void onQueryMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings&, 304 int* effectiveSampleCnt, SamplePattern*) override { 305 *effectiveSampleCnt = rt->desc().fSampleCnt; 306 } 307 308 GrGpuCommandBuffer* createCommandBuffer(const GrGpuCommandBuffer::LoadAndStoreInfo&, 309 const GrGpuCommandBuffer::LoadAndStoreInfo&) override { 310 return nullptr; 311 } 312 313 void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) override {} 314 315 GrFence SK_WARN_UNUSED_RESULT insertFence() override { return 0; } 316 bool waitFence(GrFence, uint64_t) override { return true; } 317 void deleteFence(GrFence) const override {} 318 void flush() override {} 319 320 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore() override { return nullptr; } 321 void insertSemaphore(sk_sp<GrSemaphore> semaphore) override {} 322 void waitSemaphore(sk_sp<GrSemaphore> semaphore) override {} 323 324private: 325 void onResetContext(uint32_t resetBits) override {} 326 327 void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {} 328 329 GrTexture* onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, 330 const SkTArray<GrMipLevel>& texels) override { 331 return nullptr; 332 } 333 334 GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, 335 const SkTArray<GrMipLevel>& texels) override { 336 return nullptr; 337 } 338 339 sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTextureDesc&, GrWrapOwnership) override { 340 return nullptr; 341 } 342 343 sk_sp<GrRenderTarget> onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) override { 344 return nullptr; 345 } 346 347 sk_sp<GrRenderTarget> onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&) override { 348 return nullptr; 349 } 350 351 GrBuffer* onCreateBuffer(size_t, GrBufferType, GrAccessPattern, const void*) override { 352 return nullptr; 353 } 354 355 gr_instanced::InstancedRendering* onCreateInstancedRendering() override { return nullptr; } 356 357 bool onReadPixels(GrSurface* surface, 358 int left, int top, int width, int height, 359 GrPixelConfig, 360 void* buffer, 361 size_t rowBytes) override { 362 return false; 363 } 364 365 bool onWritePixels(GrSurface* surface, 366 int left, int top, int width, int height, 367 GrPixelConfig config, const SkTArray<GrMipLevel>& texels) override { 368 return false; 369 } 370 371 bool onTransferPixels(GrSurface* surface, 372 int left, int top, int width, int height, 373 GrPixelConfig config, GrBuffer* transferBuffer, 374 size_t offset, size_t rowBytes) override { 375 return false; 376 } 377 378 void onResolveRenderTarget(GrRenderTarget* target) override { return; } 379 380 GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*, 381 int width, 382 int height) override { 383 return nullptr; 384 } 385 386 void clearStencil(GrRenderTarget* target) override {} 387 388 GrBackendObject createTestingOnlyBackendTexture(void* pixels, int w, int h, 389 GrPixelConfig config, bool isRT) override { 390 return 0; 391 } 392 bool isTestingOnlyBackendTexture(GrBackendObject ) const override { return false; } 393 void deleteTestingOnlyBackendTexture(GrBackendObject, bool abandonTexture) override {} 394 395 typedef GrGpu INHERITED; 396}; 397 398GrContext* GrContext::CreateMockContext() { 399 GrContext* context = new GrContext; 400 401 context->initMockContext(); 402 return context; 403} 404 405void GrContext::initMockContext() { 406 GrContextOptions options; 407 options.fBufferMapThreshold = 0; 408 SkASSERT(nullptr == fGpu); 409 fGpu = new MockGpu(this, options); 410 SkASSERT(fGpu); 411 this->initCommon(options); 412 413 // We delete these because we want to test the cache starting with zero resources. Also, none of 414 // these objects are required for any of tests that use this context. TODO: make stop allocating 415 // resources in the buffer pools. 416 fDrawingManager->abandon(); 417} 418