blob: 0c2edfba431e0081f104629bc0654d96de7cde2a [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 Phillipseb35f4d2017-03-21 07:56:47 -040017#include "GrRenderTargetContextPriv.h"
18#include "GrResourceProvider.h"
19#include "GrQuad.h"
Cary Clark74f623d2017-11-06 20:02:02 -050020#include "SkPointPriv.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040021#include "effects/GrSimpleTextureEffect.h"
Brian Salomon9a036422017-07-13 17:04:43 -040022#include "ops/GrSimpleMeshDrawOpHelper.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040023
Brian Salomon9a036422017-07-13 17:04:43 -040024namespace {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040025// This is a simplified mesh drawing op that can be used in the atlas generation test.
26// Please see AtlasedRectOp below.
Brian Salomon9a036422017-07-13 17:04:43 -040027class NonAARectOp : public GrMeshDrawOp {
28protected:
29 using Helper = GrSimpleMeshDrawOpHelper;
30
Robert Phillipseb35f4d2017-03-21 07:56:47 -040031public:
32 DEFINE_OP_CLASS_ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -040033
34 // This creates an instance of a simple non-AA solid color rect-drawing Op
Brian Salomon9a036422017-07-13 17:04:43 -040035 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& r) {
36 return Helper::FactoryHelper<NonAARectOp>(std::move(paint), r, nullptr, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040037 }
38
39 // This creates an instance of a simple non-AA textured rect-drawing Op
Brian Salomon9a036422017-07-13 17:04:43 -040040 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& r, const SkRect& local) {
41 return Helper::FactoryHelper<NonAARectOp>(std::move(paint), r, &local, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040042 }
43
44 GrColor color() const { return fColor; }
45
Brian Salomon9a036422017-07-13 17:04:43 -040046 NonAARectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r,
47 const SkRect* localRect, int32_t classID)
48 : INHERITED(classID)
49 , fColor(color)
50 , fHasLocalRect(SkToBool(localRect))
51 , fRect(r)
52 , fHelper(helperArgs, GrAAType::kNone) {
53 if (fHasLocalRect) {
54 fLocalQuad.set(*localRect);
55 }
56 // Choose some conservative values for aa bloat and zero area.
57 this->setBounds(r, HasAABloat::kYes, IsZeroArea::kYes);
58 }
59
Robert Phillipsb493eeb2017-09-13 13:10:52 -040060 const char* name() const override { return "NonAARectOp"; }
61
Robert Phillipsf1748f52017-09-14 14:11:24 -040062 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -040063 fHelper.visitProxies(func);
64 }
65
Brian Salomon9a036422017-07-13 17:04:43 -040066 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
67
Brian Osman9a725dd2017-09-20 09:53:22 -040068 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip*,
69 GrPixelConfigIsClamped dstIsClamped) override {
Brian Salomon9a036422017-07-13 17:04:43 -040070 // Set the color to unknown because the subclass may change the color later.
71 GrProcessorAnalysisColor gpColor;
72 gpColor.setToUnknown();
73 // We ignore the clip so pass this rather than the GrAppliedClip param.
74 static GrAppliedClip kNoClip;
Brian Osman9a725dd2017-09-20 09:53:22 -040075 return fHelper.xpRequiresDstTexture(caps, &kNoClip, dstIsClamped,
76 GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomon9a036422017-07-13 17:04:43 -040077 }
78
Robert Phillipseb35f4d2017-03-21 07:56:47 -040079protected:
Robert Phillipseb35f4d2017-03-21 07:56:47 -040080 GrColor fColor;
81 bool fHasLocalRect;
82 GrQuad fLocalQuad;
83 SkRect fRect;
84
85private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -040086 bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
87
Brian Salomon91326c32017-08-09 16:02:19 -040088 void onPrepareDraws(Target* target) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040089 using namespace GrDefaultGeoProcFactory;
90
91 // The vertex attrib order is always pos, color, local coords.
92 static const int kColorOffset = sizeof(SkPoint);
93 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
94
95 sk_sp<GrGeometryProcessor> gp =
96 GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
97 Coverage::kSolid_Type,
98 fHasLocalRect ? LocalCoords::kHasExplicit_Type
99 : LocalCoords::kUnused_Type,
100 SkMatrix::I());
101 if (!gp) {
102 SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n");
103 return;
104 }
105
106 size_t vertexStride = gp->getVertexStride();
107
108 SkASSERT(fHasLocalRect
109 ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
110 : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
111
112 const GrBuffer* indexBuffer;
113 int firstIndex;
114 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
115 if (!indices) {
116 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
117 return;
118 }
119
120 const GrBuffer* vertexBuffer;
121 int firstVertex;
122 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
123 if (!vertices) {
124 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
125 return;
126 }
127
128 // Setup indices
129 indices[0] = 0;
130 indices[1] = 1;
131 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000132 indices[3] = 2;
133 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400134 indices[5] = 3;
135
136 // Setup positions
137 SkPoint* position = (SkPoint*) vertices;
Cary Clark74f623d2017-11-06 20:02:02 -0500138 SkPointPriv::SetRectTriStrip(position, fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
Brian Salomon57caa662017-10-18 12:21:05 +0000139 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) {
144 *color = fColor;
145 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
Chris Dalton3809bab2017-06-13 10:55:06 -0600157 GrMesh mesh(GrPrimitiveType::kTriangles);
Chris Dalton114a3c02017-05-26 15:17:19 -0600158 mesh.setIndexed(indexBuffer, 6, firstIndex, 0, 3);
159 mesh.setVertexData(vertexBuffer, firstVertex);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400160
Brian Salomon9a036422017-07-13 17:04:43 -0400161 target->draw(gp.get(), fHelper.makePipeline(target), mesh);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400162 }
163
Brian Salomon9a036422017-07-13 17:04:43 -0400164 Helper fHelper;
165
166 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400167};
168
Brian Salomon9a036422017-07-13 17:04:43 -0400169} // anonymous namespace
170
Brian Salomon9a036422017-07-13 17:04:43 -0400171static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
172
173namespace {
174
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400175/*
176 * Atlased ops just draw themselves as textured rects with the texture pixels being
177 * pulled out of the atlas. Their color is based on their ID.
178 */
179class AtlasedRectOp final : public NonAARectOp {
180public:
181 DEFINE_OP_CLASS_ID
182
183 ~AtlasedRectOp() override {
184 fID = -1;
185 }
186
187 const char* name() const override { return "AtlasedRectOp"; }
188
189 int id() const { return fID; }
190
Brian Salomon9a036422017-07-13 17:04:43 -0400191 static std::unique_ptr<AtlasedRectOp> Make(GrPaint&& paint, const SkRect& r, int id) {
192 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(std::move(paint), r, id).release();
193 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
194 }
195
196 // We set the initial color of the NonAARectOp based on the ID.
197 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
198 // pulling from the atlas.
199 AtlasedRectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r, int id)
200 : INHERITED(helperArgs, kColors[id], r, &kEmptyRect, ClassID())
201 , fID(id)
202 , fNext(nullptr) {
203 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400204 }
205
206 void setColor(GrColor color) { fColor = color; }
207 void setLocalRect(const SkRect& localRect) {
208 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
209 fLocalQuad.set(localRect);
210 }
211
212 AtlasedRectOp* next() const { return fNext; }
213 void setNext(AtlasedRectOp* next) {
214 fNext = next;
215 }
216
217private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400218
219 static const int kMaxIDs = 9;
220 static const SkColor kColors[kMaxIDs];
221
222 int fID;
223 // The Atlased ops have an internal singly-linked list of ops that land in the same opList
224 AtlasedRectOp* fNext;
225
226 typedef NonAARectOp INHERITED;
227};
228
Brian Salomon9a036422017-07-13 17:04:43 -0400229} // anonymous namespace
230
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400231const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
232 GrColorPackRGBA(255, 0, 0, 255),
233 GrColorPackRGBA(0, 255, 0, 255),
234 GrColorPackRGBA(0, 0, 255, 255),
235 GrColorPackRGBA(0, 255, 255, 255),
236 GrColorPackRGBA(255, 0, 255, 255),
237 GrColorPackRGBA(255, 255, 0, 255),
238 GrColorPackRGBA(0, 0, 0, 255),
239 GrColorPackRGBA(128, 128, 128, 255),
240 GrColorPackRGBA(255, 255, 255, 255)
241};
242
243static const int kDrawnTileSize = 16;
244
245/*
246 * Rather than performing any rect packing, this atlaser just lays out constant-sized
247 * tiles in an Nx1 row
248 */
249static const int kAtlasTileSize = 2;
250
251/*
252 * This class aggregates the op information required for atlasing
253 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400254class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400255public:
256 AtlasObject() : fDone(false) { }
257
258 ~AtlasObject() override {
259 SkASSERT(fDone);
260 }
261
262 void markAsDone() {
263 fDone = true;
264 }
265
266 // Insert the new op in an internal singly-linked list for 'opListID'
267 void addOp(uint32_t opListID, AtlasedRectOp* op) {
268 LinkedListHeader* header = nullptr;
269 for (int i = 0; i < fOps.count(); ++i) {
270 if (opListID == fOps[i].fID) {
271 header = &(fOps[i]);
272 }
273 }
274
275 if (!header) {
276 fOps.push({opListID, nullptr});
277 header = &(fOps[fOps.count()-1]);
278 }
279
280 op->setNext(header->fHead);
281 header->fHead = op;
282 }
283
284 // For the time being we need to pre-allocate the atlas.
285 void setAtlasDest(sk_sp<GrTextureProxy> atlasDest) {
286 fAtlasDest = atlasDest;
287 }
288
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400289 /*
290 * This callback back creates the atlas and updates the AtlasedRectOps to read from it
291 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400292 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400293 const uint32_t* opListIDs, int numOpListIDs,
294 SkTArray<sk_sp<GrRenderTargetContext>>* results) override {
295 SkASSERT(!results->count());
296
297 // Until MDB is landed we will most-likely only have one opList.
298 SkTDArray<LinkedListHeader*> lists;
299 for (int i = 0; i < numOpListIDs; ++i) {
300 if (LinkedListHeader* list = this->getList(opListIDs[i])) {
301 lists.push(list);
302 }
303 }
304
305 if (!lists.count()) {
306 return; // nothing to atlas
307 }
308
309 // TODO: right now we have to pre-allocate the atlas bc the TextureSamplers need a
310 // hard GrTexture
311#if 0
312 GrSurfaceDesc desc;
313 desc.fFlags = kRenderTarget_GrSurfaceFlag;
314 desc.fWidth = this->numOps() * kAtlasTileSize;
315 desc.fHeight = kAtlasTileSize;
316 desc.fConfig = kRGBA_8888_GrPixelConfig;
317
318 sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(desc,
319 nullptr,
320 nullptr);
321#else
322 // At this point all the GrAtlasedOp's should have lined up to read from 'atlasDest' and
323 // there should either be two writes to clear it or no writes.
324 SkASSERT(9 == fAtlasDest->getPendingReadCnt_TestOnly());
325 SkASSERT(2 == fAtlasDest->getPendingWriteCnt_TestOnly() ||
326 0 == fAtlasDest->getPendingWriteCnt_TestOnly());
327 sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(
328 fAtlasDest,
329 nullptr, nullptr);
330#endif
331
332 rtc->clear(nullptr, 0xFFFFFFFF, true); // clear the atlas
333
334 int blocksInAtlas = 0;
335 for (int i = 0; i < lists.count(); ++i) {
336 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
337 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
338 kAtlasTileSize, kAtlasTileSize);
339
340 // For now, we avoid the resource buffer issues and just use clears
341#if 1
342 rtc->clear(&r, op->color(), false);
343#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400344 GrPaint paint;
Brian Salomon9a036422017-07-13 17:04:43 -0400345 paint.setColor4f(GrColor4f::FromGrColor(op->color()));
346 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
347 SkRect::Make(r)));
348 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400349#endif
350 blocksInAtlas++;
351
352 // Set the atlased Op's color to white (so we know we're not using it for
353 // the final draw).
354 op->setColor(0xFFFFFFFF);
355
356 // Set the atlased Op's localRect to point to where it landed in the atlas
357 op->setLocalRect(SkRect::Make(r));
358
359 // TODO: we also need to set the op's GrSuperDeferredSimpleTextureEffect to point
360 // to the rtc's proxy!
361 }
362
363 // We've updated all these ops and we certainly don't want to process them again
364 this->clearOpsFor(lists[i]);
365 }
366
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400367 results->push_back(std::move(rtc));
368 }
369
370private:
371 typedef struct {
372 uint32_t fID;
373 AtlasedRectOp* fHead;
374 } LinkedListHeader;
375
376 LinkedListHeader* getList(uint32_t opListID) {
377 for (int i = 0; i < fOps.count(); ++i) {
378 if (opListID == fOps[i].fID) {
379 return &(fOps[i]);
380 }
381 }
382 return nullptr;
383 }
384
385 void clearOpsFor(LinkedListHeader* header) {
386 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
387 // forget about them in the laziest way possible.
388 header->fHead = nullptr;
389 header->fID = 0; // invalid opList ID
390 }
391
392 // Each opList containing AtlasedRectOps gets its own internal singly-linked list
393 SkTDArray<LinkedListHeader> fOps;
394
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400395 // For the time being we need to pre-allocate the atlas bc the TextureSamplers require
396 // a GrTexture
397 sk_sp<GrTextureProxy> fAtlasDest;
398
399 // Set to true when the testing harness expects this object to be no longer used
400 bool fDone;
401};
402
403// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
404static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
405 sk_sp<GrTextureProxy> fakeAtlas) {
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400406 sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContext(
407 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400408 3*kDrawnTileSize,
409 kDrawnTileSize,
410 kRGBA_8888_GrPixelConfig,
411 nullptr));
412
413 rtc->clear(nullptr, GrColorPackRGBA(255, 0, 0, 255), true);
414
415 for (int i = 0; i < 3; ++i) {
416 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
417
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400418 // TODO: here is the blocker for deferring creation of the atlas. The TextureSamplers
419 // created here currently require a hard GrTexture.
Brian Osman2240be92017-10-18 13:15:13 -0400420 auto fp = GrSimpleTextureEffect::Make(fakeAtlas, SkMatrix::I());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400421 GrPaint paint;
422 paint.addColorFragmentProcessor(std::move(fp));
423 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Salomon9a036422017-07-13 17:04:43 -0400424 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400425
426 AtlasedRectOp* sparePtr = op.get();
427
Brian Salomon9a036422017-07-13 17:04:43 -0400428 uint32_t opListID = rtc->priv().testingOnly_addDrawOp(std::move(op));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400429
430 object->addOp(opListID, sparePtr);
431 }
432
433 return rtc->asTextureProxyRef();
434}
435
436// Enable this if you want to debug the final draws w/o having the atlasCallback create the
437// atlas
438#if 0
Chris Dalton12658942017-10-05 19:45:25 -0600439#include "SkImageEncoder.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400440#include "SkGrPriv.h"
Chris Dalton12658942017-10-05 19:45:25 -0600441#include "sk_tool_utils.h"
442
443static void save_bm(const SkBitmap& bm, const char name[]) {
444 bool result = sk_tool_utils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
445 SkASSERT(result);
446}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400447
448sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
449 SkBitmap bm;
450 bm.allocN32Pixels(18, 2, true);
451 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
452 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
453 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
454 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
455 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
456 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
457 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
458 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
459 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
460
461#if 1
462 save_bm(bm, "atlas-fake.png");
463#endif
464
465 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info(), *context->caps());
466 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
467
468 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
469 context->textureProvider(),
470 desc, SkBudgeted::kYes,
471 bm.getPixels(), bm.rowBytes());
472
473 return sk_ref_sp(tmp->asTextureProxy());
474}
475#else
476// TODO: this is unfortunate and must be removed. We want the atlas to be created later.
477sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
478 GrSurfaceDesc desc;
479 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400480 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
481 desc.fWidth = 32;
482 desc.fHeight = 16;
Robert Phillips16d8ec62017-07-27 16:16:25 -0400483 desc.fConfig = kSkia8888_GrPixelConfig;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400484 sk_sp<GrSurfaceProxy> atlasDest = GrSurfaceProxy::MakeDeferred(
485 context->resourceProvider(),
486 desc, SkBackingFit::kExact,
487 SkBudgeted::kYes,
488 GrResourceProvider::kNoPendingIO_Flag);
489 return sk_ref_sp(atlasDest->asTextureProxy());
490}
491#endif
492
493static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
494 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
495 REPORTER_ASSERT(reporter, expected == readback);
496 if (expected != readback) {
497 SkDebugf("Color mismatch: %x %x\n", expected, readback);
498 }
499}
500
501/*
502 * For the atlasing test we make a DAG that looks like:
503 *
504 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
505 * \ /
506 * \ /
507 * RT4
508 * We then flush RT4 and expect only ops 0-5 to be atlased together.
509 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
510 * R G B C M Y
511 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
512 *
513 * Note: until MDB lands, the atlas will actually have width= 9*kAtlasTileSize and look like:
514 * R G B C M Y K Grey White
515 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400516DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400517 static const int kNumProxies = 3;
518
519 GrContext* context = ctxInfo.grContext();
520
Chris Daltonfe199b72017-05-05 11:26:15 -0400521 AtlasObject object;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400522
523 // For now (until we add a GrSuperDeferredSimpleTextureEffect), we create the final atlas
524 // proxy ahead of time.
525 sk_sp<GrTextureProxy> atlasDest = pre_create_atlas(context);
526
Chris Daltonfe199b72017-05-05 11:26:15 -0400527 object.setAtlasDest(atlasDest);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400528
Chris Daltonfe199b72017-05-05 11:26:15 -0400529 context->contextPriv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400530
531 sk_sp<GrTextureProxy> proxies[kNumProxies];
532 for (int i = 0; i < kNumProxies; ++i) {
Chris Daltonfe199b72017-05-05 11:26:15 -0400533 proxies[i] = make_upstream_image(context, &object, i*3, atlasDest);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400534 }
535
536 static const int kFinalWidth = 6*kDrawnTileSize;
537 static const int kFinalHeight = kDrawnTileSize;
538
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400539 sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContext(
540 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400541 kFinalWidth,
542 kFinalHeight,
543 kRGBA_8888_GrPixelConfig,
544 nullptr));
545
546 rtc->clear(nullptr, 0xFFFFFFFF, true);
547
548 // Note that this doesn't include the third texture proxy
549 for (int i = 0; i < kNumProxies-1; ++i) {
550 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
551
552 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
553
554 GrPaint paint;
Brian Osman2240be92017-10-18 13:15:13 -0400555 auto fp = GrSimpleTextureEffect::Make(std::move(proxies[i]), t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400556 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
557 paint.addColorFragmentProcessor(std::move(fp));
558
559 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
560 }
561
Greg Daniela5cb7812017-06-16 09:45:32 -0400562 rtc->prepareForExternalIO(0, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400563
564 SkBitmap readBack;
565 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
566
567 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
568 readBack.rowBytes(), 0, 0);
569 SkASSERT(result);
570
Chris Daltonfe199b72017-05-05 11:26:15 -0400571 context->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
572
573 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400574
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400575 int x = kDrawnTileSize/2;
576 test_color(reporter, readBack, x, SK_ColorRED);
577 x += kDrawnTileSize;
578 test_color(reporter, readBack, x, SK_ColorGREEN);
579 x += kDrawnTileSize;
580 test_color(reporter, readBack, x, SK_ColorBLUE);
581 x += kDrawnTileSize;
582 test_color(reporter, readBack, x, SK_ColorCYAN);
583 x += kDrawnTileSize;
584 test_color(reporter, readBack, x, SK_ColorMAGENTA);
585 x += kDrawnTileSize;
586 test_color(reporter, readBack, x, SK_ColorYELLOW);
587}
588
589#endif