blob: 6993430762897057934e2e2a9f064f98dcc145b6 [file] [log] [blame]
Robert Phillips4bc70112018-03-01 10:24:02 -05001/*
2 * Copyright 2018 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 "SkTypes.h"
9
Ben Wagnerd90cd3b2018-05-22 10:48:08 -040010#include "GrContext.h"
11#include "GrContextFactory.h"
Robert Phillips4bc70112018-03-01 10:24:02 -050012#include "GrContextPriv.h"
Ben Wagnerd90cd3b2018-05-22 10:48:08 -040013#include "GrDeferredUpload.h"
14#include "GrDrawOpAtlas.h"
15#include "GrDrawingManager.h"
Robert Phillipsc994a932018-06-19 13:09:54 -040016#include "GrMemoryPool.h"
Ben Wagnerd90cd3b2018-05-22 10:48:08 -040017#include "GrOnFlushResourceProvider.h"
18#include "GrOpFlushState.h"
19#include "GrRenderTargetContext.h"
20#include "GrSurfaceProxyPriv.h"
21#include "GrTextureProxy.h"
22#include "GrTypesPriv.h"
23#include "GrXferProcessor.h"
24#include "SkBitmap.h"
25#include "SkColor.h"
26#include "SkColorSpace.h"
27#include "SkIPoint16.h"
28#include "SkImageInfo.h"
29#include "SkMatrix.h"
30#include "SkPaint.h"
31#include "SkPoint.h"
32#include "SkRefCnt.h"
Robert Phillips4bc70112018-03-01 10:24:02 -050033#include "Test.h"
Ben Wagnerd90cd3b2018-05-22 10:48:08 -040034#include "ops/GrDrawOp.h"
35#include "text/GrAtlasManager.h"
Herb Derby26cbe512018-05-24 14:39:01 -040036#include "text/GrTextContext.h"
Ben Wagnerd90cd3b2018-05-22 10:48:08 -040037#include "text/GrTextUtils.h"
38
39#include <memory>
40
41class GrResourceProvider;
Robert Phillips4bc70112018-03-01 10:24:02 -050042
43static const int kNumPlots = 2;
44static const int kPlotSize = 32;
45static const int kAtlasSize = kNumPlots * kPlotSize;
46
47int GrDrawOpAtlas::numAllocated_TestingOnly() const {
48 int count = 0;
49 for (uint32_t i = 0; i < this->maxPages(); ++i) {
Brian Salomonfd98c2c2018-07-31 17:25:29 -040050 if (fProxies[i]->isInstantiated()) {
Robert Phillips4bc70112018-03-01 10:24:02 -050051 ++count;
52 }
53 }
54
55 return count;
56}
57
Kevin Lubickb5502b22018-03-12 10:17:06 -040058void GrAtlasManager::setMaxPages_TestingOnly(uint32_t maxPages) {
Robert Phillipsd2e9f762018-03-07 11:54:37 -050059 for (int i = 0; i < kMaskFormatCount; i++) {
60 if (fAtlases[i]) {
Kevin Lubickb5502b22018-03-12 10:17:06 -040061 fAtlases[i]->setMaxPages_TestingOnly(maxPages);
Robert Phillipsd2e9f762018-03-07 11:54:37 -050062 }
63 }
64}
65
66void GrDrawOpAtlas::setMaxPages_TestingOnly(uint32_t maxPages) {
67 SkASSERT(!fNumActivePages);
68
69 fMaxPages = maxPages;
70}
71
Robert Phillips4bc70112018-03-01 10:24:02 -050072void EvictionFunc(GrDrawOpAtlas::AtlasID atlasID, void*) {
73 SkASSERT(0); // The unit test shouldn't exercise this code path
74}
75
76static void check(skiatest::Reporter* r, GrDrawOpAtlas* atlas,
77 uint32_t expectedActive, uint32_t expectedMax, int expectedAlloced) {
78 REPORTER_ASSERT(r, expectedActive == atlas->numActivePages());
79 REPORTER_ASSERT(r, expectedMax == atlas->maxPages());
80 REPORTER_ASSERT(r, expectedAlloced == atlas->numAllocated_TestingOnly());
81}
82
83class TestingUploadTarget : public GrDeferredUploadTarget {
84public:
85 TestingUploadTarget() { }
86
Robert Phillipsd2e9f762018-03-07 11:54:37 -050087 const GrTokenTracker* tokenTracker() final { return &fTokenTracker; }
88 GrTokenTracker* writeableTokenTracker() { return &fTokenTracker; }
Robert Phillips4bc70112018-03-01 10:24:02 -050089
90 GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) final {
91 SkASSERT(0); // this test shouldn't invoke this code path
92 return fTokenTracker.nextDrawToken();
93 }
94
95 virtual GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&& upload) final {
96 return fTokenTracker.nextTokenToFlush();
97 }
98
99 void issueDrawToken() { fTokenTracker.issueDrawToken(); }
100 void flushToken() { fTokenTracker.flushToken(); }
101
102private:
103 GrTokenTracker fTokenTracker;
104
105 typedef GrDeferredUploadTarget INHERITED;
106};
107
108static bool fill_plot(GrDrawOpAtlas* atlas,
109 GrResourceProvider* resourceProvider,
110 GrDeferredUploadTarget* target,
111 GrDrawOpAtlas::AtlasID* atlasID,
112 int alpha) {
113 SkImageInfo ii = SkImageInfo::MakeA8(kPlotSize, kPlotSize);
114
115 SkBitmap data;
116 data.allocPixels(ii);
117 data.eraseARGB(alpha, 0, 0, 0);
118
119 SkIPoint16 loc;
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500120 GrDrawOpAtlas::ErrorCode code;
121 code = atlas->addToAtlas(resourceProvider, atlasID, target, kPlotSize, kPlotSize,
122 data.getAddr(0, 0), &loc);
123 return GrDrawOpAtlas::ErrorCode::kSucceeded == code;
Robert Phillips4bc70112018-03-01 10:24:02 -0500124}
125
126
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500127// This is a basic DrawOpAtlas test. It simply verifies that multitexture atlases correctly
128// add and remove pages. Note that this is simulating flush-time behavior.
129DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BasicDrawOpAtlas, reporter, ctxInfo) {
Robert Phillips4bc70112018-03-01 10:24:02 -0500130 auto context = ctxInfo.grContext();
131 auto proxyProvider = context->contextPriv().proxyProvider();
132 auto resourceProvider = context->contextPriv().resourceProvider();
133 auto drawingManager = context->contextPriv().drawingManager();
134
135 GrOnFlushResourceProvider onFlushResourceProvider(drawingManager);
136 TestingUploadTarget uploadTarget;
137
138 std::unique_ptr<GrDrawOpAtlas> atlas = GrDrawOpAtlas::Make(
139 proxyProvider,
140 kAlpha_8_GrPixelConfig,
141 kAtlasSize, kAtlasSize,
142 kNumPlots, kNumPlots,
143 GrDrawOpAtlas::AllowMultitexturing::kYes,
144 EvictionFunc, nullptr);
145 check(reporter, atlas.get(), 0, 4, 0);
146
147 // Fill up the first level
148 GrDrawOpAtlas::AtlasID atlasIDs[kNumPlots * kNumPlots];
149 for (int i = 0; i < kNumPlots * kNumPlots; ++i) {
150 bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasIDs[i], i*32);
151 REPORTER_ASSERT(reporter, result);
152 check(reporter, atlas.get(), 1, 4, 1);
153 }
154
155 atlas->instantiate(&onFlushResourceProvider);
156 check(reporter, atlas.get(), 1, 4, 1);
157
158 // Force allocation of a second level
159 GrDrawOpAtlas::AtlasID atlasID;
160 bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasID, 4*32);
161 REPORTER_ASSERT(reporter, result);
162 check(reporter, atlas.get(), 2, 4, 2);
163
164 // Simulate a lot of draws using only the first plot. The last texture should be compacted.
165 for (int i = 0; i < 512; ++i) {
166 atlas->setLastUseToken(atlasIDs[0], uploadTarget.tokenTracker()->nextDrawToken());
167 uploadTarget.issueDrawToken();
168 uploadTarget.flushToken();
169 atlas->compact(uploadTarget.tokenTracker()->nextTokenToFlush());
170 }
171
172 check(reporter, atlas.get(), 1, 4, 1);
173}
174
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500175// This test verifies that the GrAtlasTextOp::onPrepare method correctly handles a failure
176// when allocating an atlas page.
177DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrAtlasTextOpPreparation, reporter, ctxInfo) {
178
179 auto context = ctxInfo.grContext();
180
181 auto gpu = context->contextPriv().getGpu();
182 auto resourceProvider = context->contextPriv().resourceProvider();
183 auto drawingManager = context->contextPriv().drawingManager();
Herb Derby26cbe512018-05-24 14:39:01 -0400184 auto textContext = drawingManager->getTextContext();
Robert Phillipsc994a932018-06-19 13:09:54 -0400185 auto opMemoryPool = context->contextPriv().opMemoryPool();
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500186
187 auto rtc = context->contextPriv().makeDeferredRenderTargetContext(SkBackingFit::kApprox,
188 32, 32,
189 kRGBA_8888_GrPixelConfig,
190 nullptr);
191
192 SkPaint paint;
193 paint.setColor(SK_ColorRED);
194 paint.setLCDRenderText(false);
195 paint.setAntiAlias(false);
196 paint.setSubpixelText(false);
197 GrTextUtils::Paint utilsPaint(&paint, &rtc->colorSpaceInfo());
198
199 const char* text = "a";
200
201 std::unique_ptr<GrDrawOp> op = textContext->createOp_TestingOnly(context, textContext,
202 rtc.get(), paint,
203 SkMatrix::I(), text,
204 16, 16);
Brian Osman532b3f92018-07-11 10:02:07 -0400205 op->finalize(*context->contextPriv().caps(), nullptr);
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500206
207 TestingUploadTarget uploadTarget;
208
209 GrOpFlushState flushState(gpu, resourceProvider, uploadTarget.writeableTokenTracker());
210 GrOpFlushState::OpArgs opArgs = {
211 op.get(),
212 rtc->asRenderTargetProxy(),
213 nullptr,
214 GrXferProcessor::DstProxy(nullptr, SkIPoint::Make(0, 0))
215 };
216
217 // Cripple the atlas manager so it can't allocate any pages. This will force a failure
218 // in the preparation of the text op
Robert Phillips5a66efb2018-03-07 15:13:18 -0500219 auto atlasManager = context->contextPriv().getAtlasManager();
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500220 unsigned int numProxies;
221 atlasManager->getProxies(kA8_GrMaskFormat, &numProxies);
222 atlasManager->setMaxPages_TestingOnly(0);
223
224 flushState.setOpArgs(&opArgs);
225 op->prepare(&flushState);
226 flushState.setOpArgs(nullptr);
Robert Phillipsc994a932018-06-19 13:09:54 -0400227 opMemoryPool->release(std::move(op));
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500228}