blob: 3c97842096fdd800f29a881508dfc617f0623851 [file] [log] [blame]
Robert Phillipseb35f4d2017-03-21 07:56:47 -04001/*
2 * Copyright 2017 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 "Test.h"
9
Greg Daniela5cb7812017-06-16 09:45:32 -040010#include "GrBackendSemaphore.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040011#include "GrClip.h"
12#include "GrContextPriv.h"
13#include "GrDefaultGeoProcFactory.h"
Chris Daltonfe199b72017-05-05 11:26:15 -040014#include "GrOnFlushResourceProvider.h"
Robert Phillips0bd24dc2018-01-16 08:06:32 -050015#include "GrProxyProvider.h"
Robert Phillips7d79e7b2018-02-14 11:09:57 -050016#include "GrQuad.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040017#include "GrRenderTargetContextPriv.h"
18#include "GrResourceProvider.h"
Robert Phillips7d79e7b2018-02-14 11:09:57 -050019#include "GrTexture.h"
20
Mike Reed75ae4212018-01-23 11:24:08 -050021#include "SkBitmap.h"
Cary Clark74f623d2017-11-06 20:02:02 -050022#include "SkPointPriv.h"
Ethan Nicholas21a9b562019-04-10 12:06:19 -040023#include "effects/generated/GrSimpleTextureEffect.h"
Brian Salomon9a036422017-07-13 17:04:43 -040024#include "ops/GrSimpleMeshDrawOpHelper.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040025
Brian Salomon9a036422017-07-13 17:04:43 -040026namespace {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040027// This is a simplified mesh drawing op that can be used in the atlas generation test.
28// Please see AtlasedRectOp below.
Brian Salomon9a036422017-07-13 17:04:43 -040029class NonAARectOp : public GrMeshDrawOp {
30protected:
31 using Helper = GrSimpleMeshDrawOpHelper;
32
Robert Phillipseb35f4d2017-03-21 07:56:47 -040033public:
34 DEFINE_OP_CLASS_ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -040035
36 // This creates an instance of a simple non-AA solid color rect-drawing Op
Robert Phillipsb97da532019-02-12 15:24:12 -050037 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040038 GrPaint&& paint,
39 const SkRect& r) {
40 return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, nullptr, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040041 }
42
43 // This creates an instance of a simple non-AA textured rect-drawing Op
Robert Phillipsb97da532019-02-12 15:24:12 -050044 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040045 GrPaint&& paint,
46 const SkRect& r,
47 const SkRect& local) {
48 return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, &local, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040049 }
50
Brian Osmancf860852018-10-31 14:04:39 -040051 const SkPMColor4f& color() const { return fColor; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -040052
Brian Osmancf860852018-10-31 14:04:39 -040053 NonAARectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Salomon9a036422017-07-13 17:04:43 -040054 const SkRect* localRect, int32_t classID)
55 : INHERITED(classID)
56 , fColor(color)
57 , fHasLocalRect(SkToBool(localRect))
58 , fRect(r)
59 , fHelper(helperArgs, GrAAType::kNone) {
60 if (fHasLocalRect) {
Brian Salomona33b67c2018-05-17 10:42:14 -040061 fLocalQuad = GrQuad(*localRect);
Brian Salomon9a036422017-07-13 17:04:43 -040062 }
63 // Choose some conservative values for aa bloat and zero area.
64 this->setBounds(r, HasAABloat::kYes, IsZeroArea::kYes);
65 }
66
Robert Phillipsb493eeb2017-09-13 13:10:52 -040067 const char* name() const override { return "NonAARectOp"; }
68
Brian Salomon7d94bb52018-10-12 14:37:19 -040069 void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -040070 fHelper.visitProxies(func);
71 }
72
Brian Salomon9a036422017-07-13 17:04:43 -040073 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
74
Brian Osman5ced0bf2019-03-15 10:15:29 -040075 GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip*,
76 GrFSAAType fsaaType, GrClampType clampType) override {
Brian Salomon9a036422017-07-13 17:04:43 -040077 // Set the color to unknown because the subclass may change the color later.
78 GrProcessorAnalysisColor gpColor;
79 gpColor.setToUnknown();
80 // We ignore the clip so pass this rather than the GrAppliedClip param.
81 static GrAppliedClip kNoClip;
Chris Daltonb8fff0d2019-03-05 10:11:58 -070082 return fHelper.finalizeProcessors(
Brian Osman5ced0bf2019-03-15 10:15:29 -040083 caps, &kNoClip, fsaaType, clampType, GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomon9a036422017-07-13 17:04:43 -040084 }
85
Robert Phillipseb35f4d2017-03-21 07:56:47 -040086protected:
Brian Osmancf860852018-10-31 14:04:39 -040087 SkPMColor4f fColor;
88 bool fHasLocalRect;
89 GrQuad fLocalQuad;
90 SkRect fRect;
Robert Phillipseb35f4d2017-03-21 07:56:47 -040091
92private:
Brian Salomon91326c32017-08-09 16:02:19 -040093 void onPrepareDraws(Target* target) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040094 using namespace GrDefaultGeoProcFactory;
95
96 // The vertex attrib order is always pos, color, local coords.
97 static const int kColorOffset = sizeof(SkPoint);
98 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
99
100 sk_sp<GrGeometryProcessor> gp =
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400101 GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(),
102 Color::kPremulGrColorAttribute_Type,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400103 Coverage::kSolid_Type,
104 fHasLocalRect ? LocalCoords::kHasExplicit_Type
105 : LocalCoords::kUnused_Type,
106 SkMatrix::I());
107 if (!gp) {
108 SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n");
109 return;
110 }
111
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500112 size_t vertexStride = gp->vertexStride();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400113
Brian Salomon12d22642019-01-29 14:38:50 -0500114 sk_sp<const GrBuffer> indexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400115 int firstIndex;
116 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
117 if (!indices) {
118 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
119 return;
120 }
121
Brian Salomon12d22642019-01-29 14:38:50 -0500122 sk_sp<const GrBuffer> vertexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400123 int firstVertex;
124 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
125 if (!vertices) {
126 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
127 return;
128 }
129
130 // Setup indices
131 indices[0] = 0;
132 indices[1] = 1;
133 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000134 indices[3] = 2;
135 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400136 indices[5] = 3;
137
138 // Setup positions
139 SkPoint* position = (SkPoint*) vertices;
Brian Salomonec42e152018-05-18 12:52:22 -0400140 SkPointPriv::SetRectTriStrip(position, fRect, vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400141
142 // Setup vertex colors
143 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
144 for (int i = 0; i < 4; ++i) {
Brian Osmancf860852018-10-31 14:04:39 -0400145 *color = fColor.toBytes_RGBA();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400146 color = (GrColor*)((intptr_t)color + vertexStride);
147 }
148
149 // Setup local coords
150 if (fHasLocalRect) {
151 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
152 for (int i = 0; i < 4; i++) {
153 *coords = fLocalQuad.point(i);
154 coords = (SkPoint*)((intptr_t) coords + vertexStride);
155 }
156 }
157
Brian Salomon7eae3e02018-08-07 14:02:38 +0000158 GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
159 mesh->setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo);
160 mesh->setVertexData(vertexBuffer, firstVertex);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400161
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700162 target->recordDraw(std::move(gp), mesh);
163 }
164
165 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
166 fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400167 }
168
Brian Salomon9a036422017-07-13 17:04:43 -0400169 Helper fHelper;
170
171 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400172};
173
Brian Salomon9a036422017-07-13 17:04:43 -0400174} // anonymous namespace
175
Brian Salomon9a036422017-07-13 17:04:43 -0400176static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
177
178namespace {
179
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400180/*
181 * Atlased ops just draw themselves as textured rects with the texture pixels being
182 * pulled out of the atlas. Their color is based on their ID.
183 */
184class AtlasedRectOp final : public NonAARectOp {
185public:
186 DEFINE_OP_CLASS_ID
187
188 ~AtlasedRectOp() override {
189 fID = -1;
190 }
191
192 const char* name() const override { return "AtlasedRectOp"; }
193
194 int id() const { return fID; }
195
Robert Phillips7c525e62018-06-12 10:11:12 -0400196 static std::unique_ptr<AtlasedRectOp> Make(GrContext* context,
197 GrPaint&& paint,
198 const SkRect& r,
199 int id) {
200 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(context, std::move(paint),
201 r, id).release();
Brian Salomon9a036422017-07-13 17:04:43 -0400202 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
203 }
204
205 // We set the initial color of the NonAARectOp based on the ID.
206 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
207 // pulling from the atlas.
Brian Osmancf860852018-10-31 14:04:39 -0400208 AtlasedRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Osman936fe7d2018-10-30 15:30:35 -0400209 int id)
Brian Osmancf860852018-10-31 14:04:39 -0400210 : INHERITED(helperArgs, SkPMColor4f::FromBytes_RGBA(kColors[id]), r, &kEmptyRect,
211 ClassID())
Brian Salomon9a036422017-07-13 17:04:43 -0400212 , fID(id)
213 , fNext(nullptr) {
214 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400215 }
216
Brian Osmancf860852018-10-31 14:04:39 -0400217 void setColor(const SkPMColor4f& color) { fColor = color; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400218 void setLocalRect(const SkRect& localRect) {
219 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
Brian Salomona33b67c2018-05-17 10:42:14 -0400220 fLocalQuad = GrQuad(localRect);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400221 }
222
223 AtlasedRectOp* next() const { return fNext; }
224 void setNext(AtlasedRectOp* next) {
225 fNext = next;
226 }
227
228private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400229
230 static const int kMaxIDs = 9;
Brian Osman1be2b7c2018-10-29 16:07:15 -0400231 static const GrColor kColors[kMaxIDs];
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400232
233 int fID;
234 // The Atlased ops have an internal singly-linked list of ops that land in the same opList
235 AtlasedRectOp* fNext;
236
237 typedef NonAARectOp INHERITED;
238};
239
Brian Salomon9a036422017-07-13 17:04:43 -0400240} // anonymous namespace
241
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400242const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
243 GrColorPackRGBA(255, 0, 0, 255),
244 GrColorPackRGBA(0, 255, 0, 255),
245 GrColorPackRGBA(0, 0, 255, 255),
246 GrColorPackRGBA(0, 255, 255, 255),
247 GrColorPackRGBA(255, 0, 255, 255),
248 GrColorPackRGBA(255, 255, 0, 255),
249 GrColorPackRGBA(0, 0, 0, 255),
250 GrColorPackRGBA(128, 128, 128, 255),
251 GrColorPackRGBA(255, 255, 255, 255)
252};
253
254static const int kDrawnTileSize = 16;
255
256/*
257 * Rather than performing any rect packing, this atlaser just lays out constant-sized
258 * tiles in an Nx1 row
259 */
260static const int kAtlasTileSize = 2;
261
262/*
263 * This class aggregates the op information required for atlasing
264 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400265class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400266public:
267 AtlasObject() : fDone(false) { }
268
269 ~AtlasObject() override {
270 SkASSERT(fDone);
271 }
272
273 void markAsDone() {
274 fDone = true;
275 }
276
277 // Insert the new op in an internal singly-linked list for 'opListID'
278 void addOp(uint32_t opListID, AtlasedRectOp* op) {
279 LinkedListHeader* header = nullptr;
280 for (int i = 0; i < fOps.count(); ++i) {
281 if (opListID == fOps[i].fID) {
282 header = &(fOps[i]);
283 }
284 }
285
286 if (!header) {
Mike Reed5edcd312018-08-08 11:23:41 -0400287 fOps.push_back({opListID, nullptr});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400288 header = &(fOps[fOps.count()-1]);
289 }
290
291 op->setNext(header->fHead);
292 header->fHead = op;
293 }
294
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500295 int numOps() const { return fOps.count(); }
296
297 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
298 // known until flush time.
Greg Daniel4065d452018-11-16 15:43:41 -0500299 sk_sp<GrTextureProxy> getAtlasProxy(GrProxyProvider* proxyProvider, const GrCaps* caps) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500300 if (fAtlasProxy) {
301 return fAtlasProxy;
302 }
303
Greg Daniel4065d452018-11-16 15:43:41 -0500304 const GrBackendFormat format = caps->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
305
Chris Dalton4c458b12018-06-16 17:22:59 -0600306 fAtlasProxy = GrProxyProvider::MakeFullyLazyProxy(
Brian Salomonb6a3a3b2019-04-01 12:29:34 -0400307 [](GrResourceProvider* resourceProvider)
308 -> GrSurfaceProxy::LazyInstantiationResult {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500309 GrSurfaceDesc desc;
310 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500311 // TODO: until partial flushes in MDB lands we're stuck having
312 // all 9 atlas draws occur
313 desc.fWidth = 9 /*this->numOps()*/ * kAtlasTileSize;
314 desc.fHeight = kAtlasTileSize;
315 desc.fConfig = kRGBA_8888_GrPixelConfig;
316
Brian Salomonb6a3a3b2019-04-01 12:29:34 -0400317 auto texture = resourceProvider->createTexture(
318 desc, SkBudgeted::kYes, GrResourceProvider::Flags::kNoPendingIO);
319 return std::move(texture);
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500320 },
Greg Daniel4065d452018-11-16 15:43:41 -0500321 format,
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500322 GrProxyProvider::Renderable::kYes,
323 kBottomLeft_GrSurfaceOrigin,
Chris Dalton4c458b12018-06-16 17:22:59 -0600324 kRGBA_8888_GrPixelConfig,
325 *proxyProvider->caps());
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500326 return fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400327 }
328
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400329 /*
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500330 * This callback creates the atlas and updates the AtlasedRectOps to read from it
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400331 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400332 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400333 const uint32_t* opListIDs, int numOpListIDs,
334 SkTArray<sk_sp<GrRenderTargetContext>>* results) override {
335 SkASSERT(!results->count());
336
337 // Until MDB is landed we will most-likely only have one opList.
338 SkTDArray<LinkedListHeader*> lists;
339 for (int i = 0; i < numOpListIDs; ++i) {
340 if (LinkedListHeader* list = this->getList(opListIDs[i])) {
Mike Reed5edcd312018-08-08 11:23:41 -0400341 lists.push_back(list);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400342 }
343 }
344
345 if (!lists.count()) {
346 return; // nothing to atlas
347 }
348
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500349 if (!resourceProvider->instatiateProxy(fAtlasProxy.get())) {
350 return;
351 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400352
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400353 // At this point all the GrAtlasedOp's should have lined up to read from 'atlasDest' and
354 // there should either be two writes to clear it or no writes.
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500355 SkASSERT(9 == fAtlasProxy->getPendingReadCnt_TestOnly());
356 SkASSERT(2 == fAtlasProxy->getPendingWriteCnt_TestOnly() ||
357 0 == fAtlasProxy->getPendingWriteCnt_TestOnly());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400358 sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500359 fAtlasProxy,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400360 nullptr, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400361
Chris Dalton344e9032017-12-11 15:42:09 -0700362 // clear the atlas
Brian Osman9a9baae2018-11-05 15:06:26 -0500363 rtc->clear(nullptr, SK_PMColor4fTRANSPARENT,
364 GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400365
366 int blocksInAtlas = 0;
367 for (int i = 0; i < lists.count(); ++i) {
368 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
369 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
370 kAtlasTileSize, kAtlasTileSize);
371
372 // For now, we avoid the resource buffer issues and just use clears
373#if 1
Brian Osman9a9baae2018-11-05 15:06:26 -0500374 rtc->clear(&r, op->color(), GrRenderTargetContext::CanClearFullscreen::kNo);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400375#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400376 GrPaint paint;
Brian Osman9a9baae2018-11-05 15:06:26 -0500377 paint.setColor4f(op->color());
Brian Salomon9a036422017-07-13 17:04:43 -0400378 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
379 SkRect::Make(r)));
380 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400381#endif
382 blocksInAtlas++;
383
384 // Set the atlased Op's color to white (so we know we're not using it for
385 // the final draw).
Brian Osmancf860852018-10-31 14:04:39 -0400386 op->setColor(SK_PMColor4fWHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400387
388 // Set the atlased Op's localRect to point to where it landed in the atlas
389 op->setLocalRect(SkRect::Make(r));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400390 }
391
392 // We've updated all these ops and we certainly don't want to process them again
393 this->clearOpsFor(lists[i]);
394 }
395
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400396 results->push_back(std::move(rtc));
397 }
398
399private:
400 typedef struct {
401 uint32_t fID;
402 AtlasedRectOp* fHead;
403 } LinkedListHeader;
404
405 LinkedListHeader* getList(uint32_t opListID) {
406 for (int i = 0; i < fOps.count(); ++i) {
407 if (opListID == fOps[i].fID) {
408 return &(fOps[i]);
409 }
410 }
411 return nullptr;
412 }
413
414 void clearOpsFor(LinkedListHeader* header) {
415 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
416 // forget about them in the laziest way possible.
417 header->fHead = nullptr;
418 header->fID = 0; // invalid opList ID
419 }
420
421 // Each opList containing AtlasedRectOps gets its own internal singly-linked list
422 SkTDArray<LinkedListHeader> fOps;
423
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500424 // The fully lazy proxy for the atlas
425 sk_sp<GrTextureProxy> fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400426
427 // Set to true when the testing harness expects this object to be no longer used
428 bool fDone;
429};
430
431// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
432static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500433 sk_sp<GrTextureProxy> atlasProxy) {
Greg Daniel4065d452018-11-16 15:43:41 -0500434 const GrBackendFormat format =
Robert Phillips9da87e02019-02-04 13:26:26 -0500435 context->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
Greg Daniel4065d452018-11-16 15:43:41 -0500436
Robert Phillips9da87e02019-02-04 13:26:26 -0500437 sk_sp<GrRenderTargetContext> rtc(context->priv().makeDeferredRenderTargetContext(
Greg Daniel4065d452018-11-16 15:43:41 -0500438 format,
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400439 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400440 3*kDrawnTileSize,
441 kDrawnTileSize,
442 kRGBA_8888_GrPixelConfig,
443 nullptr));
444
Brian Osman9a9baae2018-11-05 15:06:26 -0500445 rtc->clear(nullptr, { 1, 0, 0, 1 }, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400446
447 for (int i = 0; i < 3; ++i) {
448 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
449
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500450 auto fp = GrSimpleTextureEffect::Make(atlasProxy, SkMatrix::I());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400451 GrPaint paint;
452 paint.addColorFragmentProcessor(std::move(fp));
453 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Robert Phillips7c525e62018-06-12 10:11:12 -0400454 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(context,
455 std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400456
457 AtlasedRectOp* sparePtr = op.get();
458
Brian Salomon348a0372018-10-31 10:42:18 -0400459 uint32_t opListID;
460 rtc->priv().testingOnly_addDrawOp(GrNoClip(), std::move(op),
461 [&opListID](GrOp* op, uint32_t id) { opListID = id; });
Chris Daltonf104fec2018-05-22 16:17:48 -0600462 SkASSERT(SK_InvalidUniqueID != opListID);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400463
464 object->addOp(opListID, sparePtr);
465 }
466
467 return rtc->asTextureProxyRef();
468}
469
470// Enable this if you want to debug the final draws w/o having the atlasCallback create the
471// atlas
472#if 0
473#include "SkGrPriv.h"
Mike Kleinea3f0142019-03-20 11:12:10 -0500474#include "SkImageEncoder.h"
475#include "ToolUtils.h"
Chris Dalton12658942017-10-05 19:45:25 -0600476
477static void save_bm(const SkBitmap& bm, const char name[]) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500478 bool result = ToolUtils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
Chris Dalton12658942017-10-05 19:45:25 -0600479 SkASSERT(result);
480}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400481
482sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
483 SkBitmap bm;
484 bm.allocN32Pixels(18, 2, true);
485 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
486 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
487 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
488 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
489 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
490 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
491 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
492 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
493 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
494
495#if 1
496 save_bm(bm, "atlas-fake.png");
497#endif
498
Brian Osman2b23c4b2018-06-01 12:25:08 -0400499 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400500 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
501
502 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
503 context->textureProvider(),
504 desc, SkBudgeted::kYes,
505 bm.getPixels(), bm.rowBytes());
506
507 return sk_ref_sp(tmp->asTextureProxy());
508}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400509#endif
510
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500511
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400512static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
513 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
514 REPORTER_ASSERT(reporter, expected == readback);
515 if (expected != readback) {
516 SkDebugf("Color mismatch: %x %x\n", expected, readback);
517 }
518}
519
520/*
521 * For the atlasing test we make a DAG that looks like:
522 *
523 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
524 * \ /
525 * \ /
526 * RT4
527 * We then flush RT4 and expect only ops 0-5 to be atlased together.
528 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
529 * R G B C M Y
530 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
531 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500532 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
533 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400534 * R G B C M Y K Grey White
535 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400536DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400537 static const int kNumProxies = 3;
538
539 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500540 auto proxyProvider = context->priv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400541
Chris Daltonfe199b72017-05-05 11:26:15 -0400542 AtlasObject object;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400543
Robert Phillips9da87e02019-02-04 13:26:26 -0500544 context->priv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400545
546 sk_sp<GrTextureProxy> proxies[kNumProxies];
547 for (int i = 0; i < kNumProxies; ++i) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500548 proxies[i] = make_upstream_image(context, &object, i*3,
Greg Daniel4065d452018-11-16 15:43:41 -0500549 object.getAtlasProxy(proxyProvider,
Robert Phillips9da87e02019-02-04 13:26:26 -0500550 context->priv().caps()));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400551 }
552
553 static const int kFinalWidth = 6*kDrawnTileSize;
554 static const int kFinalHeight = kDrawnTileSize;
555
Greg Daniel4065d452018-11-16 15:43:41 -0500556 const GrBackendFormat format =
Robert Phillips9da87e02019-02-04 13:26:26 -0500557 context->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
Greg Daniel4065d452018-11-16 15:43:41 -0500558
Robert Phillips9da87e02019-02-04 13:26:26 -0500559 sk_sp<GrRenderTargetContext> rtc(context->priv().makeDeferredRenderTargetContext(
Greg Daniel4065d452018-11-16 15:43:41 -0500560 format,
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400561 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400562 kFinalWidth,
563 kFinalHeight,
564 kRGBA_8888_GrPixelConfig,
565 nullptr));
566
Brian Osman9a9baae2018-11-05 15:06:26 -0500567 rtc->clear(nullptr, SK_PMColor4fWHITE, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400568
569 // Note that this doesn't include the third texture proxy
570 for (int i = 0; i < kNumProxies-1; ++i) {
571 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
572
573 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
574
575 GrPaint paint;
Brian Osman2240be92017-10-18 13:15:13 -0400576 auto fp = GrSimpleTextureEffect::Make(std::move(proxies[i]), t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400577 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
578 paint.addColorFragmentProcessor(std::move(fp));
579
580 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
581 }
582
Greg Danielbae71212019-03-01 15:24:35 -0500583 rtc->prepareForExternalIO(SkSurface::BackendSurfaceAccess::kNoAccess,
Greg Danielb9990e42019-04-10 16:28:52 -0400584 kNone_GrFlushFlags, 0, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400585
586 SkBitmap readBack;
587 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
588
589 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
590 readBack.rowBytes(), 0, 0);
591 SkASSERT(result);
592
Robert Phillips9da87e02019-02-04 13:26:26 -0500593 context->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
Chris Daltonfe199b72017-05-05 11:26:15 -0400594
595 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400596
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400597 int x = kDrawnTileSize/2;
598 test_color(reporter, readBack, x, SK_ColorRED);
599 x += kDrawnTileSize;
600 test_color(reporter, readBack, x, SK_ColorGREEN);
601 x += kDrawnTileSize;
602 test_color(reporter, readBack, x, SK_ColorBLUE);
603 x += kDrawnTileSize;
604 test_color(reporter, readBack, x, SK_ColorCYAN);
605 x += kDrawnTileSize;
606 test_color(reporter, readBack, x, SK_ColorMAGENTA);
607 x += kDrawnTileSize;
608 test_color(reporter, readBack, x, SK_ColorYELLOW);
609}