blob: 9f0e4f0571a1fe212af4bf2a6cb45160668547c4 [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"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040025
Brian Salomon9a036422017-07-13 17:04:43 -040026namespace {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040027// This is a simplified mesh drawing op that can be used in the atlas generation test.
28// Please see AtlasedRectOp below.
Brian Salomon9a036422017-07-13 17:04:43 -040029class NonAARectOp : public GrMeshDrawOp {
30protected:
31 using Helper = GrSimpleMeshDrawOpHelper;
32
Robert Phillipseb35f4d2017-03-21 07:56:47 -040033public:
34 DEFINE_OP_CLASS_ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -040035
36 // This creates an instance of a simple non-AA solid color rect-drawing Op
Robert Phillipsb97da532019-02-12 15:24:12 -050037 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040038 GrPaint&& paint,
39 const SkRect& r) {
40 return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, nullptr, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040041 }
42
43 // This creates an instance of a simple non-AA textured rect-drawing Op
Robert Phillipsb97da532019-02-12 15:24:12 -050044 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040045 GrPaint&& paint,
46 const SkRect& r,
47 const SkRect& local) {
48 return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, &local, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040049 }
50
Brian Osmancf860852018-10-31 14:04:39 -040051 const SkPMColor4f& color() const { return fColor; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -040052
Brian Osmancf860852018-10-31 14:04:39 -040053 NonAARectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Salomon9a036422017-07-13 17:04:43 -040054 const SkRect* localRect, int32_t classID)
55 : INHERITED(classID)
56 , fColor(color)
57 , fHasLocalRect(SkToBool(localRect))
58 , fRect(r)
59 , fHelper(helperArgs, GrAAType::kNone) {
60 if (fHasLocalRect) {
Brian Salomona33b67c2018-05-17 10:42:14 -040061 fLocalQuad = GrQuad(*localRect);
Brian Salomon9a036422017-07-13 17:04:43 -040062 }
63 // Choose some conservative values for aa bloat and zero area.
Greg Daniel5faf4742019-10-01 15:14:44 -040064 this->setBounds(r, HasAABloat::kYes, IsHairline::kYes);
Brian Salomon9a036422017-07-13 17:04:43 -040065 }
66
Robert Phillipsb493eeb2017-09-13 13:10:52 -040067 const char* name() const override { return "NonAARectOp"; }
68
Chris Dalton1706cbf2019-05-21 19:35:29 -060069 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsb493eeb2017-09-13 13:10:52 -040070 fHelper.visitProxies(func);
71 }
72
Brian Salomon9a036422017-07-13 17:04:43 -040073 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
74
Chris Dalton6ce447a2019-06-23 18:07:38 -060075 GrProcessorSet::Analysis finalize(
76 const GrCaps& caps, const GrAppliedClip*, bool hasMixedSampledCoverage,
77 GrClampType clampType) override {
Brian Salomon9a036422017-07-13 17:04:43 -040078 // Set the color to unknown because the subclass may change the color later.
79 GrProcessorAnalysisColor gpColor;
80 gpColor.setToUnknown();
81 // We ignore the clip so pass this rather than the GrAppliedClip param.
82 static GrAppliedClip kNoClip;
Chris Dalton6ce447a2019-06-23 18:07:38 -060083 return fHelper.finalizeProcessors(caps, &kNoClip, hasMixedSampledCoverage, clampType,
84 GrProcessorAnalysisCoverage::kNone, &gpColor);
Brian Salomon9a036422017-07-13 17:04:43 -040085 }
86
Robert Phillipseb35f4d2017-03-21 07:56:47 -040087protected:
Brian Osmancf860852018-10-31 14:04:39 -040088 SkPMColor4f fColor;
89 bool fHasLocalRect;
90 GrQuad fLocalQuad;
91 SkRect fRect;
Robert Phillipseb35f4d2017-03-21 07:56:47 -040092
93private:
Brian Salomon91326c32017-08-09 16:02:19 -040094 void onPrepareDraws(Target* target) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040095 using namespace GrDefaultGeoProcFactory;
96
97 // The vertex attrib order is always pos, color, local coords.
98 static const int kColorOffset = sizeof(SkPoint);
99 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
100
101 sk_sp<GrGeometryProcessor> gp =
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400102 GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(),
103 Color::kPremulGrColorAttribute_Type,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400104 Coverage::kSolid_Type,
105 fHasLocalRect ? LocalCoords::kHasExplicit_Type
106 : LocalCoords::kUnused_Type,
107 SkMatrix::I());
108 if (!gp) {
109 SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n");
110 return;
111 }
112
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500113 size_t vertexStride = gp->vertexStride();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400114
Brian Salomon12d22642019-01-29 14:38:50 -0500115 sk_sp<const GrBuffer> indexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400116 int firstIndex;
117 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
118 if (!indices) {
119 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
120 return;
121 }
122
Brian Salomon12d22642019-01-29 14:38:50 -0500123 sk_sp<const GrBuffer> vertexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400124 int firstVertex;
125 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
126 if (!vertices) {
127 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
128 return;
129 }
130
131 // Setup indices
132 indices[0] = 0;
133 indices[1] = 1;
134 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000135 indices[3] = 2;
136 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400137 indices[5] = 3;
138
139 // Setup positions
140 SkPoint* position = (SkPoint*) vertices;
Brian Salomonec42e152018-05-18 12:52:22 -0400141 SkPointPriv::SetRectTriStrip(position, fRect, vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400142
143 // Setup vertex colors
144 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
145 for (int i = 0; i < 4; ++i) {
Brian Osmancf860852018-10-31 14:04:39 -0400146 *color = fColor.toBytes_RGBA();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400147 color = (GrColor*)((intptr_t)color + vertexStride);
148 }
149
150 // Setup local coords
151 if (fHasLocalRect) {
152 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
153 for (int i = 0; i < 4; i++) {
154 *coords = fLocalQuad.point(i);
155 coords = (SkPoint*)((intptr_t) coords + vertexStride);
156 }
157 }
158
Brian Salomon7eae3e02018-08-07 14:02:38 +0000159 GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
160 mesh->setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo);
161 mesh->setVertexData(vertexBuffer, firstVertex);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400162
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700163 target->recordDraw(std::move(gp), mesh);
164 }
165
166 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
167 fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400168 }
169
Brian Salomon9a036422017-07-13 17:04:43 -0400170 Helper fHelper;
171
172 typedef GrMeshDrawOp INHERITED;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400173};
174
Brian Salomon9a036422017-07-13 17:04:43 -0400175} // anonymous namespace
176
Brian Salomon9a036422017-07-13 17:04:43 -0400177static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
178
179namespace {
180
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400181/*
182 * Atlased ops just draw themselves as textured rects with the texture pixels being
183 * pulled out of the atlas. Their color is based on their ID.
184 */
185class AtlasedRectOp final : public NonAARectOp {
186public:
187 DEFINE_OP_CLASS_ID
188
189 ~AtlasedRectOp() override {
190 fID = -1;
191 }
192
193 const char* name() const override { return "AtlasedRectOp"; }
194
195 int id() const { return fID; }
196
Robert Phillips7c525e62018-06-12 10:11:12 -0400197 static std::unique_ptr<AtlasedRectOp> Make(GrContext* context,
198 GrPaint&& paint,
199 const SkRect& r,
200 int id) {
201 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(context, std::move(paint),
202 r, id).release();
Brian Salomon9a036422017-07-13 17:04:43 -0400203 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
204 }
205
206 // We set the initial color of the NonAARectOp based on the ID.
207 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
208 // pulling from the atlas.
Brian Osmancf860852018-10-31 14:04:39 -0400209 AtlasedRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Osman936fe7d2018-10-30 15:30:35 -0400210 int id)
Brian Osmancf860852018-10-31 14:04:39 -0400211 : INHERITED(helperArgs, SkPMColor4f::FromBytes_RGBA(kColors[id]), r, &kEmptyRect,
212 ClassID())
Brian Salomon9a036422017-07-13 17:04:43 -0400213 , fID(id)
214 , fNext(nullptr) {
215 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400216 }
217
Brian Osmancf860852018-10-31 14:04:39 -0400218 void setColor(const SkPMColor4f& color) { fColor = color; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400219 void setLocalRect(const SkRect& localRect) {
220 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
Brian Salomona33b67c2018-05-17 10:42:14 -0400221 fLocalQuad = GrQuad(localRect);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400222 }
223
224 AtlasedRectOp* next() const { return fNext; }
225 void setNext(AtlasedRectOp* next) {
226 fNext = next;
227 }
228
229private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400230
231 static const int kMaxIDs = 9;
Brian Osman1be2b7c2018-10-29 16:07:15 -0400232 static const GrColor kColors[kMaxIDs];
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400233
234 int fID;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400235 // The Atlased ops have an internal singly-linked list of ops that land in the same opsTask
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400236 AtlasedRectOp* fNext;
237
238 typedef NonAARectOp INHERITED;
239};
240
Brian Salomon9a036422017-07-13 17:04:43 -0400241} // anonymous namespace
242
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400243const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
244 GrColorPackRGBA(255, 0, 0, 255),
245 GrColorPackRGBA(0, 255, 0, 255),
246 GrColorPackRGBA(0, 0, 255, 255),
247 GrColorPackRGBA(0, 255, 255, 255),
248 GrColorPackRGBA(255, 0, 255, 255),
249 GrColorPackRGBA(255, 255, 0, 255),
250 GrColorPackRGBA(0, 0, 0, 255),
251 GrColorPackRGBA(128, 128, 128, 255),
252 GrColorPackRGBA(255, 255, 255, 255)
253};
254
255static const int kDrawnTileSize = 16;
256
257/*
258 * Rather than performing any rect packing, this atlaser just lays out constant-sized
259 * tiles in an Nx1 row
260 */
261static const int kAtlasTileSize = 2;
262
263/*
264 * This class aggregates the op information required for atlasing
265 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400266class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400267public:
268 AtlasObject() : fDone(false) { }
269
270 ~AtlasObject() override {
271 SkASSERT(fDone);
272 }
273
274 void markAsDone() {
275 fDone = true;
276 }
277
Greg Danielf41b2bd2019-08-22 16:19:24 -0400278 // Insert the new op in an internal singly-linked list for 'opsTaskID'
279 void addOp(uint32_t opsTaskID, AtlasedRectOp* op) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400280 LinkedListHeader* header = nullptr;
281 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400282 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400283 header = &(fOps[i]);
284 }
285 }
286
287 if (!header) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400288 fOps.push_back({opsTaskID, nullptr});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400289 header = &(fOps[fOps.count()-1]);
290 }
291
292 op->setNext(header->fHead);
293 header->fHead = op;
294 }
295
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500296 int numOps() const { return fOps.count(); }
297
298 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
299 // known until flush time.
Greg Daniel4065d452018-11-16 15:43:41 -0500300 sk_sp<GrTextureProxy> getAtlasProxy(GrProxyProvider* proxyProvider, const GrCaps* caps) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500301 if (fAtlasProxy) {
302 return fAtlasProxy;
303 }
304
Robert Phillips0a15cc62019-07-30 12:49:10 -0400305 const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
306 GrRenderable::kYes);
Greg Daniel4065d452018-11-16 15:43:41 -0500307
Chris Dalton4c458b12018-06-16 17:22:59 -0600308 fAtlasProxy = GrProxyProvider::MakeFullyLazyProxy(
Brian Salomon4eb38b72019-08-05 12:58:39 -0400309 [format](GrResourceProvider* resourceProvider)
Brian Salomonbeb7f522019-08-30 16:19:42 -0400310 -> GrSurfaceProxy::LazyCallbackResult {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500311 GrSurfaceDesc desc;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500312 // TODO: until partial flushes in MDB lands we're stuck having
313 // all 9 atlas draws occur
314 desc.fWidth = 9 /*this->numOps()*/ * kAtlasTileSize;
315 desc.fHeight = kAtlasTileSize;
316 desc.fConfig = kRGBA_8888_GrPixelConfig;
317
Robert Phillipsaee18c92019-09-06 11:48:27 -0400318 return resourceProvider->createTexture(desc, format, GrRenderable::kYes, 1,
Brian Salomona90382f2019-09-17 09:01:56 -0400319 GrMipMapped::kNo, SkBudgeted::kYes,
320 GrProtected::kNo);
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500321 },
Greg Daniel4065d452018-11-16 15:43:41 -0500322 format,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400323 GrRenderable::kYes,
324 1,
Brian Salomone8a766b2019-07-19 14:24:36 -0400325 GrProtected::kNo,
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500326 kBottomLeft_GrSurfaceOrigin,
Chris Dalton4c458b12018-06-16 17:22:59 -0600327 kRGBA_8888_GrPixelConfig,
Brian Salomonbeb7f522019-08-30 16:19:42 -0400328 *proxyProvider->caps(),
329 GrSurfaceProxy::UseAllocator::kNo);
Robert Phillips5f78adf2019-04-22 12:41:39 -0400330
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500331 return fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400332 }
333
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400334 /*
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500335 * This callback creates the atlas and updates the AtlasedRectOps to read from it
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400336 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400337 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400338 const uint32_t* opsTaskIDs,
Chris Daltonc4b47352019-08-23 10:10:36 -0600339 int numOpsTaskIDs) override {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400340 // Until MDB is landed we will most-likely only have one opsTask.
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400341 SkTDArray<LinkedListHeader*> lists;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400342 for (int i = 0; i < numOpsTaskIDs; ++i) {
343 if (LinkedListHeader* list = this->getList(opsTaskIDs[i])) {
Mike Reed5edcd312018-08-08 11:23:41 -0400344 lists.push_back(list);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400345 }
346 }
347
348 if (!lists.count()) {
349 return; // nothing to atlas
350 }
351
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500352 if (!resourceProvider->instatiateProxy(fAtlasProxy.get())) {
353 return;
354 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400355
Robert Phillips3d4cac52019-06-11 08:08:08 -0400356 // At this point 'fAtlasProxy' should be instantiated and have:
357 // 1 ref from the 'fAtlasProxy' sk_sp
358 // 9 refs from the 9 AtlasedRectOps
Brian Salomona036f0d2019-08-29 11:16:04 -0400359 SkASSERT(10 == fAtlasProxy->refCnt());
Robert Phillipse5f73282019-06-18 17:15:04 -0400360 // The backing GrSurface should have only 1 though bc there is only one proxy
Robert Phillipsb5204762019-06-19 14:12:13 -0400361 SkASSERT(1 == fAtlasProxy->testingOnly_getBackingRefCnt());
Brian Salomonbf6b9792019-08-21 09:38:10 -0400362 auto rtc = resourceProvider->makeRenderTargetContext(fAtlasProxy, GrColorType::kRGBA_8888,
363 nullptr, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400364
Chris Dalton344e9032017-12-11 15:42:09 -0700365 // clear the atlas
Brian Osman9a9baae2018-11-05 15:06:26 -0500366 rtc->clear(nullptr, SK_PMColor4fTRANSPARENT,
367 GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400368
369 int blocksInAtlas = 0;
370 for (int i = 0; i < lists.count(); ++i) {
371 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
372 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
373 kAtlasTileSize, kAtlasTileSize);
374
375 // For now, we avoid the resource buffer issues and just use clears
376#if 1
Brian Osman9a9baae2018-11-05 15:06:26 -0500377 rtc->clear(&r, op->color(), GrRenderTargetContext::CanClearFullscreen::kNo);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400378#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400379 GrPaint paint;
Brian Osman9a9baae2018-11-05 15:06:26 -0500380 paint.setColor4f(op->color());
Brian Salomon9a036422017-07-13 17:04:43 -0400381 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
382 SkRect::Make(r)));
383 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400384#endif
385 blocksInAtlas++;
386
387 // Set the atlased Op's color to white (so we know we're not using it for
388 // the final draw).
Brian Osmancf860852018-10-31 14:04:39 -0400389 op->setColor(SK_PMColor4fWHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400390
391 // Set the atlased Op's localRect to point to where it landed in the atlas
392 op->setLocalRect(SkRect::Make(r));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400393 }
394
395 // We've updated all these ops and we certainly don't want to process them again
396 this->clearOpsFor(lists[i]);
397 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400398 }
399
400private:
401 typedef struct {
402 uint32_t fID;
403 AtlasedRectOp* fHead;
404 } LinkedListHeader;
405
Greg Danielf41b2bd2019-08-22 16:19:24 -0400406 LinkedListHeader* getList(uint32_t opsTaskID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400407 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400408 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400409 return &(fOps[i]);
410 }
411 }
412 return nullptr;
413 }
414
415 void clearOpsFor(LinkedListHeader* header) {
416 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
417 // forget about them in the laziest way possible.
418 header->fHead = nullptr;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400419 header->fID = 0; // invalid opsTask ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400420 }
421
Greg Danielf41b2bd2019-08-22 16:19:24 -0400422 // Each opsTask containing AtlasedRectOps gets its own internal singly-linked list
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400423 SkTDArray<LinkedListHeader> fOps;
424
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500425 // The fully lazy proxy for the atlas
426 sk_sp<GrTextureProxy> fAtlasProxy;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400427
428 // Set to true when the testing harness expects this object to be no longer used
429 bool fDone;
430};
431
432// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
433static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
Greg Danielc594e622019-10-15 14:01:49 -0400434 sk_sp<GrTextureProxy> atlasProxy,
435 GrColorType atlasColorType) {
Brian Salomonbf6b9792019-08-21 09:38:10 -0400436 auto rtc = context->priv().makeDeferredRenderTargetContext(SkBackingFit::kApprox,
437 3* kDrawnTileSize,
438 kDrawnTileSize,
439 GrColorType::kRGBA_8888,
440 nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400441
Brian Osman9a9baae2018-11-05 15:06:26 -0500442 rtc->clear(nullptr, { 1, 0, 0, 1 }, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400443
444 for (int i = 0; i < 3; ++i) {
445 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
446
Greg Danielc594e622019-10-15 14:01:49 -0400447 auto fp = GrSimpleTextureEffect::Make(atlasProxy, atlasColorType, SkMatrix::I());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400448 GrPaint paint;
449 paint.addColorFragmentProcessor(std::move(fp));
450 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Robert Phillips7c525e62018-06-12 10:11:12 -0400451 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(context,
452 std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400453
454 AtlasedRectOp* sparePtr = op.get();
455
Greg Danielf41b2bd2019-08-22 16:19:24 -0400456 uint32_t opsTaskID;
Brian Salomon348a0372018-10-31 10:42:18 -0400457 rtc->priv().testingOnly_addDrawOp(GrNoClip(), std::move(op),
Greg Danielf41b2bd2019-08-22 16:19:24 -0400458 [&opsTaskID](GrOp* op, uint32_t id) { opsTaskID = id; });
459 SkASSERT(SK_InvalidUniqueID != opsTaskID);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400460
Greg Danielf41b2bd2019-08-22 16:19:24 -0400461 object->addOp(opsTaskID, sparePtr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400462 }
463
464 return rtc->asTextureProxyRef();
465}
466
467// Enable this if you want to debug the final draws w/o having the atlasCallback create the
468// atlas
469#if 0
470#include "SkGrPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500471#include "include/core/SkImageEncoder.h"
472#include "tools/ToolUtils.h"
Chris Dalton12658942017-10-05 19:45:25 -0600473
474static void save_bm(const SkBitmap& bm, const char name[]) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500475 bool result = ToolUtils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
Chris Dalton12658942017-10-05 19:45:25 -0600476 SkASSERT(result);
477}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400478
479sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
480 SkBitmap bm;
481 bm.allocN32Pixels(18, 2, true);
482 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
483 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
484 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
485 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
486 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
487 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
488 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
489 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
490 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
491
492#if 1
493 save_bm(bm, "atlas-fake.png");
494#endif
495
Brian Osman2b23c4b2018-06-01 12:25:08 -0400496 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400497 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
498
499 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
500 context->textureProvider(),
501 desc, SkBudgeted::kYes,
502 bm.getPixels(), bm.rowBytes());
503
504 return sk_ref_sp(tmp->asTextureProxy());
505}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400506#endif
507
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500508
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400509static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
510 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
511 REPORTER_ASSERT(reporter, expected == readback);
512 if (expected != readback) {
513 SkDebugf("Color mismatch: %x %x\n", expected, readback);
514 }
515}
516
517/*
518 * For the atlasing test we make a DAG that looks like:
519 *
520 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
521 * \ /
522 * \ /
523 * RT4
524 * We then flush RT4 and expect only ops 0-5 to be atlased together.
525 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
526 * R G B C M Y
527 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
528 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500529 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
530 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400531 * R G B C M Y K Grey White
532 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400533DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400534 static const int kNumProxies = 3;
535
536 GrContext* context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500537 auto proxyProvider = context->priv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400538
Chris Daltonfe199b72017-05-05 11:26:15 -0400539 AtlasObject object;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400540
Robert Phillips9da87e02019-02-04 13:26:26 -0500541 context->priv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400542
543 sk_sp<GrTextureProxy> proxies[kNumProxies];
544 for (int i = 0; i < kNumProxies; ++i) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500545 proxies[i] = make_upstream_image(context, &object, i*3,
Greg Daniel4065d452018-11-16 15:43:41 -0500546 object.getAtlasProxy(proxyProvider,
Greg Danielc594e622019-10-15 14:01:49 -0400547 context->priv().caps()),
548 GrColorType::kRGBA_8888);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400549 }
550
551 static const int kFinalWidth = 6*kDrawnTileSize;
552 static const int kFinalHeight = kDrawnTileSize;
553
Brian Salomonbf6b9792019-08-21 09:38:10 -0400554 auto rtc = context->priv().makeDeferredRenderTargetContext(
555 SkBackingFit::kApprox, kFinalWidth, kFinalHeight, GrColorType::kRGBA_8888, nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400556
Brian Osman9a9baae2018-11-05 15:06:26 -0500557 rtc->clear(nullptr, SK_PMColor4fWHITE, GrRenderTargetContext::CanClearFullscreen::kYes);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400558
559 // Note that this doesn't include the third texture proxy
560 for (int i = 0; i < kNumProxies-1; ++i) {
561 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
562
563 SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
564
565 GrPaint paint;
Greg Danielc594e622019-10-15 14:01:49 -0400566 auto fp = GrSimpleTextureEffect::Make(std::move(proxies[i]), GrColorType::kRGBA_8888, t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400567 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
568 paint.addColorFragmentProcessor(std::move(fp));
569
570 rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
571 }
572
Greg Daniele6bfb7d2019-04-17 15:26:11 -0400573 rtc->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400574
575 SkBitmap readBack;
576 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
577
578 SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
Brian Salomon1d435302019-07-01 13:05:28 -0400579 readBack.rowBytes(), {0, 0});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400580 SkASSERT(result);
581
Robert Phillips9da87e02019-02-04 13:26:26 -0500582 context->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
Chris Daltonfe199b72017-05-05 11:26:15 -0400583
584 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400585
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400586 int x = kDrawnTileSize/2;
587 test_color(reporter, readBack, x, SK_ColorRED);
588 x += kDrawnTileSize;
589 test_color(reporter, readBack, x, SK_ColorGREEN);
590 x += kDrawnTileSize;
591 test_color(reporter, readBack, x, SK_ColorBLUE);
592 x += kDrawnTileSize;
593 test_color(reporter, readBack, x, SK_ColorCYAN);
594 x += kDrawnTileSize;
595 test_color(reporter, readBack, x, SK_ColorMAGENTA);
596 x += kDrawnTileSize;
597 test_color(reporter, readBack, x, SK_ColorYELLOW);
598}