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