blob: 370165121dd9be284d519c8bdffb2f51fccfc964 [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;
131 indices[3] = 0;
132 indices[4] = 2;
133 indices[5] = 3;
134
135 // Setup positions
136 SkPoint* position = (SkPoint*) vertices;
137 position->setRectFan(fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom, vertexStride);
138
139 // Setup vertex colors
140 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
141 for (int i = 0; i < 4; ++i) {
142 *color = fColor;
143 color = (GrColor*)((intptr_t)color + vertexStride);
144 }
145
146 // Setup local coords
147 if (fHasLocalRect) {
148 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
149 for (int i = 0; i < 4; i++) {
150 *coords = fLocalQuad.point(i);
151 coords = (SkPoint*)((intptr_t) coords + vertexStride);
152 }
153 }
154
Chris Dalton3809bab2017-06-13 10:55:06 -0600155 GrMesh mesh(GrPrimitiveType::kTriangles);
Chris Dalton114a3c02017-05-26 15:17:19 -0600156 mesh.setIndexed(indexBuffer, 6, firstIndex, 0, 3);
157 mesh.setVertexData(vertexBuffer, firstVertex);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400158
Brian Salomon9a036422017-07-13 17:04:43 -0400159 target->draw(gp.get(), fHelper.makePipeline(target), mesh);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400160 }
161
Brian Salomon9a036422017-07-13 17:04:43 -0400162 Helper fHelper;
163
164 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400165};
166
Brian Salomon9a036422017-07-13 17:04:43 -0400167} // anonymous namespace
168
Brian Salomon9a036422017-07-13 17:04:43 -0400169static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
170
171namespace {
172
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400173/*
174 * Atlased ops just draw themselves as textured rects with the texture pixels being
175 * pulled out of the atlas. Their color is based on their ID.
176 */
177class AtlasedRectOp final : public NonAARectOp {
178public:
179 DEFINE_OP_CLASS_ID
180
181 ~AtlasedRectOp() override {
182 fID = -1;
183 }
184
185 const char* name() const override { return "AtlasedRectOp"; }
186
187 int id() const { return fID; }
188
Brian Salomon9a036422017-07-13 17:04:43 -0400189 static std::unique_ptr<AtlasedRectOp> Make(GrPaint&& paint, const SkRect& r, int id) {
190 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(std::move(paint), r, id).release();
191 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
192 }
193
194 // We set the initial color of the NonAARectOp based on the ID.
195 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
196 // pulling from the atlas.
197 AtlasedRectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r, int id)
198 : INHERITED(helperArgs, kColors[id], r, &kEmptyRect, ClassID())
199 , fID(id)
200 , fNext(nullptr) {
201 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400202 }
203
204 void setColor(GrColor color) { fColor = color; }
205 void setLocalRect(const SkRect& localRect) {
206 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
207 fLocalQuad.set(localRect);
208 }
209
210 AtlasedRectOp* next() const { return fNext; }
211 void setNext(AtlasedRectOp* next) {
212 fNext = next;
213 }
214
215private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400216
217 static const int kMaxIDs = 9;
218 static const SkColor kColors[kMaxIDs];
219
220 int fID;
221 // The Atlased ops have an internal singly-linked list of ops that land in the same opList
222 AtlasedRectOp* fNext;
223
224 typedef NonAARectOp INHERITED;
225};
226
Brian Salomon9a036422017-07-13 17:04:43 -0400227} // anonymous namespace
228
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400229const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
230 GrColorPackRGBA(255, 0, 0, 255),
231 GrColorPackRGBA(0, 255, 0, 255),
232 GrColorPackRGBA(0, 0, 255, 255),
233 GrColorPackRGBA(0, 255, 255, 255),
234 GrColorPackRGBA(255, 0, 255, 255),
235 GrColorPackRGBA(255, 255, 0, 255),
236 GrColorPackRGBA(0, 0, 0, 255),
237 GrColorPackRGBA(128, 128, 128, 255),
238 GrColorPackRGBA(255, 255, 255, 255)
239};
240
241static const int kDrawnTileSize = 16;
242
243/*
244 * Rather than performing any rect packing, this atlaser just lays out constant-sized
245 * tiles in an Nx1 row
246 */
247static const int kAtlasTileSize = 2;
248
249/*
250 * This class aggregates the op information required for atlasing
251 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400252class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400253public:
254 AtlasObject() : fDone(false) { }
255
256 ~AtlasObject() override {
257 SkASSERT(fDone);
258 }
259
260 void markAsDone() {
261 fDone = true;
262 }
263
264 // Insert the new op in an internal singly-linked list for 'opListID'
265 void addOp(uint32_t opListID, AtlasedRectOp* op) {
266 LinkedListHeader* header = nullptr;
267 for (int i = 0; i < fOps.count(); ++i) {
268 if (opListID == fOps[i].fID) {
269 header = &(fOps[i]);
270 }
271 }
272
273 if (!header) {
274 fOps.push({opListID, nullptr});
275 header = &(fOps[fOps.count()-1]);
276 }
277
278 op->setNext(header->fHead);
279 header->fHead = op;
280 }
281
282 // For the time being we need to pre-allocate the atlas.
283 void setAtlasDest(sk_sp<GrTextureProxy> atlasDest) {
284 fAtlasDest = atlasDest;
285 }
286
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400287 /*
288 * This callback back creates the atlas and updates the AtlasedRectOps to read from it
289 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400290 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400291 const uint32_t* opListIDs, int numOpListIDs,
292 SkTArray<sk_sp<GrRenderTargetContext>>* results) override {
293 SkASSERT(!results->count());
294
295 // Until MDB is landed we will most-likely only have one opList.
296 SkTDArray<LinkedListHeader*> lists;
297 for (int i = 0; i < numOpListIDs; ++i) {
298 if (LinkedListHeader* list = this->getList(opListIDs[i])) {
299 lists.push(list);
300 }
301 }
302
303 if (!lists.count()) {
304 return; // nothing to atlas
305 }
306
307 // TODO: right now we have to pre-allocate the atlas bc the TextureSamplers need a
308 // hard GrTexture
309#if 0
310 GrSurfaceDesc desc;
311 desc.fFlags = kRenderTarget_GrSurfaceFlag;
312 desc.fWidth = this->numOps() * kAtlasTileSize;
313 desc.fHeight = kAtlasTileSize;
314 desc.fConfig = kRGBA_8888_GrPixelConfig;
315
316 sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(desc,
317 nullptr,
318 nullptr);
319#else
320 // At this point all the GrAtlasedOp's should have lined up to read from 'atlasDest' and
321 // there should either be two writes to clear it or no writes.
322 SkASSERT(9 == fAtlasDest->getPendingReadCnt_TestOnly());
323 SkASSERT(2 == fAtlasDest->getPendingWriteCnt_TestOnly() ||
324 0 == fAtlasDest->getPendingWriteCnt_TestOnly());
325 sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(
326 fAtlasDest,
327 nullptr, nullptr);
328#endif
329
330 rtc->clear(nullptr, 0xFFFFFFFF, true); // clear the atlas
331
332 int blocksInAtlas = 0;
333 for (int i = 0; i < lists.count(); ++i) {
334 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
335 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
336 kAtlasTileSize, kAtlasTileSize);
337
338 // For now, we avoid the resource buffer issues and just use clears
339#if 1
340 rtc->clear(&r, op->color(), false);
341#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400342 GrPaint paint;
Brian Salomon9a036422017-07-13 17:04:43 -0400343 paint.setColor4f(GrColor4f::FromGrColor(op->color()));
344 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
345 SkRect::Make(r)));
346 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400347#endif
348 blocksInAtlas++;
349
350 // Set the atlased Op's color to white (so we know we're not using it for
351 // the final draw).
352 op->setColor(0xFFFFFFFF);
353
354 // Set the atlased Op's localRect to point to where it landed in the atlas
355 op->setLocalRect(SkRect::Make(r));
356
357 // TODO: we also need to set the op's GrSuperDeferredSimpleTextureEffect to point
358 // to the rtc's proxy!
359 }
360
361 // We've updated all these ops and we certainly don't want to process them again
362 this->clearOpsFor(lists[i]);
363 }
364
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400365 results->push_back(std::move(rtc));
366 }
367
368private:
369 typedef struct {
370 uint32_t fID;
371 AtlasedRectOp* fHead;
372 } LinkedListHeader;
373
374 LinkedListHeader* getList(uint32_t opListID) {
375 for (int i = 0; i < fOps.count(); ++i) {
376 if (opListID == fOps[i].fID) {
377 return &(fOps[i]);
378 }
379 }
380 return nullptr;
381 }
382
383 void clearOpsFor(LinkedListHeader* header) {
384 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
385 // forget about them in the laziest way possible.
386 header->fHead = nullptr;
387 header->fID = 0; // invalid opList ID
388 }
389
390 // Each opList containing AtlasedRectOps gets its own internal singly-linked list
391 SkTDArray<LinkedListHeader> fOps;
392
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400393 // For the time being we need to pre-allocate the atlas bc the TextureSamplers require
394 // a GrTexture
395 sk_sp<GrTextureProxy> fAtlasDest;
396
397 // Set to true when the testing harness expects this object to be no longer used
398 bool fDone;
399};
400
401// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
402static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
403 sk_sp<GrTextureProxy> fakeAtlas) {
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400404 sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContext(
405 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400406 3*kDrawnTileSize,
407 kDrawnTileSize,
408 kRGBA_8888_GrPixelConfig,
409 nullptr));
410
411 rtc->clear(nullptr, GrColorPackRGBA(255, 0, 0, 255), true);
412
413 for (int i = 0; i < 3; ++i) {
414 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
415
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400416 // TODO: here is the blocker for deferring creation of the atlas. The TextureSamplers
417 // created here currently require a hard GrTexture.
Brian Salomonaff329b2017-08-11 09:40:37 -0400418 auto fp = GrSimpleTextureEffect::Make(fakeAtlas, nullptr, SkMatrix::I());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400419 GrPaint paint;
420 paint.addColorFragmentProcessor(std::move(fp));
421 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Salomon9a036422017-07-13 17:04:43 -0400422 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400423
424 AtlasedRectOp* sparePtr = op.get();
425
Brian Salomon9a036422017-07-13 17:04:43 -0400426 uint32_t opListID = rtc->priv().testingOnly_addDrawOp(std::move(op));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400427
428 object->addOp(opListID, sparePtr);
429 }
430
431 return rtc->asTextureProxyRef();
432}
433
434// Enable this if you want to debug the final draws w/o having the atlasCallback create the
435// atlas
436#if 0
Chris Dalton12658942017-10-05 19:45:25 -0600437#include "SkImageEncoder.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400438#include "SkGrPriv.h"
Chris Dalton12658942017-10-05 19:45:25 -0600439#include "sk_tool_utils.h"
440
441static void save_bm(const SkBitmap& bm, const char name[]) {
442 bool result = sk_tool_utils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
443 SkASSERT(result);
444}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400445
446sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
447 SkBitmap bm;
448 bm.allocN32Pixels(18, 2, true);
449 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
450 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
451 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
452 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
453 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
454 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
455 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
456 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
457 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
458
459#if 1
460 save_bm(bm, "atlas-fake.png");
461#endif
462
463 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info(), *context->caps());
464 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
465
466 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
467 context->textureProvider(),
468 desc, SkBudgeted::kYes,
469 bm.getPixels(), bm.rowBytes());
470
471 return sk_ref_sp(tmp->asTextureProxy());
472}
473#else
474// TODO: this is unfortunate and must be removed. We want the atlas to be created later.
475sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
476 GrSurfaceDesc desc;
477 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400478 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
479 desc.fWidth = 32;
480 desc.fHeight = 16;
Robert Phillips16d8ec62017-07-27 16:16:25 -0400481 desc.fConfig = kSkia8888_GrPixelConfig;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400482 sk_sp<GrSurfaceProxy> atlasDest = GrSurfaceProxy::MakeDeferred(
483 context->resourceProvider(),
484 desc, SkBackingFit::kExact,
485 SkBudgeted::kYes,
486 GrResourceProvider::kNoPendingIO_Flag);
487 return sk_ref_sp(atlasDest->asTextureProxy());
488}
489#endif
490
491static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
492 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
493 REPORTER_ASSERT(reporter, expected == readback);
494 if (expected != readback) {
495 SkDebugf("Color mismatch: %x %x\n", expected, readback);
496 }
497}
498
499/*
500 * For the atlasing test we make a DAG that looks like:
501 *
502 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
503 * \ /
504 * \ /
505 * RT4
506 * We then flush RT4 and expect only ops 0-5 to be atlased together.
507 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
508 * R G B C M Y
509 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
510 *
511 * Note: until MDB lands, the atlas will actually have width= 9*kAtlasTileSize and look like:
512 * R G B C M Y K Grey White
513 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400514DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400515 static const int kNumProxies = 3;
516
517 GrContext* context = ctxInfo.grContext();
518
519 if (context->caps()->useDrawInsteadOfClear()) {
520 // TODO: fix the buffer issues so this can run on all devices
521 return;
522 }
523
Chris Daltonfe199b72017-05-05 11:26:15 -0400524 AtlasObject object;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400525
526 // For now (until we add a GrSuperDeferredSimpleTextureEffect), we create the final atlas
527 // proxy ahead of time.
528 sk_sp<GrTextureProxy> atlasDest = pre_create_atlas(context);
529
Chris Daltonfe199b72017-05-05 11:26:15 -0400530 object.setAtlasDest(atlasDest);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400531
Chris Daltonfe199b72017-05-05 11:26:15 -0400532 context->contextPriv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400533
534 sk_sp<GrTextureProxy> proxies[kNumProxies];
535 for (int i = 0; i < kNumProxies; ++i) {
Chris Daltonfe199b72017-05-05 11:26:15 -0400536 proxies[i] = make_upstream_image(context, &object, i*3, atlasDest);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400537 }
538
539 static const int kFinalWidth = 6*kDrawnTileSize;
540 static const int kFinalHeight = kDrawnTileSize;
541
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400542 sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContext(
543 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400544 kFinalWidth,
545 kFinalHeight,
546 kRGBA_8888_GrPixelConfig,
547 nullptr));
548
549 rtc->clear(nullptr, 0xFFFFFFFF, true);
550
551 // Note that this doesn't include the third texture proxy
552 for (int i = 0; i < kNumProxies-1; ++i) {
553 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
554
555 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
556
557 GrPaint paint;
Brian Salomonaff329b2017-08-11 09:40:37 -0400558 auto fp = GrSimpleTextureEffect::Make(std::move(proxies[i]), nullptr, t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400559 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
560 paint.addColorFragmentProcessor(std::move(fp));
561
562 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
563 }
564
Greg Daniela5cb7812017-06-16 09:45:32 -0400565 rtc->prepareForExternalIO(0, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400566
567 SkBitmap readBack;
568 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
569
570 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
571 readBack.rowBytes(), 0, 0);
572 SkASSERT(result);
573
Chris Daltonfe199b72017-05-05 11:26:15 -0400574 context->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
575
576 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400577
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400578 int x = kDrawnTileSize/2;
579 test_color(reporter, readBack, x, SK_ColorRED);
580 x += kDrawnTileSize;
581 test_color(reporter, readBack, x, SK_ColorGREEN);
582 x += kDrawnTileSize;
583 test_color(reporter, readBack, x, SK_ColorBLUE);
584 x += kDrawnTileSize;
585 test_color(reporter, readBack, x, SK_ColorCYAN);
586 x += kDrawnTileSize;
587 test_color(reporter, readBack, x, SK_ColorMAGENTA);
588 x += kDrawnTileSize;
589 test_color(reporter, readBack, x, SK_ColorYELLOW);
590}
591
592#endif