blob: efbc43a6ef495c6fc31a25ec1646a7c63167da16 [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
51 GrColor color() const { return fColor; }
52
Brian Salomon9a036422017-07-13 17:04:43 -040053 NonAARectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r,
54 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
Robert Phillipsf1748f52017-09-14 14:11:24 -040069 void visitProxies(const VisitProxyFunc& func) 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:
Robert Phillipseb35f4d2017-03-21 07:56:47 -040086 GrColor fColor;
87 bool fHasLocalRect;
88 GrQuad fLocalQuad;
89 SkRect fRect;
90
91private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -040092 bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
93
Brian Salomon91326c32017-08-09 16:02:19 -040094 void onPrepareDraws(Target* target) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040095 using namespace GrDefaultGeoProcFactory;
96
97 // The vertex attrib order is always pos, color, local coords.
98 static const int kColorOffset = sizeof(SkPoint);
99 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
100
101 sk_sp<GrGeometryProcessor> gp =
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400102 GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(),
103 Color::kPremulGrColorAttribute_Type,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400104 Coverage::kSolid_Type,
105 fHasLocalRect ? LocalCoords::kHasExplicit_Type
106 : LocalCoords::kUnused_Type,
107 SkMatrix::I());
108 if (!gp) {
109 SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n");
110 return;
111 }
112
Brian Salomon92be2f72018-06-19 14:33:47 -0400113 size_t vertexStride = fHasLocalRect
114 ? sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
115 : sizeof(GrDefaultGeoProcFactory::PositionColorAttr);
116 SkASSERT(vertexStride == gp->debugOnly_vertexStride());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400117
118 const GrBuffer* indexBuffer;
119 int firstIndex;
120 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
121 if (!indices) {
122 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
123 return;
124 }
125
126 const GrBuffer* vertexBuffer;
127 int firstVertex;
128 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
129 if (!vertices) {
130 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
131 return;
132 }
133
134 // Setup indices
135 indices[0] = 0;
136 indices[1] = 1;
137 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000138 indices[3] = 2;
139 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400140 indices[5] = 3;
141
142 // Setup positions
143 SkPoint* position = (SkPoint*) vertices;
Brian Salomonec42e152018-05-18 12:52:22 -0400144 SkPointPriv::SetRectTriStrip(position, fRect, vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400145
146 // Setup vertex colors
147 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
148 for (int i = 0; i < 4; ++i) {
149 *color = fColor;
150 color = (GrColor*)((intptr_t)color + vertexStride);
151 }
152
153 // Setup local coords
154 if (fHasLocalRect) {
155 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
156 for (int i = 0; i < 4; i++) {
157 *coords = fLocalQuad.point(i);
158 coords = (SkPoint*)((intptr_t) coords + vertexStride);
159 }
160 }
161
Chris Dalton3809bab2017-06-13 10:55:06 -0600162 GrMesh mesh(GrPrimitiveType::kTriangles);
Brian Salomon802cb312018-06-08 18:05:20 -0400163 mesh.setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo);
Chris Dalton114a3c02017-05-26 15:17:19 -0600164 mesh.setVertexData(vertexBuffer, firstVertex);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400165
Brian Salomon49348902018-06-26 09:12:38 -0400166 auto pipe = fHelper.makePipeline(target);
167 target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400168 }
169
Brian Salomon9a036422017-07-13 17:04:43 -0400170 Helper fHelper;
171
172 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400173};
174
Brian Salomon9a036422017-07-13 17:04:43 -0400175} // anonymous namespace
176
Brian Salomon9a036422017-07-13 17:04:43 -0400177static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
178
179namespace {
180
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400181/*
182 * Atlased ops just draw themselves as textured rects with the texture pixels being
183 * pulled out of the atlas. Their color is based on their ID.
184 */
185class AtlasedRectOp final : public NonAARectOp {
186public:
187 DEFINE_OP_CLASS_ID
188
189 ~AtlasedRectOp() override {
190 fID = -1;
191 }
192
193 const char* name() const override { return "AtlasedRectOp"; }
194
195 int id() const { return fID; }
196
Robert Phillips7c525e62018-06-12 10:11:12 -0400197 static std::unique_ptr<AtlasedRectOp> Make(GrContext* context,
198 GrPaint&& paint,
199 const SkRect& r,
200 int id) {
201 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(context, std::move(paint),
202 r, id).release();
Brian Salomon9a036422017-07-13 17:04:43 -0400203 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
204 }
205
206 // We set the initial color of the NonAARectOp based on the ID.
207 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
208 // pulling from the atlas.
209 AtlasedRectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r, int id)
210 : INHERITED(helperArgs, kColors[id], r, &kEmptyRect, ClassID())
211 , fID(id)
212 , fNext(nullptr) {
213 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400214 }
215
216 void setColor(GrColor color) { fColor = color; }
217 void setLocalRect(const SkRect& localRect) {
218 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
Brian Salomona33b67c2018-05-17 10:42:14 -0400219 fLocalQuad = GrQuad(localRect);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400220 }
221
222 AtlasedRectOp* next() const { return fNext; }
223 void setNext(AtlasedRectOp* next) {
224 fNext = next;
225 }
226
227private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400228
229 static const int kMaxIDs = 9;
230 static const SkColor kColors[kMaxIDs];
231
232 int fID;
233 // The Atlased ops have an internal singly-linked list of ops that land in the same opList
234 AtlasedRectOp* fNext;
235
236 typedef NonAARectOp INHERITED;
237};
238
Brian Salomon9a036422017-07-13 17:04:43 -0400239} // anonymous namespace
240
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400241const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
242 GrColorPackRGBA(255, 0, 0, 255),
243 GrColorPackRGBA(0, 255, 0, 255),
244 GrColorPackRGBA(0, 0, 255, 255),
245 GrColorPackRGBA(0, 255, 255, 255),
246 GrColorPackRGBA(255, 0, 255, 255),
247 GrColorPackRGBA(255, 255, 0, 255),
248 GrColorPackRGBA(0, 0, 0, 255),
249 GrColorPackRGBA(128, 128, 128, 255),
250 GrColorPackRGBA(255, 255, 255, 255)
251};
252
253static const int kDrawnTileSize = 16;
254
255/*
256 * Rather than performing any rect packing, this atlaser just lays out constant-sized
257 * tiles in an Nx1 row
258 */
259static const int kAtlasTileSize = 2;
260
261/*
262 * This class aggregates the op information required for atlasing
263 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400264class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400265public:
266 AtlasObject() : fDone(false) { }
267
268 ~AtlasObject() override {
269 SkASSERT(fDone);
270 }
271
272 void markAsDone() {
273 fDone = true;
274 }
275
276 // Insert the new op in an internal singly-linked list for 'opListID'
277 void addOp(uint32_t opListID, AtlasedRectOp* op) {
278 LinkedListHeader* header = nullptr;
279 for (int i = 0; i < fOps.count(); ++i) {
280 if (opListID == fOps[i].fID) {
281 header = &(fOps[i]);
282 }
283 }
284
285 if (!header) {
286 fOps.push({opListID, nullptr});
287 header = &(fOps[fOps.count()-1]);
288 }
289
290 op->setNext(header->fHead);
291 header->fHead = op;
292 }
293
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500294 int numOps() const { return fOps.count(); }
295
296 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
297 // known until flush time.
298 sk_sp<GrTextureProxy> getAtlasProxy(GrProxyProvider* proxyProvider) {
299 if (fAtlasProxy) {
300 return fAtlasProxy;
301 }
302
Chris Dalton4c458b12018-06-16 17:22:59 -0600303 fAtlasProxy = GrProxyProvider::MakeFullyLazyProxy(
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500304 [](GrResourceProvider* resourceProvider) {
305 if (!resourceProvider) {
306 return sk_sp<GrTexture>();
307 }
308
309 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
317 return resourceProvider->createTexture(desc, SkBudgeted::kYes,
318 GrResourceProvider::kNoPendingIO_Flag);
319 },
320 GrProxyProvider::Renderable::kYes,
321 kBottomLeft_GrSurfaceOrigin,
Chris Dalton4c458b12018-06-16 17:22:59 -0600322 kRGBA_8888_GrPixelConfig,
323 *proxyProvider->caps());
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500324 return fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400325 }
326
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400327 /*
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500328 * This callback creates the atlas and updates the AtlasedRectOps to read from it
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400329 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400330 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400331 const uint32_t* opListIDs, int numOpListIDs,
332 SkTArray<sk_sp<GrRenderTargetContext>>* results) override {
333 SkASSERT(!results->count());
334
335 // Until MDB is landed we will most-likely only have one opList.
336 SkTDArray<LinkedListHeader*> lists;
337 for (int i = 0; i < numOpListIDs; ++i) {
338 if (LinkedListHeader* list = this->getList(opListIDs[i])) {
339 lists.push(list);
340 }
341 }
342
343 if (!lists.count()) {
344 return; // nothing to atlas
345 }
346
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500347 if (!resourceProvider->instatiateProxy(fAtlasProxy.get())) {
348 return;
349 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400350
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400351 // At this point all the GrAtlasedOp's should have lined up to read from 'atlasDest' and
352 // there should either be two writes to clear it or no writes.
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500353 SkASSERT(9 == fAtlasProxy->getPendingReadCnt_TestOnly());
354 SkASSERT(2 == fAtlasProxy->getPendingWriteCnt_TestOnly() ||
355 0 == fAtlasProxy->getPendingWriteCnt_TestOnly());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400356 sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500357 fAtlasProxy,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400358 nullptr, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400359
Chris Dalton344e9032017-12-11 15:42:09 -0700360 // clear the atlas
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500361 rtc->clear(nullptr, 0x0, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400362
363 int blocksInAtlas = 0;
364 for (int i = 0; i < lists.count(); ++i) {
365 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
366 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
367 kAtlasTileSize, kAtlasTileSize);
368
369 // For now, we avoid the resource buffer issues and just use clears
370#if 1
Chris Dalton344e9032017-12-11 15:42:09 -0700371 rtc->clear(&r, op->color(), GrRenderTargetContext::CanClearFullscreen::kNo);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400372#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400373 GrPaint paint;
Brian Salomon9a036422017-07-13 17:04:43 -0400374 paint.setColor4f(GrColor4f::FromGrColor(op->color()));
375 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).
383 op->setColor(0xFFFFFFFF);
384
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 Salomon9a036422017-07-13 17:04:43 -0400453 uint32_t opListID = rtc->priv().testingOnly_addDrawOp(std::move(op));
Chris Daltonf104fec2018-05-22 16:17:48 -0600454 SkASSERT(SK_InvalidUniqueID != opListID);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400455
456 object->addOp(opListID, sparePtr);
457 }
458
459 return rtc->asTextureProxyRef();
460}
461
462// Enable this if you want to debug the final draws w/o having the atlasCallback create the
463// atlas
464#if 0
Chris Dalton12658942017-10-05 19:45:25 -0600465#include "SkImageEncoder.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400466#include "SkGrPriv.h"
Chris Dalton12658942017-10-05 19:45:25 -0600467#include "sk_tool_utils.h"
468
469static void save_bm(const SkBitmap& bm, const char name[]) {
470 bool result = sk_tool_utils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
471 SkASSERT(result);
472}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400473
474sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
475 SkBitmap bm;
476 bm.allocN32Pixels(18, 2, true);
477 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
478 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
479 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
480 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
481 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
482 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
483 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
484 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
485 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
486
487#if 1
488 save_bm(bm, "atlas-fake.png");
489#endif
490
Brian Osman2b23c4b2018-06-01 12:25:08 -0400491 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400492 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
493
494 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
495 context->textureProvider(),
496 desc, SkBudgeted::kYes,
497 bm.getPixels(), bm.rowBytes());
498
499 return sk_ref_sp(tmp->asTextureProxy());
500}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400501#endif
502
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500503
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400504static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
505 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
506 REPORTER_ASSERT(reporter, expected == readback);
507 if (expected != readback) {
508 SkDebugf("Color mismatch: %x %x\n", expected, readback);
509 }
510}
511
512/*
513 * For the atlasing test we make a DAG that looks like:
514 *
515 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
516 * \ /
517 * \ /
518 * RT4
519 * We then flush RT4 and expect only ops 0-5 to be atlased together.
520 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
521 * R G B C M Y
522 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
523 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500524 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
525 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400526 * R G B C M Y K Grey White
527 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400528DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400529 static const int kNumProxies = 3;
530
531 GrContext* context = ctxInfo.grContext();
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500532 auto proxyProvider = context->contextPriv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400533
Chris Daltonfe199b72017-05-05 11:26:15 -0400534 AtlasObject object;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400535
Chris Daltonfe199b72017-05-05 11:26:15 -0400536 context->contextPriv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400537
538 sk_sp<GrTextureProxy> proxies[kNumProxies];
539 for (int i = 0; i < kNumProxies; ++i) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500540 proxies[i] = make_upstream_image(context, &object, i*3,
541 object.getAtlasProxy(proxyProvider));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400542 }
543
544 static const int kFinalWidth = 6*kDrawnTileSize;
545 static const int kFinalHeight = kDrawnTileSize;
546
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500547 sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeDeferredRenderTargetContext(
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400548 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400549 kFinalWidth,
550 kFinalHeight,
551 kRGBA_8888_GrPixelConfig,
552 nullptr));
553
Chris Dalton344e9032017-12-11 15:42:09 -0700554 rtc->clear(nullptr, 0xFFFFFFFF, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400555
556 // Note that this doesn't include the third texture proxy
557 for (int i = 0; i < kNumProxies-1; ++i) {
558 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
559
560 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
561
562 GrPaint paint;
Brian Osman2240be92017-10-18 13:15:13 -0400563 auto fp = GrSimpleTextureEffect::Make(std::move(proxies[i]), t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400564 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
565 paint.addColorFragmentProcessor(std::move(fp));
566
567 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
568 }
569
Greg Daniela5cb7812017-06-16 09:45:32 -0400570 rtc->prepareForExternalIO(0, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400571
572 SkBitmap readBack;
573 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
574
575 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
576 readBack.rowBytes(), 0, 0);
577 SkASSERT(result);
578
Chris Daltonfe199b72017-05-05 11:26:15 -0400579 context->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
580
581 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400582
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400583 int x = kDrawnTileSize/2;
584 test_color(reporter, readBack, x, SK_ColorRED);
585 x += kDrawnTileSize;
586 test_color(reporter, readBack, x, SK_ColorGREEN);
587 x += kDrawnTileSize;
588 test_color(reporter, readBack, x, SK_ColorBLUE);
589 x += kDrawnTileSize;
590 test_color(reporter, readBack, x, SK_ColorCYAN);
591 x += kDrawnTileSize;
592 test_color(reporter, readBack, x, SK_ColorMAGENTA);
593 x += kDrawnTileSize;
594 test_color(reporter, readBack, x, SK_ColorYELLOW);
595}