blob: 8c7cb585ad9b796556a7daca09c8bba5cff341f3 [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/GrClip.h"
14#include "src/gpu/GrContextPriv.h"
15#include "src/gpu/GrDefaultGeoProcFactory.h"
Brian Salomonf2ebdd92019-09-30 12:15:30 -040016#include "src/gpu/GrImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/gpu/GrOnFlushResourceProvider.h"
Robert Phillipsd2f18732020-03-04 16:12:08 -050018#include "src/gpu/GrProgramInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/gpu/GrProxyProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/gpu/GrRenderTargetContextPriv.h"
21#include "src/gpu/GrResourceProvider.h"
Greg Daniel456f9b52020-03-05 19:14:18 +000022#include "src/gpu/GrTexture.h"
Brian Salomonb8f098d2020-01-07 11:15:44 -050023#include "src/gpu/effects/GrTextureEffect.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040024#include "src/gpu/geometry/GrQuad.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
Brian Salomon557e8122019-10-24 10:37:08 -040026#include "tests/TestUtils.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
Robert Phillipsb97da532019-02-12 15:24:12 -050039 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040040 GrPaint&& paint,
41 const SkRect& r) {
42 return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, nullptr, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040043 }
44
45 // This creates an instance of a simple non-AA textured rect-drawing Op
Robert Phillipsb97da532019-02-12 15:24:12 -050046 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040047 GrPaint&& paint,
48 const SkRect& r,
49 const SkRect& local) {
50 return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, &local, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040051 }
52
Brian Osmancf860852018-10-31 14:04:39 -040053 const SkPMColor4f& color() const { return fColor; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -040054
Brian Osmancf860852018-10-31 14:04:39 -040055 NonAARectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Salomon9a036422017-07-13 17:04:43 -040056 const SkRect* localRect, int32_t classID)
57 : INHERITED(classID)
58 , fColor(color)
59 , fHasLocalRect(SkToBool(localRect))
60 , fRect(r)
61 , fHelper(helperArgs, GrAAType::kNone) {
62 if (fHasLocalRect) {
Brian Salomona33b67c2018-05-17 10:42:14 -040063 fLocalQuad = GrQuad(*localRect);
Brian Salomon9a036422017-07-13 17:04:43 -040064 }
65 // Choose some conservative values for aa bloat and zero area.
Greg Daniel5faf4742019-10-01 15:14:44 -040066 this->setBounds(r, HasAABloat::kYes, IsHairline::kYes);
Brian Salomon9a036422017-07-13 17:04:43 -040067 }
68
Robert Phillipsb493eeb2017-09-13 13:10:52 -040069 const char* name() const override { return "NonAARectOp"; }
70
Chris Dalton1706cbf2019-05-21 19:35:29 -060071 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsd2f18732020-03-04 16:12:08 -050072 if (fProgramInfo) {
73 fProgramInfo->visitProxies(func);
74 } else {
75 fHelper.visitProxies(func);
76 }
Robert Phillipsb493eeb2017-09-13 13:10:52 -040077 }
78
Brian Salomon9a036422017-07-13 17:04:43 -040079 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
80
Chris Dalton6ce447a2019-06-23 18:07:38 -060081 GrProcessorSet::Analysis finalize(
82 const GrCaps& caps, const GrAppliedClip*, bool hasMixedSampledCoverage,
83 GrClampType clampType) override {
Brian Salomon9a036422017-07-13 17:04:43 -040084 // Set the color to unknown because the subclass may change the color later.
85 GrProcessorAnalysisColor gpColor;
86 gpColor.setToUnknown();
87 // We ignore the clip so pass this rather than the GrAppliedClip param.
88 static GrAppliedClip kNoClip;
Chris Dalton6ce447a2019-06-23 18:07:38 -060089 return fHelper.finalizeProcessors(caps, &kNoClip, hasMixedSampledCoverage, clampType,
90 GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomon9a036422017-07-13 17:04:43 -040091 }
92
Robert Phillipseb35f4d2017-03-21 07:56:47 -040093protected:
Brian Osmancf860852018-10-31 14:04:39 -040094 SkPMColor4f fColor;
95 bool fHasLocalRect;
96 GrQuad fLocalQuad;
97 SkRect fRect;
Robert Phillipseb35f4d2017-03-21 07:56:47 -040098
99private:
Robert Phillips2669a7b2020-03-12 12:07:19 -0400100 GrProgramInfo* programInfo() override { return fProgramInfo; }
101
Robert Phillips4133dc42020-03-11 15:55:55 -0400102 void onCreateProgramInfo(const GrCaps* caps,
103 SkArenaAlloc* arena,
104 const GrSurfaceProxyView* outputView,
105 GrAppliedClip&& appliedClip,
106 const GrXferProcessor::DstProxyView& dstProxyView) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400107 using namespace GrDefaultGeoProcFactory;
108
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500109 GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Make(
Robert Phillipsd2f18732020-03-04 16:12:08 -0500110 arena,
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400111 Color::kPremulGrColorAttribute_Type,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400112 Coverage::kSolid_Type,
113 fHasLocalRect ? LocalCoords::kHasExplicit_Type
114 : LocalCoords::kUnused_Type,
115 SkMatrix::I());
116 if (!gp) {
Robert Phillipsd2f18732020-03-04 16:12:08 -0500117 SkDebugf("Couldn't create GrGeometryProcessor\n");
Robert Phillips4133dc42020-03-11 15:55:55 -0400118 return;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400119 }
120
Robert Phillips4133dc42020-03-11 15:55:55 -0400121 fProgramInfo = fHelper.createProgramInfo(caps, arena, outputView, std::move(appliedClip),
122 dstProxyView, gp, GrPrimitiveType::kTriangles);
Robert Phillipsd2f18732020-03-04 16:12:08 -0500123 }
124
Robert Phillipsd2f18732020-03-04 16:12:08 -0500125 void onPrepareDraws(Target* target) override {
126
127 // The vertex attrib order is always pos, color, local coords.
128 static const int kColorOffset = sizeof(SkPoint);
129 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
130
131 if (!fProgramInfo) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400132 this->createProgramInfo(target);
Robert Phillipsd2f18732020-03-04 16:12:08 -0500133 if (!fProgramInfo) {
134 return;
135 }
136 }
137
138 size_t vertexStride = fProgramInfo->primProc().vertexStride();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400139
Brian Salomon12d22642019-01-29 14:38:50 -0500140 sk_sp<const GrBuffer> indexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400141 int firstIndex;
142 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
143 if (!indices) {
144 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
145 return;
146 }
147
Brian Salomon12d22642019-01-29 14:38:50 -0500148 sk_sp<const GrBuffer> vertexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400149 int firstVertex;
150 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
151 if (!vertices) {
152 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
153 return;
154 }
155
156 // Setup indices
157 indices[0] = 0;
158 indices[1] = 1;
159 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000160 indices[3] = 2;
161 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400162 indices[5] = 3;
163
164 // Setup positions
165 SkPoint* position = (SkPoint*) vertices;
Brian Salomonec42e152018-05-18 12:52:22 -0400166 SkPointPriv::SetRectTriStrip(position, fRect, vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400167
168 // Setup vertex colors
169 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
170 for (int i = 0; i < 4; ++i) {
Brian Osmancf860852018-10-31 14:04:39 -0400171 *color = fColor.toBytes_RGBA();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400172 color = (GrColor*)((intptr_t)color + vertexStride);
173 }
174
175 // Setup local coords
176 if (fHasLocalRect) {
177 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
178 for (int i = 0; i < 4; i++) {
179 *coords = fLocalQuad.point(i);
180 coords = (SkPoint*)((intptr_t) coords + vertexStride);
181 }
182 }
183
Robert Phillipsd2f18732020-03-04 16:12:08 -0500184 fMesh = target->allocMesh();
Chris Dalton37c7bdd2020-03-13 09:21:12 -0600185 fMesh->setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo, vertexBuffer,
186 firstVertex);
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700187 }
188
189 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Robert Phillipsd2f18732020-03-04 16:12:08 -0500190 if (!fProgramInfo || !fMesh) {
191 return;
192 }
Robert Phillips3968fcb2019-12-05 16:40:31 -0500193
Chris Dalton765ed362020-03-16 17:34:44 -0600194 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
195 flushState->bindTextures(fProgramInfo->primProc(), nullptr, fProgramInfo->pipeline());
196 flushState->drawMesh(*fMesh);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400197 }
198
Robert Phillipsd2f18732020-03-04 16:12:08 -0500199 Helper fHelper;
Chris Daltoneb694b72020-03-16 09:25:50 -0600200 GrSimpleMesh* fMesh = nullptr;
Robert Phillipsd2f18732020-03-04 16:12:08 -0500201 GrProgramInfo* fProgramInfo = nullptr;
Brian Salomon9a036422017-07-13 17:04:43 -0400202
203 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400204};
205
Brian Salomon9a036422017-07-13 17:04:43 -0400206} // anonymous namespace
207
Brian Salomon9a036422017-07-13 17:04:43 -0400208static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
209
210namespace {
211
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400212/*
213 * Atlased ops just draw themselves as textured rects with the texture pixels being
214 * pulled out of the atlas. Their color is based on their ID.
215 */
216class AtlasedRectOp final : public NonAARectOp {
217public:
218 DEFINE_OP_CLASS_ID
219
220 ~AtlasedRectOp() override {
221 fID = -1;
222 }
223
224 const char* name() const override { return "AtlasedRectOp"; }
225
226 int id() const { return fID; }
227
Robert Phillips7c525e62018-06-12 10:11:12 -0400228 static std::unique_ptr<AtlasedRectOp> Make(GrContext* context,
229 GrPaint&& paint,
230 const SkRect& r,
231 int id) {
232 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(context, std::move(paint),
233 r, id).release();
Brian Salomon9a036422017-07-13 17:04:43 -0400234 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
235 }
236
237 // We set the initial color of the NonAARectOp based on the ID.
238 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
239 // pulling from the atlas.
Brian Osmancf860852018-10-31 14:04:39 -0400240 AtlasedRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Osman936fe7d2018-10-30 15:30:35 -0400241 int id)
Brian Osmancf860852018-10-31 14:04:39 -0400242 : INHERITED(helperArgs, SkPMColor4f::FromBytes_RGBA(kColors[id]), r, &kEmptyRect,
243 ClassID())
Brian Salomon9a036422017-07-13 17:04:43 -0400244 , fID(id)
245 , fNext(nullptr) {
246 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400247 }
248
Brian Osmancf860852018-10-31 14:04:39 -0400249 void setColor(const SkPMColor4f& color) { fColor = color; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400250 void setLocalRect(const SkRect& localRect) {
251 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
Brian Salomona33b67c2018-05-17 10:42:14 -0400252 fLocalQuad = GrQuad(localRect);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400253 }
254
255 AtlasedRectOp* next() const { return fNext; }
256 void setNext(AtlasedRectOp* next) {
257 fNext = next;
258 }
259
260private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400261
262 static const int kMaxIDs = 9;
Brian Osman1be2b7c2018-10-29 16:07:15 -0400263 static const GrColor kColors[kMaxIDs];
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400264
265 int fID;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400266 // The Atlased ops have an internal singly-linked list of ops that land in the same opsTask
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400267 AtlasedRectOp* fNext;
268
269 typedef NonAARectOp INHERITED;
270};
271
Brian Salomon9a036422017-07-13 17:04:43 -0400272} // anonymous namespace
273
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400274const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
275 GrColorPackRGBA(255, 0, 0, 255),
276 GrColorPackRGBA(0, 255, 0, 255),
277 GrColorPackRGBA(0, 0, 255, 255),
278 GrColorPackRGBA(0, 255, 255, 255),
279 GrColorPackRGBA(255, 0, 255, 255),
280 GrColorPackRGBA(255, 255, 0, 255),
281 GrColorPackRGBA(0, 0, 0, 255),
282 GrColorPackRGBA(128, 128, 128, 255),
283 GrColorPackRGBA(255, 255, 255, 255)
284};
285
286static const int kDrawnTileSize = 16;
287
288/*
289 * Rather than performing any rect packing, this atlaser just lays out constant-sized
290 * tiles in an Nx1 row
291 */
292static const int kAtlasTileSize = 2;
293
294/*
295 * This class aggregates the op information required for atlasing
296 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400297class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400298public:
Brian Salomon557e8122019-10-24 10:37:08 -0400299 AtlasObject(skiatest::Reporter* reporter) : fDone(false), fReporter(reporter) {}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400300
301 ~AtlasObject() override {
302 SkASSERT(fDone);
303 }
304
305 void markAsDone() {
306 fDone = true;
307 }
308
Greg Danielf41b2bd2019-08-22 16:19:24 -0400309 // Insert the new op in an internal singly-linked list for 'opsTaskID'
310 void addOp(uint32_t opsTaskID, AtlasedRectOp* op) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400311 LinkedListHeader* header = nullptr;
312 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400313 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400314 header = &(fOps[i]);
315 }
316 }
317
318 if (!header) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400319 fOps.push_back({opsTaskID, nullptr});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400320 header = &(fOps[fOps.count()-1]);
321 }
322
323 op->setNext(header->fHead);
324 header->fHead = op;
325 }
326
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500327 int numOps() const { return fOps.count(); }
328
329 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
330 // known until flush time.
Greg Danield11ae2e2020-02-10 16:36:07 -0500331 GrSurfaceProxyView getAtlasView(GrProxyProvider* proxyProvider, const GrCaps* caps) {
332 if (fAtlasView) {
333 return fAtlasView;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500334 }
335
Robert Phillips0a15cc62019-07-30 12:49:10 -0400336 const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
337 GrRenderable::kYes);
Greg Danielce3ddaa2020-01-22 16:58:15 -0500338 GrSwizzle readSwizzle = caps->getReadSwizzle(format, GrColorType::kRGBA_8888);
Greg Daniel4065d452018-11-16 15:43:41 -0500339
Greg Danield11ae2e2020-02-10 16:36:07 -0500340 auto proxy = GrProxyProvider::MakeFullyLazyProxy(
Brian Salomon4eb38b72019-08-05 12:58:39 -0400341 [format](GrResourceProvider* resourceProvider)
Brian Salomonbeb7f522019-08-30 16:19:42 -0400342 -> GrSurfaceProxy::LazyCallbackResult {
Brian Salomona56a7462020-02-07 14:17:25 -0500343 SkISize dims;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500344 // TODO: until partial flushes in MDB lands we're stuck having
345 // all 9 atlas draws occur
Brian Salomona56a7462020-02-07 14:17:25 -0500346 dims.fWidth = 9 /*this->numOps()*/ * kAtlasTileSize;
347 dims.fHeight = kAtlasTileSize;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500348
Brian Salomona56a7462020-02-07 14:17:25 -0500349 return resourceProvider->createTexture(dims, format, GrRenderable::kYes, 1,
Brian Salomona90382f2019-09-17 09:01:56 -0400350 GrMipMapped::kNo, SkBudgeted::kYes,
351 GrProtected::kNo);
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500352 },
Greg Daniel4065d452018-11-16 15:43:41 -0500353 format,
Greg Danielce3ddaa2020-01-22 16:58:15 -0500354 readSwizzle,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400355 GrRenderable::kYes,
356 1,
Brian Salomone8a766b2019-07-19 14:24:36 -0400357 GrProtected::kNo,
Brian Salomonbeb7f522019-08-30 16:19:42 -0400358 *proxyProvider->caps(),
359 GrSurfaceProxy::UseAllocator::kNo);
Robert Phillips5f78adf2019-04-22 12:41:39 -0400360
Greg Danield11ae2e2020-02-10 16:36:07 -0500361 fAtlasView = {std::move(proxy), kBottomLeft_GrSurfaceOrigin, readSwizzle};
362 return fAtlasView;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400363 }
364
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400365 /*
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500366 * This callback creates the atlas and updates the AtlasedRectOps to read from it
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400367 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400368 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400369 const uint32_t* opsTaskIDs,
Chris Daltonc4b47352019-08-23 10:10:36 -0600370 int numOpsTaskIDs) override {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400371 // Until MDB is landed we will most-likely only have one opsTask.
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400372 SkTDArray<LinkedListHeader*> lists;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400373 for (int i = 0; i < numOpsTaskIDs; ++i) {
374 if (LinkedListHeader* list = this->getList(opsTaskIDs[i])) {
Mike Reed5edcd312018-08-08 11:23:41 -0400375 lists.push_back(list);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400376 }
377 }
378
379 if (!lists.count()) {
380 return; // nothing to atlas
381 }
382
Greg Danield11ae2e2020-02-10 16:36:07 -0500383 if (!resourceProvider->instatiateProxy(fAtlasView.proxy())) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500384 return;
385 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400386
Greg Danield11ae2e2020-02-10 16:36:07 -0500387 // At this point 'fAtlasView' proxy should be instantiated and have:
388 // 1 ref from the 'fAtlasView' proxy sk_sp
Robert Phillips3d4cac52019-06-11 08:08:08 -0400389 // 9 refs from the 9 AtlasedRectOps
Robert Phillipse5f73282019-06-18 17:15:04 -0400390 // The backing GrSurface should have only 1 though bc there is only one proxy
Greg Danield11ae2e2020-02-10 16:36:07 -0500391 CheckSingleThreadedProxyRefs(fReporter, fAtlasView.proxy(), 10, 1);
392 auto rtc = resourceProvider->makeRenderTargetContext(
393 fAtlasView.refProxy(), fAtlasView.origin(), GrColorType::kRGBA_8888, nullptr,
394 nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400395
Chris Dalton344e9032017-12-11 15:42:09 -0700396 // clear the atlas
Brian Osman9a9baae2018-11-05 15:06:26 -0500397 rtc->clear(nullptr, SK_PMColor4fTRANSPARENT,
398 GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400399
400 int blocksInAtlas = 0;
401 for (int i = 0; i < lists.count(); ++i) {
402 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
403 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
404 kAtlasTileSize, kAtlasTileSize);
405
406 // For now, we avoid the resource buffer issues and just use clears
407#if 1
Brian Osman9a9baae2018-11-05 15:06:26 -0500408 rtc->clear(&r, op->color(), GrRenderTargetContext::CanClearFullscreen::kNo);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400409#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400410 GrPaint paint;
Brian Osman9a9baae2018-11-05 15:06:26 -0500411 paint.setColor4f(op->color());
Brian Salomon9a036422017-07-13 17:04:43 -0400412 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
413 SkRect::Make(r)));
414 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400415#endif
416 blocksInAtlas++;
417
418 // Set the atlased Op's color to white (so we know we're not using it for
419 // the final draw).
Brian Osmancf860852018-10-31 14:04:39 -0400420 op->setColor(SK_PMColor4fWHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400421
422 // Set the atlased Op's localRect to point to where it landed in the atlas
423 op->setLocalRect(SkRect::Make(r));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400424 }
425
426 // We've updated all these ops and we certainly don't want to process them again
427 this->clearOpsFor(lists[i]);
428 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400429 }
430
431private:
432 typedef struct {
433 uint32_t fID;
434 AtlasedRectOp* fHead;
435 } LinkedListHeader;
436
Greg Danielf41b2bd2019-08-22 16:19:24 -0400437 LinkedListHeader* getList(uint32_t opsTaskID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400438 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400439 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400440 return &(fOps[i]);
441 }
442 }
443 return nullptr;
444 }
445
446 void clearOpsFor(LinkedListHeader* header) {
447 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
448 // forget about them in the laziest way possible.
449 header->fHead = nullptr;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400450 header->fID = 0; // invalid opsTask ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400451 }
452
Greg Danielf41b2bd2019-08-22 16:19:24 -0400453 // Each opsTask containing AtlasedRectOps gets its own internal singly-linked list
Greg Danield11ae2e2020-02-10 16:36:07 -0500454 SkTDArray<LinkedListHeader> fOps;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400455
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500456 // The fully lazy proxy for the atlas
Greg Danield11ae2e2020-02-10 16:36:07 -0500457 GrSurfaceProxyView fAtlasView;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400458
459 // Set to true when the testing harness expects this object to be no longer used
Greg Danield11ae2e2020-02-10 16:36:07 -0500460 bool fDone;
Brian Salomon557e8122019-10-24 10:37:08 -0400461
Greg Danield11ae2e2020-02-10 16:36:07 -0500462 skiatest::Reporter* fReporter;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400463};
464
465// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
Greg Danield11ae2e2020-02-10 16:36:07 -0500466static GrSurfaceProxyView make_upstream_image(GrContext* context, AtlasObject* object, int start,
467 GrSurfaceProxyView atlasView,
468 SkAlphaType atlasAlphaType) {
Greg Daniele20fcad2020-01-08 11:52:34 -0500469 auto rtc = GrRenderTargetContext::Make(
470 context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox,
471 {3 * kDrawnTileSize, kDrawnTileSize});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400472
Brian Osman9a9baae2018-11-05 15:06:26 -0500473 rtc->clear(nullptr, { 1, 0, 0, 1 }, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400474
475 for (int i = 0; i < 3; ++i) {
476 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
477
Greg Danield2ccbb52020-02-05 10:45:39 -0500478 auto fp = GrTextureEffect::Make(atlasView, atlasAlphaType);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400479 GrPaint paint;
480 paint.addColorFragmentProcessor(std::move(fp));
481 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Robert Phillips7c525e62018-06-12 10:11:12 -0400482 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(context,
483 std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400484
485 AtlasedRectOp* sparePtr = op.get();
486
Greg Danielf41b2bd2019-08-22 16:19:24 -0400487 uint32_t opsTaskID;
Brian Salomon348a0372018-10-31 10:42:18 -0400488 rtc->priv().testingOnly_addDrawOp(GrNoClip(), std::move(op),
Greg Danielf41b2bd2019-08-22 16:19:24 -0400489 [&opsTaskID](GrOp* op, uint32_t id) { opsTaskID = id; });
490 SkASSERT(SK_InvalidUniqueID != opsTaskID);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400491
Greg Danielf41b2bd2019-08-22 16:19:24 -0400492 object->addOp(opsTaskID, sparePtr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400493 }
494
Greg Danield11ae2e2020-02-10 16:36:07 -0500495 return rtc->readSurfaceView();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400496}
497
498// Enable this if you want to debug the final draws w/o having the atlasCallback create the
499// atlas
500#if 0
501#include "SkGrPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500502#include "include/core/SkImageEncoder.h"
503#include "tools/ToolUtils.h"
Chris Dalton12658942017-10-05 19:45:25 -0600504
505static void save_bm(const SkBitmap& bm, const char name[]) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500506 bool result = ToolUtils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
Chris Dalton12658942017-10-05 19:45:25 -0600507 SkASSERT(result);
508}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400509
510sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
511 SkBitmap bm;
512 bm.allocN32Pixels(18, 2, true);
513 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
514 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
515 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
516 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
517 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
518 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
519 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
520 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
521 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
522
523#if 1
524 save_bm(bm, "atlas-fake.png");
525#endif
526
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400527 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
528
529 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
530 context->textureProvider(),
Brian Salomona56a7462020-02-07 14:17:25 -0500531 dm.dimensions(), SkBudgeted::kYes,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400532 bm.getPixels(), bm.rowBytes());
533
534 return sk_ref_sp(tmp->asTextureProxy());
535}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400536#endif
537
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500538
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400539static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
540 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
541 REPORTER_ASSERT(reporter, expected == readback);
542 if (expected != readback) {
543 SkDebugf("Color mismatch: %x %x\n", expected, readback);
544 }
545}
546
547/*
548 * For the atlasing test we make a DAG that looks like:
549 *
550 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
551 * \ /
552 * \ /
553 * RT4
554 * We then flush RT4 and expect only ops 0-5 to be atlased together.
555 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
556 * R G B C M Y
557 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
558 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500559 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
560 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400561 * R G B C M Y K Grey White
562 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400563DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Greg Danield11ae2e2020-02-10 16:36:07 -0500564 static const int kNumViews = 3;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400565
566 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500567 auto proxyProvider = context->priv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400568
Brian Salomon557e8122019-10-24 10:37:08 -0400569 AtlasObject object(reporter);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400570
Robert Phillips9da87e02019-02-04 13:26:26 -0500571 context->priv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400572
Greg Danield11ae2e2020-02-10 16:36:07 -0500573 GrSurfaceProxyView views[kNumViews];
574 for (int i = 0; i < kNumViews; ++i) {
575 views[i] = make_upstream_image(context, &object, i * 3,
576 object.getAtlasView(proxyProvider, context->priv().caps()),
577 kPremul_SkAlphaType);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400578 }
579
580 static const int kFinalWidth = 6*kDrawnTileSize;
581 static const int kFinalHeight = kDrawnTileSize;
582
Greg Daniele20fcad2020-01-08 11:52:34 -0500583 auto rtc = GrRenderTargetContext::Make(
584 context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox,
585 {kFinalWidth, kFinalHeight});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400586
Brian Osman9a9baae2018-11-05 15:06:26 -0500587 rtc->clear(nullptr, SK_PMColor4fWHITE, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400588
589 // Note that this doesn't include the third texture proxy
Greg Danield11ae2e2020-02-10 16:36:07 -0500590 for (int i = 0; i < kNumViews - 1; ++i) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400591 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
592
593 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
594
595 GrPaint paint;
Greg Danield11ae2e2020-02-10 16:36:07 -0500596 auto fp = GrTextureEffect::Make(std::move(views[i]), kPremul_SkAlphaType, t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400597 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
598 paint.addColorFragmentProcessor(std::move(fp));
599
600 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
601 }
602
Greg Daniele6bfb7d2019-04-17 15:26:11 -0400603 rtc->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400604
605 SkBitmap readBack;
606 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
607
608 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
Brian Salomon1d435302019-07-01 13:05:28 -0400609 readBack.rowBytes(), {0, 0});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400610 SkASSERT(result);
611
Robert Phillips9da87e02019-02-04 13:26:26 -0500612 context->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
Chris Daltonfe199b72017-05-05 11:26:15 -0400613
614 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400615
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400616 int x = kDrawnTileSize/2;
617 test_color(reporter, readBack, x, SK_ColorRED);
618 x += kDrawnTileSize;
619 test_color(reporter, readBack, x, SK_ColorGREEN);
620 x += kDrawnTileSize;
621 test_color(reporter, readBack, x, SK_ColorBLUE);
622 x += kDrawnTileSize;
623 test_color(reporter, readBack, x, SK_ColorCYAN);
624 x += kDrawnTileSize;
625 test_color(reporter, readBack, x, SK_ColorMAGENTA);
626 x += kDrawnTileSize;
627 test_color(reporter, readBack, x, SK_ColorYELLOW);
628}