blob: 55675329220905f5262f8c12d4a031c8e0f6d29d [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "tests/Test.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -04009
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040010#include "include/core/SkBitmap.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/gpu/GrBackendSemaphore.h"
12#include "include/gpu/GrTexture.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040013#include "src/core/SkPointPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/gpu/GrClip.h"
15#include "src/gpu/GrContextPriv.h"
16#include "src/gpu/GrDefaultGeoProcFactory.h"
Brian Salomonf2ebdd92019-09-30 12:15:30 -040017#include "src/gpu/GrImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/gpu/GrOnFlushResourceProvider.h"
19#include "src/gpu/GrProxyProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/gpu/GrRenderTargetContextPriv.h"
21#include "src/gpu/GrResourceProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/gpu/effects/generated/GrSimpleTextureEffect.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040023#include "src/gpu/geometry/GrQuad.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040025
Brian Salomon9a036422017-07-13 17:04:43 -040026namespace {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040027// This is a simplified mesh drawing op that can be used in the atlas generation test.
28// Please see AtlasedRectOp below.
Brian Salomon9a036422017-07-13 17:04:43 -040029class NonAARectOp : public GrMeshDrawOp {
30protected:
31 using Helper = GrSimpleMeshDrawOpHelper;
32
Robert Phillipseb35f4d2017-03-21 07:56:47 -040033public:
34 DEFINE_OP_CLASS_ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -040035
36 // This creates an instance of a simple non-AA solid color rect-drawing Op
Robert Phillipsb97da532019-02-12 15:24:12 -050037 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040038 GrPaint&& paint,
39 const SkRect& r) {
40 return Helper::FactoryHelper<NonAARectOp>(context, 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
Robert Phillipsb97da532019-02-12 15:24:12 -050044 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040045 GrPaint&& paint,
46 const SkRect& r,
47 const SkRect& local) {
48 return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, &local, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040049 }
50
Brian Osmancf860852018-10-31 14:04:39 -040051 const SkPMColor4f& color() const { return fColor; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -040052
Brian Osmancf860852018-10-31 14:04:39 -040053 NonAARectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Salomon9a036422017-07-13 17:04:43 -040054 const SkRect* localRect, int32_t classID)
55 : INHERITED(classID)
56 , fColor(color)
57 , fHasLocalRect(SkToBool(localRect))
58 , fRect(r)
59 , fHelper(helperArgs, GrAAType::kNone) {
60 if (fHasLocalRect) {
Brian Salomona33b67c2018-05-17 10:42:14 -040061 fLocalQuad = GrQuad(*localRect);
Brian Salomon9a036422017-07-13 17:04:43 -040062 }
63 // Choose some conservative values for aa bloat and zero area.
Greg Daniel5faf4742019-10-01 15:14:44 -040064 this->setBounds(r, HasAABloat::kYes, IsHairline::kYes);
Brian Salomon9a036422017-07-13 17:04:43 -040065 }
66
Robert Phillipsb493eeb2017-09-13 13:10:52 -040067 const char* name() const override { return "NonAARectOp"; }
68
Chris Dalton1706cbf2019-05-21 19:35:29 -060069 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -040070 fHelper.visitProxies(func);
71 }
72
Brian Salomon9a036422017-07-13 17:04:43 -040073 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
74
Chris Dalton6ce447a2019-06-23 18:07:38 -060075 GrProcessorSet::Analysis finalize(
76 const GrCaps& caps, const GrAppliedClip*, bool hasMixedSampledCoverage,
77 GrClampType clampType) override {
Brian Salomon9a036422017-07-13 17:04:43 -040078 // Set the color to unknown because the subclass may change the color later.
79 GrProcessorAnalysisColor gpColor;
80 gpColor.setToUnknown();
81 // We ignore the clip so pass this rather than the GrAppliedClip param.
82 static GrAppliedClip kNoClip;
Chris Dalton6ce447a2019-06-23 18:07:38 -060083 return fHelper.finalizeProcessors(caps, &kNoClip, hasMixedSampledCoverage, clampType,
84 GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomon9a036422017-07-13 17:04:43 -040085 }
86
Robert Phillipseb35f4d2017-03-21 07:56:47 -040087protected:
Brian Osmancf860852018-10-31 14:04:39 -040088 SkPMColor4f fColor;
89 bool fHasLocalRect;
90 GrQuad fLocalQuad;
91 SkRect fRect;
Robert Phillipseb35f4d2017-03-21 07:56:47 -040092
93private:
Brian Salomon91326c32017-08-09 16:02:19 -040094 void onPrepareDraws(Target* target) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040095 using namespace GrDefaultGeoProcFactory;
96
97 // The vertex attrib order is always pos, color, local coords.
98 static const int kColorOffset = sizeof(SkPoint);
99 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
100
101 sk_sp<GrGeometryProcessor> gp =
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400102 GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(),
103 Color::kPremulGrColorAttribute_Type,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400104 Coverage::kSolid_Type,
105 fHasLocalRect ? LocalCoords::kHasExplicit_Type
106 : LocalCoords::kUnused_Type,
107 SkMatrix::I());
108 if (!gp) {
109 SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n");
110 return;
111 }
112
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500113 size_t vertexStride = gp->vertexStride();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400114
Brian Salomon12d22642019-01-29 14:38:50 -0500115 sk_sp<const GrBuffer> indexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400116 int firstIndex;
117 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
118 if (!indices) {
119 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
120 return;
121 }
122
Brian Salomon12d22642019-01-29 14:38:50 -0500123 sk_sp<const GrBuffer> vertexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400124 int firstVertex;
125 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
126 if (!vertices) {
127 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
128 return;
129 }
130
131 // Setup indices
132 indices[0] = 0;
133 indices[1] = 1;
134 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000135 indices[3] = 2;
136 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400137 indices[5] = 3;
138
139 // Setup positions
140 SkPoint* position = (SkPoint*) vertices;
Brian Salomonec42e152018-05-18 12:52:22 -0400141 SkPointPriv::SetRectTriStrip(position, fRect, vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400142
143 // Setup vertex colors
144 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
145 for (int i = 0; i < 4; ++i) {
Brian Osmancf860852018-10-31 14:04:39 -0400146 *color = fColor.toBytes_RGBA();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400147 color = (GrColor*)((intptr_t)color + vertexStride);
148 }
149
150 // Setup local coords
151 if (fHasLocalRect) {
152 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
153 for (int i = 0; i < 4; i++) {
154 *coords = fLocalQuad.point(i);
155 coords = (SkPoint*)((intptr_t) coords + vertexStride);
156 }
157 }
158
Brian Salomon7eae3e02018-08-07 14:02:38 +0000159 GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
160 mesh->setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo);
161 mesh->setVertexData(vertexBuffer, firstVertex);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400162
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700163 target->recordDraw(std::move(gp), mesh);
164 }
165
166 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
167 fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400168 }
169
Brian Salomon9a036422017-07-13 17:04:43 -0400170 Helper fHelper;
171
172 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400173};
174
Brian Salomon9a036422017-07-13 17:04:43 -0400175} // anonymous namespace
176
Brian Salomon9a036422017-07-13 17:04:43 -0400177static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
178
179namespace {
180
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400181/*
182 * Atlased ops just draw themselves as textured rects with the texture pixels being
183 * pulled out of the atlas. Their color is based on their ID.
184 */
185class AtlasedRectOp final : public NonAARectOp {
186public:
187 DEFINE_OP_CLASS_ID
188
189 ~AtlasedRectOp() override {
190 fID = -1;
191 }
192
193 const char* name() const override { return "AtlasedRectOp"; }
194
195 int id() const { return fID; }
196
Robert Phillips7c525e62018-06-12 10:11:12 -0400197 static std::unique_ptr<AtlasedRectOp> Make(GrContext* context,
198 GrPaint&& paint,
199 const SkRect& r,
200 int id) {
201 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(context, std::move(paint),
202 r, id).release();
Brian Salomon9a036422017-07-13 17:04:43 -0400203 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
204 }
205
206 // We set the initial color of the NonAARectOp based on the ID.
207 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
208 // pulling from the atlas.
Brian Osmancf860852018-10-31 14:04:39 -0400209 AtlasedRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Osman936fe7d2018-10-30 15:30:35 -0400210 int id)
Brian Osmancf860852018-10-31 14:04:39 -0400211 : INHERITED(helperArgs, SkPMColor4f::FromBytes_RGBA(kColors[id]), r, &kEmptyRect,
212 ClassID())
Brian Salomon9a036422017-07-13 17:04:43 -0400213 , fID(id)
214 , fNext(nullptr) {
215 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400216 }
217
Brian Osmancf860852018-10-31 14:04:39 -0400218 void setColor(const SkPMColor4f& color) { fColor = color; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400219 void setLocalRect(const SkRect& localRect) {
220 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
Brian Salomona33b67c2018-05-17 10:42:14 -0400221 fLocalQuad = GrQuad(localRect);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400222 }
223
224 AtlasedRectOp* next() const { return fNext; }
225 void setNext(AtlasedRectOp* next) {
226 fNext = next;
227 }
228
229private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400230
231 static const int kMaxIDs = 9;
Brian Osman1be2b7c2018-10-29 16:07:15 -0400232 static const GrColor kColors[kMaxIDs];
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400233
234 int fID;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400235 // The Atlased ops have an internal singly-linked list of ops that land in the same opsTask
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400236 AtlasedRectOp* fNext;
237
238 typedef NonAARectOp INHERITED;
239};
240
Brian Salomon9a036422017-07-13 17:04:43 -0400241} // anonymous namespace
242
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400243const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
244 GrColorPackRGBA(255, 0, 0, 255),
245 GrColorPackRGBA(0, 255, 0, 255),
246 GrColorPackRGBA(0, 0, 255, 255),
247 GrColorPackRGBA(0, 255, 255, 255),
248 GrColorPackRGBA(255, 0, 255, 255),
249 GrColorPackRGBA(255, 255, 0, 255),
250 GrColorPackRGBA(0, 0, 0, 255),
251 GrColorPackRGBA(128, 128, 128, 255),
252 GrColorPackRGBA(255, 255, 255, 255)
253};
254
255static const int kDrawnTileSize = 16;
256
257/*
258 * Rather than performing any rect packing, this atlaser just lays out constant-sized
259 * tiles in an Nx1 row
260 */
261static const int kAtlasTileSize = 2;
262
263/*
264 * This class aggregates the op information required for atlasing
265 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400266class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400267public:
268 AtlasObject() : fDone(false) { }
269
270 ~AtlasObject() override {
271 SkASSERT(fDone);
272 }
273
274 void markAsDone() {
275 fDone = true;
276 }
277
Greg Danielf41b2bd2019-08-22 16:19:24 -0400278 // Insert the new op in an internal singly-linked list for 'opsTaskID'
279 void addOp(uint32_t opsTaskID, AtlasedRectOp* op) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400280 LinkedListHeader* header = nullptr;
281 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400282 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400283 header = &(fOps[i]);
284 }
285 }
286
287 if (!header) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400288 fOps.push_back({opsTaskID, nullptr});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400289 header = &(fOps[fOps.count()-1]);
290 }
291
292 op->setNext(header->fHead);
293 header->fHead = op;
294 }
295
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500296 int numOps() const { return fOps.count(); }
297
298 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
299 // known until flush time.
Greg Daniel4065d452018-11-16 15:43:41 -0500300 sk_sp<GrTextureProxy> getAtlasProxy(GrProxyProvider* proxyProvider, const GrCaps* caps) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500301 if (fAtlasProxy) {
302 return fAtlasProxy;
303 }
304
Robert Phillips0a15cc62019-07-30 12:49:10 -0400305 const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
306 GrRenderable::kYes);
Greg Daniel4065d452018-11-16 15:43:41 -0500307
Chris Dalton4c458b12018-06-16 17:22:59 -0600308 fAtlasProxy = GrProxyProvider::MakeFullyLazyProxy(
Brian Salomon4eb38b72019-08-05 12:58:39 -0400309 [format](GrResourceProvider* resourceProvider)
Brian Salomonbeb7f522019-08-30 16:19:42 -0400310 -> GrSurfaceProxy::LazyCallbackResult {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500311 GrSurfaceDesc desc;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500312 // TODO: until partial flushes in MDB lands we're stuck having
313 // all 9 atlas draws occur
314 desc.fWidth = 9 /*this->numOps()*/ * kAtlasTileSize;
315 desc.fHeight = kAtlasTileSize;
316 desc.fConfig = kRGBA_8888_GrPixelConfig;
317
Robert Phillipsaee18c92019-09-06 11:48:27 -0400318 return resourceProvider->createTexture(desc, format, GrRenderable::kYes, 1,
Brian Salomona90382f2019-09-17 09:01:56 -0400319 GrMipMapped::kNo, SkBudgeted::kYes,
320 GrProtected::kNo);
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500321 },
Greg Daniel4065d452018-11-16 15:43:41 -0500322 format,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400323 GrRenderable::kYes,
324 1,
Brian Salomone8a766b2019-07-19 14:24:36 -0400325 GrProtected::kNo,
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500326 kBottomLeft_GrSurfaceOrigin,
Chris Dalton4c458b12018-06-16 17:22:59 -0600327 kRGBA_8888_GrPixelConfig,
Brian Salomonbeb7f522019-08-30 16:19:42 -0400328 *proxyProvider->caps(),
329 GrSurfaceProxy::UseAllocator::kNo);
Robert Phillips5f78adf2019-04-22 12:41:39 -0400330
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500331 return fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400332 }
333
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400334 /*
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500335 * This callback creates the atlas and updates the AtlasedRectOps to read from it
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400336 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400337 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400338 const uint32_t* opsTaskIDs,
Chris Daltonc4b47352019-08-23 10:10:36 -0600339 int numOpsTaskIDs) override {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400340 // Until MDB is landed we will most-likely only have one opsTask.
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400341 SkTDArray<LinkedListHeader*> lists;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400342 for (int i = 0; i < numOpsTaskIDs; ++i) {
343 if (LinkedListHeader* list = this->getList(opsTaskIDs[i])) {
Mike Reed5edcd312018-08-08 11:23:41 -0400344 lists.push_back(list);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400345 }
346 }
347
348 if (!lists.count()) {
349 return; // nothing to atlas
350 }
351
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500352 if (!resourceProvider->instatiateProxy(fAtlasProxy.get())) {
353 return;
354 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400355
Robert Phillips3d4cac52019-06-11 08:08:08 -0400356 // At this point 'fAtlasProxy' should be instantiated and have:
357 // 1 ref from the 'fAtlasProxy' sk_sp
358 // 9 refs from the 9 AtlasedRectOps
Brian Salomona036f0d2019-08-29 11:16:04 -0400359 SkASSERT(10 == fAtlasProxy->refCnt());
Robert Phillipse5f73282019-06-18 17:15:04 -0400360 // The backing GrSurface should have only 1 though bc there is only one proxy
Robert Phillipsb5204762019-06-19 14:12:13 -0400361 SkASSERT(1 == fAtlasProxy->testingOnly_getBackingRefCnt());
Brian Salomonbf6b9792019-08-21 09:38:10 -0400362 auto rtc = resourceProvider->makeRenderTargetContext(fAtlasProxy, GrColorType::kRGBA_8888,
363 nullptr, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400364
Chris Dalton344e9032017-12-11 15:42:09 -0700365 // clear the atlas
Brian Osman9a9baae2018-11-05 15:06:26 -0500366 rtc->clear(nullptr, SK_PMColor4fTRANSPARENT,
367 GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400368
369 int blocksInAtlas = 0;
370 for (int i = 0; i < lists.count(); ++i) {
371 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
372 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
373 kAtlasTileSize, kAtlasTileSize);
374
375 // For now, we avoid the resource buffer issues and just use clears
376#if 1
Brian Osman9a9baae2018-11-05 15:06:26 -0500377 rtc->clear(&r, op->color(), GrRenderTargetContext::CanClearFullscreen::kNo);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400378#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400379 GrPaint paint;
Brian Osman9a9baae2018-11-05 15:06:26 -0500380 paint.setColor4f(op->color());
Brian Salomon9a036422017-07-13 17:04:43 -0400381 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
382 SkRect::Make(r)));
383 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400384#endif
385 blocksInAtlas++;
386
387 // Set the atlased Op's color to white (so we know we're not using it for
388 // the final draw).
Brian Osmancf860852018-10-31 14:04:39 -0400389 op->setColor(SK_PMColor4fWHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400390
391 // Set the atlased Op's localRect to point to where it landed in the atlas
392 op->setLocalRect(SkRect::Make(r));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400393 }
394
395 // We've updated all these ops and we certainly don't want to process them again
396 this->clearOpsFor(lists[i]);
397 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400398 }
399
400private:
401 typedef struct {
402 uint32_t fID;
403 AtlasedRectOp* fHead;
404 } LinkedListHeader;
405
Greg Danielf41b2bd2019-08-22 16:19:24 -0400406 LinkedListHeader* getList(uint32_t opsTaskID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400407 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400408 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400409 return &(fOps[i]);
410 }
411 }
412 return nullptr;
413 }
414
415 void clearOpsFor(LinkedListHeader* header) {
416 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
417 // forget about them in the laziest way possible.
418 header->fHead = nullptr;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400419 header->fID = 0; // invalid opsTask ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400420 }
421
Greg Danielf41b2bd2019-08-22 16:19:24 -0400422 // Each opsTask containing AtlasedRectOps gets its own internal singly-linked list
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400423 SkTDArray<LinkedListHeader> fOps;
424
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500425 // The fully lazy proxy for the atlas
426 sk_sp<GrTextureProxy> fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400427
428 // Set to true when the testing harness expects this object to be no longer used
429 bool fDone;
430};
431
432// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
433static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500434 sk_sp<GrTextureProxy> atlasProxy) {
Brian Salomonbf6b9792019-08-21 09:38:10 -0400435 auto rtc = context->priv().makeDeferredRenderTargetContext(SkBackingFit::kApprox,
436 3* kDrawnTileSize,
437 kDrawnTileSize,
438 GrColorType::kRGBA_8888,
439 nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400440
Brian Osman9a9baae2018-11-05 15:06:26 -0500441 rtc->clear(nullptr, { 1, 0, 0, 1 }, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400442
443 for (int i = 0; i < 3; ++i) {
444 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
445
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500446 auto fp = GrSimpleTextureEffect::Make(atlasProxy, SkMatrix::I());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400447 GrPaint paint;
448 paint.addColorFragmentProcessor(std::move(fp));
449 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Robert Phillips7c525e62018-06-12 10:11:12 -0400450 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(context,
451 std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400452
453 AtlasedRectOp* sparePtr = op.get();
454
Greg Danielf41b2bd2019-08-22 16:19:24 -0400455 uint32_t opsTaskID;
Brian Salomon348a0372018-10-31 10:42:18 -0400456 rtc->priv().testingOnly_addDrawOp(GrNoClip(), std::move(op),
Greg Danielf41b2bd2019-08-22 16:19:24 -0400457 [&opsTaskID](GrOp* op, uint32_t id) { opsTaskID = id; });
458 SkASSERT(SK_InvalidUniqueID != opsTaskID);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400459
Greg Danielf41b2bd2019-08-22 16:19:24 -0400460 object->addOp(opsTaskID, sparePtr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400461 }
462
463 return rtc->asTextureProxyRef();
464}
465
466// Enable this if you want to debug the final draws w/o having the atlasCallback create the
467// atlas
468#if 0
469#include "SkGrPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500470#include "include/core/SkImageEncoder.h"
471#include "tools/ToolUtils.h"
Chris Dalton12658942017-10-05 19:45:25 -0600472
473static void save_bm(const SkBitmap& bm, const char name[]) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500474 bool result = ToolUtils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
Chris Dalton12658942017-10-05 19:45:25 -0600475 SkASSERT(result);
476}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400477
478sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
479 SkBitmap bm;
480 bm.allocN32Pixels(18, 2, true);
481 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
482 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
483 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
484 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
485 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
486 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
487 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
488 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
489 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
490
491#if 1
492 save_bm(bm, "atlas-fake.png");
493#endif
494
Brian Osman2b23c4b2018-06-01 12:25:08 -0400495 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400496 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
497
498 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
499 context->textureProvider(),
500 desc, SkBudgeted::kYes,
501 bm.getPixels(), bm.rowBytes());
502
503 return sk_ref_sp(tmp->asTextureProxy());
504}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400505#endif
506
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500507
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400508static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
509 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
510 REPORTER_ASSERT(reporter, expected == readback);
511 if (expected != readback) {
512 SkDebugf("Color mismatch: %x %x\n", expected, readback);
513 }
514}
515
516/*
517 * For the atlasing test we make a DAG that looks like:
518 *
519 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
520 * \ /
521 * \ /
522 * RT4
523 * We then flush RT4 and expect only ops 0-5 to be atlased together.
524 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
525 * R G B C M Y
526 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
527 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500528 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
529 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400530 * R G B C M Y K Grey White
531 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400532DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400533 static const int kNumProxies = 3;
534
535 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500536 auto proxyProvider = context->priv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400537
Chris Daltonfe199b72017-05-05 11:26:15 -0400538 AtlasObject object;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400539
Robert Phillips9da87e02019-02-04 13:26:26 -0500540 context->priv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400541
542 sk_sp<GrTextureProxy> proxies[kNumProxies];
543 for (int i = 0; i < kNumProxies; ++i) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500544 proxies[i] = make_upstream_image(context, &object, i*3,
Greg Daniel4065d452018-11-16 15:43:41 -0500545 object.getAtlasProxy(proxyProvider,
Robert Phillips9da87e02019-02-04 13:26:26 -0500546 context->priv().caps()));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400547 }
548
549 static const int kFinalWidth = 6*kDrawnTileSize;
550 static const int kFinalHeight = kDrawnTileSize;
551
Brian Salomonbf6b9792019-08-21 09:38:10 -0400552 auto rtc = context->priv().makeDeferredRenderTargetContext(
553 SkBackingFit::kApprox, kFinalWidth, kFinalHeight, GrColorType::kRGBA_8888, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400554
Brian Osman9a9baae2018-11-05 15:06:26 -0500555 rtc->clear(nullptr, SK_PMColor4fWHITE, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400556
557 // Note that this doesn't include the third texture proxy
558 for (int i = 0; i < kNumProxies-1; ++i) {
559 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
560
561 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
562
563 GrPaint paint;
Brian Osman2240be92017-10-18 13:15:13 -0400564 auto fp = GrSimpleTextureEffect::Make(std::move(proxies[i]), t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400565 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
566 paint.addColorFragmentProcessor(std::move(fp));
567
568 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
569 }
570
Greg Daniele6bfb7d2019-04-17 15:26:11 -0400571 rtc->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400572
573 SkBitmap readBack;
574 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
575
576 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
Brian Salomon1d435302019-07-01 13:05:28 -0400577 readBack.rowBytes(), {0, 0});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400578 SkASSERT(result);
579
Robert Phillips9da87e02019-02-04 13:26:26 -0500580 context->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
Chris Daltonfe199b72017-05-05 11:26:15 -0400581
582 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400583
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400584 int x = kDrawnTileSize/2;
585 test_color(reporter, readBack, x, SK_ColorRED);
586 x += kDrawnTileSize;
587 test_color(reporter, readBack, x, SK_ColorGREEN);
588 x += kDrawnTileSize;
589 test_color(reporter, readBack, x, SK_ColorBLUE);
590 x += kDrawnTileSize;
591 test_color(reporter, readBack, x, SK_ColorCYAN);
592 x += kDrawnTileSize;
593 test_color(reporter, readBack, x, SK_ColorMAGENTA);
594 x += kDrawnTileSize;
595 test_color(reporter, readBack, x, SK_ColorYELLOW);
596}