blob: 62f6c0f110bf8426dfd5128b3eb30727fea0eb42 [file] [log] [blame]
Robert Phillipseb35f4d2017-03-21 07:56:47 -04001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "Test.h"
9
10#if SK_SUPPORT_GPU
11
Greg Daniela5cb7812017-06-16 09:45:32 -040012#include "GrBackendSemaphore.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040013#include "GrClip.h"
14#include "GrContextPriv.h"
15#include "GrDefaultGeoProcFactory.h"
Chris Daltonfe199b72017-05-05 11:26:15 -040016#include "GrOnFlushResourceProvider.h"
Robert Phillips0bd24dc2018-01-16 08:06:32 -050017#include "GrProxyProvider.h"
Robert Phillips7d79e7b2018-02-14 11:09:57 -050018#include "GrQuad.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040019#include "GrRenderTargetContextPriv.h"
20#include "GrResourceProvider.h"
Robert Phillips7d79e7b2018-02-14 11:09:57 -050021#include "GrTexture.h"
22
Mike Reed75ae4212018-01-23 11:24:08 -050023#include "SkBitmap.h"
Cary Clark74f623d2017-11-06 20:02:02 -050024#include "SkPointPriv.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040025#include "effects/GrSimpleTextureEffect.h"
Brian Salomon9a036422017-07-13 17:04:43 -040026#include "ops/GrSimpleMeshDrawOpHelper.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040027
Brian Salomon9a036422017-07-13 17:04:43 -040028namespace {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040029// This is a simplified mesh drawing op that can be used in the atlas generation test.
30// Please see AtlasedRectOp below.
Brian Salomon9a036422017-07-13 17:04:43 -040031class NonAARectOp : public GrMeshDrawOp {
32protected:
33 using Helper = GrSimpleMeshDrawOpHelper;
34
Robert Phillipseb35f4d2017-03-21 07:56:47 -040035public:
36 DEFINE_OP_CLASS_ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -040037
38 // This creates an instance of a simple non-AA solid color rect-drawing Op
Brian Salomon9a036422017-07-13 17:04:43 -040039 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& r) {
40 return Helper::FactoryHelper<NonAARectOp>(std::move(paint), r, nullptr, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040041 }
42
43 // This creates an instance of a simple non-AA textured rect-drawing Op
Brian Salomon9a036422017-07-13 17:04:43 -040044 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& r, const SkRect& local) {
45 return Helper::FactoryHelper<NonAARectOp>(std::move(paint), r, &local, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040046 }
47
48 GrColor color() const { return fColor; }
49
Brian Salomon9a036422017-07-13 17:04:43 -040050 NonAARectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r,
51 const SkRect* localRect, int32_t classID)
52 : INHERITED(classID)
53 , fColor(color)
54 , fHasLocalRect(SkToBool(localRect))
55 , fRect(r)
56 , fHelper(helperArgs, GrAAType::kNone) {
57 if (fHasLocalRect) {
58 fLocalQuad.set(*localRect);
59 }
60 // Choose some conservative values for aa bloat and zero area.
61 this->setBounds(r, HasAABloat::kYes, IsZeroArea::kYes);
62 }
63
Robert Phillipsb493eeb2017-09-13 13:10:52 -040064 const char* name() const override { return "NonAARectOp"; }
65
Robert Phillipsf1748f52017-09-14 14:11:24 -040066 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -040067 fHelper.visitProxies(func);
68 }
69
Brian Salomon9a036422017-07-13 17:04:43 -040070 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
71
Brian Osman9a725dd2017-09-20 09:53:22 -040072 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip*,
73 GrPixelConfigIsClamped dstIsClamped) override {
Brian Salomon9a036422017-07-13 17:04:43 -040074 // Set the color to unknown because the subclass may change the color later.
75 GrProcessorAnalysisColor gpColor;
76 gpColor.setToUnknown();
77 // We ignore the clip so pass this rather than the GrAppliedClip param.
78 static GrAppliedClip kNoClip;
Brian Osman9a725dd2017-09-20 09:53:22 -040079 return fHelper.xpRequiresDstTexture(caps, &kNoClip, dstIsClamped,
80 GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomon9a036422017-07-13 17:04:43 -040081 }
82
Robert Phillipseb35f4d2017-03-21 07:56:47 -040083protected:
Robert Phillipseb35f4d2017-03-21 07:56:47 -040084 GrColor fColor;
85 bool fHasLocalRect;
86 GrQuad fLocalQuad;
87 SkRect fRect;
88
89private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -040090 bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
91
Brian Salomon91326c32017-08-09 16:02:19 -040092 void onPrepareDraws(Target* target) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040093 using namespace GrDefaultGeoProcFactory;
94
95 // The vertex attrib order is always pos, color, local coords.
96 static const int kColorOffset = sizeof(SkPoint);
97 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
98
99 sk_sp<GrGeometryProcessor> gp =
100 GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
101 Coverage::kSolid_Type,
102 fHasLocalRect ? LocalCoords::kHasExplicit_Type
103 : LocalCoords::kUnused_Type,
104 SkMatrix::I());
105 if (!gp) {
106 SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n");
107 return;
108 }
109
110 size_t vertexStride = gp->getVertexStride();
111
112 SkASSERT(fHasLocalRect
113 ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
114 : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
115
116 const GrBuffer* indexBuffer;
117 int firstIndex;
118 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
119 if (!indices) {
120 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
121 return;
122 }
123
124 const GrBuffer* vertexBuffer;
125 int firstVertex;
126 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
127 if (!vertices) {
128 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
129 return;
130 }
131
132 // Setup indices
133 indices[0] = 0;
134 indices[1] = 1;
135 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000136 indices[3] = 2;
137 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400138 indices[5] = 3;
139
140 // Setup positions
141 SkPoint* position = (SkPoint*) vertices;
Cary Clark74f623d2017-11-06 20:02:02 -0500142 SkPointPriv::SetRectTriStrip(position, fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
Brian Salomon57caa662017-10-18 12:21:05 +0000143 vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400144
145 // Setup vertex colors
146 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
147 for (int i = 0; i < 4; ++i) {
148 *color = fColor;
149 color = (GrColor*)((intptr_t)color + vertexStride);
150 }
151
152 // Setup local coords
153 if (fHasLocalRect) {
154 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
155 for (int i = 0; i < 4; i++) {
156 *coords = fLocalQuad.point(i);
157 coords = (SkPoint*)((intptr_t) coords + vertexStride);
158 }
159 }
160
Chris Dalton3809bab2017-06-13 10:55:06 -0600161 GrMesh mesh(GrPrimitiveType::kTriangles);
Chris Dalton114a3c02017-05-26 15:17:19 -0600162 mesh.setIndexed(indexBuffer, 6, firstIndex, 0, 3);
163 mesh.setVertexData(vertexBuffer, firstVertex);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400164
Brian Salomon9a036422017-07-13 17:04:43 -0400165 target->draw(gp.get(), fHelper.makePipeline(target), mesh);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400166 }
167
Brian Salomon9a036422017-07-13 17:04:43 -0400168 Helper fHelper;
169
170 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400171};
172
Brian Salomon9a036422017-07-13 17:04:43 -0400173} // anonymous namespace
174
Brian Salomon9a036422017-07-13 17:04:43 -0400175static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
176
177namespace {
178
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400179/*
180 * Atlased ops just draw themselves as textured rects with the texture pixels being
181 * pulled out of the atlas. Their color is based on their ID.
182 */
183class AtlasedRectOp final : public NonAARectOp {
184public:
185 DEFINE_OP_CLASS_ID
186
187 ~AtlasedRectOp() override {
188 fID = -1;
189 }
190
191 const char* name() const override { return "AtlasedRectOp"; }
192
193 int id() const { return fID; }
194
Brian Salomon9a036422017-07-13 17:04:43 -0400195 static std::unique_ptr<AtlasedRectOp> Make(GrPaint&& paint, const SkRect& r, int id) {
196 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(std::move(paint), r, id).release();
197 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
198 }
199
200 // We set the initial color of the NonAARectOp based on the ID.
201 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
202 // pulling from the atlas.
203 AtlasedRectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r, int id)
204 : INHERITED(helperArgs, kColors[id], r, &kEmptyRect, ClassID())
205 , fID(id)
206 , fNext(nullptr) {
207 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400208 }
209
210 void setColor(GrColor color) { fColor = color; }
211 void setLocalRect(const SkRect& localRect) {
212 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
213 fLocalQuad.set(localRect);
214 }
215
216 AtlasedRectOp* next() const { return fNext; }
217 void setNext(AtlasedRectOp* next) {
218 fNext = next;
219 }
220
221private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400222
223 static const int kMaxIDs = 9;
224 static const SkColor kColors[kMaxIDs];
225
226 int fID;
227 // The Atlased ops have an internal singly-linked list of ops that land in the same opList
228 AtlasedRectOp* fNext;
229
230 typedef NonAARectOp INHERITED;
231};
232
Brian Salomon9a036422017-07-13 17:04:43 -0400233} // anonymous namespace
234
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400235const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
236 GrColorPackRGBA(255, 0, 0, 255),
237 GrColorPackRGBA(0, 255, 0, 255),
238 GrColorPackRGBA(0, 0, 255, 255),
239 GrColorPackRGBA(0, 255, 255, 255),
240 GrColorPackRGBA(255, 0, 255, 255),
241 GrColorPackRGBA(255, 255, 0, 255),
242 GrColorPackRGBA(0, 0, 0, 255),
243 GrColorPackRGBA(128, 128, 128, 255),
244 GrColorPackRGBA(255, 255, 255, 255)
245};
246
247static const int kDrawnTileSize = 16;
248
249/*
250 * Rather than performing any rect packing, this atlaser just lays out constant-sized
251 * tiles in an Nx1 row
252 */
253static const int kAtlasTileSize = 2;
254
255/*
256 * This class aggregates the op information required for atlasing
257 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400258class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400259public:
260 AtlasObject() : fDone(false) { }
261
262 ~AtlasObject() override {
263 SkASSERT(fDone);
264 }
265
266 void markAsDone() {
267 fDone = true;
268 }
269
270 // Insert the new op in an internal singly-linked list for 'opListID'
271 void addOp(uint32_t opListID, AtlasedRectOp* op) {
272 LinkedListHeader* header = nullptr;
273 for (int i = 0; i < fOps.count(); ++i) {
274 if (opListID == fOps[i].fID) {
275 header = &(fOps[i]);
276 }
277 }
278
279 if (!header) {
280 fOps.push({opListID, nullptr});
281 header = &(fOps[fOps.count()-1]);
282 }
283
284 op->setNext(header->fHead);
285 header->fHead = op;
286 }
287
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500288 int numOps() const { return fOps.count(); }
289
290 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
291 // known until flush time.
292 sk_sp<GrTextureProxy> getAtlasProxy(GrProxyProvider* proxyProvider) {
293 if (fAtlasProxy) {
294 return fAtlasProxy;
295 }
296
297 fAtlasProxy = proxyProvider->createFullyLazyProxy(
298 [](GrResourceProvider* resourceProvider) {
299 if (!resourceProvider) {
300 return sk_sp<GrTexture>();
301 }
302
303 GrSurfaceDesc desc;
304 desc.fFlags = kRenderTarget_GrSurfaceFlag;
305 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
306 // TODO: until partial flushes in MDB lands we're stuck having
307 // all 9 atlas draws occur
308 desc.fWidth = 9 /*this->numOps()*/ * kAtlasTileSize;
309 desc.fHeight = kAtlasTileSize;
310 desc.fConfig = kRGBA_8888_GrPixelConfig;
311
312 return resourceProvider->createTexture(desc, SkBudgeted::kYes,
313 GrResourceProvider::kNoPendingIO_Flag);
314 },
315 GrProxyProvider::Renderable::kYes,
316 kBottomLeft_GrSurfaceOrigin,
317 kRGBA_8888_GrPixelConfig);
318 return fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400319 }
320
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400321 /*
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500322 * This callback creates the atlas and updates the AtlasedRectOps to read from it
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400323 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400324 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400325 const uint32_t* opListIDs, int numOpListIDs,
326 SkTArray<sk_sp<GrRenderTargetContext>>* results) override {
327 SkASSERT(!results->count());
328
329 // Until MDB is landed we will most-likely only have one opList.
330 SkTDArray<LinkedListHeader*> lists;
331 for (int i = 0; i < numOpListIDs; ++i) {
332 if (LinkedListHeader* list = this->getList(opListIDs[i])) {
333 lists.push(list);
334 }
335 }
336
337 if (!lists.count()) {
338 return; // nothing to atlas
339 }
340
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500341 if (!resourceProvider->instatiateProxy(fAtlasProxy.get())) {
342 return;
343 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400344
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400345 // At this point all the GrAtlasedOp's should have lined up to read from 'atlasDest' and
346 // there should either be two writes to clear it or no writes.
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500347 SkASSERT(9 == fAtlasProxy->getPendingReadCnt_TestOnly());
348 SkASSERT(2 == fAtlasProxy->getPendingWriteCnt_TestOnly() ||
349 0 == fAtlasProxy->getPendingWriteCnt_TestOnly());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400350 sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500351 fAtlasProxy,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400352 nullptr, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400353
Chris Dalton344e9032017-12-11 15:42:09 -0700354 // clear the atlas
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500355 rtc->clear(nullptr, 0x0, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400356
357 int blocksInAtlas = 0;
358 for (int i = 0; i < lists.count(); ++i) {
359 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
360 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
361 kAtlasTileSize, kAtlasTileSize);
362
363 // For now, we avoid the resource buffer issues and just use clears
364#if 1
Chris Dalton344e9032017-12-11 15:42:09 -0700365 rtc->clear(&r, op->color(), GrRenderTargetContext::CanClearFullscreen::kNo);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400366#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400367 GrPaint paint;
Brian Salomon9a036422017-07-13 17:04:43 -0400368 paint.setColor4f(GrColor4f::FromGrColor(op->color()));
369 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
370 SkRect::Make(r)));
371 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400372#endif
373 blocksInAtlas++;
374
375 // Set the atlased Op's color to white (so we know we're not using it for
376 // the final draw).
377 op->setColor(0xFFFFFFFF);
378
379 // Set the atlased Op's localRect to point to where it landed in the atlas
380 op->setLocalRect(SkRect::Make(r));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400381 }
382
383 // We've updated all these ops and we certainly don't want to process them again
384 this->clearOpsFor(lists[i]);
385 }
386
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400387 results->push_back(std::move(rtc));
388 }
389
390private:
391 typedef struct {
392 uint32_t fID;
393 AtlasedRectOp* fHead;
394 } LinkedListHeader;
395
396 LinkedListHeader* getList(uint32_t opListID) {
397 for (int i = 0; i < fOps.count(); ++i) {
398 if (opListID == fOps[i].fID) {
399 return &(fOps[i]);
400 }
401 }
402 return nullptr;
403 }
404
405 void clearOpsFor(LinkedListHeader* header) {
406 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
407 // forget about them in the laziest way possible.
408 header->fHead = nullptr;
409 header->fID = 0; // invalid opList ID
410 }
411
412 // Each opList containing AtlasedRectOps gets its own internal singly-linked list
413 SkTDArray<LinkedListHeader> fOps;
414
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500415 // The fully lazy proxy for the atlas
416 sk_sp<GrTextureProxy> fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400417
418 // Set to true when the testing harness expects this object to be no longer used
419 bool fDone;
420};
421
422// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
423static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500424 sk_sp<GrTextureProxy> atlasProxy) {
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400425 sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContext(
426 SkBackingFit::kApprox,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400427 3*kDrawnTileSize,
428 kDrawnTileSize,
429 kRGBA_8888_GrPixelConfig,
430 nullptr));
431
Chris Dalton344e9032017-12-11 15:42:09 -0700432 rtc->clear(nullptr, GrColorPackRGBA(255, 0, 0, 255),
433 GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400434
435 for (int i = 0; i < 3; ++i) {
436 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
437
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500438 auto fp = GrSimpleTextureEffect::Make(atlasProxy, SkMatrix::I());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400439 GrPaint paint;
440 paint.addColorFragmentProcessor(std::move(fp));
441 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Salomon9a036422017-07-13 17:04:43 -0400442 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400443
444 AtlasedRectOp* sparePtr = op.get();
445
Brian Salomon9a036422017-07-13 17:04:43 -0400446 uint32_t opListID = rtc->priv().testingOnly_addDrawOp(std::move(op));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400447
448 object->addOp(opListID, sparePtr);
449 }
450
451 return rtc->asTextureProxyRef();
452}
453
454// Enable this if you want to debug the final draws w/o having the atlasCallback create the
455// atlas
456#if 0
Chris Dalton12658942017-10-05 19:45:25 -0600457#include "SkImageEncoder.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400458#include "SkGrPriv.h"
Chris Dalton12658942017-10-05 19:45:25 -0600459#include "sk_tool_utils.h"
460
461static void save_bm(const SkBitmap& bm, const char name[]) {
462 bool result = sk_tool_utils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
463 SkASSERT(result);
464}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400465
466sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
467 SkBitmap bm;
468 bm.allocN32Pixels(18, 2, true);
469 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
470 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
471 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
472 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
473 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
474 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
475 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
476 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
477 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
478
479#if 1
480 save_bm(bm, "atlas-fake.png");
481#endif
482
483 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info(), *context->caps());
484 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
485
486 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
487 context->textureProvider(),
488 desc, SkBudgeted::kYes,
489 bm.getPixels(), bm.rowBytes());
490
491 return sk_ref_sp(tmp->asTextureProxy());
492}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400493#endif
494
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500495
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400496static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
497 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
498 REPORTER_ASSERT(reporter, expected == readback);
499 if (expected != readback) {
500 SkDebugf("Color mismatch: %x %x\n", expected, readback);
501 }
502}
503
504/*
505 * For the atlasing test we make a DAG that looks like:
506 *
507 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
508 * \ /
509 * \ /
510 * RT4
511 * We then flush RT4 and expect only ops 0-5 to be atlased together.
512 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
513 * R G B C M Y
514 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
515 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500516 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
517 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400518 * R G B C M Y K Grey White
519 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400520DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400521 static const int kNumProxies = 3;
522
523 GrContext* context = ctxInfo.grContext();
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500524 auto proxyProvider = context->contextPriv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400525
Chris Daltonfe199b72017-05-05 11:26:15 -0400526 AtlasObject object;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400527
Chris Daltonfe199b72017-05-05 11:26:15 -0400528 context->contextPriv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400529
530 sk_sp<GrTextureProxy> proxies[kNumProxies];
531 for (int i = 0; i < kNumProxies; ++i) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500532 proxies[i] = make_upstream_image(context, &object, i*3,
533 object.getAtlasProxy(proxyProvider));
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
Chris Dalton344e9032017-12-11 15:42:09 -0700546 rtc->clear(nullptr, 0xFFFFFFFF, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400547
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