blob: 73ac5f191e3bc257bf420cbb619f6797ae4bd1e2 [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
10#if SK_SUPPORT_GPU
11
Greg Daniela5cb7812017-06-16 09:45:32 -040012#include "GrBackendSemaphore.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040013#include "GrClip.h"
14#include "GrContextPriv.h"
15#include "GrDefaultGeoProcFactory.h"
Chris Daltonfe199b72017-05-05 11:26:15 -040016#include "GrOnFlushResourceProvider.h"
Robert Phillips0bd24dc2018-01-16 08:06:32 -050017#include "GrProxyProvider.h"
Robert Phillips7d79e7b2018-02-14 11:09:57 -050018#include "GrQuad.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040019#include "GrRenderTargetContextPriv.h"
20#include "GrResourceProvider.h"
Robert Phillips7d79e7b2018-02-14 11:09:57 -050021#include "GrTexture.h"
22
Mike Reed75ae4212018-01-23 11:24:08 -050023#include "SkBitmap.h"
Cary Clark74f623d2017-11-06 20:02:02 -050024#include "SkPointPriv.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040025#include "effects/GrSimpleTextureEffect.h"
Brian Salomon9a036422017-07-13 17:04:43 -040026#include "ops/GrSimpleMeshDrawOpHelper.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040027
Brian Salomon9a036422017-07-13 17:04:43 -040028namespace {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040029// This is a simplified mesh drawing op that can be used in the atlas generation test.
30// Please see AtlasedRectOp below.
Brian Salomon9a036422017-07-13 17:04:43 -040031class NonAARectOp : public GrMeshDrawOp {
32protected:
33 using Helper = GrSimpleMeshDrawOpHelper;
34
Robert Phillipseb35f4d2017-03-21 07:56:47 -040035public:
36 DEFINE_OP_CLASS_ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -040037
38 // This creates an instance of a simple non-AA solid color rect-drawing Op
Brian Salomon9a036422017-07-13 17:04:43 -040039 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& r) {
40 return Helper::FactoryHelper<NonAARectOp>(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
Brian Salomon9a036422017-07-13 17:04:43 -040044 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& r, const SkRect& local) {
45 return Helper::FactoryHelper<NonAARectOp>(std::move(paint), r, &local, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040046 }
47
48 GrColor color() const { return fColor; }
49
Brian Salomon9a036422017-07-13 17:04:43 -040050 NonAARectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r,
51 const SkRect* localRect, int32_t classID)
52 : INHERITED(classID)
53 , fColor(color)
54 , fHasLocalRect(SkToBool(localRect))
55 , fRect(r)
56 , fHelper(helperArgs, GrAAType::kNone) {
57 if (fHasLocalRect) {
58 fLocalQuad.set(*localRect);
59 }
60 // Choose some conservative values for aa bloat and zero area.
61 this->setBounds(r, HasAABloat::kYes, IsZeroArea::kYes);
62 }
63
Robert Phillipsb493eeb2017-09-13 13:10:52 -040064 const char* name() const override { return "NonAARectOp"; }
65
Robert Phillipsf1748f52017-09-14 14:11:24 -040066 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -040067 fHelper.visitProxies(func);
68 }
69
Brian Salomon9a036422017-07-13 17:04:43 -040070 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
71
Brian Osman9a725dd2017-09-20 09:53:22 -040072 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip*,
73 GrPixelConfigIsClamped dstIsClamped) override {
Brian Salomon9a036422017-07-13 17:04:43 -040074 // Set the color to unknown because the subclass may change the color later.
75 GrProcessorAnalysisColor gpColor;
76 gpColor.setToUnknown();
77 // We ignore the clip so pass this rather than the GrAppliedClip param.
78 static GrAppliedClip kNoClip;
Brian Osman9a725dd2017-09-20 09:53:22 -040079 return fHelper.xpRequiresDstTexture(caps, &kNoClip, dstIsClamped,
80 GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomon9a036422017-07-13 17:04:43 -040081 }
82
Robert Phillipseb35f4d2017-03-21 07:56:47 -040083protected:
Robert Phillipseb35f4d2017-03-21 07:56:47 -040084 GrColor fColor;
85 bool fHasLocalRect;
86 GrQuad fLocalQuad;
87 SkRect fRect;
88
89private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -040090 bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
91
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 =
100 GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
101 Coverage::kSolid_Type,
102 fHasLocalRect ? LocalCoords::kHasExplicit_Type
103 : LocalCoords::kUnused_Type,
104 SkMatrix::I());
105 if (!gp) {
106 SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n");
107 return;
108 }
109
110 size_t vertexStride = gp->getVertexStride();
111
112 SkASSERT(fHasLocalRect
113 ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
114 : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
115
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;
Cary Clark74f623d2017-11-06 20:02:02 -0500142 SkPointPriv::SetRectTriStrip(position, fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
Brian Salomon57caa662017-10-18 12:21:05 +0000143 vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400144
145 // Setup vertex colors
146 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
147 for (int i = 0; i < 4; ++i) {
148 *color = fColor;
149 color = (GrColor*)((intptr_t)color + vertexStride);
150 }
151
152 // Setup local coords
153 if (fHasLocalRect) {
154 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
155 for (int i = 0; i < 4; i++) {
156 *coords = fLocalQuad.point(i);
157 coords = (SkPoint*)((intptr_t) coords + vertexStride);
158 }
159 }
160
Chris Dalton3809bab2017-06-13 10:55:06 -0600161 GrMesh mesh(GrPrimitiveType::kTriangles);
Chris Dalton114a3c02017-05-26 15:17:19 -0600162 mesh.setIndexed(indexBuffer, 6, firstIndex, 0, 3);
163 mesh.setVertexData(vertexBuffer, firstVertex);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400164
Brian Salomon9a036422017-07-13 17:04:43 -0400165 target->draw(gp.get(), fHelper.makePipeline(target), 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
Brian Salomon9a036422017-07-13 17:04:43 -0400195 static std::unique_ptr<AtlasedRectOp> Make(GrPaint&& paint, const SkRect& r, int id) {
196 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(std::move(paint), r, id).release();
197 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
198 }
199
200 // We set the initial color of the NonAARectOp based on the ID.
201 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
202 // pulling from the atlas.
203 AtlasedRectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r, int id)
204 : INHERITED(helperArgs, kColors[id], r, &kEmptyRect, ClassID())
205 , fID(id)
206 , fNext(nullptr) {
207 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400208 }
209
210 void setColor(GrColor color) { fColor = color; }
211 void setLocalRect(const SkRect& localRect) {
212 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
213 fLocalQuad.set(localRect);
214 }
215
216 AtlasedRectOp* next() const { return fNext; }
217 void setNext(AtlasedRectOp* next) {
218 fNext = next;
219 }
220
221private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400222
223 static const int kMaxIDs = 9;
224 static const SkColor kColors[kMaxIDs];
225
226 int fID;
227 // The Atlased ops have an internal singly-linked list of ops that land in the same opList
228 AtlasedRectOp* fNext;
229
230 typedef NonAARectOp INHERITED;
231};
232
Brian Salomon9a036422017-07-13 17:04:43 -0400233} // anonymous namespace
234
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400235const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
236 GrColorPackRGBA(255, 0, 0, 255),
237 GrColorPackRGBA(0, 255, 0, 255),
238 GrColorPackRGBA(0, 0, 255, 255),
239 GrColorPackRGBA(0, 255, 255, 255),
240 GrColorPackRGBA(255, 0, 255, 255),
241 GrColorPackRGBA(255, 255, 0, 255),
242 GrColorPackRGBA(0, 0, 0, 255),
243 GrColorPackRGBA(128, 128, 128, 255),
244 GrColorPackRGBA(255, 255, 255, 255)
245};
246
247static const int kDrawnTileSize = 16;
248
249/*
250 * Rather than performing any rect packing, this atlaser just lays out constant-sized
251 * tiles in an Nx1 row
252 */
253static const int kAtlasTileSize = 2;
254
255/*
256 * This class aggregates the op information required for atlasing
257 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400258class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400259public:
260 AtlasObject() : fDone(false) { }
261
262 ~AtlasObject() override {
263 SkASSERT(fDone);
264 }
265
266 void markAsDone() {
267 fDone = true;
268 }
269
270 // Insert the new op in an internal singly-linked list for 'opListID'
271 void addOp(uint32_t opListID, AtlasedRectOp* op) {
272 LinkedListHeader* header = nullptr;
273 for (int i = 0; i < fOps.count(); ++i) {
274 if (opListID == fOps[i].fID) {
275 header = &(fOps[i]);
276 }
277 }
278
279 if (!header) {
280 fOps.push({opListID, nullptr});
281 header = &(fOps[fOps.count()-1]);
282 }
283
284 op->setNext(header->fHead);
285 header->fHead = op;
286 }
287
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500288 int numOps() const { return fOps.count(); }
289
290 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
291 // known until flush time.
292 sk_sp<GrTextureProxy> getAtlasProxy(GrProxyProvider* proxyProvider) {
293 if (fAtlasProxy) {
294 return fAtlasProxy;
295 }
296
297 fAtlasProxy = proxyProvider->createFullyLazyProxy(
298 [](GrResourceProvider* resourceProvider) {
299 if (!resourceProvider) {
300 return sk_sp<GrTexture>();
301 }
302
303 GrSurfaceDesc desc;
304 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500305 // TODO: until partial flushes in MDB lands we're stuck having
306 // all 9 atlas draws occur
307 desc.fWidth = 9 /*this->numOps()*/ * kAtlasTileSize;
308 desc.fHeight = kAtlasTileSize;
309 desc.fConfig = kRGBA_8888_GrPixelConfig;
310
311 return resourceProvider->createTexture(desc, SkBudgeted::kYes,
312 GrResourceProvider::kNoPendingIO_Flag);
313 },
314 GrProxyProvider::Renderable::kYes,
315 kBottomLeft_GrSurfaceOrigin,
316 kRGBA_8888_GrPixelConfig);
317 return fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400318 }
319
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400320 /*
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500321 * This callback creates the atlas and updates the AtlasedRectOps to read from it
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400322 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400323 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400324 const uint32_t* opListIDs, int numOpListIDs,
325 SkTArray<sk_sp<GrRenderTargetContext>>* results) override {
326 SkASSERT(!results->count());
327
328 // Until MDB is landed we will most-likely only have one opList.
329 SkTDArray<LinkedListHeader*> lists;
330 for (int i = 0; i < numOpListIDs; ++i) {
331 if (LinkedListHeader* list = this->getList(opListIDs[i])) {
332 lists.push(list);
333 }
334 }
335
336 if (!lists.count()) {
337 return; // nothing to atlas
338 }
339
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500340 if (!resourceProvider->instatiateProxy(fAtlasProxy.get())) {
341 return;
342 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400343
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400344 // At this point all the GrAtlasedOp's should have lined up to read from 'atlasDest' and
345 // there should either be two writes to clear it or no writes.
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500346 SkASSERT(9 == fAtlasProxy->getPendingReadCnt_TestOnly());
347 SkASSERT(2 == fAtlasProxy->getPendingWriteCnt_TestOnly() ||
348 0 == fAtlasProxy->getPendingWriteCnt_TestOnly());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400349 sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500350 fAtlasProxy,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400351 nullptr, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400352
Chris Dalton344e9032017-12-11 15:42:09 -0700353 // clear the atlas
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500354 rtc->clear(nullptr, 0x0, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400355
356 int blocksInAtlas = 0;
357 for (int i = 0; i < lists.count(); ++i) {
358 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
359 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
360 kAtlasTileSize, kAtlasTileSize);
361
362 // For now, we avoid the resource buffer issues and just use clears
363#if 1
Chris Dalton344e9032017-12-11 15:42:09 -0700364 rtc->clear(&r, op->color(), GrRenderTargetContext::CanClearFullscreen::kNo);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400365#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400366 GrPaint paint;
Brian Salomon9a036422017-07-13 17:04:43 -0400367 paint.setColor4f(GrColor4f::FromGrColor(op->color()));
368 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
369 SkRect::Make(r)));
370 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400371#endif
372 blocksInAtlas++;
373
374 // Set the atlased Op's color to white (so we know we're not using it for
375 // the final draw).
376 op->setColor(0xFFFFFFFF);
377
378 // Set the atlased Op's localRect to point to where it landed in the atlas
379 op->setLocalRect(SkRect::Make(r));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400380 }
381
382 // We've updated all these ops and we certainly don't want to process them again
383 this->clearOpsFor(lists[i]);
384 }
385
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400386 results->push_back(std::move(rtc));
387 }
388
389private:
390 typedef struct {
391 uint32_t fID;
392 AtlasedRectOp* fHead;
393 } LinkedListHeader;
394
395 LinkedListHeader* getList(uint32_t opListID) {
396 for (int i = 0; i < fOps.count(); ++i) {
397 if (opListID == fOps[i].fID) {
398 return &(fOps[i]);
399 }
400 }
401 return nullptr;
402 }
403
404 void clearOpsFor(LinkedListHeader* header) {
405 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
406 // forget about them in the laziest way possible.
407 header->fHead = nullptr;
408 header->fID = 0; // invalid opList ID
409 }
410
411 // Each opList containing AtlasedRectOps gets its own internal singly-linked list
412 SkTDArray<LinkedListHeader> fOps;
413
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500414 // The fully lazy proxy for the atlas
415 sk_sp<GrTextureProxy> fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400416
417 // Set to true when the testing harness expects this object to be no longer used
418 bool fDone;
419};
420
421// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
422static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500423 sk_sp<GrTextureProxy> atlasProxy) {
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500424 sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeDeferredRenderTargetContext(
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400425 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400426 3*kDrawnTileSize,
427 kDrawnTileSize,
428 kRGBA_8888_GrPixelConfig,
429 nullptr));
430
Chris Dalton344e9032017-12-11 15:42:09 -0700431 rtc->clear(nullptr, GrColorPackRGBA(255, 0, 0, 255),
432 GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400433
434 for (int i = 0; i < 3; ++i) {
435 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
436
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500437 auto fp = GrSimpleTextureEffect::Make(atlasProxy, SkMatrix::I());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400438 GrPaint paint;
439 paint.addColorFragmentProcessor(std::move(fp));
440 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Salomon9a036422017-07-13 17:04:43 -0400441 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400442
443 AtlasedRectOp* sparePtr = op.get();
444
Brian Salomon9a036422017-07-13 17:04:43 -0400445 uint32_t opListID = rtc->priv().testingOnly_addDrawOp(std::move(op));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400446
447 object->addOp(opListID, sparePtr);
448 }
449
450 return rtc->asTextureProxyRef();
451}
452
453// Enable this if you want to debug the final draws w/o having the atlasCallback create the
454// atlas
455#if 0
Chris Dalton12658942017-10-05 19:45:25 -0600456#include "SkImageEncoder.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400457#include "SkGrPriv.h"
Chris Dalton12658942017-10-05 19:45:25 -0600458#include "sk_tool_utils.h"
459
460static void save_bm(const SkBitmap& bm, const char name[]) {
461 bool result = sk_tool_utils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
462 SkASSERT(result);
463}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400464
465sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
466 SkBitmap bm;
467 bm.allocN32Pixels(18, 2, true);
468 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
469 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
470 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
471 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
472 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
473 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
474 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
475 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
476 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
477
478#if 1
479 save_bm(bm, "atlas-fake.png");
480#endif
481
482 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info(), *context->caps());
483 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
484
485 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
486 context->textureProvider(),
487 desc, SkBudgeted::kYes,
488 bm.getPixels(), bm.rowBytes());
489
490 return sk_ref_sp(tmp->asTextureProxy());
491}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400492#endif
493
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500494
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400495static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
496 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
497 REPORTER_ASSERT(reporter, expected == readback);
498 if (expected != readback) {
499 SkDebugf("Color mismatch: %x %x\n", expected, readback);
500 }
501}
502
503/*
504 * For the atlasing test we make a DAG that looks like:
505 *
506 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
507 * \ /
508 * \ /
509 * RT4
510 * We then flush RT4 and expect only ops 0-5 to be atlased together.
511 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
512 * R G B C M Y
513 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
514 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500515 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
516 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400517 * R G B C M Y K Grey White
518 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400519DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400520 static const int kNumProxies = 3;
521
522 GrContext* context = ctxInfo.grContext();
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500523 auto proxyProvider = context->contextPriv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400524
Chris Daltonfe199b72017-05-05 11:26:15 -0400525 AtlasObject object;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400526
Chris Daltonfe199b72017-05-05 11:26:15 -0400527 context->contextPriv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400528
529 sk_sp<GrTextureProxy> proxies[kNumProxies];
530 for (int i = 0; i < kNumProxies; ++i) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500531 proxies[i] = make_upstream_image(context, &object, i*3,
532 object.getAtlasProxy(proxyProvider));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400533 }
534
535 static const int kFinalWidth = 6*kDrawnTileSize;
536 static const int kFinalHeight = kDrawnTileSize;
537
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500538 sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeDeferredRenderTargetContext(
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400539 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400540 kFinalWidth,
541 kFinalHeight,
542 kRGBA_8888_GrPixelConfig,
543 nullptr));
544
Chris Dalton344e9032017-12-11 15:42:09 -0700545 rtc->clear(nullptr, 0xFFFFFFFF, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400546
547 // Note that this doesn't include the third texture proxy
548 for (int i = 0; i < kNumProxies-1; ++i) {
549 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
550
551 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
552
553 GrPaint paint;
Brian Osman2240be92017-10-18 13:15:13 -0400554 auto fp = GrSimpleTextureEffect::Make(std::move(proxies[i]), t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400555 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
556 paint.addColorFragmentProcessor(std::move(fp));
557
558 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
559 }
560
Greg Daniela5cb7812017-06-16 09:45:32 -0400561 rtc->prepareForExternalIO(0, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400562
563 SkBitmap readBack;
564 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
565
566 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
567 readBack.rowBytes(), 0, 0);
568 SkASSERT(result);
569
Chris Daltonfe199b72017-05-05 11:26:15 -0400570 context->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
571
572 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400573
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400574 int x = kDrawnTileSize/2;
575 test_color(reporter, readBack, x, SK_ColorRED);
576 x += kDrawnTileSize;
577 test_color(reporter, readBack, x, SK_ColorGREEN);
578 x += kDrawnTileSize;
579 test_color(reporter, readBack, x, SK_ColorBLUE);
580 x += kDrawnTileSize;
581 test_color(reporter, readBack, x, SK_ColorCYAN);
582 x += kDrawnTileSize;
583 test_color(reporter, readBack, x, SK_ColorMAGENTA);
584 x += kDrawnTileSize;
585 test_color(reporter, readBack, x, SK_ColorYELLOW);
586}
587
588#endif