blob: 5bd7e8fca7cadc436a5bb2df25bf04d2be003cf7 [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"
Robert Phillips6d344c32020-07-06 10:56:46 -040012#include "include/gpu/GrDirectContext.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/GrDefaultGeoProcFactory.h"
Adlai Hollera0693042020-10-14 11:23:11 -040015#include "src/gpu/GrDirectContextPriv.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/GrResourceProvider.h"
Brian Salomoneebe7352020-12-09 16:37:04 -050021#include "src/gpu/GrSurfaceDrawContext.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
Herb Derbyc76d4092020-10-07 16:46:15 -040039 static GrOp::Owner Make(GrRecordingContext* context,
40 GrPaint&& paint,
41 const SkRect& r) {
Robert Phillips7c525e62018-06-12 10:11:12 -040042 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
Herb Derbyc76d4092020-10-07 16:46:15 -040046 static GrOp::Owner Make(GrRecordingContext* context,
47 GrPaint&& paint,
48 const SkRect& r,
49 const SkRect& local) {
Robert Phillips7c525e62018-06-12 10:11:12 -040050 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
Herb Derbyc76d4092020-10-07 16:46:15 -040055 NonAARectOp(GrProcessorSet* processorSet, 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)
Herb Derbyc76d4092020-10-07 16:46:15 -040061 , fHelper(processorSet, GrAAType::kNone) {
Brian Salomon9a036422017-07-13 17:04:43 -040062 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) {
Chris Daltonbe457422020-03-16 18:05:03 -060073 fProgramInfo->visitFPProxies(func);
Robert Phillipsd2f18732020-03-04 16:12:08 -050074 } 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.
Michael Ludwigd1d997e2020-06-04 15:52:44 -040088 static GrAppliedClip kNoClip = GrAppliedClip::Disabled();
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,
Adlai Hollere2296f72020-11-19 13:41:26 -0500104 const GrSurfaceProxyView& writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400105 GrAppliedClip&& appliedClip,
Greg Danield358cbe2020-09-11 09:33:54 -0400106 const GrXferProcessor::DstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500107 GrXferBarrierFlags renderPassXferBarriers,
108 GrLoadOp colorLoadOp) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400109 using namespace GrDefaultGeoProcFactory;
110
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500111 GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Make(
Robert Phillipsd2f18732020-03-04 16:12:08 -0500112 arena,
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400113 Color::kPremulGrColorAttribute_Type,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400114 Coverage::kSolid_Type,
115 fHasLocalRect ? LocalCoords::kHasExplicit_Type
116 : LocalCoords::kUnused_Type,
117 SkMatrix::I());
118 if (!gp) {
Robert Phillipsd2f18732020-03-04 16:12:08 -0500119 SkDebugf("Couldn't create GrGeometryProcessor\n");
Robert Phillips4133dc42020-03-11 15:55:55 -0400120 return;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400121 }
122
Brian Salomon8afde5f2020-04-01 16:22:00 -0400123 fProgramInfo = fHelper.createProgramInfo(caps, arena, writeView, std::move(appliedClip),
Greg Danield358cbe2020-09-11 09:33:54 -0400124 dstProxyView, gp, GrPrimitiveType::kTriangles,
Greg Daniel42dbca52020-11-20 10:22:43 -0500125 renderPassXferBarriers, colorLoadOp);
Robert Phillipsd2f18732020-03-04 16:12:08 -0500126 }
127
Robert Phillipsd2f18732020-03-04 16:12:08 -0500128 void onPrepareDraws(Target* target) override {
129
130 // The vertex attrib order is always pos, color, local coords.
131 static const int kColorOffset = sizeof(SkPoint);
132 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
133
134 if (!fProgramInfo) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400135 this->createProgramInfo(target);
Robert Phillipsd2f18732020-03-04 16:12:08 -0500136 if (!fProgramInfo) {
137 return;
138 }
139 }
140
141 size_t vertexStride = fProgramInfo->primProc().vertexStride();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400142
Brian Salomon12d22642019-01-29 14:38:50 -0500143 sk_sp<const GrBuffer> indexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400144 int firstIndex;
145 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
146 if (!indices) {
147 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
148 return;
149 }
150
Brian Salomon12d22642019-01-29 14:38:50 -0500151 sk_sp<const GrBuffer> vertexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400152 int firstVertex;
153 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
154 if (!vertices) {
155 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
156 return;
157 }
158
159 // Setup indices
160 indices[0] = 0;
161 indices[1] = 1;
162 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000163 indices[3] = 2;
164 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400165 indices[5] = 3;
166
167 // Setup positions
168 SkPoint* position = (SkPoint*) vertices;
Brian Salomonec42e152018-05-18 12:52:22 -0400169 SkPointPriv::SetRectTriStrip(position, fRect, vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400170
171 // Setup vertex colors
172 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
173 for (int i = 0; i < 4; ++i) {
Brian Osmancf860852018-10-31 14:04:39 -0400174 *color = fColor.toBytes_RGBA();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400175 color = (GrColor*)((intptr_t)color + vertexStride);
176 }
177
178 // Setup local coords
179 if (fHasLocalRect) {
180 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
181 for (int i = 0; i < 4; i++) {
182 *coords = fLocalQuad.point(i);
183 coords = (SkPoint*)((intptr_t) coords + vertexStride);
184 }
185 }
186
Robert Phillipsd2f18732020-03-04 16:12:08 -0500187 fMesh = target->allocMesh();
Chris Dalton37c7bdd2020-03-13 09:21:12 -0600188 fMesh->setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo, vertexBuffer,
189 firstVertex);
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700190 }
191
192 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Robert Phillipsd2f18732020-03-04 16:12:08 -0500193 if (!fProgramInfo || !fMesh) {
194 return;
195 }
Robert Phillips3968fcb2019-12-05 16:40:31 -0500196
Chris Dalton765ed362020-03-16 17:34:44 -0600197 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
198 flushState->bindTextures(fProgramInfo->primProc(), nullptr, fProgramInfo->pipeline());
199 flushState->drawMesh(*fMesh);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400200 }
201
Robert Phillipsd2f18732020-03-04 16:12:08 -0500202 Helper fHelper;
Chris Daltoneb694b72020-03-16 09:25:50 -0600203 GrSimpleMesh* fMesh = nullptr;
Robert Phillipsd2f18732020-03-04 16:12:08 -0500204 GrProgramInfo* fProgramInfo = nullptr;
Brian Salomon9a036422017-07-13 17:04:43 -0400205
John Stiles7571f9e2020-09-02 22:42:33 -0400206 using INHERITED = GrMeshDrawOp;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400207};
208
Brian Salomon9a036422017-07-13 17:04:43 -0400209} // anonymous namespace
210
Brian Salomon9a036422017-07-13 17:04:43 -0400211static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
212
213namespace {
214
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400215/*
216 * Atlased ops just draw themselves as textured rects with the texture pixels being
217 * pulled out of the atlas. Their color is based on their ID.
218 */
219class AtlasedRectOp final : public NonAARectOp {
220public:
221 DEFINE_OP_CLASS_ID
222
223 ~AtlasedRectOp() override {
224 fID = -1;
225 }
226
227 const char* name() const override { return "AtlasedRectOp"; }
228
229 int id() const { return fID; }
230
Herb Derbyc76d4092020-10-07 16:46:15 -0400231 static GrOp::Owner Make(GrRecordingContext* rContext,
232 GrPaint&& paint,
233 const SkRect& r,
234 int id) {
235 return Helper::FactoryHelper<AtlasedRectOp>(rContext, std::move(paint), r, id);
Brian Salomon9a036422017-07-13 17:04:43 -0400236 }
237
238 // We set the initial color of the NonAARectOp based on the ID.
239 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
240 // pulling from the atlas.
Herb Derbyc76d4092020-10-07 16:46:15 -0400241 AtlasedRectOp(GrProcessorSet* processorSet, const SkPMColor4f& color, const SkRect& r,
Brian Osman936fe7d2018-10-30 15:30:35 -0400242 int id)
Herb Derbyc76d4092020-10-07 16:46:15 -0400243 : INHERITED(processorSet, SkPMColor4f::FromBytes_RGBA(kColors[id]), r, &kEmptyRect,
Brian Osmancf860852018-10-31 14:04:39 -0400244 ClassID())
Brian Salomon9a036422017-07-13 17:04:43 -0400245 , fID(id)
246 , fNext(nullptr) {
247 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400248 }
249
Brian Osmancf860852018-10-31 14:04:39 -0400250 void setColor(const SkPMColor4f& color) { fColor = color; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400251 void setLocalRect(const SkRect& localRect) {
252 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
Brian Salomona33b67c2018-05-17 10:42:14 -0400253 fLocalQuad = GrQuad(localRect);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400254 }
255
256 AtlasedRectOp* next() const { return fNext; }
257 void setNext(AtlasedRectOp* next) {
258 fNext = next;
259 }
260
261private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400262
263 static const int kMaxIDs = 9;
Brian Osman1be2b7c2018-10-29 16:07:15 -0400264 static const GrColor kColors[kMaxIDs];
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400265
266 int fID;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400267 // The Atlased ops have an internal singly-linked list of ops that land in the same opsTask
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400268 AtlasedRectOp* fNext;
269
John Stiles7571f9e2020-09-02 22:42:33 -0400270 using INHERITED = NonAARectOp;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400271};
272
Brian Salomon9a036422017-07-13 17:04:43 -0400273} // anonymous namespace
274
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400275const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
276 GrColorPackRGBA(255, 0, 0, 255),
277 GrColorPackRGBA(0, 255, 0, 255),
278 GrColorPackRGBA(0, 0, 255, 255),
279 GrColorPackRGBA(0, 255, 255, 255),
280 GrColorPackRGBA(255, 0, 255, 255),
281 GrColorPackRGBA(255, 255, 0, 255),
282 GrColorPackRGBA(0, 0, 0, 255),
283 GrColorPackRGBA(128, 128, 128, 255),
284 GrColorPackRGBA(255, 255, 255, 255)
285};
286
287static const int kDrawnTileSize = 16;
288
289/*
290 * Rather than performing any rect packing, this atlaser just lays out constant-sized
291 * tiles in an Nx1 row
292 */
293static const int kAtlasTileSize = 2;
294
295/*
296 * This class aggregates the op information required for atlasing
297 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400298class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400299public:
Brian Salomon557e8122019-10-24 10:37:08 -0400300 AtlasObject(skiatest::Reporter* reporter) : fDone(false), fReporter(reporter) {}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400301
302 ~AtlasObject() override {
303 SkASSERT(fDone);
304 }
305
306 void markAsDone() {
307 fDone = true;
308 }
309
Greg Danielf41b2bd2019-08-22 16:19:24 -0400310 // Insert the new op in an internal singly-linked list for 'opsTaskID'
311 void addOp(uint32_t opsTaskID, AtlasedRectOp* op) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400312 LinkedListHeader* header = nullptr;
313 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400314 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400315 header = &(fOps[i]);
316 }
317 }
318
319 if (!header) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400320 fOps.push_back({opsTaskID, nullptr});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400321 header = &(fOps[fOps.count()-1]);
322 }
323
324 op->setNext(header->fHead);
325 header->fHead = op;
326 }
327
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500328 int numOps() const { return fOps.count(); }
329
330 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
331 // known until flush time.
Greg Danield11ae2e2020-02-10 16:36:07 -0500332 GrSurfaceProxyView getAtlasView(GrProxyProvider* proxyProvider, const GrCaps* caps) {
333 if (fAtlasView) {
334 return fAtlasView;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500335 }
336
Robert Phillips0a15cc62019-07-30 12:49:10 -0400337 const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
338 GrRenderable::kYes);
Greg Danield11ae2e2020-02-10 16:36:07 -0500339 auto proxy = GrProxyProvider::MakeFullyLazyProxy(
Brian Salomon63410e92020-03-23 18:32:50 -0400340 [](GrResourceProvider* resourceProvider,
341 const GrSurfaceProxy::LazySurfaceDesc& desc)
Brian Salomonbeb7f522019-08-30 16:19:42 -0400342 -> GrSurfaceProxy::LazyCallbackResult {
Brian Salomon63410e92020-03-23 18:32:50 -0400343 SkASSERT(desc.fDimensions.width() < 0 && desc.fDimensions.height() < 0);
Brian Salomona56a7462020-02-07 14:17:25 -0500344 SkISize dims;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500345 // TODO: until partial flushes in MDB lands we're stuck having
346 // all 9 atlas draws occur
Brian Salomona56a7462020-02-07 14:17:25 -0500347 dims.fWidth = 9 /*this->numOps()*/ * kAtlasTileSize;
348 dims.fHeight = kAtlasTileSize;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500349
Brian Salomon63410e92020-03-23 18:32:50 -0400350 return resourceProvider->createTexture(dims, desc.fFormat, desc.fRenderable,
Brian Salomon40a40622020-07-21 10:32:07 -0400351 desc.fSampleCnt, desc.fMipmapped,
Brian Salomon63410e92020-03-23 18:32:50 -0400352 desc.fBudgeted, desc.fProtected);
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500353 },
Greg Daniel4065d452018-11-16 15:43:41 -0500354 format,
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
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400361 GrSwizzle readSwizzle = caps->getReadSwizzle(format, GrColorType::kRGBA_8888);
Greg Danield11ae2e2020-02-10 16:36:07 -0500362 fAtlasView = {std::move(proxy), kBottomLeft_GrSurfaceOrigin, readSwizzle};
363 return fAtlasView;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400364 }
365
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400366 /*
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500367 * This callback creates the atlas and updates the AtlasedRectOps to read from it
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400368 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400369 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Adlai Holler9902cff2020-11-11 08:51:25 -0500370 SkSpan<const uint32_t> renderTaskIDs) 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;
Adlai Holler9902cff2020-11-11 08:51:25 -0500373 for (uint32_t taskID : renderTaskIDs) {
374 if (LinkedListHeader* list = this->getList(taskID)) {
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
Michael Ludwig81d41722020-05-26 16:57:38 -0400397 rtc->clear(SK_PMColor4fTRANSPARENT);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400398
399 int blocksInAtlas = 0;
400 for (int i = 0; i < lists.count(); ++i) {
401 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
402 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
403 kAtlasTileSize, kAtlasTileSize);
404
405 // For now, we avoid the resource buffer issues and just use clears
406#if 1
Michael Ludwig81d41722020-05-26 16:57:38 -0400407 rtc->clear(r, op->color());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400408#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400409 GrPaint paint;
Brian Osman9a9baae2018-11-05 15:06:26 -0500410 paint.setColor4f(op->color());
Brian Salomon9a036422017-07-13 17:04:43 -0400411 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
412 SkRect::Make(r)));
Brian Salomon70fe17e2020-11-30 14:33:58 -0500413 rtc->addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400414#endif
415 blocksInAtlas++;
416
417 // Set the atlased Op's color to white (so we know we're not using it for
418 // the final draw).
Brian Osmancf860852018-10-31 14:04:39 -0400419 op->setColor(SK_PMColor4fWHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400420
421 // Set the atlased Op's localRect to point to where it landed in the atlas
422 op->setLocalRect(SkRect::Make(r));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400423 }
424
425 // We've updated all these ops and we certainly don't want to process them again
426 this->clearOpsFor(lists[i]);
427 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400428 }
429
430private:
431 typedef struct {
432 uint32_t fID;
433 AtlasedRectOp* fHead;
434 } LinkedListHeader;
435
Greg Danielf41b2bd2019-08-22 16:19:24 -0400436 LinkedListHeader* getList(uint32_t opsTaskID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400437 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400438 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400439 return &(fOps[i]);
440 }
441 }
442 return nullptr;
443 }
444
445 void clearOpsFor(LinkedListHeader* header) {
446 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
447 // forget about them in the laziest way possible.
448 header->fHead = nullptr;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400449 header->fID = 0; // invalid opsTask ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400450 }
451
Greg Danielf41b2bd2019-08-22 16:19:24 -0400452 // Each opsTask containing AtlasedRectOps gets its own internal singly-linked list
Greg Danield11ae2e2020-02-10 16:36:07 -0500453 SkTDArray<LinkedListHeader> fOps;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400454
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500455 // The fully lazy proxy for the atlas
Greg Danield11ae2e2020-02-10 16:36:07 -0500456 GrSurfaceProxyView fAtlasView;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400457
458 // Set to true when the testing harness expects this object to be no longer used
Greg Danield11ae2e2020-02-10 16:36:07 -0500459 bool fDone;
Brian Salomon557e8122019-10-24 10:37:08 -0400460
Greg Danield11ae2e2020-02-10 16:36:07 -0500461 skiatest::Reporter* fReporter;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400462};
463
464// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
Robert Phillips58adb342020-07-23 09:41:57 -0400465static GrSurfaceProxyView make_upstream_image(GrRecordingContext* rContext,
466 AtlasObject* object,
467 int start,
Greg Danield11ae2e2020-02-10 16:36:07 -0500468 GrSurfaceProxyView atlasView,
469 SkAlphaType atlasAlphaType) {
Brian Salomoneebe7352020-12-09 16:37:04 -0500470 auto rtc = GrSurfaceDrawContext::Make(
471 rContext, GrColorType::kRGBA_8888, nullptr,
472 SkBackingFit::kApprox, {3 * kDrawnTileSize, kDrawnTileSize});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400473
Brian Salomon590f5672020-12-16 11:44:47 -0500474 rtc->clear(SkPMColor4f{1, 0, 0, 1});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400475
476 for (int i = 0; i < 3; ++i) {
477 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
478
Greg Danield2ccbb52020-02-05 10:45:39 -0500479 auto fp = GrTextureEffect::Make(atlasView, atlasAlphaType);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400480 GrPaint paint;
John Stiles5933d7d2020-07-21 12:28:35 -0400481 paint.setColorFragmentProcessor(std::move(fp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400482 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Herb Derbyc76d4092020-10-07 16:46:15 -0400483 GrOp::Owner op = AtlasedRectOp::Make(rContext, std::move(paint), r, start + i);
484 AtlasedRectOp* sparePtr = (AtlasedRectOp*)op.get();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400485
Greg Danielf41b2bd2019-08-22 16:19:24 -0400486 uint32_t opsTaskID;
Brian Salomon70fe17e2020-11-30 14:33:58 -0500487 rtc->addDrawOp(nullptr, std::move(op),
488 [&opsTaskID](GrOp* op, uint32_t id) { opsTaskID = id; });
Greg Danielf41b2bd2019-08-22 16:19:24 -0400489 SkASSERT(SK_InvalidUniqueID != opsTaskID);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400490
Greg Danielf41b2bd2019-08-22 16:19:24 -0400491 object->addOp(opsTaskID, sparePtr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400492 }
493
Greg Danield11ae2e2020-02-10 16:36:07 -0500494 return rtc->readSurfaceView();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400495}
496
497// Enable this if you want to debug the final draws w/o having the atlasCallback create the
498// atlas
499#if 0
500#include "SkGrPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500501#include "include/core/SkImageEncoder.h"
502#include "tools/ToolUtils.h"
Chris Dalton12658942017-10-05 19:45:25 -0600503
504static void save_bm(const SkBitmap& bm, const char name[]) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500505 bool result = ToolUtils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
Chris Dalton12658942017-10-05 19:45:25 -0600506 SkASSERT(result);
507}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400508
Robert Phillips58adb342020-07-23 09:41:57 -0400509sk_sp<GrTextureProxy> pre_create_atlas(GrRecordingContext* rContext) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400510 SkBitmap bm;
511 bm.allocN32Pixels(18, 2, true);
512 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
513 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
514 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
515 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
516 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
517 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
518 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
519 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
520 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
521
522#if 1
523 save_bm(bm, "atlas-fake.png");
524#endif
525
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400526 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
527
Robert Phillips58adb342020-07-23 09:41:57 -0400528 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*rContext->caps(),
529 rContext->textureProvider(),
Brian Salomona56a7462020-02-07 14:17:25 -0500530 dm.dimensions(), SkBudgeted::kYes,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400531 bm.getPixels(), bm.rowBytes());
532
533 return sk_ref_sp(tmp->asTextureProxy());
534}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400535#endif
536
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500537
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400538static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
539 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
540 REPORTER_ASSERT(reporter, expected == readback);
541 if (expected != readback) {
542 SkDebugf("Color mismatch: %x %x\n", expected, readback);
543 }
544}
545
546/*
547 * For the atlasing test we make a DAG that looks like:
548 *
549 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
550 * \ /
551 * \ /
552 * RT4
553 * We then flush RT4 and expect only ops 0-5 to be atlased together.
554 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
555 * R G B C M Y
556 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
557 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500558 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
559 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400560 * R G B C M Y K Grey White
561 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400562DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Greg Danield11ae2e2020-02-10 16:36:07 -0500563 static const int kNumViews = 3;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400564
Adlai Hollerc95b5892020-08-11 12:02:22 -0400565 auto dContext = ctxInfo.directContext();
566 auto proxyProvider = dContext->priv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400567
Brian Salomon557e8122019-10-24 10:37:08 -0400568 AtlasObject object(reporter);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400569
Adlai Hollerc95b5892020-08-11 12:02:22 -0400570 dContext->priv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400571
Greg Danield11ae2e2020-02-10 16:36:07 -0500572 GrSurfaceProxyView views[kNumViews];
573 for (int i = 0; i < kNumViews; ++i) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400574 views[i] = make_upstream_image(dContext, &object, i * 3,
575 object.getAtlasView(proxyProvider, dContext->priv().caps()),
Greg Danield11ae2e2020-02-10 16:36:07 -0500576 kPremul_SkAlphaType);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400577 }
578
579 static const int kFinalWidth = 6*kDrawnTileSize;
580 static const int kFinalHeight = kDrawnTileSize;
581
Brian Salomoneebe7352020-12-09 16:37:04 -0500582 auto rtc = GrSurfaceDrawContext::Make(
Adlai Hollerc95b5892020-08-11 12:02:22 -0400583 dContext, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox,
Greg Daniele20fcad2020-01-08 11:52:34 -0500584 {kFinalWidth, kFinalHeight});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400585
Michael Ludwig81d41722020-05-26 16:57:38 -0400586 rtc->clear(SK_PMColor4fWHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400587
588 // Note that this doesn't include the third texture proxy
Greg Danield11ae2e2020-02-10 16:36:07 -0500589 for (int i = 0; i < kNumViews - 1; ++i) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400590 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
591
Mike Reed1f607332020-05-21 12:11:27 -0400592 SkMatrix t = SkMatrix::Translate(-i*3*kDrawnTileSize, 0);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400593
594 GrPaint paint;
Greg Danield11ae2e2020-02-10 16:36:07 -0500595 auto fp = GrTextureEffect::Make(std::move(views[i]), kPremul_SkAlphaType, t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400596 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
John Stiles5933d7d2020-07-21 12:28:35 -0400597 paint.setColorFragmentProcessor(std::move(fp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400598
Michael Ludwig7c12e282020-05-29 09:54:07 -0400599 rtc->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), r);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400600 }
601
Robert Phillips80bfda82020-11-12 09:23:36 -0500602 dContext->priv().flushSurface(rtc->asSurfaceProxy());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400603
604 SkBitmap readBack;
605 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
606
Brian Salomondd4087d2020-12-23 20:36:44 -0500607 SkAssertResult(rtc->readPixels(dContext, readBack.pixmap(), {0, 0}));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400608
Adlai Hollerc95b5892020-08-11 12:02:22 -0400609 dContext->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
Chris Daltonfe199b72017-05-05 11:26:15 -0400610
611 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400612
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400613 int x = kDrawnTileSize/2;
614 test_color(reporter, readBack, x, SK_ColorRED);
615 x += kDrawnTileSize;
616 test_color(reporter, readBack, x, SK_ColorGREEN);
617 x += kDrawnTileSize;
618 test_color(reporter, readBack, x, SK_ColorBLUE);
619 x += kDrawnTileSize;
620 test_color(reporter, readBack, x, SK_ColorCYAN);
621 x += kDrawnTileSize;
622 test_color(reporter, readBack, x, SK_ColorMAGENTA);
623 x += kDrawnTileSize;
624 test_color(reporter, readBack, x, SK_ColorYELLOW);
625}