blob: 52bed86e48c20b5d48607f23a16e60acde91a534 [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"
20#include "effects/GrSimpleTextureEffect.h"
Brian Salomon9a036422017-07-13 17:04:43 -040021#include "ops/GrSimpleMeshDrawOpHelper.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040022
Brian Salomon9a036422017-07-13 17:04:43 -040023namespace {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040024// This is a simplified mesh drawing op that can be used in the atlas generation test.
25// Please see AtlasedRectOp below.
Brian Salomon9a036422017-07-13 17:04:43 -040026class NonAARectOp : public GrMeshDrawOp {
27protected:
28 using Helper = GrSimpleMeshDrawOpHelper;
29
Robert Phillipseb35f4d2017-03-21 07:56:47 -040030public:
31 DEFINE_OP_CLASS_ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -040032
33 // This creates an instance of a simple non-AA solid color rect-drawing Op
Brian Salomon9a036422017-07-13 17:04:43 -040034 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& r) {
35 return Helper::FactoryHelper<NonAARectOp>(std::move(paint), r, nullptr, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040036 }
37
38 // This creates an instance of a simple non-AA textured rect-drawing Op
Brian Salomon9a036422017-07-13 17:04:43 -040039 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& r, const SkRect& local) {
40 return Helper::FactoryHelper<NonAARectOp>(std::move(paint), r, &local, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040041 }
42
43 GrColor color() const { return fColor; }
44
Brian Salomon9a036422017-07-13 17:04:43 -040045 NonAARectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r,
46 const SkRect* localRect, int32_t classID)
47 : INHERITED(classID)
48 , fColor(color)
49 , fHasLocalRect(SkToBool(localRect))
50 , fRect(r)
51 , fHelper(helperArgs, GrAAType::kNone) {
52 if (fHasLocalRect) {
53 fLocalQuad.set(*localRect);
54 }
55 // Choose some conservative values for aa bloat and zero area.
56 this->setBounds(r, HasAABloat::kYes, IsZeroArea::kYes);
57 }
58
Robert Phillipsb493eeb2017-09-13 13:10:52 -040059 const char* name() const override { return "NonAARectOp"; }
60
Robert Phillipsf1748f52017-09-14 14:11:24 -040061 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -040062 fHelper.visitProxies(func);
63 }
64
Brian Salomon9a036422017-07-13 17:04:43 -040065 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
66
Brian Osman9a725dd2017-09-20 09:53:22 -040067 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip*,
68 GrPixelConfigIsClamped dstIsClamped) override {
Brian Salomon9a036422017-07-13 17:04:43 -040069 // Set the color to unknown because the subclass may change the color later.
70 GrProcessorAnalysisColor gpColor;
71 gpColor.setToUnknown();
72 // We ignore the clip so pass this rather than the GrAppliedClip param.
73 static GrAppliedClip kNoClip;
Brian Osman9a725dd2017-09-20 09:53:22 -040074 return fHelper.xpRequiresDstTexture(caps, &kNoClip, dstIsClamped,
75 GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomon9a036422017-07-13 17:04:43 -040076 }
77
Robert Phillipseb35f4d2017-03-21 07:56:47 -040078protected:
Robert Phillipseb35f4d2017-03-21 07:56:47 -040079 GrColor fColor;
80 bool fHasLocalRect;
81 GrQuad fLocalQuad;
82 SkRect fRect;
83
84private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -040085 bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
86
Brian Salomon91326c32017-08-09 16:02:19 -040087 void onPrepareDraws(Target* target) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040088 using namespace GrDefaultGeoProcFactory;
89
90 // The vertex attrib order is always pos, color, local coords.
91 static const int kColorOffset = sizeof(SkPoint);
92 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
93
94 sk_sp<GrGeometryProcessor> gp =
95 GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
96 Coverage::kSolid_Type,
97 fHasLocalRect ? LocalCoords::kHasExplicit_Type
98 : LocalCoords::kUnused_Type,
99 SkMatrix::I());
100 if (!gp) {
101 SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n");
102 return;
103 }
104
105 size_t vertexStride = gp->getVertexStride();
106
107 SkASSERT(fHasLocalRect
108 ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
109 : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
110
111 const GrBuffer* indexBuffer;
112 int firstIndex;
113 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
114 if (!indices) {
115 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
116 return;
117 }
118
119 const GrBuffer* vertexBuffer;
120 int firstVertex;
121 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
122 if (!vertices) {
123 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
124 return;
125 }
126
127 // Setup indices
128 indices[0] = 0;
129 indices[1] = 1;
130 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000131 indices[3] = 2;
132 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400133 indices[5] = 3;
134
135 // Setup positions
136 SkPoint* position = (SkPoint*) vertices;
Brian Salomon57caa662017-10-18 12:21:05 +0000137 position->setRectTriStrip(fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
138 vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400139
140 // Setup vertex colors
141 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
142 for (int i = 0; i < 4; ++i) {
143 *color = fColor;
144 color = (GrColor*)((intptr_t)color + vertexStride);
145 }
146
147 // Setup local coords
148 if (fHasLocalRect) {
149 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
150 for (int i = 0; i < 4; i++) {
151 *coords = fLocalQuad.point(i);
152 coords = (SkPoint*)((intptr_t) coords + vertexStride);
153 }
154 }
155
Chris Dalton3809bab2017-06-13 10:55:06 -0600156 GrMesh mesh(GrPrimitiveType::kTriangles);
Chris Dalton114a3c02017-05-26 15:17:19 -0600157 mesh.setIndexed(indexBuffer, 6, firstIndex, 0, 3);
158 mesh.setVertexData(vertexBuffer, firstVertex);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400159
Brian Salomon9a036422017-07-13 17:04:43 -0400160 target->draw(gp.get(), fHelper.makePipeline(target), mesh);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400161 }
162
Brian Salomon9a036422017-07-13 17:04:43 -0400163 Helper fHelper;
164
165 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400166};
167
Brian Salomon9a036422017-07-13 17:04:43 -0400168} // anonymous namespace
169
Brian Salomon9a036422017-07-13 17:04:43 -0400170static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
171
172namespace {
173
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400174/*
175 * Atlased ops just draw themselves as textured rects with the texture pixels being
176 * pulled out of the atlas. Their color is based on their ID.
177 */
178class AtlasedRectOp final : public NonAARectOp {
179public:
180 DEFINE_OP_CLASS_ID
181
182 ~AtlasedRectOp() override {
183 fID = -1;
184 }
185
186 const char* name() const override { return "AtlasedRectOp"; }
187
188 int id() const { return fID; }
189
Brian Salomon9a036422017-07-13 17:04:43 -0400190 static std::unique_ptr<AtlasedRectOp> Make(GrPaint&& paint, const SkRect& r, int id) {
191 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(std::move(paint), r, id).release();
192 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
193 }
194
195 // We set the initial color of the NonAARectOp based on the ID.
196 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
197 // pulling from the atlas.
198 AtlasedRectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r, int id)
199 : INHERITED(helperArgs, kColors[id], r, &kEmptyRect, ClassID())
200 , fID(id)
201 , fNext(nullptr) {
202 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400203 }
204
205 void setColor(GrColor color) { fColor = color; }
206 void setLocalRect(const SkRect& localRect) {
207 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
208 fLocalQuad.set(localRect);
209 }
210
211 AtlasedRectOp* next() const { return fNext; }
212 void setNext(AtlasedRectOp* next) {
213 fNext = next;
214 }
215
216private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400217
218 static const int kMaxIDs = 9;
219 static const SkColor kColors[kMaxIDs];
220
221 int fID;
222 // The Atlased ops have an internal singly-linked list of ops that land in the same opList
223 AtlasedRectOp* fNext;
224
225 typedef NonAARectOp INHERITED;
226};
227
Brian Salomon9a036422017-07-13 17:04:43 -0400228} // anonymous namespace
229
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400230const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
231 GrColorPackRGBA(255, 0, 0, 255),
232 GrColorPackRGBA(0, 255, 0, 255),
233 GrColorPackRGBA(0, 0, 255, 255),
234 GrColorPackRGBA(0, 255, 255, 255),
235 GrColorPackRGBA(255, 0, 255, 255),
236 GrColorPackRGBA(255, 255, 0, 255),
237 GrColorPackRGBA(0, 0, 0, 255),
238 GrColorPackRGBA(128, 128, 128, 255),
239 GrColorPackRGBA(255, 255, 255, 255)
240};
241
242static const int kDrawnTileSize = 16;
243
244/*
245 * Rather than performing any rect packing, this atlaser just lays out constant-sized
246 * tiles in an Nx1 row
247 */
248static const int kAtlasTileSize = 2;
249
250/*
251 * This class aggregates the op information required for atlasing
252 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400253class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400254public:
255 AtlasObject() : fDone(false) { }
256
257 ~AtlasObject() override {
258 SkASSERT(fDone);
259 }
260
261 void markAsDone() {
262 fDone = true;
263 }
264
265 // Insert the new op in an internal singly-linked list for 'opListID'
266 void addOp(uint32_t opListID, AtlasedRectOp* op) {
267 LinkedListHeader* header = nullptr;
268 for (int i = 0; i < fOps.count(); ++i) {
269 if (opListID == fOps[i].fID) {
270 header = &(fOps[i]);
271 }
272 }
273
274 if (!header) {
275 fOps.push({opListID, nullptr});
276 header = &(fOps[fOps.count()-1]);
277 }
278
279 op->setNext(header->fHead);
280 header->fHead = op;
281 }
282
283 // For the time being we need to pre-allocate the atlas.
284 void setAtlasDest(sk_sp<GrTextureProxy> atlasDest) {
285 fAtlasDest = atlasDest;
286 }
287
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400288 /*
289 * This callback back creates the atlas and updates the AtlasedRectOps to read from it
290 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400291 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400292 const uint32_t* opListIDs, int numOpListIDs,
293 SkTArray<sk_sp<GrRenderTargetContext>>* results) override {
294 SkASSERT(!results->count());
295
296 // Until MDB is landed we will most-likely only have one opList.
297 SkTDArray<LinkedListHeader*> lists;
298 for (int i = 0; i < numOpListIDs; ++i) {
299 if (LinkedListHeader* list = this->getList(opListIDs[i])) {
300 lists.push(list);
301 }
302 }
303
304 if (!lists.count()) {
305 return; // nothing to atlas
306 }
307
308 // TODO: right now we have to pre-allocate the atlas bc the TextureSamplers need a
309 // hard GrTexture
310#if 0
311 GrSurfaceDesc desc;
312 desc.fFlags = kRenderTarget_GrSurfaceFlag;
313 desc.fWidth = this->numOps() * kAtlasTileSize;
314 desc.fHeight = kAtlasTileSize;
315 desc.fConfig = kRGBA_8888_GrPixelConfig;
316
317 sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(desc,
318 nullptr,
319 nullptr);
320#else
321 // At this point all the GrAtlasedOp's should have lined up to read from 'atlasDest' and
322 // there should either be two writes to clear it or no writes.
323 SkASSERT(9 == fAtlasDest->getPendingReadCnt_TestOnly());
324 SkASSERT(2 == fAtlasDest->getPendingWriteCnt_TestOnly() ||
325 0 == fAtlasDest->getPendingWriteCnt_TestOnly());
326 sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(
327 fAtlasDest,
328 nullptr, nullptr);
329#endif
330
331 rtc->clear(nullptr, 0xFFFFFFFF, true); // clear the atlas
332
333 int blocksInAtlas = 0;
334 for (int i = 0; i < lists.count(); ++i) {
335 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
336 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
337 kAtlasTileSize, kAtlasTileSize);
338
339 // For now, we avoid the resource buffer issues and just use clears
340#if 1
341 rtc->clear(&r, op->color(), false);
342#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400343 GrPaint paint;
Brian Salomon9a036422017-07-13 17:04:43 -0400344 paint.setColor4f(GrColor4f::FromGrColor(op->color()));
345 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
346 SkRect::Make(r)));
347 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400348#endif
349 blocksInAtlas++;
350
351 // Set the atlased Op's color to white (so we know we're not using it for
352 // the final draw).
353 op->setColor(0xFFFFFFFF);
354
355 // Set the atlased Op's localRect to point to where it landed in the atlas
356 op->setLocalRect(SkRect::Make(r));
357
358 // TODO: we also need to set the op's GrSuperDeferredSimpleTextureEffect to point
359 // to the rtc's proxy!
360 }
361
362 // We've updated all these ops and we certainly don't want to process them again
363 this->clearOpsFor(lists[i]);
364 }
365
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400366 results->push_back(std::move(rtc));
367 }
368
369private:
370 typedef struct {
371 uint32_t fID;
372 AtlasedRectOp* fHead;
373 } LinkedListHeader;
374
375 LinkedListHeader* getList(uint32_t opListID) {
376 for (int i = 0; i < fOps.count(); ++i) {
377 if (opListID == fOps[i].fID) {
378 return &(fOps[i]);
379 }
380 }
381 return nullptr;
382 }
383
384 void clearOpsFor(LinkedListHeader* header) {
385 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
386 // forget about them in the laziest way possible.
387 header->fHead = nullptr;
388 header->fID = 0; // invalid opList ID
389 }
390
391 // Each opList containing AtlasedRectOps gets its own internal singly-linked list
392 SkTDArray<LinkedListHeader> fOps;
393
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400394 // For the time being we need to pre-allocate the atlas bc the TextureSamplers require
395 // a GrTexture
396 sk_sp<GrTextureProxy> fAtlasDest;
397
398 // Set to true when the testing harness expects this object to be no longer used
399 bool fDone;
400};
401
402// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
403static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
404 sk_sp<GrTextureProxy> fakeAtlas) {
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400405 sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContext(
406 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400407 3*kDrawnTileSize,
408 kDrawnTileSize,
409 kRGBA_8888_GrPixelConfig,
410 nullptr));
411
412 rtc->clear(nullptr, GrColorPackRGBA(255, 0, 0, 255), true);
413
414 for (int i = 0; i < 3; ++i) {
415 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
416
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400417 // TODO: here is the blocker for deferring creation of the atlas. The TextureSamplers
418 // created here currently require a hard GrTexture.
Brian Salomonaff329b2017-08-11 09:40:37 -0400419 auto fp = GrSimpleTextureEffect::Make(fakeAtlas, nullptr, SkMatrix::I());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400420 GrPaint paint;
421 paint.addColorFragmentProcessor(std::move(fp));
422 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Salomon9a036422017-07-13 17:04:43 -0400423 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400424
425 AtlasedRectOp* sparePtr = op.get();
426
Brian Salomon9a036422017-07-13 17:04:43 -0400427 uint32_t opListID = rtc->priv().testingOnly_addDrawOp(std::move(op));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400428
429 object->addOp(opListID, sparePtr);
430 }
431
432 return rtc->asTextureProxyRef();
433}
434
435// Enable this if you want to debug the final draws w/o having the atlasCallback create the
436// atlas
437#if 0
Chris Dalton12658942017-10-05 19:45:25 -0600438#include "SkImageEncoder.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400439#include "SkGrPriv.h"
Chris Dalton12658942017-10-05 19:45:25 -0600440#include "sk_tool_utils.h"
441
442static void save_bm(const SkBitmap& bm, const char name[]) {
443 bool result = sk_tool_utils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
444 SkASSERT(result);
445}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400446
447sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
448 SkBitmap bm;
449 bm.allocN32Pixels(18, 2, true);
450 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
451 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
452 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
453 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
454 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
455 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
456 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
457 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
458 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
459
460#if 1
461 save_bm(bm, "atlas-fake.png");
462#endif
463
464 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info(), *context->caps());
465 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
466
467 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
468 context->textureProvider(),
469 desc, SkBudgeted::kYes,
470 bm.getPixels(), bm.rowBytes());
471
472 return sk_ref_sp(tmp->asTextureProxy());
473}
474#else
475// TODO: this is unfortunate and must be removed. We want the atlas to be created later.
476sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
477 GrSurfaceDesc desc;
478 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400479 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
480 desc.fWidth = 32;
481 desc.fHeight = 16;
Robert Phillips16d8ec62017-07-27 16:16:25 -0400482 desc.fConfig = kSkia8888_GrPixelConfig;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400483 sk_sp<GrSurfaceProxy> atlasDest = GrSurfaceProxy::MakeDeferred(
484 context->resourceProvider(),
485 desc, SkBackingFit::kExact,
486 SkBudgeted::kYes,
487 GrResourceProvider::kNoPendingIO_Flag);
488 return sk_ref_sp(atlasDest->asTextureProxy());
489}
490#endif
491
492static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
493 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
494 REPORTER_ASSERT(reporter, expected == readback);
495 if (expected != readback) {
496 SkDebugf("Color mismatch: %x %x\n", expected, readback);
497 }
498}
499
500/*
501 * For the atlasing test we make a DAG that looks like:
502 *
503 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
504 * \ /
505 * \ /
506 * RT4
507 * We then flush RT4 and expect only ops 0-5 to be atlased together.
508 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
509 * R G B C M Y
510 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
511 *
512 * Note: until MDB lands, the atlas will actually have width= 9*kAtlasTileSize and look like:
513 * R G B C M Y K Grey White
514 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400515DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400516 static const int kNumProxies = 3;
517
518 GrContext* context = ctxInfo.grContext();
519
520 if (context->caps()->useDrawInsteadOfClear()) {
521 // TODO: fix the buffer issues so this can run on all devices
522 return;
523 }
524
Chris Daltonfe199b72017-05-05 11:26:15 -0400525 AtlasObject object;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400526
527 // For now (until we add a GrSuperDeferredSimpleTextureEffect), we create the final atlas
528 // proxy ahead of time.
529 sk_sp<GrTextureProxy> atlasDest = pre_create_atlas(context);
530
Chris Daltonfe199b72017-05-05 11:26:15 -0400531 object.setAtlasDest(atlasDest);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400532
Chris Daltonfe199b72017-05-05 11:26:15 -0400533 context->contextPriv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400534
535 sk_sp<GrTextureProxy> proxies[kNumProxies];
536 for (int i = 0; i < kNumProxies; ++i) {
Chris Daltonfe199b72017-05-05 11:26:15 -0400537 proxies[i] = make_upstream_image(context, &object, i*3, atlasDest);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400538 }
539
540 static const int kFinalWidth = 6*kDrawnTileSize;
541 static const int kFinalHeight = kDrawnTileSize;
542
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400543 sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContext(
544 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400545 kFinalWidth,
546 kFinalHeight,
547 kRGBA_8888_GrPixelConfig,
548 nullptr));
549
550 rtc->clear(nullptr, 0xFFFFFFFF, true);
551
552 // Note that this doesn't include the third texture proxy
553 for (int i = 0; i < kNumProxies-1; ++i) {
554 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
555
556 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
557
558 GrPaint paint;
Brian Salomonaff329b2017-08-11 09:40:37 -0400559 auto fp = GrSimpleTextureEffect::Make(std::move(proxies[i]), nullptr, t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400560 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
561 paint.addColorFragmentProcessor(std::move(fp));
562
563 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
564 }
565
Greg Daniela5cb7812017-06-16 09:45:32 -0400566 rtc->prepareForExternalIO(0, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400567
568 SkBitmap readBack;
569 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
570
571 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
572 readBack.rowBytes(), 0, 0);
573 SkASSERT(result);
574
Chris Daltonfe199b72017-05-05 11:26:15 -0400575 context->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
576
577 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400578
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400579 int x = kDrawnTileSize/2;
580 test_color(reporter, readBack, x, SK_ColorRED);
581 x += kDrawnTileSize;
582 test_color(reporter, readBack, x, SK_ColorGREEN);
583 x += kDrawnTileSize;
584 test_color(reporter, readBack, x, SK_ColorBLUE);
585 x += kDrawnTileSize;
586 test_color(reporter, readBack, x, SK_ColorCYAN);
587 x += kDrawnTileSize;
588 test_color(reporter, readBack, x, SK_ColorMAGENTA);
589 x += kDrawnTileSize;
590 test_color(reporter, readBack, x, SK_ColorYELLOW);
591}
592
593#endif