blob: 6a5e9c9fcf78e471608f4f2390c06d9b3abd9231 [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"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040012#include "src/core/SkPointPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/GrContextPriv.h"
14#include "src/gpu/GrDefaultGeoProcFactory.h"
Brian Salomonf2ebdd92019-09-30 12:15:30 -040015#include "src/gpu/GrImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/gpu/GrOnFlushResourceProvider.h"
Robert Phillipsd2f18732020-03-04 16:12:08 -050017#include "src/gpu/GrProgramInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/gpu/GrProxyProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/gpu/GrRenderTargetContextPriv.h"
20#include "src/gpu/GrResourceProvider.h"
Greg Daniel456f9b52020-03-05 19:14:18 +000021#include "src/gpu/GrTexture.h"
Brian Salomonb8f098d2020-01-07 11:15:44 -050022#include "src/gpu/effects/GrTextureEffect.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"
Brian Salomon557e8122019-10-24 10:37:08 -040025#include "tests/TestUtils.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040026
Brian Salomon9a036422017-07-13 17:04:43 -040027namespace {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040028// This is a simplified mesh drawing op that can be used in the atlas generation test.
29// Please see AtlasedRectOp below.
Brian Salomon9a036422017-07-13 17:04:43 -040030class NonAARectOp : public GrMeshDrawOp {
31protected:
32 using Helper = GrSimpleMeshDrawOpHelper;
33
Robert Phillipseb35f4d2017-03-21 07:56:47 -040034public:
35 DEFINE_OP_CLASS_ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -040036
37 // This creates an instance of a simple non-AA solid color rect-drawing Op
Robert Phillipsb97da532019-02-12 15:24:12 -050038 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040039 GrPaint&& paint,
40 const SkRect& r) {
41 return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, nullptr, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040042 }
43
44 // This creates an instance of a simple non-AA textured rect-drawing Op
Robert Phillipsb97da532019-02-12 15:24:12 -050045 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040046 GrPaint&& paint,
47 const SkRect& r,
48 const SkRect& local) {
49 return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, &local, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040050 }
51
Brian Osmancf860852018-10-31 14:04:39 -040052 const SkPMColor4f& color() const { return fColor; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -040053
Brian Osmancf860852018-10-31 14:04:39 -040054 NonAARectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Salomon9a036422017-07-13 17:04:43 -040055 const SkRect* localRect, int32_t classID)
56 : INHERITED(classID)
57 , fColor(color)
58 , fHasLocalRect(SkToBool(localRect))
59 , fRect(r)
60 , fHelper(helperArgs, GrAAType::kNone) {
61 if (fHasLocalRect) {
Brian Salomona33b67c2018-05-17 10:42:14 -040062 fLocalQuad = GrQuad(*localRect);
Brian Salomon9a036422017-07-13 17:04:43 -040063 }
64 // Choose some conservative values for aa bloat and zero area.
Greg Daniel5faf4742019-10-01 15:14:44 -040065 this->setBounds(r, HasAABloat::kYes, IsHairline::kYes);
Brian Salomon9a036422017-07-13 17:04:43 -040066 }
67
Robert Phillipsb493eeb2017-09-13 13:10:52 -040068 const char* name() const override { return "NonAARectOp"; }
69
Chris Dalton1706cbf2019-05-21 19:35:29 -060070 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsd2f18732020-03-04 16:12:08 -050071 if (fProgramInfo) {
Chris Daltonbe457422020-03-16 18:05:03 -060072 fProgramInfo->visitFPProxies(func);
Robert Phillipsd2f18732020-03-04 16:12:08 -050073 } else {
74 fHelper.visitProxies(func);
75 }
Robert Phillipsb493eeb2017-09-13 13:10:52 -040076 }
77
Brian Salomon9a036422017-07-13 17:04:43 -040078 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
79
Chris Dalton6ce447a2019-06-23 18:07:38 -060080 GrProcessorSet::Analysis finalize(
81 const GrCaps& caps, const GrAppliedClip*, bool hasMixedSampledCoverage,
82 GrClampType clampType) override {
Brian Salomon9a036422017-07-13 17:04:43 -040083 // Set the color to unknown because the subclass may change the color later.
84 GrProcessorAnalysisColor gpColor;
85 gpColor.setToUnknown();
86 // We ignore the clip so pass this rather than the GrAppliedClip param.
Michael Ludwigd1d997e2020-06-04 15:52:44 -040087 static GrAppliedClip kNoClip = GrAppliedClip::Disabled();
Chris Dalton6ce447a2019-06-23 18:07:38 -060088 return fHelper.finalizeProcessors(caps, &kNoClip, hasMixedSampledCoverage, clampType,
89 GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomon9a036422017-07-13 17:04:43 -040090 }
91
Robert Phillipseb35f4d2017-03-21 07:56:47 -040092protected:
Brian Osmancf860852018-10-31 14:04:39 -040093 SkPMColor4f fColor;
94 bool fHasLocalRect;
95 GrQuad fLocalQuad;
96 SkRect fRect;
Robert Phillipseb35f4d2017-03-21 07:56:47 -040097
98private:
Robert Phillips2669a7b2020-03-12 12:07:19 -040099 GrProgramInfo* programInfo() override { return fProgramInfo; }
100
Robert Phillips4133dc42020-03-11 15:55:55 -0400101 void onCreateProgramInfo(const GrCaps* caps,
102 SkArenaAlloc* arena,
Brian Salomon8afde5f2020-04-01 16:22:00 -0400103 const GrSurfaceProxyView* writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400104 GrAppliedClip&& appliedClip,
105 const GrXferProcessor::DstProxyView& dstProxyView) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400106 using namespace GrDefaultGeoProcFactory;
107
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500108 GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Make(
Robert Phillipsd2f18732020-03-04 16:12:08 -0500109 arena,
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400110 Color::kPremulGrColorAttribute_Type,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400111 Coverage::kSolid_Type,
112 fHasLocalRect ? LocalCoords::kHasExplicit_Type
113 : LocalCoords::kUnused_Type,
114 SkMatrix::I());
115 if (!gp) {
Robert Phillipsd2f18732020-03-04 16:12:08 -0500116 SkDebugf("Couldn't create GrGeometryProcessor\n");
Robert Phillips4133dc42020-03-11 15:55:55 -0400117 return;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400118 }
119
Brian Salomon8afde5f2020-04-01 16:22:00 -0400120 fProgramInfo = fHelper.createProgramInfo(caps, arena, writeView, std::move(appliedClip),
Robert Phillips4133dc42020-03-11 15:55:55 -0400121 dstProxyView, gp, GrPrimitiveType::kTriangles);
Robert Phillipsd2f18732020-03-04 16:12:08 -0500122 }
123
Robert Phillipsd2f18732020-03-04 16:12:08 -0500124 void onPrepareDraws(Target* target) override {
125
126 // The vertex attrib order is always pos, color, local coords.
127 static const int kColorOffset = sizeof(SkPoint);
128 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
129
130 if (!fProgramInfo) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400131 this->createProgramInfo(target);
Robert Phillipsd2f18732020-03-04 16:12:08 -0500132 if (!fProgramInfo) {
133 return;
134 }
135 }
136
137 size_t vertexStride = fProgramInfo->primProc().vertexStride();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400138
Brian Salomon12d22642019-01-29 14:38:50 -0500139 sk_sp<const GrBuffer> indexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400140 int firstIndex;
141 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
142 if (!indices) {
143 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
144 return;
145 }
146
Brian Salomon12d22642019-01-29 14:38:50 -0500147 sk_sp<const GrBuffer> vertexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400148 int firstVertex;
149 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
150 if (!vertices) {
151 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
152 return;
153 }
154
155 // Setup indices
156 indices[0] = 0;
157 indices[1] = 1;
158 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000159 indices[3] = 2;
160 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400161 indices[5] = 3;
162
163 // Setup positions
164 SkPoint* position = (SkPoint*) vertices;
Brian Salomonec42e152018-05-18 12:52:22 -0400165 SkPointPriv::SetRectTriStrip(position, fRect, vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400166
167 // Setup vertex colors
168 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
169 for (int i = 0; i < 4; ++i) {
Brian Osmancf860852018-10-31 14:04:39 -0400170 *color = fColor.toBytes_RGBA();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400171 color = (GrColor*)((intptr_t)color + vertexStride);
172 }
173
174 // Setup local coords
175 if (fHasLocalRect) {
176 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
177 for (int i = 0; i < 4; i++) {
178 *coords = fLocalQuad.point(i);
179 coords = (SkPoint*)((intptr_t) coords + vertexStride);
180 }
181 }
182
Robert Phillipsd2f18732020-03-04 16:12:08 -0500183 fMesh = target->allocMesh();
Chris Dalton37c7bdd2020-03-13 09:21:12 -0600184 fMesh->setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo, vertexBuffer,
185 firstVertex);
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700186 }
187
188 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Robert Phillipsd2f18732020-03-04 16:12:08 -0500189 if (!fProgramInfo || !fMesh) {
190 return;
191 }
Robert Phillips3968fcb2019-12-05 16:40:31 -0500192
Chris Dalton765ed362020-03-16 17:34:44 -0600193 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
194 flushState->bindTextures(fProgramInfo->primProc(), nullptr, fProgramInfo->pipeline());
195 flushState->drawMesh(*fMesh);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400196 }
197
Robert Phillipsd2f18732020-03-04 16:12:08 -0500198 Helper fHelper;
Chris Daltoneb694b72020-03-16 09:25:50 -0600199 GrSimpleMesh* fMesh = nullptr;
Robert Phillipsd2f18732020-03-04 16:12:08 -0500200 GrProgramInfo* fProgramInfo = nullptr;
Brian Salomon9a036422017-07-13 17:04:43 -0400201
202 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400203};
204
Brian Salomon9a036422017-07-13 17:04:43 -0400205} // anonymous namespace
206
Brian Salomon9a036422017-07-13 17:04:43 -0400207static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
208
209namespace {
210
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400211/*
212 * Atlased ops just draw themselves as textured rects with the texture pixels being
213 * pulled out of the atlas. Their color is based on their ID.
214 */
215class AtlasedRectOp final : public NonAARectOp {
216public:
217 DEFINE_OP_CLASS_ID
218
219 ~AtlasedRectOp() override {
220 fID = -1;
221 }
222
223 const char* name() const override { return "AtlasedRectOp"; }
224
225 int id() const { return fID; }
226
Robert Phillips7c525e62018-06-12 10:11:12 -0400227 static std::unique_ptr<AtlasedRectOp> Make(GrContext* context,
228 GrPaint&& paint,
229 const SkRect& r,
230 int id) {
231 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(context, std::move(paint),
232 r, id).release();
Brian Salomon9a036422017-07-13 17:04:43 -0400233 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
234 }
235
236 // We set the initial color of the NonAARectOp based on the ID.
237 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
238 // pulling from the atlas.
Brian Osmancf860852018-10-31 14:04:39 -0400239 AtlasedRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Osman936fe7d2018-10-30 15:30:35 -0400240 int id)
Brian Osmancf860852018-10-31 14:04:39 -0400241 : INHERITED(helperArgs, SkPMColor4f::FromBytes_RGBA(kColors[id]), r, &kEmptyRect,
242 ClassID())
Brian Salomon9a036422017-07-13 17:04:43 -0400243 , fID(id)
244 , fNext(nullptr) {
245 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400246 }
247
Brian Osmancf860852018-10-31 14:04:39 -0400248 void setColor(const SkPMColor4f& color) { fColor = color; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400249 void setLocalRect(const SkRect& localRect) {
250 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
Brian Salomona33b67c2018-05-17 10:42:14 -0400251 fLocalQuad = GrQuad(localRect);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400252 }
253
254 AtlasedRectOp* next() const { return fNext; }
255 void setNext(AtlasedRectOp* next) {
256 fNext = next;
257 }
258
259private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400260
261 static const int kMaxIDs = 9;
Brian Osman1be2b7c2018-10-29 16:07:15 -0400262 static const GrColor kColors[kMaxIDs];
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400263
264 int fID;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400265 // The Atlased ops have an internal singly-linked list of ops that land in the same opsTask
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400266 AtlasedRectOp* fNext;
267
268 typedef NonAARectOp INHERITED;
269};
270
Brian Salomon9a036422017-07-13 17:04:43 -0400271} // anonymous namespace
272
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400273const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
274 GrColorPackRGBA(255, 0, 0, 255),
275 GrColorPackRGBA(0, 255, 0, 255),
276 GrColorPackRGBA(0, 0, 255, 255),
277 GrColorPackRGBA(0, 255, 255, 255),
278 GrColorPackRGBA(255, 0, 255, 255),
279 GrColorPackRGBA(255, 255, 0, 255),
280 GrColorPackRGBA(0, 0, 0, 255),
281 GrColorPackRGBA(128, 128, 128, 255),
282 GrColorPackRGBA(255, 255, 255, 255)
283};
284
285static const int kDrawnTileSize = 16;
286
287/*
288 * Rather than performing any rect packing, this atlaser just lays out constant-sized
289 * tiles in an Nx1 row
290 */
291static const int kAtlasTileSize = 2;
292
293/*
294 * This class aggregates the op information required for atlasing
295 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400296class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400297public:
Brian Salomon557e8122019-10-24 10:37:08 -0400298 AtlasObject(skiatest::Reporter* reporter) : fDone(false), fReporter(reporter) {}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400299
300 ~AtlasObject() override {
301 SkASSERT(fDone);
302 }
303
304 void markAsDone() {
305 fDone = true;
306 }
307
Greg Danielf41b2bd2019-08-22 16:19:24 -0400308 // Insert the new op in an internal singly-linked list for 'opsTaskID'
309 void addOp(uint32_t opsTaskID, AtlasedRectOp* op) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400310 LinkedListHeader* header = nullptr;
311 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400312 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400313 header = &(fOps[i]);
314 }
315 }
316
317 if (!header) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400318 fOps.push_back({opsTaskID, nullptr});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400319 header = &(fOps[fOps.count()-1]);
320 }
321
322 op->setNext(header->fHead);
323 header->fHead = op;
324 }
325
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500326 int numOps() const { return fOps.count(); }
327
328 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
329 // known until flush time.
Greg Danield11ae2e2020-02-10 16:36:07 -0500330 GrSurfaceProxyView getAtlasView(GrProxyProvider* proxyProvider, const GrCaps* caps) {
331 if (fAtlasView) {
332 return fAtlasView;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500333 }
334
Robert Phillips0a15cc62019-07-30 12:49:10 -0400335 const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
336 GrRenderable::kYes);
Greg Danield11ae2e2020-02-10 16:36:07 -0500337 auto proxy = GrProxyProvider::MakeFullyLazyProxy(
Brian Salomon63410e92020-03-23 18:32:50 -0400338 [](GrResourceProvider* resourceProvider,
339 const GrSurfaceProxy::LazySurfaceDesc& desc)
Brian Salomonbeb7f522019-08-30 16:19:42 -0400340 -> GrSurfaceProxy::LazyCallbackResult {
Brian Salomon63410e92020-03-23 18:32:50 -0400341 SkASSERT(desc.fDimensions.width() < 0 && desc.fDimensions.height() < 0);
Brian Salomona56a7462020-02-07 14:17:25 -0500342 SkISize dims;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500343 // TODO: until partial flushes in MDB lands we're stuck having
344 // all 9 atlas draws occur
Brian Salomona56a7462020-02-07 14:17:25 -0500345 dims.fWidth = 9 /*this->numOps()*/ * kAtlasTileSize;
346 dims.fHeight = kAtlasTileSize;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500347
Brian Salomon63410e92020-03-23 18:32:50 -0400348 return resourceProvider->createTexture(dims, desc.fFormat, desc.fRenderable,
349 desc.fSampleCnt, desc.fMipMapped,
350 desc.fBudgeted, desc.fProtected);
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500351 },
Greg Daniel4065d452018-11-16 15:43:41 -0500352 format,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400353 GrRenderable::kYes,
354 1,
Brian Salomone8a766b2019-07-19 14:24:36 -0400355 GrProtected::kNo,
Brian Salomonbeb7f522019-08-30 16:19:42 -0400356 *proxyProvider->caps(),
357 GrSurfaceProxy::UseAllocator::kNo);
Robert Phillips5f78adf2019-04-22 12:41:39 -0400358
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400359 GrSwizzle readSwizzle = caps->getReadSwizzle(format, GrColorType::kRGBA_8888);
Greg Danield11ae2e2020-02-10 16:36:07 -0500360 fAtlasView = {std::move(proxy), kBottomLeft_GrSurfaceOrigin, readSwizzle};
361 return fAtlasView;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400362 }
363
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400364 /*
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500365 * This callback creates the atlas and updates the AtlasedRectOps to read from it
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400366 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400367 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400368 const uint32_t* opsTaskIDs,
Chris Daltonc4b47352019-08-23 10:10:36 -0600369 int numOpsTaskIDs) override {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400370 // Until MDB is landed we will most-likely only have one opsTask.
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400371 SkTDArray<LinkedListHeader*> lists;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400372 for (int i = 0; i < numOpsTaskIDs; ++i) {
373 if (LinkedListHeader* list = this->getList(opsTaskIDs[i])) {
Mike Reed5edcd312018-08-08 11:23:41 -0400374 lists.push_back(list);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400375 }
376 }
377
378 if (!lists.count()) {
379 return; // nothing to atlas
380 }
381
Greg Danield11ae2e2020-02-10 16:36:07 -0500382 if (!resourceProvider->instatiateProxy(fAtlasView.proxy())) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500383 return;
384 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400385
Greg Danield11ae2e2020-02-10 16:36:07 -0500386 // At this point 'fAtlasView' proxy should be instantiated and have:
387 // 1 ref from the 'fAtlasView' proxy sk_sp
Robert Phillips3d4cac52019-06-11 08:08:08 -0400388 // 9 refs from the 9 AtlasedRectOps
Robert Phillipse5f73282019-06-18 17:15:04 -0400389 // The backing GrSurface should have only 1 though bc there is only one proxy
Greg Danield11ae2e2020-02-10 16:36:07 -0500390 CheckSingleThreadedProxyRefs(fReporter, fAtlasView.proxy(), 10, 1);
391 auto rtc = resourceProvider->makeRenderTargetContext(
392 fAtlasView.refProxy(), fAtlasView.origin(), GrColorType::kRGBA_8888, nullptr,
393 nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400394
Chris Dalton344e9032017-12-11 15:42:09 -0700395 // clear the atlas
Michael Ludwig81d41722020-05-26 16:57:38 -0400396 rtc->clear(SK_PMColor4fTRANSPARENT);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400397
398 int blocksInAtlas = 0;
399 for (int i = 0; i < lists.count(); ++i) {
400 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
401 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
402 kAtlasTileSize, kAtlasTileSize);
403
404 // For now, we avoid the resource buffer issues and just use clears
405#if 1
Michael Ludwig81d41722020-05-26 16:57:38 -0400406 rtc->clear(r, op->color());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400407#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400408 GrPaint paint;
Brian Osman9a9baae2018-11-05 15:06:26 -0500409 paint.setColor4f(op->color());
Brian Salomon9a036422017-07-13 17:04:43 -0400410 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
411 SkRect::Make(r)));
412 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400413#endif
414 blocksInAtlas++;
415
416 // Set the atlased Op's color to white (so we know we're not using it for
417 // the final draw).
Brian Osmancf860852018-10-31 14:04:39 -0400418 op->setColor(SK_PMColor4fWHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400419
420 // Set the atlased Op's localRect to point to where it landed in the atlas
421 op->setLocalRect(SkRect::Make(r));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400422 }
423
424 // We've updated all these ops and we certainly don't want to process them again
425 this->clearOpsFor(lists[i]);
426 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400427 }
428
429private:
430 typedef struct {
431 uint32_t fID;
432 AtlasedRectOp* fHead;
433 } LinkedListHeader;
434
Greg Danielf41b2bd2019-08-22 16:19:24 -0400435 LinkedListHeader* getList(uint32_t opsTaskID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400436 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400437 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400438 return &(fOps[i]);
439 }
440 }
441 return nullptr;
442 }
443
444 void clearOpsFor(LinkedListHeader* header) {
445 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
446 // forget about them in the laziest way possible.
447 header->fHead = nullptr;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400448 header->fID = 0; // invalid opsTask ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400449 }
450
Greg Danielf41b2bd2019-08-22 16:19:24 -0400451 // Each opsTask containing AtlasedRectOps gets its own internal singly-linked list
Greg Danield11ae2e2020-02-10 16:36:07 -0500452 SkTDArray<LinkedListHeader> fOps;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400453
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500454 // The fully lazy proxy for the atlas
Greg Danield11ae2e2020-02-10 16:36:07 -0500455 GrSurfaceProxyView fAtlasView;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400456
457 // Set to true when the testing harness expects this object to be no longer used
Greg Danield11ae2e2020-02-10 16:36:07 -0500458 bool fDone;
Brian Salomon557e8122019-10-24 10:37:08 -0400459
Greg Danield11ae2e2020-02-10 16:36:07 -0500460 skiatest::Reporter* fReporter;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400461};
462
463// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
Greg Danield11ae2e2020-02-10 16:36:07 -0500464static GrSurfaceProxyView make_upstream_image(GrContext* context, AtlasObject* object, int start,
465 GrSurfaceProxyView atlasView,
466 SkAlphaType atlasAlphaType) {
Greg Daniele20fcad2020-01-08 11:52:34 -0500467 auto rtc = GrRenderTargetContext::Make(
468 context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox,
469 {3 * kDrawnTileSize, kDrawnTileSize});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400470
Michael Ludwig81d41722020-05-26 16:57:38 -0400471 rtc->clear({ 1, 0, 0, 1 });
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400472
473 for (int i = 0; i < 3; ++i) {
474 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
475
Greg Danield2ccbb52020-02-05 10:45:39 -0500476 auto fp = GrTextureEffect::Make(atlasView, atlasAlphaType);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400477 GrPaint paint;
478 paint.addColorFragmentProcessor(std::move(fp));
479 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Robert Phillips7c525e62018-06-12 10:11:12 -0400480 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(context,
481 std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400482
483 AtlasedRectOp* sparePtr = op.get();
484
Greg Danielf41b2bd2019-08-22 16:19:24 -0400485 uint32_t opsTaskID;
Michael Ludwig7c12e282020-05-29 09:54:07 -0400486 rtc->priv().testingOnly_addDrawOp(nullptr, std::move(op),
Greg Danielf41b2bd2019-08-22 16:19:24 -0400487 [&opsTaskID](GrOp* op, uint32_t id) { opsTaskID = id; });
488 SkASSERT(SK_InvalidUniqueID != opsTaskID);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400489
Greg Danielf41b2bd2019-08-22 16:19:24 -0400490 object->addOp(opsTaskID, sparePtr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400491 }
492
Greg Danield11ae2e2020-02-10 16:36:07 -0500493 return rtc->readSurfaceView();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400494}
495
496// Enable this if you want to debug the final draws w/o having the atlasCallback create the
497// atlas
498#if 0
499#include "SkGrPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500500#include "include/core/SkImageEncoder.h"
501#include "tools/ToolUtils.h"
Chris Dalton12658942017-10-05 19:45:25 -0600502
503static void save_bm(const SkBitmap& bm, const char name[]) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500504 bool result = ToolUtils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
Chris Dalton12658942017-10-05 19:45:25 -0600505 SkASSERT(result);
506}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400507
508sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
509 SkBitmap bm;
510 bm.allocN32Pixels(18, 2, true);
511 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
512 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
513 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
514 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
515 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
516 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
517 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
518 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
519 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
520
521#if 1
522 save_bm(bm, "atlas-fake.png");
523#endif
524
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400525 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
526
527 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
528 context->textureProvider(),
Brian Salomona56a7462020-02-07 14:17:25 -0500529 dm.dimensions(), SkBudgeted::kYes,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400530 bm.getPixels(), bm.rowBytes());
531
532 return sk_ref_sp(tmp->asTextureProxy());
533}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400534#endif
535
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500536
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400537static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
538 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
539 REPORTER_ASSERT(reporter, expected == readback);
540 if (expected != readback) {
541 SkDebugf("Color mismatch: %x %x\n", expected, readback);
542 }
543}
544
545/*
546 * For the atlasing test we make a DAG that looks like:
547 *
548 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
549 * \ /
550 * \ /
551 * RT4
552 * We then flush RT4 and expect only ops 0-5 to be atlased together.
553 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
554 * R G B C M Y
555 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
556 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500557 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
558 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400559 * R G B C M Y K Grey White
560 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400561DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Greg Danield11ae2e2020-02-10 16:36:07 -0500562 static const int kNumViews = 3;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400563
564 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500565 auto proxyProvider = context->priv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400566
Brian Salomon557e8122019-10-24 10:37:08 -0400567 AtlasObject object(reporter);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400568
Robert Phillips9da87e02019-02-04 13:26:26 -0500569 context->priv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400570
Greg Danield11ae2e2020-02-10 16:36:07 -0500571 GrSurfaceProxyView views[kNumViews];
572 for (int i = 0; i < kNumViews; ++i) {
573 views[i] = make_upstream_image(context, &object, i * 3,
574 object.getAtlasView(proxyProvider, context->priv().caps()),
575 kPremul_SkAlphaType);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400576 }
577
578 static const int kFinalWidth = 6*kDrawnTileSize;
579 static const int kFinalHeight = kDrawnTileSize;
580
Greg Daniele20fcad2020-01-08 11:52:34 -0500581 auto rtc = GrRenderTargetContext::Make(
582 context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox,
583 {kFinalWidth, kFinalHeight});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400584
Michael Ludwig81d41722020-05-26 16:57:38 -0400585 rtc->clear(SK_PMColor4fWHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400586
587 // Note that this doesn't include the third texture proxy
Greg Danield11ae2e2020-02-10 16:36:07 -0500588 for (int i = 0; i < kNumViews - 1; ++i) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400589 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
590
Mike Reed1f607332020-05-21 12:11:27 -0400591 SkMatrix t = SkMatrix::Translate(-i*3*kDrawnTileSize, 0);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400592
593 GrPaint paint;
Greg Danield11ae2e2020-02-10 16:36:07 -0500594 auto fp = GrTextureEffect::Make(std::move(views[i]), kPremul_SkAlphaType, t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400595 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
596 paint.addColorFragmentProcessor(std::move(fp));
597
Michael Ludwig7c12e282020-05-29 09:54:07 -0400598 rtc->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), r);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400599 }
600
Greg Daniel9efe3862020-06-11 11:51:06 -0400601 rtc->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo(), nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400602
603 SkBitmap readBack;
604 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
605
606 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
Brian Salomon1d435302019-07-01 13:05:28 -0400607 readBack.rowBytes(), {0, 0});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400608 SkASSERT(result);
609
Robert Phillips9da87e02019-02-04 13:26:26 -0500610 context->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
Chris Daltonfe199b72017-05-05 11:26:15 -0400611
612 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400613
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400614 int x = kDrawnTileSize/2;
615 test_color(reporter, readBack, x, SK_ColorRED);
616 x += kDrawnTileSize;
617 test_color(reporter, readBack, x, SK_ColorGREEN);
618 x += kDrawnTileSize;
619 test_color(reporter, readBack, x, SK_ColorBLUE);
620 x += kDrawnTileSize;
621 test_color(reporter, readBack, x, SK_ColorCYAN);
622 x += kDrawnTileSize;
623 test_color(reporter, readBack, x, SK_ColorMAGENTA);
624 x += kDrawnTileSize;
625 test_color(reporter, readBack, x, SK_ColorYELLOW);
626}