blob: c82f654d08d89d19e6d85328515306ac54ada50e [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"
Brian Salomonb8f098d2020-01-07 11:15:44 -050022#include "src/gpu/effects/GrTextureEffect.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040023#include "src/gpu/geometry/GrQuad.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
Brian Salomon557e8122019-10-24 10:37:08 -040025#include "tests/TestUtils.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040026
Brian Salomon9a036422017-07-13 17:04:43 -040027namespace {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040028// This is a simplified mesh drawing op that can be used in the atlas generation test.
29// Please see AtlasedRectOp below.
Brian Salomon9a036422017-07-13 17:04:43 -040030class NonAARectOp : public GrMeshDrawOp {
31protected:
32 using Helper = GrSimpleMeshDrawOpHelper;
33
Robert Phillipseb35f4d2017-03-21 07:56:47 -040034public:
35 DEFINE_OP_CLASS_ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -040036
37 // This creates an instance of a simple non-AA solid color rect-drawing Op
Robert Phillipsb97da532019-02-12 15:24:12 -050038 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040039 GrPaint&& paint,
40 const SkRect& r) {
41 return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, nullptr, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040042 }
43
44 // This creates an instance of a simple non-AA textured rect-drawing Op
Robert Phillipsb97da532019-02-12 15:24:12 -050045 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040046 GrPaint&& paint,
47 const SkRect& r,
48 const SkRect& local) {
49 return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, &local, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040050 }
51
Brian Osmancf860852018-10-31 14:04:39 -040052 const SkPMColor4f& color() const { return fColor; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -040053
Brian Osmancf860852018-10-31 14:04:39 -040054 NonAARectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Salomon9a036422017-07-13 17:04:43 -040055 const SkRect* localRect, int32_t classID)
56 : INHERITED(classID)
57 , fColor(color)
58 , fHasLocalRect(SkToBool(localRect))
59 , fRect(r)
60 , fHelper(helperArgs, GrAAType::kNone) {
61 if (fHasLocalRect) {
Brian Salomona33b67c2018-05-17 10:42:14 -040062 fLocalQuad = GrQuad(*localRect);
Brian Salomon9a036422017-07-13 17:04:43 -040063 }
64 // Choose some conservative values for aa bloat and zero area.
Greg Daniel5faf4742019-10-01 15:14:44 -040065 this->setBounds(r, HasAABloat::kYes, IsHairline::kYes);
Brian Salomon9a036422017-07-13 17:04:43 -040066 }
67
Robert Phillipsb493eeb2017-09-13 13:10:52 -040068 const char* name() const override { return "NonAARectOp"; }
69
Chris Dalton1706cbf2019-05-21 19:35:29 -060070 void visitProxies(const VisitProxyFunc& func) const override {
Robert 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 {
Robert Phillips3968fcb2019-12-05 16:40:31 -0500169 auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState,
170 fHelper.detachProcessorSet(),
171 fHelper.pipelineFlags());
172
173 flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400174 }
175
Brian Salomon9a036422017-07-13 17:04:43 -0400176 Helper fHelper;
177
178 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400179};
180
Brian Salomon9a036422017-07-13 17:04:43 -0400181} // anonymous namespace
182
Brian Salomon9a036422017-07-13 17:04:43 -0400183static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
184
185namespace {
186
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400187/*
188 * Atlased ops just draw themselves as textured rects with the texture pixels being
189 * pulled out of the atlas. Their color is based on their ID.
190 */
191class AtlasedRectOp final : public NonAARectOp {
192public:
193 DEFINE_OP_CLASS_ID
194
195 ~AtlasedRectOp() override {
196 fID = -1;
197 }
198
199 const char* name() const override { return "AtlasedRectOp"; }
200
201 int id() const { return fID; }
202
Robert Phillips7c525e62018-06-12 10:11:12 -0400203 static std::unique_ptr<AtlasedRectOp> Make(GrContext* context,
204 GrPaint&& paint,
205 const SkRect& r,
206 int id) {
207 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(context, std::move(paint),
208 r, id).release();
Brian Salomon9a036422017-07-13 17:04:43 -0400209 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
210 }
211
212 // We set the initial color of the NonAARectOp based on the ID.
213 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
214 // pulling from the atlas.
Brian Osmancf860852018-10-31 14:04:39 -0400215 AtlasedRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Osman936fe7d2018-10-30 15:30:35 -0400216 int id)
Brian Osmancf860852018-10-31 14:04:39 -0400217 : INHERITED(helperArgs, SkPMColor4f::FromBytes_RGBA(kColors[id]), r, &kEmptyRect,
218 ClassID())
Brian Salomon9a036422017-07-13 17:04:43 -0400219 , fID(id)
220 , fNext(nullptr) {
221 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400222 }
223
Brian Osmancf860852018-10-31 14:04:39 -0400224 void setColor(const SkPMColor4f& color) { fColor = color; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400225 void setLocalRect(const SkRect& localRect) {
226 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
Brian Salomona33b67c2018-05-17 10:42:14 -0400227 fLocalQuad = GrQuad(localRect);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400228 }
229
230 AtlasedRectOp* next() const { return fNext; }
231 void setNext(AtlasedRectOp* next) {
232 fNext = next;
233 }
234
235private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400236
237 static const int kMaxIDs = 9;
Brian Osman1be2b7c2018-10-29 16:07:15 -0400238 static const GrColor kColors[kMaxIDs];
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400239
240 int fID;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400241 // The Atlased ops have an internal singly-linked list of ops that land in the same opsTask
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400242 AtlasedRectOp* fNext;
243
244 typedef NonAARectOp INHERITED;
245};
246
Brian Salomon9a036422017-07-13 17:04:43 -0400247} // anonymous namespace
248
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400249const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
250 GrColorPackRGBA(255, 0, 0, 255),
251 GrColorPackRGBA(0, 255, 0, 255),
252 GrColorPackRGBA(0, 0, 255, 255),
253 GrColorPackRGBA(0, 255, 255, 255),
254 GrColorPackRGBA(255, 0, 255, 255),
255 GrColorPackRGBA(255, 255, 0, 255),
256 GrColorPackRGBA(0, 0, 0, 255),
257 GrColorPackRGBA(128, 128, 128, 255),
258 GrColorPackRGBA(255, 255, 255, 255)
259};
260
261static const int kDrawnTileSize = 16;
262
263/*
264 * Rather than performing any rect packing, this atlaser just lays out constant-sized
265 * tiles in an Nx1 row
266 */
267static const int kAtlasTileSize = 2;
268
269/*
270 * This class aggregates the op information required for atlasing
271 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400272class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400273public:
Brian Salomon557e8122019-10-24 10:37:08 -0400274 AtlasObject(skiatest::Reporter* reporter) : fDone(false), fReporter(reporter) {}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400275
276 ~AtlasObject() override {
277 SkASSERT(fDone);
278 }
279
280 void markAsDone() {
281 fDone = true;
282 }
283
Greg Danielf41b2bd2019-08-22 16:19:24 -0400284 // Insert the new op in an internal singly-linked list for 'opsTaskID'
285 void addOp(uint32_t opsTaskID, AtlasedRectOp* op) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400286 LinkedListHeader* header = nullptr;
287 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400288 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400289 header = &(fOps[i]);
290 }
291 }
292
293 if (!header) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400294 fOps.push_back({opsTaskID, nullptr});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400295 header = &(fOps[fOps.count()-1]);
296 }
297
298 op->setNext(header->fHead);
299 header->fHead = op;
300 }
301
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500302 int numOps() const { return fOps.count(); }
303
304 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
305 // known until flush time.
Greg Daniel4065d452018-11-16 15:43:41 -0500306 sk_sp<GrTextureProxy> getAtlasProxy(GrProxyProvider* proxyProvider, const GrCaps* caps) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500307 if (fAtlasProxy) {
308 return fAtlasProxy;
309 }
310
Robert Phillips0a15cc62019-07-30 12:49:10 -0400311 const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
312 GrRenderable::kYes);
Greg Danielce3ddaa2020-01-22 16:58:15 -0500313 GrSwizzle readSwizzle = caps->getReadSwizzle(format, GrColorType::kRGBA_8888);
Greg Daniel4065d452018-11-16 15:43:41 -0500314
Chris Dalton4c458b12018-06-16 17:22:59 -0600315 fAtlasProxy = GrProxyProvider::MakeFullyLazyProxy(
Brian Salomon4eb38b72019-08-05 12:58:39 -0400316 [format](GrResourceProvider* resourceProvider)
Brian Salomonbeb7f522019-08-30 16:19:42 -0400317 -> GrSurfaceProxy::LazyCallbackResult {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500318 GrSurfaceDesc desc;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500319 // TODO: until partial flushes in MDB lands we're stuck having
320 // all 9 atlas draws occur
321 desc.fWidth = 9 /*this->numOps()*/ * kAtlasTileSize;
322 desc.fHeight = kAtlasTileSize;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500323
Robert Phillipsaee18c92019-09-06 11:48:27 -0400324 return resourceProvider->createTexture(desc, format, GrRenderable::kYes, 1,
Brian Salomona90382f2019-09-17 09:01:56 -0400325 GrMipMapped::kNo, SkBudgeted::kYes,
326 GrProtected::kNo);
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500327 },
Greg Daniel4065d452018-11-16 15:43:41 -0500328 format,
Greg Danielce3ddaa2020-01-22 16:58:15 -0500329 readSwizzle,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400330 GrRenderable::kYes,
331 1,
Brian Salomone8a766b2019-07-19 14:24:36 -0400332 GrProtected::kNo,
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500333 kBottomLeft_GrSurfaceOrigin,
Brian Salomonbeb7f522019-08-30 16:19:42 -0400334 *proxyProvider->caps(),
335 GrSurfaceProxy::UseAllocator::kNo);
Robert Phillips5f78adf2019-04-22 12:41:39 -0400336
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500337 return fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400338 }
339
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400340 /*
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500341 * This callback creates the atlas and updates the AtlasedRectOps to read from it
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400342 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400343 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400344 const uint32_t* opsTaskIDs,
Chris Daltonc4b47352019-08-23 10:10:36 -0600345 int numOpsTaskIDs) override {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400346 // Until MDB is landed we will most-likely only have one opsTask.
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400347 SkTDArray<LinkedListHeader*> lists;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400348 for (int i = 0; i < numOpsTaskIDs; ++i) {
349 if (LinkedListHeader* list = this->getList(opsTaskIDs[i])) {
Mike Reed5edcd312018-08-08 11:23:41 -0400350 lists.push_back(list);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400351 }
352 }
353
354 if (!lists.count()) {
355 return; // nothing to atlas
356 }
357
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500358 if (!resourceProvider->instatiateProxy(fAtlasProxy.get())) {
359 return;
360 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400361
Robert Phillips3d4cac52019-06-11 08:08:08 -0400362 // At this point 'fAtlasProxy' should be instantiated and have:
363 // 1 ref from the 'fAtlasProxy' sk_sp
364 // 9 refs from the 9 AtlasedRectOps
Robert Phillipse5f73282019-06-18 17:15:04 -0400365 // The backing GrSurface should have only 1 though bc there is only one proxy
Brian Salomon28a8f282019-10-24 20:07:39 -0400366 CheckSingleThreadedProxyRefs(fReporter, fAtlasProxy.get(), 10, 1);
Brian Salomonbf6b9792019-08-21 09:38:10 -0400367 auto rtc = resourceProvider->makeRenderTargetContext(fAtlasProxy, GrColorType::kRGBA_8888,
368 nullptr, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400369
Chris Dalton344e9032017-12-11 15:42:09 -0700370 // clear the atlas
Brian Osman9a9baae2018-11-05 15:06:26 -0500371 rtc->clear(nullptr, SK_PMColor4fTRANSPARENT,
372 GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400373
374 int blocksInAtlas = 0;
375 for (int i = 0; i < lists.count(); ++i) {
376 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
377 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
378 kAtlasTileSize, kAtlasTileSize);
379
380 // For now, we avoid the resource buffer issues and just use clears
381#if 1
Brian Osman9a9baae2018-11-05 15:06:26 -0500382 rtc->clear(&r, op->color(), GrRenderTargetContext::CanClearFullscreen::kNo);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400383#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400384 GrPaint paint;
Brian Osman9a9baae2018-11-05 15:06:26 -0500385 paint.setColor4f(op->color());
Brian Salomon9a036422017-07-13 17:04:43 -0400386 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
387 SkRect::Make(r)));
388 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400389#endif
390 blocksInAtlas++;
391
392 // Set the atlased Op's color to white (so we know we're not using it for
393 // the final draw).
Brian Osmancf860852018-10-31 14:04:39 -0400394 op->setColor(SK_PMColor4fWHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400395
396 // Set the atlased Op's localRect to point to where it landed in the atlas
397 op->setLocalRect(SkRect::Make(r));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400398 }
399
400 // We've updated all these ops and we certainly don't want to process them again
401 this->clearOpsFor(lists[i]);
402 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400403 }
404
405private:
406 typedef struct {
407 uint32_t fID;
408 AtlasedRectOp* fHead;
409 } LinkedListHeader;
410
Greg Danielf41b2bd2019-08-22 16:19:24 -0400411 LinkedListHeader* getList(uint32_t opsTaskID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400412 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400413 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400414 return &(fOps[i]);
415 }
416 }
417 return nullptr;
418 }
419
420 void clearOpsFor(LinkedListHeader* header) {
421 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
422 // forget about them in the laziest way possible.
423 header->fHead = nullptr;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400424 header->fID = 0; // invalid opsTask ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400425 }
426
Greg Danielf41b2bd2019-08-22 16:19:24 -0400427 // Each opsTask containing AtlasedRectOps gets its own internal singly-linked list
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400428 SkTDArray<LinkedListHeader> fOps;
429
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500430 // The fully lazy proxy for the atlas
431 sk_sp<GrTextureProxy> fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400432
433 // Set to true when the testing harness expects this object to be no longer used
434 bool fDone;
Brian Salomon557e8122019-10-24 10:37:08 -0400435
436 skiatest::Reporter* fReporter;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400437};
438
439// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
440static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
Greg Danielc594e622019-10-15 14:01:49 -0400441 sk_sp<GrTextureProxy> atlasProxy,
Brian Salomonfc118442019-11-22 19:09:27 -0500442 SkAlphaType atlasAlphaType) {
Greg Daniele20fcad2020-01-08 11:52:34 -0500443 auto rtc = GrRenderTargetContext::Make(
444 context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox,
445 {3 * kDrawnTileSize, kDrawnTileSize});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400446
Brian Osman9a9baae2018-11-05 15:06:26 -0500447 rtc->clear(nullptr, { 1, 0, 0, 1 }, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400448
449 for (int i = 0; i < 3; ++i) {
450 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
451
Brian Salomonbfb72112020-01-13 10:51:50 -0500452 auto fp = GrTextureEffect::Make(atlasProxy, atlasAlphaType);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400453 GrPaint paint;
454 paint.addColorFragmentProcessor(std::move(fp));
455 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Robert Phillips7c525e62018-06-12 10:11:12 -0400456 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(context,
457 std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400458
459 AtlasedRectOp* sparePtr = op.get();
460
Greg Danielf41b2bd2019-08-22 16:19:24 -0400461 uint32_t opsTaskID;
Brian Salomon348a0372018-10-31 10:42:18 -0400462 rtc->priv().testingOnly_addDrawOp(GrNoClip(), std::move(op),
Greg Danielf41b2bd2019-08-22 16:19:24 -0400463 [&opsTaskID](GrOp* op, uint32_t id) { opsTaskID = id; });
464 SkASSERT(SK_InvalidUniqueID != opsTaskID);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400465
Greg Danielf41b2bd2019-08-22 16:19:24 -0400466 object->addOp(opsTaskID, sparePtr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400467 }
468
469 return rtc->asTextureProxyRef();
470}
471
472// Enable this if you want to debug the final draws w/o having the atlasCallback create the
473// atlas
474#if 0
475#include "SkGrPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500476#include "include/core/SkImageEncoder.h"
477#include "tools/ToolUtils.h"
Chris Dalton12658942017-10-05 19:45:25 -0600478
479static void save_bm(const SkBitmap& bm, const char name[]) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500480 bool result = ToolUtils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
Chris Dalton12658942017-10-05 19:45:25 -0600481 SkASSERT(result);
482}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400483
484sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
485 SkBitmap bm;
486 bm.allocN32Pixels(18, 2, true);
487 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
488 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
489 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
490 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
491 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
492 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
493 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
494 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
495 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
496
497#if 1
498 save_bm(bm, "atlas-fake.png");
499#endif
500
Brian Osman2b23c4b2018-06-01 12:25:08 -0400501 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400502 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
503
504 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
505 context->textureProvider(),
506 desc, SkBudgeted::kYes,
507 bm.getPixels(), bm.rowBytes());
508
509 return sk_ref_sp(tmp->asTextureProxy());
510}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400511#endif
512
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500513
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400514static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
515 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
516 REPORTER_ASSERT(reporter, expected == readback);
517 if (expected != readback) {
518 SkDebugf("Color mismatch: %x %x\n", expected, readback);
519 }
520}
521
522/*
523 * For the atlasing test we make a DAG that looks like:
524 *
525 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
526 * \ /
527 * \ /
528 * RT4
529 * We then flush RT4 and expect only ops 0-5 to be atlased together.
530 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
531 * R G B C M Y
532 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
533 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500534 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
535 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400536 * R G B C M Y K Grey White
537 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400538DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400539 static const int kNumProxies = 3;
540
541 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500542 auto proxyProvider = context->priv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400543
Brian Salomon557e8122019-10-24 10:37:08 -0400544 AtlasObject object(reporter);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400545
Robert Phillips9da87e02019-02-04 13:26:26 -0500546 context->priv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400547
548 sk_sp<GrTextureProxy> proxies[kNumProxies];
549 for (int i = 0; i < kNumProxies; ++i) {
Brian Salomonfc118442019-11-22 19:09:27 -0500550 proxies[i] = make_upstream_image(
551 context, &object, i*3,
552 object.getAtlasProxy(proxyProvider, context->priv().caps()), kPremul_SkAlphaType);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400553 }
554
555 static const int kFinalWidth = 6*kDrawnTileSize;
556 static const int kFinalHeight = kDrawnTileSize;
557
Greg Daniele20fcad2020-01-08 11:52:34 -0500558 auto rtc = GrRenderTargetContext::Make(
559 context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox,
560 {kFinalWidth, kFinalHeight});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400561
Brian Osman9a9baae2018-11-05 15:06:26 -0500562 rtc->clear(nullptr, SK_PMColor4fWHITE, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400563
564 // Note that this doesn't include the third texture proxy
565 for (int i = 0; i < kNumProxies-1; ++i) {
566 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
567
568 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
569
570 GrPaint paint;
Brian Salomonb8f098d2020-01-07 11:15:44 -0500571 auto fp = GrTextureEffect::Make(std::move(proxies[i]), kPremul_SkAlphaType, t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400572 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
573 paint.addColorFragmentProcessor(std::move(fp));
574
575 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
576 }
577
Greg Daniele6bfb7d2019-04-17 15:26:11 -0400578 rtc->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400579
580 SkBitmap readBack;
581 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
582
583 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
Brian Salomon1d435302019-07-01 13:05:28 -0400584 readBack.rowBytes(), {0, 0});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400585 SkASSERT(result);
586
Robert Phillips9da87e02019-02-04 13:26:26 -0500587 context->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
Chris Daltonfe199b72017-05-05 11:26:15 -0400588
589 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400590
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400591 int x = kDrawnTileSize/2;
592 test_color(reporter, readBack, x, SK_ColorRED);
593 x += kDrawnTileSize;
594 test_color(reporter, readBack, x, SK_ColorGREEN);
595 x += kDrawnTileSize;
596 test_color(reporter, readBack, x, SK_ColorBLUE);
597 x += kDrawnTileSize;
598 test_color(reporter, readBack, x, SK_ColorCYAN);
599 x += kDrawnTileSize;
600 test_color(reporter, readBack, x, SK_ColorMAGENTA);
601 x += kDrawnTileSize;
602 test_color(reporter, readBack, x, SK_ColorYELLOW);
603}