blob: 3de06d5d2c8d14e4a97fed4900ef2cab0952b041 [file] [log] [blame]
Robert Phillipseb35f4d2017-03-21 07:56:47 -04001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "tests/Test.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -04009
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040010#include "include/core/SkBitmap.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/gpu/GrBackendSemaphore.h"
12#include "include/gpu/GrTexture.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040013#include "src/core/SkPointPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/gpu/GrClip.h"
15#include "src/gpu/GrContextPriv.h"
16#include "src/gpu/GrDefaultGeoProcFactory.h"
Brian Salomonf2ebdd92019-09-30 12:15:30 -040017#include "src/gpu/GrImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/gpu/GrOnFlushResourceProvider.h"
19#include "src/gpu/GrProxyProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/gpu/GrRenderTargetContextPriv.h"
21#include "src/gpu/GrResourceProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/gpu/effects/generated/GrSimpleTextureEffect.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040023#include "src/gpu/geometry/GrQuad.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
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 Phillipsb493eeb2017-09-13 13:10:52 -040071 fHelper.visitProxies(func);
72 }
73
Brian Salomon9a036422017-07-13 17:04:43 -040074 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
75
Chris Dalton6ce447a2019-06-23 18:07:38 -060076 GrProcessorSet::Analysis finalize(
77 const GrCaps& caps, const GrAppliedClip*, bool hasMixedSampledCoverage,
78 GrClampType clampType) override {
Brian Salomon9a036422017-07-13 17:04:43 -040079 // Set the color to unknown because the subclass may change the color later.
80 GrProcessorAnalysisColor gpColor;
81 gpColor.setToUnknown();
82 // We ignore the clip so pass this rather than the GrAppliedClip param.
83 static GrAppliedClip kNoClip;
Chris Dalton6ce447a2019-06-23 18:07:38 -060084 return fHelper.finalizeProcessors(caps, &kNoClip, hasMixedSampledCoverage, clampType,
85 GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomon9a036422017-07-13 17:04:43 -040086 }
87
Robert Phillipseb35f4d2017-03-21 07:56:47 -040088protected:
Brian Osmancf860852018-10-31 14:04:39 -040089 SkPMColor4f fColor;
90 bool fHasLocalRect;
91 GrQuad fLocalQuad;
92 SkRect fRect;
Robert Phillipseb35f4d2017-03-21 07:56:47 -040093
94private:
Brian Salomon91326c32017-08-09 16:02:19 -040095 void onPrepareDraws(Target* target) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040096 using namespace GrDefaultGeoProcFactory;
97
98 // The vertex attrib order is always pos, color, local coords.
99 static const int kColorOffset = sizeof(SkPoint);
100 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
101
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500102 GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Make(
103 target->allocator(),
104 target->caps().shaderCaps(),
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400105 Color::kPremulGrColorAttribute_Type,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400106 Coverage::kSolid_Type,
107 fHasLocalRect ? LocalCoords::kHasExplicit_Type
108 : LocalCoords::kUnused_Type,
109 SkMatrix::I());
110 if (!gp) {
111 SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n");
112 return;
113 }
114
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500115 size_t vertexStride = gp->vertexStride();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400116
Brian Salomon12d22642019-01-29 14:38:50 -0500117 sk_sp<const GrBuffer> indexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400118 int firstIndex;
119 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
120 if (!indices) {
121 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
122 return;
123 }
124
Brian Salomon12d22642019-01-29 14:38:50 -0500125 sk_sp<const GrBuffer> vertexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400126 int firstVertex;
127 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
128 if (!vertices) {
129 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
130 return;
131 }
132
133 // Setup indices
134 indices[0] = 0;
135 indices[1] = 1;
136 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000137 indices[3] = 2;
138 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400139 indices[5] = 3;
140
141 // Setup positions
142 SkPoint* position = (SkPoint*) vertices;
Brian Salomonec42e152018-05-18 12:52:22 -0400143 SkPointPriv::SetRectTriStrip(position, fRect, vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400144
145 // Setup vertex colors
146 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
147 for (int i = 0; i < 4; ++i) {
Brian Osmancf860852018-10-31 14:04:39 -0400148 *color = fColor.toBytes_RGBA();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400149 color = (GrColor*)((intptr_t)color + vertexStride);
150 }
151
152 // Setup local coords
153 if (fHasLocalRect) {
154 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
155 for (int i = 0; i < 4; i++) {
156 *coords = fLocalQuad.point(i);
157 coords = (SkPoint*)((intptr_t) coords + vertexStride);
158 }
159 }
160
Brian Salomon7eae3e02018-08-07 14:02:38 +0000161 GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
162 mesh->setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo);
163 mesh->setVertexData(vertexBuffer, firstVertex);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400164
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500165 target->recordDraw(gp, mesh, 1, GrPrimitiveType::kTriangles);
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700166 }
167
168 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
169 fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400170 }
171
Brian Salomon9a036422017-07-13 17:04:43 -0400172 Helper fHelper;
173
174 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400175};
176
Brian Salomon9a036422017-07-13 17:04:43 -0400177} // anonymous namespace
178
Brian Salomon9a036422017-07-13 17:04:43 -0400179static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
180
181namespace {
182
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400183/*
184 * Atlased ops just draw themselves as textured rects with the texture pixels being
185 * pulled out of the atlas. Their color is based on their ID.
186 */
187class AtlasedRectOp final : public NonAARectOp {
188public:
189 DEFINE_OP_CLASS_ID
190
191 ~AtlasedRectOp() override {
192 fID = -1;
193 }
194
195 const char* name() const override { return "AtlasedRectOp"; }
196
197 int id() const { return fID; }
198
Robert Phillips7c525e62018-06-12 10:11:12 -0400199 static std::unique_ptr<AtlasedRectOp> Make(GrContext* context,
200 GrPaint&& paint,
201 const SkRect& r,
202 int id) {
203 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(context, std::move(paint),
204 r, id).release();
Brian Salomon9a036422017-07-13 17:04:43 -0400205 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
206 }
207
208 // We set the initial color of the NonAARectOp based on the ID.
209 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
210 // pulling from the atlas.
Brian Osmancf860852018-10-31 14:04:39 -0400211 AtlasedRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Osman936fe7d2018-10-30 15:30:35 -0400212 int id)
Brian Osmancf860852018-10-31 14:04:39 -0400213 : INHERITED(helperArgs, SkPMColor4f::FromBytes_RGBA(kColors[id]), r, &kEmptyRect,
214 ClassID())
Brian Salomon9a036422017-07-13 17:04:43 -0400215 , fID(id)
216 , fNext(nullptr) {
217 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400218 }
219
Brian Osmancf860852018-10-31 14:04:39 -0400220 void setColor(const SkPMColor4f& color) { fColor = color; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400221 void setLocalRect(const SkRect& localRect) {
222 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
Brian Salomona33b67c2018-05-17 10:42:14 -0400223 fLocalQuad = GrQuad(localRect);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400224 }
225
226 AtlasedRectOp* next() const { return fNext; }
227 void setNext(AtlasedRectOp* next) {
228 fNext = next;
229 }
230
231private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400232
233 static const int kMaxIDs = 9;
Brian Osman1be2b7c2018-10-29 16:07:15 -0400234 static const GrColor kColors[kMaxIDs];
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400235
236 int fID;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400237 // The Atlased ops have an internal singly-linked list of ops that land in the same opsTask
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400238 AtlasedRectOp* fNext;
239
240 typedef NonAARectOp INHERITED;
241};
242
Brian Salomon9a036422017-07-13 17:04:43 -0400243} // anonymous namespace
244
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400245const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
246 GrColorPackRGBA(255, 0, 0, 255),
247 GrColorPackRGBA(0, 255, 0, 255),
248 GrColorPackRGBA(0, 0, 255, 255),
249 GrColorPackRGBA(0, 255, 255, 255),
250 GrColorPackRGBA(255, 0, 255, 255),
251 GrColorPackRGBA(255, 255, 0, 255),
252 GrColorPackRGBA(0, 0, 0, 255),
253 GrColorPackRGBA(128, 128, 128, 255),
254 GrColorPackRGBA(255, 255, 255, 255)
255};
256
257static const int kDrawnTileSize = 16;
258
259/*
260 * Rather than performing any rect packing, this atlaser just lays out constant-sized
261 * tiles in an Nx1 row
262 */
263static const int kAtlasTileSize = 2;
264
265/*
266 * This class aggregates the op information required for atlasing
267 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400268class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400269public:
Brian Salomon557e8122019-10-24 10:37:08 -0400270 AtlasObject(skiatest::Reporter* reporter) : fDone(false), fReporter(reporter) {}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400271
272 ~AtlasObject() override {
273 SkASSERT(fDone);
274 }
275
276 void markAsDone() {
277 fDone = true;
278 }
279
Greg Danielf41b2bd2019-08-22 16:19:24 -0400280 // Insert the new op in an internal singly-linked list for 'opsTaskID'
281 void addOp(uint32_t opsTaskID, AtlasedRectOp* op) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400282 LinkedListHeader* header = nullptr;
283 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400284 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400285 header = &(fOps[i]);
286 }
287 }
288
289 if (!header) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400290 fOps.push_back({opsTaskID, nullptr});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400291 header = &(fOps[fOps.count()-1]);
292 }
293
294 op->setNext(header->fHead);
295 header->fHead = op;
296 }
297
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500298 int numOps() const { return fOps.count(); }
299
300 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
301 // known until flush time.
Greg Daniel4065d452018-11-16 15:43:41 -0500302 sk_sp<GrTextureProxy> getAtlasProxy(GrProxyProvider* proxyProvider, const GrCaps* caps) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500303 if (fAtlasProxy) {
304 return fAtlasProxy;
305 }
306
Robert Phillips0a15cc62019-07-30 12:49:10 -0400307 const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
308 GrRenderable::kYes);
Greg Daniel4065d452018-11-16 15:43:41 -0500309
Chris Dalton4c458b12018-06-16 17:22:59 -0600310 fAtlasProxy = GrProxyProvider::MakeFullyLazyProxy(
Brian Salomon4eb38b72019-08-05 12:58:39 -0400311 [format](GrResourceProvider* resourceProvider)
Brian Salomonbeb7f522019-08-30 16:19:42 -0400312 -> GrSurfaceProxy::LazyCallbackResult {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500313 GrSurfaceDesc desc;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500314 // TODO: until partial flushes in MDB lands we're stuck having
315 // all 9 atlas draws occur
316 desc.fWidth = 9 /*this->numOps()*/ * kAtlasTileSize;
317 desc.fHeight = kAtlasTileSize;
318 desc.fConfig = kRGBA_8888_GrPixelConfig;
319
Robert Phillipsaee18c92019-09-06 11:48:27 -0400320 return resourceProvider->createTexture(desc, format, GrRenderable::kYes, 1,
Brian Salomona90382f2019-09-17 09:01:56 -0400321 GrMipMapped::kNo, SkBudgeted::kYes,
322 GrProtected::kNo);
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500323 },
Greg Daniel4065d452018-11-16 15:43:41 -0500324 format,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400325 GrRenderable::kYes,
326 1,
Brian Salomone8a766b2019-07-19 14:24:36 -0400327 GrProtected::kNo,
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500328 kBottomLeft_GrSurfaceOrigin,
Chris Dalton4c458b12018-06-16 17:22:59 -0600329 kRGBA_8888_GrPixelConfig,
Brian Salomonbeb7f522019-08-30 16:19:42 -0400330 *proxyProvider->caps(),
331 GrSurfaceProxy::UseAllocator::kNo);
Robert Phillips5f78adf2019-04-22 12:41:39 -0400332
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500333 return fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400334 }
335
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400336 /*
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500337 * This callback creates the atlas and updates the AtlasedRectOps to read from it
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400338 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400339 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400340 const uint32_t* opsTaskIDs,
Chris Daltonc4b47352019-08-23 10:10:36 -0600341 int numOpsTaskIDs) override {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400342 // Until MDB is landed we will most-likely only have one opsTask.
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400343 SkTDArray<LinkedListHeader*> lists;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400344 for (int i = 0; i < numOpsTaskIDs; ++i) {
345 if (LinkedListHeader* list = this->getList(opsTaskIDs[i])) {
Mike Reed5edcd312018-08-08 11:23:41 -0400346 lists.push_back(list);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400347 }
348 }
349
350 if (!lists.count()) {
351 return; // nothing to atlas
352 }
353
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500354 if (!resourceProvider->instatiateProxy(fAtlasProxy.get())) {
355 return;
356 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400357
Robert Phillips3d4cac52019-06-11 08:08:08 -0400358 // At this point 'fAtlasProxy' should be instantiated and have:
359 // 1 ref from the 'fAtlasProxy' sk_sp
360 // 9 refs from the 9 AtlasedRectOps
Robert Phillipse5f73282019-06-18 17:15:04 -0400361 // The backing GrSurface should have only 1 though bc there is only one proxy
Brian Salomon28a8f282019-10-24 20:07:39 -0400362 CheckSingleThreadedProxyRefs(fReporter, fAtlasProxy.get(), 10, 1);
Brian Salomonbf6b9792019-08-21 09:38:10 -0400363 auto rtc = resourceProvider->makeRenderTargetContext(fAtlasProxy, GrColorType::kRGBA_8888,
364 nullptr, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400365
Chris Dalton344e9032017-12-11 15:42:09 -0700366 // clear the atlas
Brian Osman9a9baae2018-11-05 15:06:26 -0500367 rtc->clear(nullptr, SK_PMColor4fTRANSPARENT,
368 GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400369
370 int blocksInAtlas = 0;
371 for (int i = 0; i < lists.count(); ++i) {
372 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
373 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
374 kAtlasTileSize, kAtlasTileSize);
375
376 // For now, we avoid the resource buffer issues and just use clears
377#if 1
Brian Osman9a9baae2018-11-05 15:06:26 -0500378 rtc->clear(&r, op->color(), GrRenderTargetContext::CanClearFullscreen::kNo);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400379#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400380 GrPaint paint;
Brian Osman9a9baae2018-11-05 15:06:26 -0500381 paint.setColor4f(op->color());
Brian Salomon9a036422017-07-13 17:04:43 -0400382 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
383 SkRect::Make(r)));
384 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400385#endif
386 blocksInAtlas++;
387
388 // Set the atlased Op's color to white (so we know we're not using it for
389 // the final draw).
Brian Osmancf860852018-10-31 14:04:39 -0400390 op->setColor(SK_PMColor4fWHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400391
392 // Set the atlased Op's localRect to point to where it landed in the atlas
393 op->setLocalRect(SkRect::Make(r));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400394 }
395
396 // We've updated all these ops and we certainly don't want to process them again
397 this->clearOpsFor(lists[i]);
398 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400399 }
400
401private:
402 typedef struct {
403 uint32_t fID;
404 AtlasedRectOp* fHead;
405 } LinkedListHeader;
406
Greg Danielf41b2bd2019-08-22 16:19:24 -0400407 LinkedListHeader* getList(uint32_t opsTaskID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400408 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400409 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400410 return &(fOps[i]);
411 }
412 }
413 return nullptr;
414 }
415
416 void clearOpsFor(LinkedListHeader* header) {
417 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
418 // forget about them in the laziest way possible.
419 header->fHead = nullptr;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400420 header->fID = 0; // invalid opsTask ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400421 }
422
Greg Danielf41b2bd2019-08-22 16:19:24 -0400423 // Each opsTask containing AtlasedRectOps gets its own internal singly-linked list
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400424 SkTDArray<LinkedListHeader> fOps;
425
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500426 // The fully lazy proxy for the atlas
427 sk_sp<GrTextureProxy> fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400428
429 // Set to true when the testing harness expects this object to be no longer used
430 bool fDone;
Brian Salomon557e8122019-10-24 10:37:08 -0400431
432 skiatest::Reporter* fReporter;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400433};
434
435// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
436static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
Greg Danielc594e622019-10-15 14:01:49 -0400437 sk_sp<GrTextureProxy> atlasProxy,
Brian Salomon078e8fa2019-11-22 04:10:18 +0000438 GrColorType atlasColorType) {
Brian Salomonbf6b9792019-08-21 09:38:10 -0400439 auto rtc = context->priv().makeDeferredRenderTargetContext(SkBackingFit::kApprox,
440 3* kDrawnTileSize,
441 kDrawnTileSize,
442 GrColorType::kRGBA_8888,
443 nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400444
Brian Osman9a9baae2018-11-05 15:06:26 -0500445 rtc->clear(nullptr, { 1, 0, 0, 1 }, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400446
447 for (int i = 0; i < 3; ++i) {
448 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
449
Brian Salomon078e8fa2019-11-22 04:10:18 +0000450 auto fp = GrSimpleTextureEffect::Make(atlasProxy, atlasColorType, SkMatrix::I());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400451 GrPaint paint;
452 paint.addColorFragmentProcessor(std::move(fp));
453 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Robert Phillips7c525e62018-06-12 10:11:12 -0400454 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(context,
455 std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400456
457 AtlasedRectOp* sparePtr = op.get();
458
Greg Danielf41b2bd2019-08-22 16:19:24 -0400459 uint32_t opsTaskID;
Brian Salomon348a0372018-10-31 10:42:18 -0400460 rtc->priv().testingOnly_addDrawOp(GrNoClip(), std::move(op),
Greg Danielf41b2bd2019-08-22 16:19:24 -0400461 [&opsTaskID](GrOp* op, uint32_t id) { opsTaskID = id; });
462 SkASSERT(SK_InvalidUniqueID != opsTaskID);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400463
Greg Danielf41b2bd2019-08-22 16:19:24 -0400464 object->addOp(opsTaskID, sparePtr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400465 }
466
467 return rtc->asTextureProxyRef();
468}
469
470// Enable this if you want to debug the final draws w/o having the atlasCallback create the
471// atlas
472#if 0
473#include "SkGrPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500474#include "include/core/SkImageEncoder.h"
475#include "tools/ToolUtils.h"
Chris Dalton12658942017-10-05 19:45:25 -0600476
477static void save_bm(const SkBitmap& bm, const char name[]) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500478 bool result = ToolUtils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
Chris Dalton12658942017-10-05 19:45:25 -0600479 SkASSERT(result);
480}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400481
482sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
483 SkBitmap bm;
484 bm.allocN32Pixels(18, 2, true);
485 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
486 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
487 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
488 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
489 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
490 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
491 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
492 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
493 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
494
495#if 1
496 save_bm(bm, "atlas-fake.png");
497#endif
498
Brian Osman2b23c4b2018-06-01 12:25:08 -0400499 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400500 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
501
502 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
503 context->textureProvider(),
504 desc, SkBudgeted::kYes,
505 bm.getPixels(), bm.rowBytes());
506
507 return sk_ref_sp(tmp->asTextureProxy());
508}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400509#endif
510
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500511
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400512static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
513 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
514 REPORTER_ASSERT(reporter, expected == readback);
515 if (expected != readback) {
516 SkDebugf("Color mismatch: %x %x\n", expected, readback);
517 }
518}
519
520/*
521 * For the atlasing test we make a DAG that looks like:
522 *
523 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
524 * \ /
525 * \ /
526 * RT4
527 * We then flush RT4 and expect only ops 0-5 to be atlased together.
528 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
529 * R G B C M Y
530 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
531 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500532 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
533 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400534 * R G B C M Y K Grey White
535 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400536DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400537 static const int kNumProxies = 3;
538
539 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500540 auto proxyProvider = context->priv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400541
Brian Salomon557e8122019-10-24 10:37:08 -0400542 AtlasObject object(reporter);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400543
Robert Phillips9da87e02019-02-04 13:26:26 -0500544 context->priv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400545
546 sk_sp<GrTextureProxy> proxies[kNumProxies];
547 for (int i = 0; i < kNumProxies; ++i) {
Brian Salomon078e8fa2019-11-22 04:10:18 +0000548 proxies[i] = make_upstream_image(context, &object, i*3,
549 object.getAtlasProxy(proxyProvider,
550 context->priv().caps()),
551 GrColorType::kRGBA_8888);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400552 }
553
554 static const int kFinalWidth = 6*kDrawnTileSize;
555 static const int kFinalHeight = kDrawnTileSize;
556
Brian Salomonbf6b9792019-08-21 09:38:10 -0400557 auto rtc = context->priv().makeDeferredRenderTargetContext(
558 SkBackingFit::kApprox, kFinalWidth, kFinalHeight, GrColorType::kRGBA_8888, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400559
Brian Osman9a9baae2018-11-05 15:06:26 -0500560 rtc->clear(nullptr, SK_PMColor4fWHITE, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400561
562 // Note that this doesn't include the third texture proxy
563 for (int i = 0; i < kNumProxies-1; ++i) {
564 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
565
566 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
567
568 GrPaint paint;
Brian Salomon078e8fa2019-11-22 04:10:18 +0000569 auto fp = GrSimpleTextureEffect::Make(std::move(proxies[i]), GrColorType::kRGBA_8888, t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400570 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
571 paint.addColorFragmentProcessor(std::move(fp));
572
573 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
574 }
575
Greg Daniele6bfb7d2019-04-17 15:26:11 -0400576 rtc->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400577
578 SkBitmap readBack;
579 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
580
581 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
Brian Salomon1d435302019-07-01 13:05:28 -0400582 readBack.rowBytes(), {0, 0});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400583 SkASSERT(result);
584
Robert Phillips9da87e02019-02-04 13:26:26 -0500585 context->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
Chris Daltonfe199b72017-05-05 11:26:15 -0400586
587 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400588
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400589 int x = kDrawnTileSize/2;
590 test_color(reporter, readBack, x, SK_ColorRED);
591 x += kDrawnTileSize;
592 test_color(reporter, readBack, x, SK_ColorGREEN);
593 x += kDrawnTileSize;
594 test_color(reporter, readBack, x, SK_ColorBLUE);
595 x += kDrawnTileSize;
596 test_color(reporter, readBack, x, SK_ColorCYAN);
597 x += kDrawnTileSize;
598 test_color(reporter, readBack, x, SK_ColorMAGENTA);
599 x += kDrawnTileSize;
600 test_color(reporter, readBack, x, SK_ColorYELLOW);
601}