blob: 805be6a8558c0034ea9163c1bbb22e70730c9291 [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 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 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 Osmancf860852018-10-31 14:04:39 -040086 SkPMColor4f 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 Osmanf04fb3c2018-11-12 15:34:00 -0500111 size_t vertexStride = gp->vertexStride();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400112
113 const GrBuffer* indexBuffer;
114 int firstIndex;
115 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
116 if (!indices) {
117 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
118 return;
119 }
120
121 const GrBuffer* vertexBuffer;
122 int firstVertex;
123 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
124 if (!vertices) {
125 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
126 return;
127 }
128
129 // Setup indices
130 indices[0] = 0;
131 indices[1] = 1;
132 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000133 indices[3] = 2;
134 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400135 indices[5] = 3;
136
137 // Setup positions
138 SkPoint* position = (SkPoint*) vertices;
Brian Salomonec42e152018-05-18 12:52:22 -0400139 SkPointPriv::SetRectTriStrip(position, fRect, vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400140
141 // Setup vertex colors
142 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
143 for (int i = 0; i < 4; ++i) {
Brian Osmancf860852018-10-31 14:04:39 -0400144 *color = fColor.toBytes_RGBA();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400145 color = (GrColor*)((intptr_t)color + vertexStride);
146 }
147
148 // Setup local coords
149 if (fHasLocalRect) {
150 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
151 for (int i = 0; i < 4; i++) {
152 *coords = fLocalQuad.point(i);
153 coords = (SkPoint*)((intptr_t) coords + vertexStride);
154 }
155 }
156
Brian Salomon7eae3e02018-08-07 14:02:38 +0000157 GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
158 mesh->setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo);
159 mesh->setVertexData(vertexBuffer, firstVertex);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400160
Brian Salomon49348902018-06-26 09:12:38 -0400161 auto pipe = fHelper.makePipeline(target);
Brian Salomon7eae3e02018-08-07 14:02:38 +0000162 target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400163 }
164
Brian Salomon9a036422017-07-13 17:04:43 -0400165 Helper fHelper;
166
167 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400168};
169
Brian Salomon9a036422017-07-13 17:04:43 -0400170} // anonymous namespace
171
Brian Salomon9a036422017-07-13 17:04:43 -0400172static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
173
174namespace {
175
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400176/*
177 * Atlased ops just draw themselves as textured rects with the texture pixels being
178 * pulled out of the atlas. Their color is based on their ID.
179 */
180class AtlasedRectOp final : public NonAARectOp {
181public:
182 DEFINE_OP_CLASS_ID
183
184 ~AtlasedRectOp() override {
185 fID = -1;
186 }
187
188 const char* name() const override { return "AtlasedRectOp"; }
189
190 int id() const { return fID; }
191
Robert Phillips7c525e62018-06-12 10:11:12 -0400192 static std::unique_ptr<AtlasedRectOp> Make(GrContext* context,
193 GrPaint&& paint,
194 const SkRect& r,
195 int id) {
196 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(context, std::move(paint),
197 r, id).release();
Brian Salomon9a036422017-07-13 17:04:43 -0400198 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
199 }
200
201 // We set the initial color of the NonAARectOp based on the ID.
202 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
203 // pulling from the atlas.
Brian Osmancf860852018-10-31 14:04:39 -0400204 AtlasedRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Osman936fe7d2018-10-30 15:30:35 -0400205 int id)
Brian Osmancf860852018-10-31 14:04:39 -0400206 : INHERITED(helperArgs, SkPMColor4f::FromBytes_RGBA(kColors[id]), r, &kEmptyRect,
207 ClassID())
Brian Salomon9a036422017-07-13 17:04:43 -0400208 , fID(id)
209 , fNext(nullptr) {
210 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400211 }
212
Brian Osmancf860852018-10-31 14:04:39 -0400213 void setColor(const SkPMColor4f& color) { fColor = color; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400214 void setLocalRect(const SkRect& localRect) {
215 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
Brian Salomona33b67c2018-05-17 10:42:14 -0400216 fLocalQuad = GrQuad(localRect);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400217 }
218
219 AtlasedRectOp* next() const { return fNext; }
220 void setNext(AtlasedRectOp* next) {
221 fNext = next;
222 }
223
224private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400225
226 static const int kMaxIDs = 9;
Brian Osman1be2b7c2018-10-29 16:07:15 -0400227 static const GrColor kColors[kMaxIDs];
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400228
229 int fID;
230 // The Atlased ops have an internal singly-linked list of ops that land in the same opList
231 AtlasedRectOp* fNext;
232
233 typedef NonAARectOp INHERITED;
234};
235
Brian Salomon9a036422017-07-13 17:04:43 -0400236} // anonymous namespace
237
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400238const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
239 GrColorPackRGBA(255, 0, 0, 255),
240 GrColorPackRGBA(0, 255, 0, 255),
241 GrColorPackRGBA(0, 0, 255, 255),
242 GrColorPackRGBA(0, 255, 255, 255),
243 GrColorPackRGBA(255, 0, 255, 255),
244 GrColorPackRGBA(255, 255, 0, 255),
245 GrColorPackRGBA(0, 0, 0, 255),
246 GrColorPackRGBA(128, 128, 128, 255),
247 GrColorPackRGBA(255, 255, 255, 255)
248};
249
250static const int kDrawnTileSize = 16;
251
252/*
253 * Rather than performing any rect packing, this atlaser just lays out constant-sized
254 * tiles in an Nx1 row
255 */
256static const int kAtlasTileSize = 2;
257
258/*
259 * This class aggregates the op information required for atlasing
260 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400261class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400262public:
263 AtlasObject() : fDone(false) { }
264
265 ~AtlasObject() override {
266 SkASSERT(fDone);
267 }
268
269 void markAsDone() {
270 fDone = true;
271 }
272
273 // Insert the new op in an internal singly-linked list for 'opListID'
274 void addOp(uint32_t opListID, AtlasedRectOp* op) {
275 LinkedListHeader* header = nullptr;
276 for (int i = 0; i < fOps.count(); ++i) {
277 if (opListID == fOps[i].fID) {
278 header = &(fOps[i]);
279 }
280 }
281
282 if (!header) {
Mike Reed5edcd312018-08-08 11:23:41 -0400283 fOps.push_back({opListID, nullptr});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400284 header = &(fOps[fOps.count()-1]);
285 }
286
287 op->setNext(header->fHead);
288 header->fHead = op;
289 }
290
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500291 int numOps() const { return fOps.count(); }
292
293 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
294 // known until flush time.
Greg Daniel4065d452018-11-16 15:43:41 -0500295 sk_sp<GrTextureProxy> getAtlasProxy(GrProxyProvider* proxyProvider, const GrCaps* caps) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500296 if (fAtlasProxy) {
297 return fAtlasProxy;
298 }
299
Greg Daniel4065d452018-11-16 15:43:41 -0500300 const GrBackendFormat format = caps->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
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 },
Greg Daniel4065d452018-11-16 15:43:41 -0500319 format,
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500320 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])) {
Mike Reed5edcd312018-08-08 11:23:41 -0400339 lists.push_back(list);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400340 }
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
Brian Osman9a9baae2018-11-05 15:06:26 -0500361 rtc->clear(nullptr, SK_PMColor4fTRANSPARENT,
362 GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400363
364 int blocksInAtlas = 0;
365 for (int i = 0; i < lists.count(); ++i) {
366 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
367 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
368 kAtlasTileSize, kAtlasTileSize);
369
370 // For now, we avoid the resource buffer issues and just use clears
371#if 1
Brian Osman9a9baae2018-11-05 15:06:26 -0500372 rtc->clear(&r, op->color(), GrRenderTargetContext::CanClearFullscreen::kNo);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400373#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400374 GrPaint paint;
Brian Osman9a9baae2018-11-05 15:06:26 -0500375 paint.setColor4f(op->color());
Brian Salomon9a036422017-07-13 17:04:43 -0400376 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
377 SkRect::Make(r)));
378 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400379#endif
380 blocksInAtlas++;
381
382 // Set the atlased Op's color to white (so we know we're not using it for
383 // the final draw).
Brian Osmancf860852018-10-31 14:04:39 -0400384 op->setColor(SK_PMColor4fWHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400385
386 // Set the atlased Op's localRect to point to where it landed in the atlas
387 op->setLocalRect(SkRect::Make(r));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400388 }
389
390 // We've updated all these ops and we certainly don't want to process them again
391 this->clearOpsFor(lists[i]);
392 }
393
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400394 results->push_back(std::move(rtc));
395 }
396
397private:
398 typedef struct {
399 uint32_t fID;
400 AtlasedRectOp* fHead;
401 } LinkedListHeader;
402
403 LinkedListHeader* getList(uint32_t opListID) {
404 for (int i = 0; i < fOps.count(); ++i) {
405 if (opListID == fOps[i].fID) {
406 return &(fOps[i]);
407 }
408 }
409 return nullptr;
410 }
411
412 void clearOpsFor(LinkedListHeader* header) {
413 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
414 // forget about them in the laziest way possible.
415 header->fHead = nullptr;
416 header->fID = 0; // invalid opList ID
417 }
418
419 // Each opList containing AtlasedRectOps gets its own internal singly-linked list
420 SkTDArray<LinkedListHeader> fOps;
421
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500422 // The fully lazy proxy for the atlas
423 sk_sp<GrTextureProxy> fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400424
425 // Set to true when the testing harness expects this object to be no longer used
426 bool fDone;
427};
428
429// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
430static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500431 sk_sp<GrTextureProxy> atlasProxy) {
Greg Daniel4065d452018-11-16 15:43:41 -0500432 const GrBackendFormat format =
433 context->contextPriv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
434
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500435 sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeDeferredRenderTargetContext(
Greg Daniel4065d452018-11-16 15:43:41 -0500436 format,
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400437 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400438 3*kDrawnTileSize,
439 kDrawnTileSize,
440 kRGBA_8888_GrPixelConfig,
441 nullptr));
442
Brian Osman9a9baae2018-11-05 15:06:26 -0500443 rtc->clear(nullptr, { 1, 0, 0, 1 }, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400444
445 for (int i = 0; i < 3; ++i) {
446 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
447
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500448 auto fp = GrSimpleTextureEffect::Make(atlasProxy, SkMatrix::I());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400449 GrPaint paint;
450 paint.addColorFragmentProcessor(std::move(fp));
451 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Robert Phillips7c525e62018-06-12 10:11:12 -0400452 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(context,
453 std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400454
455 AtlasedRectOp* sparePtr = op.get();
456
Brian Salomon348a0372018-10-31 10:42:18 -0400457 uint32_t opListID;
458 rtc->priv().testingOnly_addDrawOp(GrNoClip(), std::move(op),
459 [&opListID](GrOp* op, uint32_t id) { opListID = id; });
Chris Daltonf104fec2018-05-22 16:17:48 -0600460 SkASSERT(SK_InvalidUniqueID != opListID);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400461
462 object->addOp(opListID, sparePtr);
463 }
464
465 return rtc->asTextureProxyRef();
466}
467
468// Enable this if you want to debug the final draws w/o having the atlasCallback create the
469// atlas
470#if 0
Chris Dalton12658942017-10-05 19:45:25 -0600471#include "SkImageEncoder.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400472#include "SkGrPriv.h"
Chris Dalton12658942017-10-05 19:45:25 -0600473#include "sk_tool_utils.h"
474
475static void save_bm(const SkBitmap& bm, const char name[]) {
476 bool result = sk_tool_utils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
477 SkASSERT(result);
478}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400479
480sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
481 SkBitmap bm;
482 bm.allocN32Pixels(18, 2, true);
483 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
484 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
485 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
486 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
487 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
488 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
489 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
490 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
491 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
492
493#if 1
494 save_bm(bm, "atlas-fake.png");
495#endif
496
Brian Osman2b23c4b2018-06-01 12:25:08 -0400497 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400498 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
499
500 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
501 context->textureProvider(),
502 desc, SkBudgeted::kYes,
503 bm.getPixels(), bm.rowBytes());
504
505 return sk_ref_sp(tmp->asTextureProxy());
506}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400507#endif
508
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500509
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400510static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
511 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
512 REPORTER_ASSERT(reporter, expected == readback);
513 if (expected != readback) {
514 SkDebugf("Color mismatch: %x %x\n", expected, readback);
515 }
516}
517
518/*
519 * For the atlasing test we make a DAG that looks like:
520 *
521 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
522 * \ /
523 * \ /
524 * RT4
525 * We then flush RT4 and expect only ops 0-5 to be atlased together.
526 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
527 * R G B C M Y
528 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
529 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500530 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
531 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400532 * R G B C M Y K Grey White
533 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400534DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400535 static const int kNumProxies = 3;
536
537 GrContext* context = ctxInfo.grContext();
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500538 auto proxyProvider = context->contextPriv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400539
Chris Daltonfe199b72017-05-05 11:26:15 -0400540 AtlasObject object;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400541
Chris Daltonfe199b72017-05-05 11:26:15 -0400542 context->contextPriv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400543
544 sk_sp<GrTextureProxy> proxies[kNumProxies];
545 for (int i = 0; i < kNumProxies; ++i) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500546 proxies[i] = make_upstream_image(context, &object, i*3,
Greg Daniel4065d452018-11-16 15:43:41 -0500547 object.getAtlasProxy(proxyProvider,
548 context->contextPriv().caps()));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400549 }
550
551 static const int kFinalWidth = 6*kDrawnTileSize;
552 static const int kFinalHeight = kDrawnTileSize;
553
Greg Daniel4065d452018-11-16 15:43:41 -0500554 const GrBackendFormat format =
555 context->contextPriv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
556
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500557 sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeDeferredRenderTargetContext(
Greg Daniel4065d452018-11-16 15:43:41 -0500558 format,
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400559 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400560 kFinalWidth,
561 kFinalHeight,
562 kRGBA_8888_GrPixelConfig,
563 nullptr));
564
Brian Osman9a9baae2018-11-05 15:06:26 -0500565 rtc->clear(nullptr, SK_PMColor4fWHITE, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400566
567 // Note that this doesn't include the third texture proxy
568 for (int i = 0; i < kNumProxies-1; ++i) {
569 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
570
571 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
572
573 GrPaint paint;
Brian Osman2240be92017-10-18 13:15:13 -0400574 auto fp = GrSimpleTextureEffect::Make(std::move(proxies[i]), t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400575 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
576 paint.addColorFragmentProcessor(std::move(fp));
577
578 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
579 }
580
Greg Daniela5cb7812017-06-16 09:45:32 -0400581 rtc->prepareForExternalIO(0, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400582
583 SkBitmap readBack;
584 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
585
586 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
587 readBack.rowBytes(), 0, 0);
588 SkASSERT(result);
589
Chris Daltonfe199b72017-05-05 11:26:15 -0400590 context->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
591
592 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400593
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400594 int x = kDrawnTileSize/2;
595 test_color(reporter, readBack, x, SK_ColorRED);
596 x += kDrawnTileSize;
597 test_color(reporter, readBack, x, SK_ColorGREEN);
598 x += kDrawnTileSize;
599 test_color(reporter, readBack, x, SK_ColorBLUE);
600 x += kDrawnTileSize;
601 test_color(reporter, readBack, x, SK_ColorCYAN);
602 x += kDrawnTileSize;
603 test_color(reporter, readBack, x, SK_ColorMAGENTA);
604 x += kDrawnTileSize;
605 test_color(reporter, readBack, x, SK_ColorYELLOW);
606}