blob: c87caf5b54e5b25e5a047c13e4c4e569d6ffdd1b [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"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040023#include "effects/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 Phillips7c525e62018-06-12 10:11:12 -040037 static std::unique_ptr<GrDrawOp> Make(GrContext* context,
38 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 Phillips7c525e62018-06-12 10:11:12 -040044 static std::unique_ptr<GrDrawOp> Make(GrContext* context,
45 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 Osman936fe7d2018-10-30 15:30:35 -040051 const GrColor4h& color() const { return fColor; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -040052
Brian Osman936fe7d2018-10-30 15:30:35 -040053 NonAARectOp(const Helper::MakeArgs& helperArgs, const GrColor4h& 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 Osman532b3f92018-07-11 10:02:07 -040075 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip*) override {
Brian Salomon9a036422017-07-13 17:04:43 -040076 // Set the color to unknown because the subclass may change the color later.
77 GrProcessorAnalysisColor gpColor;
78 gpColor.setToUnknown();
79 // We ignore the clip so pass this rather than the GrAppliedClip param.
80 static GrAppliedClip kNoClip;
Brian Osman532b3f92018-07-11 10:02:07 -040081 return fHelper.xpRequiresDstTexture(caps, &kNoClip, GrProcessorAnalysisCoverage::kNone,
82 &gpColor);
Brian Salomon9a036422017-07-13 17:04:43 -040083 }
84
Robert Phillipseb35f4d2017-03-21 07:56:47 -040085protected:
Brian Osman1be2b7c2018-10-29 16:07:15 -040086 GrColor4h fColor;
87 bool fHasLocalRect;
88 GrQuad fLocalQuad;
89 SkRect fRect;
Robert Phillipseb35f4d2017-03-21 07:56:47 -040090
91private:
Brian Salomon91326c32017-08-09 16:02:19 -040092 void onPrepareDraws(Target* target) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040093 using namespace GrDefaultGeoProcFactory;
94
95 // The vertex attrib order is always pos, color, local coords.
96 static const int kColorOffset = sizeof(SkPoint);
97 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
98
99 sk_sp<GrGeometryProcessor> gp =
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400100 GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(),
101 Color::kPremulGrColorAttribute_Type,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400102 Coverage::kSolid_Type,
103 fHasLocalRect ? LocalCoords::kHasExplicit_Type
104 : LocalCoords::kUnused_Type,
105 SkMatrix::I());
106 if (!gp) {
107 SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n");
108 return;
109 }
110
Brian Salomon92be2f72018-06-19 14:33:47 -0400111 size_t vertexStride = fHasLocalRect
112 ? sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
113 : sizeof(GrDefaultGeoProcFactory::PositionColorAttr);
114 SkASSERT(vertexStride == gp->debugOnly_vertexStride());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400115
116 const GrBuffer* indexBuffer;
117 int firstIndex;
118 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
119 if (!indices) {
120 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
121 return;
122 }
123
124 const GrBuffer* vertexBuffer;
125 int firstVertex;
126 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
127 if (!vertices) {
128 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
129 return;
130 }
131
132 // Setup indices
133 indices[0] = 0;
134 indices[1] = 1;
135 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000136 indices[3] = 2;
137 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400138 indices[5] = 3;
139
140 // Setup positions
141 SkPoint* position = (SkPoint*) vertices;
Brian Salomonec42e152018-05-18 12:52:22 -0400142 SkPointPriv::SetRectTriStrip(position, fRect, vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400143
144 // Setup vertex colors
145 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
146 for (int i = 0; i < 4; ++i) {
Brian Osman1be2b7c2018-10-29 16:07:15 -0400147 *color = fColor.toGrColor();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400148 color = (GrColor*)((intptr_t)color + vertexStride);
149 }
150
151 // Setup local coords
152 if (fHasLocalRect) {
153 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
154 for (int i = 0; i < 4; i++) {
155 *coords = fLocalQuad.point(i);
156 coords = (SkPoint*)((intptr_t) coords + vertexStride);
157 }
158 }
159
Brian Salomon7eae3e02018-08-07 14:02:38 +0000160 GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
161 mesh->setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo);
162 mesh->setVertexData(vertexBuffer, firstVertex);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400163
Brian Salomon49348902018-06-26 09:12:38 -0400164 auto pipe = fHelper.makePipeline(target);
Brian Salomon7eae3e02018-08-07 14:02:38 +0000165 target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400166 }
167
Brian Salomon9a036422017-07-13 17:04:43 -0400168 Helper fHelper;
169
170 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400171};
172
Brian Salomon9a036422017-07-13 17:04:43 -0400173} // anonymous namespace
174
Brian Salomon9a036422017-07-13 17:04:43 -0400175static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
176
177namespace {
178
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400179/*
180 * Atlased ops just draw themselves as textured rects with the texture pixels being
181 * pulled out of the atlas. Their color is based on their ID.
182 */
183class AtlasedRectOp final : public NonAARectOp {
184public:
185 DEFINE_OP_CLASS_ID
186
187 ~AtlasedRectOp() override {
188 fID = -1;
189 }
190
191 const char* name() const override { return "AtlasedRectOp"; }
192
193 int id() const { return fID; }
194
Robert Phillips7c525e62018-06-12 10:11:12 -0400195 static std::unique_ptr<AtlasedRectOp> Make(GrContext* context,
196 GrPaint&& paint,
197 const SkRect& r,
198 int id) {
199 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(context, std::move(paint),
200 r, id).release();
Brian Salomon9a036422017-07-13 17:04:43 -0400201 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
202 }
203
204 // We set the initial color of the NonAARectOp based on the ID.
205 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
206 // pulling from the atlas.
Brian Osman936fe7d2018-10-30 15:30:35 -0400207 AtlasedRectOp(const Helper::MakeArgs& helperArgs, const GrColor4h& color, const SkRect& r,
208 int id)
Brian Osman1be2b7c2018-10-29 16:07:15 -0400209 : INHERITED(helperArgs, GrColor4h::FromGrColor(kColors[id]), r, &kEmptyRect, ClassID())
Brian Salomon9a036422017-07-13 17:04:43 -0400210 , fID(id)
211 , fNext(nullptr) {
212 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400213 }
214
Brian Osman936fe7d2018-10-30 15:30:35 -0400215 void setColor(const GrColor4h& color) { fColor = color; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400216 void setLocalRect(const SkRect& localRect) {
217 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
Brian Salomona33b67c2018-05-17 10:42:14 -0400218 fLocalQuad = GrQuad(localRect);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400219 }
220
221 AtlasedRectOp* next() const { return fNext; }
222 void setNext(AtlasedRectOp* next) {
223 fNext = next;
224 }
225
226private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400227
228 static const int kMaxIDs = 9;
Brian Osman1be2b7c2018-10-29 16:07:15 -0400229 static const GrColor kColors[kMaxIDs];
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400230
231 int fID;
232 // The Atlased ops have an internal singly-linked list of ops that land in the same opList
233 AtlasedRectOp* fNext;
234
235 typedef NonAARectOp INHERITED;
236};
237
Brian Salomon9a036422017-07-13 17:04:43 -0400238} // anonymous namespace
239
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400240const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
241 GrColorPackRGBA(255, 0, 0, 255),
242 GrColorPackRGBA(0, 255, 0, 255),
243 GrColorPackRGBA(0, 0, 255, 255),
244 GrColorPackRGBA(0, 255, 255, 255),
245 GrColorPackRGBA(255, 0, 255, 255),
246 GrColorPackRGBA(255, 255, 0, 255),
247 GrColorPackRGBA(0, 0, 0, 255),
248 GrColorPackRGBA(128, 128, 128, 255),
249 GrColorPackRGBA(255, 255, 255, 255)
250};
251
252static const int kDrawnTileSize = 16;
253
254/*
255 * Rather than performing any rect packing, this atlaser just lays out constant-sized
256 * tiles in an Nx1 row
257 */
258static const int kAtlasTileSize = 2;
259
260/*
261 * This class aggregates the op information required for atlasing
262 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400263class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400264public:
265 AtlasObject() : fDone(false) { }
266
267 ~AtlasObject() override {
268 SkASSERT(fDone);
269 }
270
271 void markAsDone() {
272 fDone = true;
273 }
274
275 // Insert the new op in an internal singly-linked list for 'opListID'
276 void addOp(uint32_t opListID, AtlasedRectOp* op) {
277 LinkedListHeader* header = nullptr;
278 for (int i = 0; i < fOps.count(); ++i) {
279 if (opListID == fOps[i].fID) {
280 header = &(fOps[i]);
281 }
282 }
283
284 if (!header) {
Mike Reed5edcd312018-08-08 11:23:41 -0400285 fOps.push_back({opListID, nullptr});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400286 header = &(fOps[fOps.count()-1]);
287 }
288
289 op->setNext(header->fHead);
290 header->fHead = op;
291 }
292
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500293 int numOps() const { return fOps.count(); }
294
295 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
296 // known until flush time.
297 sk_sp<GrTextureProxy> getAtlasProxy(GrProxyProvider* proxyProvider) {
298 if (fAtlasProxy) {
299 return fAtlasProxy;
300 }
301
Chris Dalton4c458b12018-06-16 17:22:59 -0600302 fAtlasProxy = GrProxyProvider::MakeFullyLazyProxy(
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500303 [](GrResourceProvider* resourceProvider) {
304 if (!resourceProvider) {
305 return sk_sp<GrTexture>();
306 }
307
308 GrSurfaceDesc desc;
309 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500310 // TODO: until partial flushes in MDB lands we're stuck having
311 // all 9 atlas draws occur
312 desc.fWidth = 9 /*this->numOps()*/ * kAtlasTileSize;
313 desc.fHeight = kAtlasTileSize;
314 desc.fConfig = kRGBA_8888_GrPixelConfig;
315
316 return resourceProvider->createTexture(desc, SkBudgeted::kYes,
Chris Daltond004e0b2018-09-27 09:28:03 -0600317 GrResourceProvider::Flags::kNoPendingIO);
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500318 },
319 GrProxyProvider::Renderable::kYes,
320 kBottomLeft_GrSurfaceOrigin,
Chris Dalton4c458b12018-06-16 17:22:59 -0600321 kRGBA_8888_GrPixelConfig,
322 *proxyProvider->caps());
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500323 return fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400324 }
325
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400326 /*
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500327 * This callback creates the atlas and updates the AtlasedRectOps to read from it
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400328 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400329 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400330 const uint32_t* opListIDs, int numOpListIDs,
331 SkTArray<sk_sp<GrRenderTargetContext>>* results) override {
332 SkASSERT(!results->count());
333
334 // Until MDB is landed we will most-likely only have one opList.
335 SkTDArray<LinkedListHeader*> lists;
336 for (int i = 0; i < numOpListIDs; ++i) {
337 if (LinkedListHeader* list = this->getList(opListIDs[i])) {
Mike Reed5edcd312018-08-08 11:23:41 -0400338 lists.push_back(list);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400339 }
340 }
341
342 if (!lists.count()) {
343 return; // nothing to atlas
344 }
345
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500346 if (!resourceProvider->instatiateProxy(fAtlasProxy.get())) {
347 return;
348 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400349
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400350 // At this point all the GrAtlasedOp's should have lined up to read from 'atlasDest' and
351 // there should either be two writes to clear it or no writes.
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500352 SkASSERT(9 == fAtlasProxy->getPendingReadCnt_TestOnly());
353 SkASSERT(2 == fAtlasProxy->getPendingWriteCnt_TestOnly() ||
354 0 == fAtlasProxy->getPendingWriteCnt_TestOnly());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400355 sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500356 fAtlasProxy,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400357 nullptr, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400358
Chris Dalton344e9032017-12-11 15:42:09 -0700359 // clear the atlas
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500360 rtc->clear(nullptr, 0x0, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400361
362 int blocksInAtlas = 0;
363 for (int i = 0; i < lists.count(); ++i) {
364 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
365 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
366 kAtlasTileSize, kAtlasTileSize);
367
368 // For now, we avoid the resource buffer issues and just use clears
369#if 1
Brian Osman1be2b7c2018-10-29 16:07:15 -0400370 rtc->clear(&r, op->color().toGrColor(),
371 GrRenderTargetContext::CanClearFullscreen::kNo);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400372#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400373 GrPaint paint;
Brian Osmancb3d0872018-10-16 15:19:28 -0400374 paint.setColor4f(SkPMColor4f::FromBytes_RGBA(op->color()));
Brian Salomon9a036422017-07-13 17:04:43 -0400375 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
376 SkRect::Make(r)));
377 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400378#endif
379 blocksInAtlas++;
380
381 // Set the atlased Op's color to white (so we know we're not using it for
382 // the final draw).
Brian Osman1be2b7c2018-10-29 16:07:15 -0400383 op->setColor(GrColor4h_WHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400384
385 // Set the atlased Op's localRect to point to where it landed in the atlas
386 op->setLocalRect(SkRect::Make(r));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400387 }
388
389 // We've updated all these ops and we certainly don't want to process them again
390 this->clearOpsFor(lists[i]);
391 }
392
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400393 results->push_back(std::move(rtc));
394 }
395
396private:
397 typedef struct {
398 uint32_t fID;
399 AtlasedRectOp* fHead;
400 } LinkedListHeader;
401
402 LinkedListHeader* getList(uint32_t opListID) {
403 for (int i = 0; i < fOps.count(); ++i) {
404 if (opListID == fOps[i].fID) {
405 return &(fOps[i]);
406 }
407 }
408 return nullptr;
409 }
410
411 void clearOpsFor(LinkedListHeader* header) {
412 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
413 // forget about them in the laziest way possible.
414 header->fHead = nullptr;
415 header->fID = 0; // invalid opList ID
416 }
417
418 // Each opList containing AtlasedRectOps gets its own internal singly-linked list
419 SkTDArray<LinkedListHeader> fOps;
420
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500421 // The fully lazy proxy for the atlas
422 sk_sp<GrTextureProxy> fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400423
424 // Set to true when the testing harness expects this object to be no longer used
425 bool fDone;
426};
427
428// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
429static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500430 sk_sp<GrTextureProxy> atlasProxy) {
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500431 sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeDeferredRenderTargetContext(
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400432 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400433 3*kDrawnTileSize,
434 kDrawnTileSize,
435 kRGBA_8888_GrPixelConfig,
436 nullptr));
437
Chris Dalton344e9032017-12-11 15:42:09 -0700438 rtc->clear(nullptr, GrColorPackRGBA(255, 0, 0, 255),
439 GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400440
441 for (int i = 0; i < 3; ++i) {
442 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
443
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500444 auto fp = GrSimpleTextureEffect::Make(atlasProxy, SkMatrix::I());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400445 GrPaint paint;
446 paint.addColorFragmentProcessor(std::move(fp));
447 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Robert Phillips7c525e62018-06-12 10:11:12 -0400448 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(context,
449 std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400450
451 AtlasedRectOp* sparePtr = op.get();
452
Brian Salomon348a0372018-10-31 10:42:18 -0400453 uint32_t opListID;
454 rtc->priv().testingOnly_addDrawOp(GrNoClip(), std::move(op),
455 [&opListID](GrOp* op, uint32_t id) { opListID = id; });
Chris Daltonf104fec2018-05-22 16:17:48 -0600456 SkASSERT(SK_InvalidUniqueID != opListID);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400457
458 object->addOp(opListID, sparePtr);
459 }
460
461 return rtc->asTextureProxyRef();
462}
463
464// Enable this if you want to debug the final draws w/o having the atlasCallback create the
465// atlas
466#if 0
Chris Dalton12658942017-10-05 19:45:25 -0600467#include "SkImageEncoder.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400468#include "SkGrPriv.h"
Chris Dalton12658942017-10-05 19:45:25 -0600469#include "sk_tool_utils.h"
470
471static void save_bm(const SkBitmap& bm, const char name[]) {
472 bool result = sk_tool_utils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
473 SkASSERT(result);
474}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400475
476sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
477 SkBitmap bm;
478 bm.allocN32Pixels(18, 2, true);
479 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
480 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
481 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
482 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
483 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
484 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
485 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
486 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
487 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
488
489#if 1
490 save_bm(bm, "atlas-fake.png");
491#endif
492
Brian Osman2b23c4b2018-06-01 12:25:08 -0400493 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400494 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
495
496 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
497 context->textureProvider(),
498 desc, SkBudgeted::kYes,
499 bm.getPixels(), bm.rowBytes());
500
501 return sk_ref_sp(tmp->asTextureProxy());
502}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400503#endif
504
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500505
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400506static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
507 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
508 REPORTER_ASSERT(reporter, expected == readback);
509 if (expected != readback) {
510 SkDebugf("Color mismatch: %x %x\n", expected, readback);
511 }
512}
513
514/*
515 * For the atlasing test we make a DAG that looks like:
516 *
517 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
518 * \ /
519 * \ /
520 * RT4
521 * We then flush RT4 and expect only ops 0-5 to be atlased together.
522 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
523 * R G B C M Y
524 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
525 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500526 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
527 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400528 * R G B C M Y K Grey White
529 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400530DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400531 static const int kNumProxies = 3;
532
533 GrContext* context = ctxInfo.grContext();
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500534 auto proxyProvider = context->contextPriv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400535
Chris Daltonfe199b72017-05-05 11:26:15 -0400536 AtlasObject object;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400537
Chris Daltonfe199b72017-05-05 11:26:15 -0400538 context->contextPriv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400539
540 sk_sp<GrTextureProxy> proxies[kNumProxies];
541 for (int i = 0; i < kNumProxies; ++i) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500542 proxies[i] = make_upstream_image(context, &object, i*3,
543 object.getAtlasProxy(proxyProvider));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400544 }
545
546 static const int kFinalWidth = 6*kDrawnTileSize;
547 static const int kFinalHeight = kDrawnTileSize;
548
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500549 sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeDeferredRenderTargetContext(
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400550 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400551 kFinalWidth,
552 kFinalHeight,
553 kRGBA_8888_GrPixelConfig,
554 nullptr));
555
Chris Dalton344e9032017-12-11 15:42:09 -0700556 rtc->clear(nullptr, 0xFFFFFFFF, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400557
558 // Note that this doesn't include the third texture proxy
559 for (int i = 0; i < kNumProxies-1; ++i) {
560 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
561
562 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
563
564 GrPaint paint;
Brian Osman2240be92017-10-18 13:15:13 -0400565 auto fp = GrSimpleTextureEffect::Make(std::move(proxies[i]), t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400566 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
567 paint.addColorFragmentProcessor(std::move(fp));
568
569 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
570 }
571
Greg Daniela5cb7812017-06-16 09:45:32 -0400572 rtc->prepareForExternalIO(0, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400573
574 SkBitmap readBack;
575 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
576
577 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
578 readBack.rowBytes(), 0, 0);
579 SkASSERT(result);
580
Chris Daltonfe199b72017-05-05 11:26:15 -0400581 context->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
582
583 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400584
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400585 int x = kDrawnTileSize/2;
586 test_color(reporter, readBack, x, SK_ColorRED);
587 x += kDrawnTileSize;
588 test_color(reporter, readBack, x, SK_ColorGREEN);
589 x += kDrawnTileSize;
590 test_color(reporter, readBack, x, SK_ColorBLUE);
591 x += kDrawnTileSize;
592 test_color(reporter, readBack, x, SK_ColorCYAN);
593 x += kDrawnTileSize;
594 test_color(reporter, readBack, x, SK_ColorMAGENTA);
595 x += kDrawnTileSize;
596 test_color(reporter, readBack, x, SK_ColorYELLOW);
597}