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