OLD | NEW |
(Empty) | |
| 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 "GrBatchAtlas.h" |
| 11 #include "GrContextOptions.h" |
| 12 #include "GrDrawContextPriv.h" |
| 13 #include "GrDrawingManager.h" |
| 14 #include "GrGpuResourceCacheAccess.h" |
| 15 #include "GrResourceCache.h" |
| 16 |
| 17 #include "SkGpuDevice.h" |
| 18 #include "SkGrPriv.h" |
| 19 #include "SkString.h" |
| 20 |
| 21 #include "text/GrBatchFontCache.h" |
| 22 #include "text/GrTextBlobCache.h" |
| 23 |
| 24 namespace GrTest { |
| 25 void SetupAlwaysEvictAtlas(GrContext* context) { |
| 26 // These sizes were selected because they allow each atlas to hold a single
plot and will thus |
| 27 // stress the atlas |
| 28 int dim = GrBatchAtlas::kGlyphMaxDim; |
| 29 GrBatchAtlasConfig configs[3]; |
| 30 configs[kA8_GrMaskFormat].fWidth = dim; |
| 31 configs[kA8_GrMaskFormat].fHeight = dim; |
| 32 configs[kA8_GrMaskFormat].fLog2Width = SkNextLog2(dim); |
| 33 configs[kA8_GrMaskFormat].fLog2Height = SkNextLog2(dim); |
| 34 configs[kA8_GrMaskFormat].fPlotWidth = dim; |
| 35 configs[kA8_GrMaskFormat].fPlotHeight = dim; |
| 36 |
| 37 configs[kA565_GrMaskFormat].fWidth = dim; |
| 38 configs[kA565_GrMaskFormat].fHeight = dim; |
| 39 configs[kA565_GrMaskFormat].fLog2Width = SkNextLog2(dim); |
| 40 configs[kA565_GrMaskFormat].fLog2Height = SkNextLog2(dim); |
| 41 configs[kA565_GrMaskFormat].fPlotWidth = dim; |
| 42 configs[kA565_GrMaskFormat].fPlotHeight = dim; |
| 43 |
| 44 configs[kARGB_GrMaskFormat].fWidth = dim; |
| 45 configs[kARGB_GrMaskFormat].fHeight = dim; |
| 46 configs[kARGB_GrMaskFormat].fLog2Width = SkNextLog2(dim); |
| 47 configs[kARGB_GrMaskFormat].fLog2Height = SkNextLog2(dim); |
| 48 configs[kARGB_GrMaskFormat].fPlotWidth = dim; |
| 49 configs[kARGB_GrMaskFormat].fPlotHeight = dim; |
| 50 |
| 51 context->setTextContextAtlasSizes_ForTesting(configs); |
| 52 } |
| 53 }; |
| 54 |
| 55 void GrTestTarget::init(GrContext* ctx, GrDrawTarget* target, GrRenderTarget* rt
) { |
| 56 SkASSERT(!fContext); |
| 57 |
| 58 fContext.reset(SkRef(ctx)); |
| 59 fDrawTarget.reset(SkRef(target)); |
| 60 fRenderTarget.reset(SkRef(rt)); |
| 61 } |
| 62 |
| 63 void GrContext::getTestTarget(GrTestTarget* tar, GrRenderTarget* rt) { |
| 64 this->flush(); |
| 65 // We could create a proxy GrDrawTarget that passes through to fGpu until ~G
rTextTarget() and |
| 66 // then disconnects. This would help prevent test writers from mixing using
the returned |
| 67 // GrDrawTarget and regular drawing. We could also assert or fail in GrConte
xt drawing methods |
| 68 // until ~GrTestTarget(). |
| 69 if (!rt) { |
| 70 GrSurfaceDesc desc; |
| 71 desc.fFlags = kRenderTarget_GrSurfaceFlag; |
| 72 desc.fWidth = 32; |
| 73 desc.fHeight = 32; |
| 74 desc.fConfig = kRGBA_8888_GrPixelConfig; |
| 75 desc.fSampleCnt = 0; |
| 76 |
| 77 SkAutoTUnref<GrTexture> texture(this->textureProvider()->createTexture( |
| 78 desc, SkBudgeted::kNo, nullptr, 0)); |
| 79 if (nullptr == texture) { |
| 80 return; |
| 81 } |
| 82 SkASSERT(nullptr != texture->asRenderTarget()); |
| 83 rt = texture->asRenderTarget(); |
| 84 } |
| 85 |
| 86 SkAutoTUnref<GrDrawTarget> dt(fDrawingManager->newDrawTarget(rt)); |
| 87 tar->init(this, dt, rt); |
| 88 } |
| 89 |
| 90 void GrContext::setTextBlobCacheLimit_ForTesting(size_t bytes) { |
| 91 fTextBlobCache->setBudget(bytes); |
| 92 } |
| 93 |
| 94 void GrContext::setTextContextAtlasSizes_ForTesting(const GrBatchAtlasConfig* co
nfigs) { |
| 95 fBatchFontCache->setAtlasSizes_ForTesting(configs); |
| 96 } |
| 97 |
| 98 /////////////////////////////////////////////////////////////////////////////// |
| 99 |
| 100 void GrContext::purgeAllUnlockedResources() { |
| 101 fResourceCache->purgeAllUnlocked(); |
| 102 } |
| 103 |
| 104 void GrContext::resetGpuStats() const { |
| 105 #if GR_GPU_STATS |
| 106 fGpu->stats()->reset(); |
| 107 #endif |
| 108 } |
| 109 |
| 110 void GrContext::dumpCacheStats(SkString* out) const { |
| 111 #if GR_CACHE_STATS |
| 112 fResourceCache->dumpStats(out); |
| 113 #endif |
| 114 } |
| 115 |
| 116 void GrContext::dumpCacheStatsKeyValuePairs(SkTArray<SkString>* keys, |
| 117 SkTArray<double>* values) const { |
| 118 #if GR_CACHE_STATS |
| 119 fResourceCache->dumpStatsKeyValuePairs(keys, values); |
| 120 #endif |
| 121 } |
| 122 |
| 123 void GrContext::printCacheStats() const { |
| 124 SkString out; |
| 125 this->dumpCacheStats(&out); |
| 126 SkDebugf("%s", out.c_str()); |
| 127 } |
| 128 |
| 129 void GrContext::dumpGpuStats(SkString* out) const { |
| 130 #if GR_GPU_STATS |
| 131 return fGpu->stats()->dump(out); |
| 132 #endif |
| 133 } |
| 134 |
| 135 void GrContext::dumpGpuStatsKeyValuePairs(SkTArray<SkString>* keys, |
| 136 SkTArray<double>* values) const { |
| 137 #if GR_GPU_STATS |
| 138 return fGpu->stats()->dumpKeyValuePairs(keys, values); |
| 139 #endif |
| 140 } |
| 141 |
| 142 void GrContext::printGpuStats() const { |
| 143 SkString out; |
| 144 this->dumpGpuStats(&out); |
| 145 SkDebugf("%s", out.c_str()); |
| 146 } |
| 147 |
| 148 GrTexture* GrContext::getFontAtlasTexture(GrMaskFormat format) { |
| 149 GrBatchFontCache* cache = this->getBatchFontCache(); |
| 150 |
| 151 return cache->getTexture(format); |
| 152 } |
| 153 |
| 154 void SkGpuDevice::drawTexture(GrTexture* tex, const SkRect& dst, const SkPaint&
paint) { |
| 155 GrPaint grPaint; |
| 156 SkMatrix mat; |
| 157 mat.reset(); |
| 158 if (!SkPaintToGrPaint(this->context(), paint, mat, &grPaint)) { |
| 159 return; |
| 160 } |
| 161 SkMatrix textureMat; |
| 162 textureMat.reset(); |
| 163 textureMat[SkMatrix::kMScaleX] = 1.0f/dst.width(); |
| 164 textureMat[SkMatrix::kMScaleY] = 1.0f/dst.height(); |
| 165 textureMat[SkMatrix::kMTransX] = -dst.fLeft/dst.width(); |
| 166 textureMat[SkMatrix::kMTransY] = -dst.fTop/dst.height(); |
| 167 |
| 168 grPaint.addColorTextureProcessor(tex, textureMat); |
| 169 |
| 170 GrClip clip; |
| 171 fDrawContext->drawRect(clip, grPaint, mat, dst); |
| 172 } |
| 173 |
| 174 |
| 175 #if GR_GPU_STATS |
| 176 void GrGpu::Stats::dump(SkString* out) { |
| 177 out->appendf("Render Target Binds: %d\n", fRenderTargetBinds); |
| 178 out->appendf("Shader Compilations: %d\n", fShaderCompilations); |
| 179 out->appendf("Textures Created: %d\n", fTextureCreates); |
| 180 out->appendf("Texture Uploads: %d\n", fTextureUploads); |
| 181 out->appendf("Transfers to Texture: %d\n", fTransfersToTexture); |
| 182 out->appendf("Stencil Buffer Creates: %d\n", fStencilAttachmentCreates); |
| 183 out->appendf("Number of draws: %d\n", fNumDraws); |
| 184 } |
| 185 |
| 186 void GrGpu::Stats::dumpKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>*
values) { |
| 187 keys->push_back(SkString("render_target_binds")); values->push_back(fRenderT
argetBinds); |
| 188 keys->push_back(SkString("shader_compilations")); values->push_back(fShaderC
ompilations); |
| 189 keys->push_back(SkString("texture_uploads")); values->push_back(fTextureUplo
ads); |
| 190 keys->push_back(SkString("number_of_draws")); values->push_back(fNumDraws); |
| 191 keys->push_back(SkString("number_of_failed_draws")); values->push_back(fNumF
ailedDraws); |
| 192 } |
| 193 |
| 194 #endif |
| 195 |
| 196 #if GR_CACHE_STATS |
| 197 void GrResourceCache::getStats(Stats* stats) const { |
| 198 stats->reset(); |
| 199 |
| 200 stats->fTotal = this->getResourceCount(); |
| 201 stats->fNumNonPurgeable = fNonpurgeableResources.count(); |
| 202 stats->fNumPurgeable = fPurgeableQueue.count(); |
| 203 |
| 204 for (int i = 0; i < fNonpurgeableResources.count(); ++i) { |
| 205 stats->update(fNonpurgeableResources[i]); |
| 206 } |
| 207 for (int i = 0; i < fPurgeableQueue.count(); ++i) { |
| 208 stats->update(fPurgeableQueue.at(i)); |
| 209 } |
| 210 } |
| 211 |
| 212 void GrResourceCache::dumpStats(SkString* out) const { |
| 213 this->validate(); |
| 214 |
| 215 Stats stats; |
| 216 |
| 217 this->getStats(&stats); |
| 218 |
| 219 float countUtilization = (100.f * fBudgetedCount) / fMaxCount; |
| 220 float byteUtilization = (100.f * fBudgetedBytes) / fMaxBytes; |
| 221 |
| 222 out->appendf("Budget: %d items %d bytes\n", fMaxCount, (int)fMaxBytes); |
| 223 out->appendf("\t\tEntry Count: current %d" |
| 224 " (%d budgeted, %d external(%d borrowed, %d adopted), %d locked
, %d scratch %.2g%% full), high %d\n", |
| 225 stats.fTotal, fBudgetedCount, stats.fExternal, stats.fBorrowed, |
| 226 stats.fAdopted, stats.fNumNonPurgeable, stats.fScratch, countUt
ilization, |
| 227 fHighWaterCount); |
| 228 out->appendf("\t\tEntry Bytes: current %d (budgeted %d, %.2g%% full, %d unbu
dgeted) high %d\n", |
| 229 SkToInt(fBytes), SkToInt(fBudgetedBytes), byteUtilization, |
| 230 SkToInt(stats.fUnbudgetedSize), SkToInt(fHighWaterBytes)); |
| 231 } |
| 232 |
| 233 void GrResourceCache::dumpStatsKeyValuePairs(SkTArray<SkString>* keys, |
| 234 SkTArray<double>* values) const { |
| 235 this->validate(); |
| 236 |
| 237 Stats stats; |
| 238 this->getStats(&stats); |
| 239 |
| 240 keys->push_back(SkString("gpu_cache_purgable_entries")); values->push_back(s
tats.fNumPurgeable); |
| 241 } |
| 242 |
| 243 #endif |
| 244 |
| 245 /////////////////////////////////////////////////////////////////////////////// |
| 246 |
| 247 void GrResourceCache::changeTimestamp(uint32_t newTimestamp) { fTimestamp = newT
imestamp; } |
| 248 |
| 249 /////////////////////////////////////////////////////////////////////////////// |
| 250 |
| 251 #define ASSERT_SINGLE_OWNER \ |
| 252 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fDrawContext->fSing
leOwner);) |
| 253 #define RETURN_IF_ABANDONED if (fDrawContext->fDrawingManager->abandoned(
)) { return; } |
| 254 |
| 255 void GrDrawContextPriv::testingOnly_drawBatch(const GrPipelineBuilder& pipelineB
uilder, |
| 256 GrDrawBatch* batch) { |
| 257 ASSERT_SINGLE_OWNER |
| 258 RETURN_IF_ABANDONED |
| 259 SkDEBUGCODE(fDrawContext->validate();) |
| 260 GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContext::testing
Only_drawBatch"); |
| 261 |
| 262 fDrawContext->getDrawTarget()->drawBatch(pipelineBuilder, batch); |
| 263 } |
| 264 |
| 265 #undef ASSERT_SINGLE_OWNER |
| 266 #undef RETURN_IF_ABANDONED |
| 267 |
| 268 /////////////////////////////////////////////////////////////////////////////// |
| 269 // Code for the mock context. It's built on a mock GrGpu class that does nothing
. |
| 270 //// |
| 271 |
| 272 #include "GrGpu.h" |
| 273 |
| 274 class GrPipeline; |
| 275 |
| 276 class MockCaps : public GrCaps { |
| 277 public: |
| 278 explicit MockCaps(const GrContextOptions& options) : INHERITED(options) {} |
| 279 bool isConfigTexturable(GrPixelConfig config) const override { return false;
} |
| 280 bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override
{ return false; } |
| 281 private: |
| 282 typedef GrCaps INHERITED; |
| 283 }; |
| 284 |
| 285 class MockGpu : public GrGpu { |
| 286 public: |
| 287 MockGpu(GrContext* context, const GrContextOptions& options) : INHERITED(con
text) { |
| 288 fCaps.reset(new MockCaps(options)); |
| 289 } |
| 290 ~MockGpu() override {} |
| 291 |
| 292 bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeigh
t, size_t rowBytes, |
| 293 GrPixelConfig readConfig, DrawPreference*, |
| 294 ReadPixelTempDrawInfo*) override { return false; } |
| 295 |
| 296 bool onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height, |
| 297 GrPixelConfig srcConfig, DrawPreference*, |
| 298 WritePixelTempDrawInfo*) override { return false;
} |
| 299 |
| 300 void discard(GrRenderTarget*) override {} |
| 301 |
| 302 bool onCopySurface(GrSurface* dst, |
| 303 GrSurface* src, |
| 304 const SkIRect& srcRect, |
| 305 const SkIPoint& dstPoint) override { return false; }; |
| 306 |
| 307 void onGetMultisampleSpecs(GrRenderTarget* rt, |
| 308 const GrStencilSettings&, |
| 309 int* effectiveSampleCnt, |
| 310 SkAutoTDeleteArray<SkPoint>*) override { |
| 311 *effectiveSampleCnt = rt->desc().fSampleCnt; |
| 312 } |
| 313 |
| 314 bool initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const
override { |
| 315 return false; |
| 316 } |
| 317 |
| 318 void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) override {}
; |
| 319 |
| 320 private: |
| 321 void onResetContext(uint32_t resetBits) override {} |
| 322 |
| 323 void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {} |
| 324 |
| 325 GrTexture* onCreateTexture(const GrSurfaceDesc& desc, GrGpuResource::LifeCyc
le lifeCycle, |
| 326 const SkTArray<GrMipLevel>& texels) override { |
| 327 return nullptr; |
| 328 } |
| 329 |
| 330 GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc, GrGpuResourc
e::LifeCycle, |
| 331 const SkTArray<GrMipLevel>& texels) ove
rride { |
| 332 return nullptr; |
| 333 } |
| 334 |
| 335 GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&, |
| 336 GrWrapOwnership) override { return nullptr;
} |
| 337 |
| 338 GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&, |
| 339 GrWrapOwnership) override { |
| 340 return nullptr; |
| 341 } |
| 342 |
| 343 GrRenderTarget* onWrapBackendTextureAsRenderTarget(const GrBackendTextureDes
c&, |
| 344 GrWrapOwnership) override
{ |
| 345 return nullptr; |
| 346 } |
| 347 |
| 348 GrBuffer* onCreateBuffer(GrBufferType, size_t, GrAccessPattern) override { r
eturn nullptr; } |
| 349 |
| 350 void onClear(GrRenderTarget*, const SkIRect& rect, GrColor color) override {
} |
| 351 |
| 352 void onClearStencilClip(GrRenderTarget*, const SkIRect& rect, bool insideCli
p) override {} |
| 353 |
| 354 void onDraw(const GrPipeline&, |
| 355 const GrPrimitiveProcessor&, |
| 356 const GrMesh*, |
| 357 int meshCount) override {} |
| 358 |
| 359 bool onReadPixels(GrSurface* surface, |
| 360 int left, int top, int width, int height, |
| 361 GrPixelConfig, |
| 362 void* buffer, |
| 363 size_t rowBytes) override { |
| 364 return false; |
| 365 } |
| 366 |
| 367 bool onWritePixels(GrSurface* surface, |
| 368 int left, int top, int width, int height, |
| 369 GrPixelConfig config, const SkTArray<GrMipLevel>& texels)
override { |
| 370 return false; |
| 371 } |
| 372 |
| 373 bool onTransferPixels(GrSurface* surface, |
| 374 int left, int top, int width, int height, |
| 375 GrPixelConfig config, GrBuffer* transferBuffer, |
| 376 size_t offset, size_t rowBytes) override { |
| 377 return false; |
| 378 } |
| 379 |
| 380 void onResolveRenderTarget(GrRenderTarget* target) override { return; } |
| 381 |
| 382 GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTa
rget*, |
| 383 int width, |
| 384 int height) over
ride { |
| 385 return nullptr; |
| 386 } |
| 387 |
| 388 void clearStencil(GrRenderTarget* target) override {} |
| 389 |
| 390 GrBackendObject createTestingOnlyBackendTexture(void* pixels, int w, int h, |
| 391 GrPixelConfig config) overri
de { |
| 392 return 0; |
| 393 } |
| 394 bool isTestingOnlyBackendTexture(GrBackendObject ) const override { return f
alse; } |
| 395 void deleteTestingOnlyBackendTexture(GrBackendObject, bool abandonTexture) o
verride {} |
| 396 |
| 397 typedef GrGpu INHERITED; |
| 398 }; |
| 399 |
| 400 GrContext* GrContext::CreateMockContext() { |
| 401 GrContext* context = new GrContext; |
| 402 |
| 403 context->initMockContext(); |
| 404 return context; |
| 405 } |
| 406 |
| 407 void GrContext::initMockContext() { |
| 408 GrContextOptions options; |
| 409 options.fBufferMapThreshold = 0; |
| 410 SkASSERT(nullptr == fGpu); |
| 411 fGpu = new MockGpu(this, options); |
| 412 SkASSERT(fGpu); |
| 413 this->initCommon(options); |
| 414 |
| 415 // We delete these because we want to test the cache starting with zero reso
urces. Also, none of |
| 416 // these objects are required for any of tests that use this context. TODO:
make stop allocating |
| 417 // resources in the buffer pools. |
| 418 fDrawingManager->abandon(); |
| 419 } |
OLD | NEW |