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 "GrDrawContext.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 {
SetupAlwaysEvictAtlas(GrContext * context)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
init(GrContext * ctx,GrDrawTarget * target,GrRenderTarget * rt)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
getTestTarget(GrTestTarget * tar,GrRenderTarget * rt)63 void GrContext::getTestTarget(GrTestTarget* tar, GrRenderTarget* rt) {
64 this->flush();
65 // We could create a proxy GrDrawTarget that passes through to fGpu until ~GrTextTarget() 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 GrContext 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
setTextBlobCacheLimit_ForTesting(size_t bytes)90 void GrContext::setTextBlobCacheLimit_ForTesting(size_t bytes) {
91 fTextBlobCache->setBudget(bytes);
92 }
93
setTextContextAtlasSizes_ForTesting(const GrBatchAtlasConfig * configs)94 void GrContext::setTextContextAtlasSizes_ForTesting(const GrBatchAtlasConfig* configs) {
95 fBatchFontCache->setAtlasSizes_ForTesting(configs);
96 }
97
98 ///////////////////////////////////////////////////////////////////////////////
99
purgeAllUnlockedResources()100 void GrContext::purgeAllUnlockedResources() {
101 fResourceCache->purgeAllUnlocked();
102 }
103
resetGpuStats() const104 void GrContext::resetGpuStats() const {
105 #if GR_GPU_STATS
106 fGpu->stats()->reset();
107 #endif
108 }
109
dumpCacheStats(SkString * out) const110 void GrContext::dumpCacheStats(SkString* out) const {
111 #if GR_CACHE_STATS
112 fResourceCache->dumpStats(out);
113 #endif
114 }
115
dumpCacheStatsKeyValuePairs(SkTArray<SkString> * keys,SkTArray<double> * values) const116 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
printCacheStats() const123 void GrContext::printCacheStats() const {
124 SkString out;
125 this->dumpCacheStats(&out);
126 SkDebugf("%s", out.c_str());
127 }
128
dumpGpuStats(SkString * out) const129 void GrContext::dumpGpuStats(SkString* out) const {
130 #if GR_GPU_STATS
131 return fGpu->stats()->dump(out);
132 #endif
133 }
134
dumpGpuStatsKeyValuePairs(SkTArray<SkString> * keys,SkTArray<double> * values) const135 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
printGpuStats() const142 void GrContext::printGpuStats() const {
143 SkString out;
144 this->dumpGpuStats(&out);
145 SkDebugf("%s", out.c_str());
146 }
147
getFontAtlasTexture(GrMaskFormat format)148 GrTexture* GrContext::getFontAtlasTexture(GrMaskFormat format) {
149 GrBatchFontCache* cache = this->getBatchFontCache();
150
151 return cache->getTexture(format);
152 }
153
drawTexture(GrTexture * tex,const SkRect & dst,const SkPaint & paint)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
dump(SkString * out)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
dumpKeyValuePairs(SkTArray<SkString> * keys,SkTArray<double> * values)186 void GrGpu::Stats::dumpKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* values) {
187 keys->push_back(SkString("render_target_binds")); values->push_back(fRenderTargetBinds);
188 keys->push_back(SkString("shader_compilations")); values->push_back(fShaderCompilations);
189 keys->push_back(SkString("textures_created")); values->push_back(fTextureCreates);
190 keys->push_back(SkString("texture_uploads")); values->push_back(fTextureUploads);
191 keys->push_back(SkString("transfers_to_texture")); values->push_back(fTransfersToTexture);
192 keys->push_back(SkString("stencil_buffer_creates")); values->push_back(fStencilAttachmentCreates);
193 keys->push_back(SkString("number_of_draws")); values->push_back(fNumDraws);
194 }
195
196 #endif
197
198 #if GR_CACHE_STATS
getStats(Stats * stats) const199 void GrResourceCache::getStats(Stats* stats) const {
200 stats->reset();
201
202 stats->fTotal = this->getResourceCount();
203 stats->fNumNonPurgeable = fNonpurgeableResources.count();
204 stats->fNumPurgeable = fPurgeableQueue.count();
205
206 for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
207 stats->update(fNonpurgeableResources[i]);
208 }
209 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
210 stats->update(fPurgeableQueue.at(i));
211 }
212 }
213
dumpStats(SkString * out) const214 void GrResourceCache::dumpStats(SkString* out) const {
215 this->validate();
216
217 Stats stats;
218
219 this->getStats(&stats);
220
221 float countUtilization = (100.f * fBudgetedCount) / fMaxCount;
222 float byteUtilization = (100.f * fBudgetedBytes) / fMaxBytes;
223
224 out->appendf("Budget: %d items %d bytes\n", fMaxCount, (int)fMaxBytes);
225 out->appendf("\t\tEntry Count: current %d"
226 " (%d budgeted, %d external(%d borrowed, %d adopted), %d locked, %d scratch %.2g%% full), high %d\n",
227 stats.fTotal, fBudgetedCount, stats.fExternal, stats.fBorrowed,
228 stats.fAdopted, stats.fNumNonPurgeable, stats.fScratch, countUtilization,
229 fHighWaterCount);
230 out->appendf("\t\tEntry Bytes: current %d (budgeted %d, %.2g%% full, %d unbudgeted) high %d\n",
231 SkToInt(fBytes), SkToInt(fBudgetedBytes), byteUtilization,
232 SkToInt(stats.fUnbudgetedSize), SkToInt(fHighWaterBytes));
233 }
234
dumpStatsKeyValuePairs(SkTArray<SkString> * keys,SkTArray<double> * values) const235 void GrResourceCache::dumpStatsKeyValuePairs(SkTArray<SkString>* keys,
236 SkTArray<double>* values) const {
237 this->validate();
238
239 Stats stats;
240 this->getStats(&stats);
241
242 keys->push_back(SkString("gpu_cache_total_entries")); values->push_back(stats.fTotal);
243 keys->push_back(SkString("gpu_cache_external_entries")); values->push_back(stats.fExternal);
244 keys->push_back(SkString("gpu_cache_borrowed_entries")); values->push_back(stats.fBorrowed);
245 keys->push_back(SkString("gpu_cache_adopted_entries")); values->push_back(stats.fAdopted);
246 keys->push_back(SkString("gpu_cache_purgable_entries")); values->push_back(stats.fNumPurgeable);
247 keys->push_back(SkString("gpu_cache_non_purgable_entries")); values->push_back(stats.fNumNonPurgeable);
248 keys->push_back(SkString("gpu_cache_scratch_entries")); values->push_back(stats.fScratch);
249 keys->push_back(SkString("gpu_cache_unbudgeted_size")); values->push_back((double)stats.fUnbudgetedSize);
250 }
251
252 #endif
253
254 ///////////////////////////////////////////////////////////////////////////////
255
changeTimestamp(uint32_t newTimestamp)256 void GrResourceCache::changeTimestamp(uint32_t newTimestamp) { fTimestamp = newTimestamp; }
257
258 ///////////////////////////////////////////////////////////////////////////////
259
260 #define ASSERT_SINGLE_OWNER \
261 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
262 #define RETURN_IF_ABANDONED if (fDrawingManager->abandoned()) { return; }
263
internal_drawBatch(const GrPipelineBuilder & pipelineBuilder,GrDrawBatch * batch)264 void GrDrawContext::internal_drawBatch(const GrPipelineBuilder& pipelineBuilder,
265 GrDrawBatch* batch) {
266 ASSERT_SINGLE_OWNER
267 RETURN_IF_ABANDONED
268 SkDEBUGCODE(this->validate();)
269 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::internal_drawBatch");
270
271 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
272 }
273
274 #undef ASSERT_SINGLE_OWNER
275 #undef RETURN_IF_ABANDONED
276
277 ///////////////////////////////////////////////////////////////////////////////
278 // Code for the mock context. It's built on a mock GrGpu class that does nothing.
279 ////
280
281 #include "GrGpu.h"
282
283 class GrPipeline;
284
285 class MockCaps : public GrCaps {
286 public:
MockCaps(const GrContextOptions & options)287 explicit MockCaps(const GrContextOptions& options) : INHERITED(options) {}
isConfigTexturable(GrPixelConfig config) const288 bool isConfigTexturable(GrPixelConfig config) const override { return false; }
isConfigRenderable(GrPixelConfig config,bool withMSAA) const289 bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override { return false; }
290 private:
291 typedef GrCaps INHERITED;
292 };
293
294 class MockGpu : public GrGpu {
295 public:
MockGpu(GrContext * context,const GrContextOptions & options)296 MockGpu(GrContext* context, const GrContextOptions& options) : INHERITED(context) {
297 fCaps.reset(new MockCaps(options));
298 }
~MockGpu()299 ~MockGpu() override {}
300
onGetReadPixelsInfo(GrSurface * srcSurface,int readWidth,int readHeight,size_t rowBytes,GrPixelConfig readConfig,DrawPreference *,ReadPixelTempDrawInfo *)301 bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes,
302 GrPixelConfig readConfig, DrawPreference*,
303 ReadPixelTempDrawInfo*) override { return false; }
304
onGetWritePixelsInfo(GrSurface * dstSurface,int width,int height,GrPixelConfig srcConfig,DrawPreference *,WritePixelTempDrawInfo *)305 bool onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
306 GrPixelConfig srcConfig, DrawPreference*,
307 WritePixelTempDrawInfo*) override { return false; }
308
buildProgramDesc(GrProgramDesc *,const GrPrimitiveProcessor &,const GrPipeline &) const309 void buildProgramDesc(GrProgramDesc*, const GrPrimitiveProcessor&,
310 const GrPipeline&) const override {}
311
discard(GrRenderTarget *)312 void discard(GrRenderTarget*) override {}
313
onCopySurface(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)314 bool onCopySurface(GrSurface* dst,
315 GrSurface* src,
316 const SkIRect& srcRect,
317 const SkIPoint& dstPoint) override { return false; };
318
initCopySurfaceDstDesc(const GrSurface * src,GrSurfaceDesc * desc) const319 bool initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const override {
320 return false;
321 }
322
drawDebugWireRect(GrRenderTarget *,const SkIRect &,GrColor)323 void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) override {};
324
325 private:
onResetContext(uint32_t resetBits)326 void onResetContext(uint32_t resetBits) override {}
327
xferBarrier(GrRenderTarget *,GrXferBarrierType)328 void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {}
329
onCreateTexture(const GrSurfaceDesc & desc,GrGpuResource::LifeCycle lifeCycle,const void * srcData,size_t rowBytes)330 GrTexture* onCreateTexture(const GrSurfaceDesc& desc, GrGpuResource::LifeCycle lifeCycle,
331 const void* srcData, size_t rowBytes) override {
332 return nullptr;
333 }
334
onCreateCompressedTexture(const GrSurfaceDesc & desc,GrGpuResource::LifeCycle,const void * srcData)335 GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc, GrGpuResource::LifeCycle,
336 const void* srcData) override {
337 return nullptr;
338 }
339
onWrapBackendTexture(const GrBackendTextureDesc &,GrWrapOwnership)340 GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&,
341 GrWrapOwnership) override { return nullptr; }
342
onWrapBackendRenderTarget(const GrBackendRenderTargetDesc &,GrWrapOwnership)343 GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&,
344 GrWrapOwnership) override {
345 return nullptr;
346 }
347
onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc &,GrWrapOwnership)348 GrRenderTarget* onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&,
349 GrWrapOwnership) override {
350 return nullptr;
351 }
352
onCreateVertexBuffer(size_t size,bool dynamic)353 GrVertexBuffer* onCreateVertexBuffer(size_t size, bool dynamic) override { return nullptr; }
354
onCreateIndexBuffer(size_t size,bool dynamic)355 GrIndexBuffer* onCreateIndexBuffer(size_t size, bool dynamic) override { return nullptr; }
356
onCreateTransferBuffer(size_t,TransferType)357 GrTransferBuffer* onCreateTransferBuffer(size_t, TransferType) override { return nullptr; }
358
onClear(GrRenderTarget *,const SkIRect & rect,GrColor color)359 void onClear(GrRenderTarget*, const SkIRect& rect, GrColor color) override {}
360
onClearStencilClip(GrRenderTarget *,const SkIRect & rect,bool insideClip)361 void onClearStencilClip(GrRenderTarget*, const SkIRect& rect, bool insideClip) override {}
362
onDraw(const DrawArgs &,const GrNonInstancedVertices &)363 void onDraw(const DrawArgs&, const GrNonInstancedVertices&) override {}
364
onReadPixels(GrSurface * surface,int left,int top,int width,int height,GrPixelConfig,void * buffer,size_t rowBytes)365 bool onReadPixels(GrSurface* surface,
366 int left, int top, int width, int height,
367 GrPixelConfig,
368 void* buffer,
369 size_t rowBytes) override {
370 return false;
371 }
372
onWritePixels(GrSurface * surface,int left,int top,int width,int height,GrPixelConfig config,const void * buffer,size_t rowBytes)373 bool onWritePixels(GrSurface* surface,
374 int left, int top, int width, int height,
375 GrPixelConfig config, const void* buffer,
376 size_t rowBytes) override {
377 return false;
378 }
379
onTransferPixels(GrSurface * surface,int left,int top,int width,int height,GrPixelConfig config,GrTransferBuffer * buffer,size_t offset,size_t rowBytes)380 bool onTransferPixels(GrSurface* surface,
381 int left, int top, int width, int height,
382 GrPixelConfig config, GrTransferBuffer* buffer,
383 size_t offset, size_t rowBytes) override {
384 return false;
385 }
386
onResolveRenderTarget(GrRenderTarget * target)387 void onResolveRenderTarget(GrRenderTarget* target) override { return; }
388
createStencilAttachmentForRenderTarget(const GrRenderTarget *,int width,int height)389 GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*,
390 int width,
391 int height) override {
392 return nullptr;
393 }
394
clearStencil(GrRenderTarget * target)395 void clearStencil(GrRenderTarget* target) override {}
396
createTestingOnlyBackendTexture(void * pixels,int w,int h,GrPixelConfig config)397 GrBackendObject createTestingOnlyBackendTexture(void* pixels, int w, int h,
398 GrPixelConfig config) override {
399 return 0;
400 }
isTestingOnlyBackendTexture(GrBackendObject) const401 bool isTestingOnlyBackendTexture(GrBackendObject ) const override { return false; }
deleteTestingOnlyBackendTexture(GrBackendObject,bool abandonTexture)402 void deleteTestingOnlyBackendTexture(GrBackendObject, bool abandonTexture) override {}
403
404 typedef GrGpu INHERITED;
405 };
406
CreateMockContext()407 GrContext* GrContext::CreateMockContext() {
408 GrContext* context = new GrContext;
409
410 context->initMockContext();
411 return context;
412 }
413
initMockContext()414 void GrContext::initMockContext() {
415 GrContextOptions options;
416 options.fGeometryBufferMapThreshold = 0;
417 SkASSERT(nullptr == fGpu);
418 fGpu = new MockGpu(this, options);
419 SkASSERT(fGpu);
420 this->initCommon(options);
421
422 // We delete these because we want to test the cache starting with zero resources. Also, none of
423 // these objects are required for any of tests that use this context. TODO: make stop allocating
424 // resources in the buffer pools.
425 fDrawingManager->abandon();
426 }
427