blob: 4ca7522ceb21e5ac6823c41be2857b9ea929cec1 [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 Phillipseb35f4d2017-03-21 07:56:47 -040018#include "GrRenderTargetContextPriv.h"
19#include "GrResourceProvider.h"
20#include "GrQuad.h"
Cary Clark74f623d2017-11-06 20:02:02 -050021#include "SkPointPriv.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040022#include "effects/GrSimpleTextureEffect.h"
Brian Salomon9a036422017-07-13 17:04:43 -040023#include "ops/GrSimpleMeshDrawOpHelper.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040024
Brian Salomon9a036422017-07-13 17:04:43 -040025namespace {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040026// This is a simplified mesh drawing op that can be used in the atlas generation test.
27// Please see AtlasedRectOp below.
Brian Salomon9a036422017-07-13 17:04:43 -040028class NonAARectOp : public GrMeshDrawOp {
29protected:
30 using Helper = GrSimpleMeshDrawOpHelper;
31
Robert Phillipseb35f4d2017-03-21 07:56:47 -040032public:
33 DEFINE_OP_CLASS_ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -040034
35 // This creates an instance of a simple non-AA solid color rect-drawing Op
Brian Salomon9a036422017-07-13 17:04:43 -040036 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& r) {
37 return Helper::FactoryHelper<NonAARectOp>(std::move(paint), r, nullptr, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040038 }
39
40 // This creates an instance of a simple non-AA textured rect-drawing Op
Brian Salomon9a036422017-07-13 17:04:43 -040041 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& r, const SkRect& local) {
42 return Helper::FactoryHelper<NonAARectOp>(std::move(paint), r, &local, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040043 }
44
45 GrColor color() const { return fColor; }
46
Brian Salomon9a036422017-07-13 17:04:43 -040047 NonAARectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r,
48 const SkRect* localRect, int32_t classID)
49 : INHERITED(classID)
50 , fColor(color)
51 , fHasLocalRect(SkToBool(localRect))
52 , fRect(r)
53 , fHelper(helperArgs, GrAAType::kNone) {
54 if (fHasLocalRect) {
55 fLocalQuad.set(*localRect);
56 }
57 // Choose some conservative values for aa bloat and zero area.
58 this->setBounds(r, HasAABloat::kYes, IsZeroArea::kYes);
59 }
60
Robert Phillipsb493eeb2017-09-13 13:10:52 -040061 const char* name() const override { return "NonAARectOp"; }
62
Robert Phillipsf1748f52017-09-14 14:11:24 -040063 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -040064 fHelper.visitProxies(func);
65 }
66
Brian Salomon9a036422017-07-13 17:04:43 -040067 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
68
Brian Osman9a725dd2017-09-20 09:53:22 -040069 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip*,
70 GrPixelConfigIsClamped dstIsClamped) override {
Brian Salomon9a036422017-07-13 17:04:43 -040071 // Set the color to unknown because the subclass may change the color later.
72 GrProcessorAnalysisColor gpColor;
73 gpColor.setToUnknown();
74 // We ignore the clip so pass this rather than the GrAppliedClip param.
75 static GrAppliedClip kNoClip;
Brian Osman9a725dd2017-09-20 09:53:22 -040076 return fHelper.xpRequiresDstTexture(caps, &kNoClip, dstIsClamped,
77 GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomon9a036422017-07-13 17:04:43 -040078 }
79
Robert Phillipseb35f4d2017-03-21 07:56:47 -040080protected:
Robert Phillipseb35f4d2017-03-21 07:56:47 -040081 GrColor fColor;
82 bool fHasLocalRect;
83 GrQuad fLocalQuad;
84 SkRect fRect;
85
86private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -040087 bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
88
Brian Salomon91326c32017-08-09 16:02:19 -040089 void onPrepareDraws(Target* target) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040090 using namespace GrDefaultGeoProcFactory;
91
92 // The vertex attrib order is always pos, color, local coords.
93 static const int kColorOffset = sizeof(SkPoint);
94 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
95
96 sk_sp<GrGeometryProcessor> gp =
97 GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
98 Coverage::kSolid_Type,
99 fHasLocalRect ? LocalCoords::kHasExplicit_Type
100 : LocalCoords::kUnused_Type,
101 SkMatrix::I());
102 if (!gp) {
103 SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n");
104 return;
105 }
106
107 size_t vertexStride = gp->getVertexStride();
108
109 SkASSERT(fHasLocalRect
110 ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
111 : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
112
113 const GrBuffer* indexBuffer;
114 int firstIndex;
115 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
116 if (!indices) {
117 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
118 return;
119 }
120
121 const GrBuffer* vertexBuffer;
122 int firstVertex;
123 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
124 if (!vertices) {
125 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
126 return;
127 }
128
129 // Setup indices
130 indices[0] = 0;
131 indices[1] = 1;
132 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000133 indices[3] = 2;
134 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400135 indices[5] = 3;
136
137 // Setup positions
138 SkPoint* position = (SkPoint*) vertices;
Cary Clark74f623d2017-11-06 20:02:02 -0500139 SkPointPriv::SetRectTriStrip(position, fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
Brian Salomon57caa662017-10-18 12:21:05 +0000140 vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400141
142 // Setup vertex colors
143 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
144 for (int i = 0; i < 4; ++i) {
145 *color = fColor;
146 color = (GrColor*)((intptr_t)color + vertexStride);
147 }
148
149 // Setup local coords
150 if (fHasLocalRect) {
151 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
152 for (int i = 0; i < 4; i++) {
153 *coords = fLocalQuad.point(i);
154 coords = (SkPoint*)((intptr_t) coords + vertexStride);
155 }
156 }
157
Chris Dalton3809bab2017-06-13 10:55:06 -0600158 GrMesh mesh(GrPrimitiveType::kTriangles);
Chris Dalton114a3c02017-05-26 15:17:19 -0600159 mesh.setIndexed(indexBuffer, 6, firstIndex, 0, 3);
160 mesh.setVertexData(vertexBuffer, firstVertex);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400161
Brian Salomon9a036422017-07-13 17:04:43 -0400162 target->draw(gp.get(), fHelper.makePipeline(target), mesh);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400163 }
164
Brian Salomon9a036422017-07-13 17:04:43 -0400165 Helper fHelper;
166
167 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400168};
169
Brian Salomon9a036422017-07-13 17:04:43 -0400170} // anonymous namespace
171
Brian Salomon9a036422017-07-13 17:04:43 -0400172static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
173
174namespace {
175
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400176/*
177 * Atlased ops just draw themselves as textured rects with the texture pixels being
178 * pulled out of the atlas. Their color is based on their ID.
179 */
180class AtlasedRectOp final : public NonAARectOp {
181public:
182 DEFINE_OP_CLASS_ID
183
184 ~AtlasedRectOp() override {
185 fID = -1;
186 }
187
188 const char* name() const override { return "AtlasedRectOp"; }
189
190 int id() const { return fID; }
191
Brian Salomon9a036422017-07-13 17:04:43 -0400192 static std::unique_ptr<AtlasedRectOp> Make(GrPaint&& paint, const SkRect& r, int id) {
193 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(std::move(paint), r, id).release();
194 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
195 }
196
197 // We set the initial color of the NonAARectOp based on the ID.
198 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
199 // pulling from the atlas.
200 AtlasedRectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r, int id)
201 : INHERITED(helperArgs, kColors[id], r, &kEmptyRect, ClassID())
202 , fID(id)
203 , fNext(nullptr) {
204 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400205 }
206
207 void setColor(GrColor color) { fColor = color; }
208 void setLocalRect(const SkRect& localRect) {
209 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
210 fLocalQuad.set(localRect);
211 }
212
213 AtlasedRectOp* next() const { return fNext; }
214 void setNext(AtlasedRectOp* next) {
215 fNext = next;
216 }
217
218private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400219
220 static const int kMaxIDs = 9;
221 static const SkColor kColors[kMaxIDs];
222
223 int fID;
224 // The Atlased ops have an internal singly-linked list of ops that land in the same opList
225 AtlasedRectOp* fNext;
226
227 typedef NonAARectOp INHERITED;
228};
229
Brian Salomon9a036422017-07-13 17:04:43 -0400230} // anonymous namespace
231
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400232const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
233 GrColorPackRGBA(255, 0, 0, 255),
234 GrColorPackRGBA(0, 255, 0, 255),
235 GrColorPackRGBA(0, 0, 255, 255),
236 GrColorPackRGBA(0, 255, 255, 255),
237 GrColorPackRGBA(255, 0, 255, 255),
238 GrColorPackRGBA(255, 255, 0, 255),
239 GrColorPackRGBA(0, 0, 0, 255),
240 GrColorPackRGBA(128, 128, 128, 255),
241 GrColorPackRGBA(255, 255, 255, 255)
242};
243
244static const int kDrawnTileSize = 16;
245
246/*
247 * Rather than performing any rect packing, this atlaser just lays out constant-sized
248 * tiles in an Nx1 row
249 */
250static const int kAtlasTileSize = 2;
251
252/*
253 * This class aggregates the op information required for atlasing
254 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400255class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400256public:
257 AtlasObject() : fDone(false) { }
258
259 ~AtlasObject() override {
260 SkASSERT(fDone);
261 }
262
263 void markAsDone() {
264 fDone = true;
265 }
266
267 // Insert the new op in an internal singly-linked list for 'opListID'
268 void addOp(uint32_t opListID, AtlasedRectOp* op) {
269 LinkedListHeader* header = nullptr;
270 for (int i = 0; i < fOps.count(); ++i) {
271 if (opListID == fOps[i].fID) {
272 header = &(fOps[i]);
273 }
274 }
275
276 if (!header) {
277 fOps.push({opListID, nullptr});
278 header = &(fOps[fOps.count()-1]);
279 }
280
281 op->setNext(header->fHead);
282 header->fHead = op;
283 }
284
285 // For the time being we need to pre-allocate the atlas.
286 void setAtlasDest(sk_sp<GrTextureProxy> atlasDest) {
287 fAtlasDest = atlasDest;
288 }
289
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400290 /*
291 * This callback back creates the atlas and updates the AtlasedRectOps to read from it
292 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400293 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400294 const uint32_t* opListIDs, int numOpListIDs,
295 SkTArray<sk_sp<GrRenderTargetContext>>* results) override {
296 SkASSERT(!results->count());
297
298 // Until MDB is landed we will most-likely only have one opList.
299 SkTDArray<LinkedListHeader*> lists;
300 for (int i = 0; i < numOpListIDs; ++i) {
301 if (LinkedListHeader* list = this->getList(opListIDs[i])) {
302 lists.push(list);
303 }
304 }
305
306 if (!lists.count()) {
307 return; // nothing to atlas
308 }
309
310 // TODO: right now we have to pre-allocate the atlas bc the TextureSamplers need a
311 // hard GrTexture
312#if 0
313 GrSurfaceDesc desc;
314 desc.fFlags = kRenderTarget_GrSurfaceFlag;
315 desc.fWidth = this->numOps() * kAtlasTileSize;
316 desc.fHeight = kAtlasTileSize;
317 desc.fConfig = kRGBA_8888_GrPixelConfig;
318
319 sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(desc,
320 nullptr,
321 nullptr);
322#else
323 // At this point all the GrAtlasedOp's should have lined up to read from 'atlasDest' and
324 // there should either be two writes to clear it or no writes.
325 SkASSERT(9 == fAtlasDest->getPendingReadCnt_TestOnly());
326 SkASSERT(2 == fAtlasDest->getPendingWriteCnt_TestOnly() ||
327 0 == fAtlasDest->getPendingWriteCnt_TestOnly());
328 sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(
329 fAtlasDest,
330 nullptr, nullptr);
331#endif
332
Chris Dalton344e9032017-12-11 15:42:09 -0700333 // clear the atlas
334 rtc->clear(nullptr, 0xFFFFFFFF, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400335
336 int blocksInAtlas = 0;
337 for (int i = 0; i < lists.count(); ++i) {
338 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
339 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
340 kAtlasTileSize, kAtlasTileSize);
341
342 // For now, we avoid the resource buffer issues and just use clears
343#if 1
Chris Dalton344e9032017-12-11 15:42:09 -0700344 rtc->clear(&r, op->color(), GrRenderTargetContext::CanClearFullscreen::kNo);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400345#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400346 GrPaint paint;
Brian Salomon9a036422017-07-13 17:04:43 -0400347 paint.setColor4f(GrColor4f::FromGrColor(op->color()));
348 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
349 SkRect::Make(r)));
350 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400351#endif
352 blocksInAtlas++;
353
354 // Set the atlased Op's color to white (so we know we're not using it for
355 // the final draw).
356 op->setColor(0xFFFFFFFF);
357
358 // Set the atlased Op's localRect to point to where it landed in the atlas
359 op->setLocalRect(SkRect::Make(r));
360
361 // TODO: we also need to set the op's GrSuperDeferredSimpleTextureEffect to point
362 // to the rtc's proxy!
363 }
364
365 // We've updated all these ops and we certainly don't want to process them again
366 this->clearOpsFor(lists[i]);
367 }
368
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400369 results->push_back(std::move(rtc));
370 }
371
372private:
373 typedef struct {
374 uint32_t fID;
375 AtlasedRectOp* fHead;
376 } LinkedListHeader;
377
378 LinkedListHeader* getList(uint32_t opListID) {
379 for (int i = 0; i < fOps.count(); ++i) {
380 if (opListID == fOps[i].fID) {
381 return &(fOps[i]);
382 }
383 }
384 return nullptr;
385 }
386
387 void clearOpsFor(LinkedListHeader* header) {
388 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
389 // forget about them in the laziest way possible.
390 header->fHead = nullptr;
391 header->fID = 0; // invalid opList ID
392 }
393
394 // Each opList containing AtlasedRectOps gets its own internal singly-linked list
395 SkTDArray<LinkedListHeader> fOps;
396
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400397 // For the time being we need to pre-allocate the atlas bc the TextureSamplers require
398 // a GrTexture
399 sk_sp<GrTextureProxy> fAtlasDest;
400
401 // Set to true when the testing harness expects this object to be no longer used
402 bool fDone;
403};
404
405// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
406static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
407 sk_sp<GrTextureProxy> fakeAtlas) {
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400408 sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContext(
409 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400410 3*kDrawnTileSize,
411 kDrawnTileSize,
412 kRGBA_8888_GrPixelConfig,
413 nullptr));
414
Chris Dalton344e9032017-12-11 15:42:09 -0700415 rtc->clear(nullptr, GrColorPackRGBA(255, 0, 0, 255),
416 GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400417
418 for (int i = 0; i < 3; ++i) {
419 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
420
Brian Osman2240be92017-10-18 13:15:13 -0400421 auto fp = GrSimpleTextureEffect::Make(fakeAtlas, SkMatrix::I());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400422 GrPaint paint;
423 paint.addColorFragmentProcessor(std::move(fp));
424 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Salomon9a036422017-07-13 17:04:43 -0400425 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400426
427 AtlasedRectOp* sparePtr = op.get();
428
Brian Salomon9a036422017-07-13 17:04:43 -0400429 uint32_t opListID = rtc->priv().testingOnly_addDrawOp(std::move(op));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400430
431 object->addOp(opListID, sparePtr);
432 }
433
434 return rtc->asTextureProxyRef();
435}
436
437// Enable this if you want to debug the final draws w/o having the atlasCallback create the
438// atlas
439#if 0
Chris Dalton12658942017-10-05 19:45:25 -0600440#include "SkImageEncoder.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400441#include "SkGrPriv.h"
Chris Dalton12658942017-10-05 19:45:25 -0600442#include "sk_tool_utils.h"
443
444static void save_bm(const SkBitmap& bm, const char name[]) {
445 bool result = sk_tool_utils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
446 SkASSERT(result);
447}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400448
449sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
450 SkBitmap bm;
451 bm.allocN32Pixels(18, 2, true);
452 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
453 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
454 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
455 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
456 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
457 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
458 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
459 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
460 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
461
462#if 1
463 save_bm(bm, "atlas-fake.png");
464#endif
465
466 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info(), *context->caps());
467 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
468
469 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
470 context->textureProvider(),
471 desc, SkBudgeted::kYes,
472 bm.getPixels(), bm.rowBytes());
473
474 return sk_ref_sp(tmp->asTextureProxy());
475}
476#else
477// TODO: this is unfortunate and must be removed. We want the atlas to be created later.
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500478sk_sp<GrTextureProxy> pre_create_atlas(GrProxyProvider* proxyProvider) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400479 GrSurfaceDesc desc;
480 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400481 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
482 desc.fWidth = 32;
483 desc.fHeight = 16;
Robert Phillips16d8ec62017-07-27 16:16:25 -0400484 desc.fConfig = kSkia8888_GrPixelConfig;
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500485
486 return proxyProvider->createProxy(desc, SkBackingFit::kExact, SkBudgeted::kYes,
487 GrResourceProvider::kNoPendingIO_Flag);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400488}
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
Chris Daltonfe199b72017-05-05 11:26:15 -0400519 AtlasObject object;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400520
521 // For now (until we add a GrSuperDeferredSimpleTextureEffect), we create the final atlas
522 // proxy ahead of time.
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500523 sk_sp<GrTextureProxy> atlasDest = pre_create_atlas(context->contextPriv().proxyProvider());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400524
Chris Daltonfe199b72017-05-05 11:26:15 -0400525 object.setAtlasDest(atlasDest);
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) {
Chris Daltonfe199b72017-05-05 11:26:15 -0400531 proxies[i] = make_upstream_image(context, &object, i*3, atlasDest);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400532 }
533
534 static const int kFinalWidth = 6*kDrawnTileSize;
535 static const int kFinalHeight = kDrawnTileSize;
536
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400537 sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContext(
538 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400539 kFinalWidth,
540 kFinalHeight,
541 kRGBA_8888_GrPixelConfig,
542 nullptr));
543
Chris Dalton344e9032017-12-11 15:42:09 -0700544 rtc->clear(nullptr, 0xFFFFFFFF, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400545
546 // Note that this doesn't include the third texture proxy
547 for (int i = 0; i < kNumProxies-1; ++i) {
548 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
549
550 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
551
552 GrPaint paint;
Brian Osman2240be92017-10-18 13:15:13 -0400553 auto fp = GrSimpleTextureEffect::Make(std::move(proxies[i]), t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400554 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
555 paint.addColorFragmentProcessor(std::move(fp));
556
557 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
558 }
559
Greg Daniela5cb7812017-06-16 09:45:32 -0400560 rtc->prepareForExternalIO(0, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400561
562 SkBitmap readBack;
563 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
564
565 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
566 readBack.rowBytes(), 0, 0);
567 SkASSERT(result);
568
Chris Daltonfe199b72017-05-05 11:26:15 -0400569 context->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
570
571 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400572
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400573 int x = kDrawnTileSize/2;
574 test_color(reporter, readBack, x, SK_ColorRED);
575 x += kDrawnTileSize;
576 test_color(reporter, readBack, x, SK_ColorGREEN);
577 x += kDrawnTileSize;
578 test_color(reporter, readBack, x, SK_ColorBLUE);
579 x += kDrawnTileSize;
580 test_color(reporter, readBack, x, SK_ColorCYAN);
581 x += kDrawnTileSize;
582 test_color(reporter, readBack, x, SK_ColorMAGENTA);
583 x += kDrawnTileSize;
584 test_color(reporter, readBack, x, SK_ColorYELLOW);
585}
586
587#endif