blob: 6dd0fad92cd0f6597ffecd771988a8025dbc4301 [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/GrRenderTargetContextPriv.h"
21#include "src/gpu/GrResourceProvider.h"
Greg Daniel456f9b52020-03-05 19:14:18 +000022#include "src/gpu/GrTexture.h"
Brian Salomonb8f098d2020-01-07 11:15:44 -050023#include "src/gpu/effects/GrTextureEffect.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040024#include "src/gpu/geometry/GrQuad.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
Brian Salomon557e8122019-10-24 10:37:08 -040026#include "tests/TestUtils.h"
Robert Phillipseb35f4d2017-03-21 07:56:47 -040027
Brian Salomon9a036422017-07-13 17:04:43 -040028namespace {
Robert Phillipseb35f4d2017-03-21 07:56:47 -040029// This is a simplified mesh drawing op that can be used in the atlas generation test.
30// Please see AtlasedRectOp below.
Brian Salomon9a036422017-07-13 17:04:43 -040031class NonAARectOp : public GrMeshDrawOp {
32protected:
33 using Helper = GrSimpleMeshDrawOpHelper;
34
Robert Phillipseb35f4d2017-03-21 07:56:47 -040035public:
36 DEFINE_OP_CLASS_ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -040037
38 // This creates an instance of a simple non-AA solid color rect-drawing Op
Robert Phillipsb97da532019-02-12 15:24:12 -050039 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040040 GrPaint&& paint,
41 const SkRect& r) {
42 return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, nullptr, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040043 }
44
45 // This creates an instance of a simple non-AA textured rect-drawing Op
Robert Phillipsb97da532019-02-12 15:24:12 -050046 static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
Robert Phillips7c525e62018-06-12 10:11:12 -040047 GrPaint&& paint,
48 const SkRect& r,
49 const SkRect& local) {
50 return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, &local, ClassID());
Robert Phillipseb35f4d2017-03-21 07:56:47 -040051 }
52
Brian Osmancf860852018-10-31 14:04:39 -040053 const SkPMColor4f& color() const { return fColor; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -040054
Brian Osmancf860852018-10-31 14:04:39 -040055 NonAARectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Salomon9a036422017-07-13 17:04:43 -040056 const SkRect* localRect, int32_t classID)
57 : INHERITED(classID)
58 , fColor(color)
59 , fHasLocalRect(SkToBool(localRect))
60 , fRect(r)
61 , fHelper(helperArgs, GrAAType::kNone) {
62 if (fHasLocalRect) {
Brian Salomona33b67c2018-05-17 10:42:14 -040063 fLocalQuad = GrQuad(*localRect);
Brian Salomon9a036422017-07-13 17:04:43 -040064 }
65 // Choose some conservative values for aa bloat and zero area.
Greg Daniel5faf4742019-10-01 15:14:44 -040066 this->setBounds(r, HasAABloat::kYes, IsHairline::kYes);
Brian Salomon9a036422017-07-13 17:04:43 -040067 }
68
Robert Phillipsb493eeb2017-09-13 13:10:52 -040069 const char* name() const override { return "NonAARectOp"; }
70
Chris Dalton1706cbf2019-05-21 19:35:29 -060071 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillipsd2f18732020-03-04 16:12:08 -050072 if (fProgramInfo) {
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,
Brian Salomon8afde5f2020-04-01 16:22:00 -0400104 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,
107 GrXferBarrierFlags renderPassXferBarriers) override {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400108 using namespace GrDefaultGeoProcFactory;
109
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500110 GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Make(
Robert Phillipsd2f18732020-03-04 16:12:08 -0500111 arena,
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400112 Color::kPremulGrColorAttribute_Type,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400113 Coverage::kSolid_Type,
114 fHasLocalRect ? LocalCoords::kHasExplicit_Type
115 : LocalCoords::kUnused_Type,
116 SkMatrix::I());
117 if (!gp) {
Robert Phillipsd2f18732020-03-04 16:12:08 -0500118 SkDebugf("Couldn't create GrGeometryProcessor\n");
Robert Phillips4133dc42020-03-11 15:55:55 -0400119 return;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400120 }
121
Brian Salomon8afde5f2020-04-01 16:22:00 -0400122 fProgramInfo = fHelper.createProgramInfo(caps, arena, writeView, std::move(appliedClip),
Greg Danield358cbe2020-09-11 09:33:54 -0400123 dstProxyView, gp, GrPrimitiveType::kTriangles,
124 renderPassXferBarriers);
Robert Phillipsd2f18732020-03-04 16:12:08 -0500125 }
126
Robert Phillipsd2f18732020-03-04 16:12:08 -0500127 void onPrepareDraws(Target* target) override {
128
129 // The vertex attrib order is always pos, color, local coords.
130 static const int kColorOffset = sizeof(SkPoint);
131 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
132
133 if (!fProgramInfo) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400134 this->createProgramInfo(target);
Robert Phillipsd2f18732020-03-04 16:12:08 -0500135 if (!fProgramInfo) {
136 return;
137 }
138 }
139
140 size_t vertexStride = fProgramInfo->primProc().vertexStride();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400141
Brian Salomon12d22642019-01-29 14:38:50 -0500142 sk_sp<const GrBuffer> indexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400143 int firstIndex;
144 uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
145 if (!indices) {
146 SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
147 return;
148 }
149
Brian Salomon12d22642019-01-29 14:38:50 -0500150 sk_sp<const GrBuffer> vertexBuffer;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400151 int firstVertex;
152 void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
153 if (!vertices) {
154 SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
155 return;
156 }
157
158 // Setup indices
159 indices[0] = 0;
160 indices[1] = 1;
161 indices[2] = 2;
Brian Salomon57caa662017-10-18 12:21:05 +0000162 indices[3] = 2;
163 indices[4] = 1;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400164 indices[5] = 3;
165
166 // Setup positions
167 SkPoint* position = (SkPoint*) vertices;
Brian Salomonec42e152018-05-18 12:52:22 -0400168 SkPointPriv::SetRectTriStrip(position, fRect, vertexStride);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400169
170 // Setup vertex colors
171 GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
172 for (int i = 0; i < 4; ++i) {
Brian Osmancf860852018-10-31 14:04:39 -0400173 *color = fColor.toBytes_RGBA();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400174 color = (GrColor*)((intptr_t)color + vertexStride);
175 }
176
177 // Setup local coords
178 if (fHasLocalRect) {
179 SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
180 for (int i = 0; i < 4; i++) {
181 *coords = fLocalQuad.point(i);
182 coords = (SkPoint*)((intptr_t) coords + vertexStride);
183 }
184 }
185
Robert Phillipsd2f18732020-03-04 16:12:08 -0500186 fMesh = target->allocMesh();
Chris Dalton37c7bdd2020-03-13 09:21:12 -0600187 fMesh->setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo, vertexBuffer,
188 firstVertex);
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700189 }
190
191 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Robert Phillipsd2f18732020-03-04 16:12:08 -0500192 if (!fProgramInfo || !fMesh) {
193 return;
194 }
Robert Phillips3968fcb2019-12-05 16:40:31 -0500195
Chris Dalton765ed362020-03-16 17:34:44 -0600196 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
197 flushState->bindTextures(fProgramInfo->primProc(), nullptr, fProgramInfo->pipeline());
198 flushState->drawMesh(*fMesh);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400199 }
200
Robert Phillipsd2f18732020-03-04 16:12:08 -0500201 Helper fHelper;
Chris Daltoneb694b72020-03-16 09:25:50 -0600202 GrSimpleMesh* fMesh = nullptr;
Robert Phillipsd2f18732020-03-04 16:12:08 -0500203 GrProgramInfo* fProgramInfo = nullptr;
Brian Salomon9a036422017-07-13 17:04:43 -0400204
John Stiles7571f9e2020-09-02 22:42:33 -0400205 using INHERITED = GrMeshDrawOp;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400206};
207
Brian Salomon9a036422017-07-13 17:04:43 -0400208} // anonymous namespace
209
Brian Salomon9a036422017-07-13 17:04:43 -0400210static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
211
212namespace {
213
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400214/*
215 * Atlased ops just draw themselves as textured rects with the texture pixels being
216 * pulled out of the atlas. Their color is based on their ID.
217 */
218class AtlasedRectOp final : public NonAARectOp {
219public:
220 DEFINE_OP_CLASS_ID
221
222 ~AtlasedRectOp() override {
223 fID = -1;
224 }
225
226 const char* name() const override { return "AtlasedRectOp"; }
227
228 int id() const { return fID; }
229
Robert Phillips58adb342020-07-23 09:41:57 -0400230 static std::unique_ptr<AtlasedRectOp> Make(GrRecordingContext* rContext,
Robert Phillips7c525e62018-06-12 10:11:12 -0400231 GrPaint&& paint,
232 const SkRect& r,
233 int id) {
Robert Phillips58adb342020-07-23 09:41:57 -0400234 GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(rContext, std::move(paint),
Robert Phillips7c525e62018-06-12 10:11:12 -0400235 r, id).release();
Brian Salomon9a036422017-07-13 17:04:43 -0400236 return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
237 }
238
239 // We set the initial color of the NonAARectOp based on the ID.
240 // Note that we force creation of a NonAARectOp that has local coords in anticipation of
241 // pulling from the atlas.
Brian Osmancf860852018-10-31 14:04:39 -0400242 AtlasedRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r,
Brian Osman936fe7d2018-10-30 15:30:35 -0400243 int id)
Brian Osmancf860852018-10-31 14:04:39 -0400244 : INHERITED(helperArgs, SkPMColor4f::FromBytes_RGBA(kColors[id]), r, &kEmptyRect,
245 ClassID())
Brian Salomon9a036422017-07-13 17:04:43 -0400246 , fID(id)
247 , fNext(nullptr) {
248 SkASSERT(fID < kMaxIDs);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400249 }
250
Brian Osmancf860852018-10-31 14:04:39 -0400251 void setColor(const SkPMColor4f& color) { fColor = color; }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400252 void setLocalRect(const SkRect& localRect) {
253 SkASSERT(fHasLocalRect); // This should've been created to anticipate this
Brian Salomona33b67c2018-05-17 10:42:14 -0400254 fLocalQuad = GrQuad(localRect);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400255 }
256
257 AtlasedRectOp* next() const { return fNext; }
258 void setNext(AtlasedRectOp* next) {
259 fNext = next;
260 }
261
262private:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400263
264 static const int kMaxIDs = 9;
Brian Osman1be2b7c2018-10-29 16:07:15 -0400265 static const GrColor kColors[kMaxIDs];
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400266
267 int fID;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400268 // The Atlased ops have an internal singly-linked list of ops that land in the same opsTask
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400269 AtlasedRectOp* fNext;
270
John Stiles7571f9e2020-09-02 22:42:33 -0400271 using INHERITED = NonAARectOp;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400272};
273
Brian Salomon9a036422017-07-13 17:04:43 -0400274} // anonymous namespace
275
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400276const GrColor AtlasedRectOp::kColors[kMaxIDs] = {
277 GrColorPackRGBA(255, 0, 0, 255),
278 GrColorPackRGBA(0, 255, 0, 255),
279 GrColorPackRGBA(0, 0, 255, 255),
280 GrColorPackRGBA(0, 255, 255, 255),
281 GrColorPackRGBA(255, 0, 255, 255),
282 GrColorPackRGBA(255, 255, 0, 255),
283 GrColorPackRGBA(0, 0, 0, 255),
284 GrColorPackRGBA(128, 128, 128, 255),
285 GrColorPackRGBA(255, 255, 255, 255)
286};
287
288static const int kDrawnTileSize = 16;
289
290/*
291 * Rather than performing any rect packing, this atlaser just lays out constant-sized
292 * tiles in an Nx1 row
293 */
294static const int kAtlasTileSize = 2;
295
296/*
297 * This class aggregates the op information required for atlasing
298 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400299class AtlasObject final : public GrOnFlushCallbackObject {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400300public:
Brian Salomon557e8122019-10-24 10:37:08 -0400301 AtlasObject(skiatest::Reporter* reporter) : fDone(false), fReporter(reporter) {}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400302
303 ~AtlasObject() override {
304 SkASSERT(fDone);
305 }
306
307 void markAsDone() {
308 fDone = true;
309 }
310
Greg Danielf41b2bd2019-08-22 16:19:24 -0400311 // Insert the new op in an internal singly-linked list for 'opsTaskID'
312 void addOp(uint32_t opsTaskID, AtlasedRectOp* op) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400313 LinkedListHeader* header = nullptr;
314 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400315 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400316 header = &(fOps[i]);
317 }
318 }
319
320 if (!header) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400321 fOps.push_back({opsTaskID, nullptr});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400322 header = &(fOps[fOps.count()-1]);
323 }
324
325 op->setNext(header->fHead);
326 header->fHead = op;
327 }
328
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500329 int numOps() const { return fOps.count(); }
330
331 // Get the fully lazy proxy that is backing the atlas. Its actual width isn't
332 // known until flush time.
Greg Danield11ae2e2020-02-10 16:36:07 -0500333 GrSurfaceProxyView getAtlasView(GrProxyProvider* proxyProvider, const GrCaps* caps) {
334 if (fAtlasView) {
335 return fAtlasView;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500336 }
337
Robert Phillips0a15cc62019-07-30 12:49:10 -0400338 const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
339 GrRenderable::kYes);
Greg Danield11ae2e2020-02-10 16:36:07 -0500340 auto proxy = GrProxyProvider::MakeFullyLazyProxy(
Brian Salomon63410e92020-03-23 18:32:50 -0400341 [](GrResourceProvider* resourceProvider,
342 const GrSurfaceProxy::LazySurfaceDesc& desc)
Brian Salomonbeb7f522019-08-30 16:19:42 -0400343 -> GrSurfaceProxy::LazyCallbackResult {
Brian Salomon63410e92020-03-23 18:32:50 -0400344 SkASSERT(desc.fDimensions.width() < 0 && desc.fDimensions.height() < 0);
Brian Salomona56a7462020-02-07 14:17:25 -0500345 SkISize dims;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500346 // TODO: until partial flushes in MDB lands we're stuck having
347 // all 9 atlas draws occur
Brian Salomona56a7462020-02-07 14:17:25 -0500348 dims.fWidth = 9 /*this->numOps()*/ * kAtlasTileSize;
349 dims.fHeight = kAtlasTileSize;
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500350
Brian Salomon63410e92020-03-23 18:32:50 -0400351 return resourceProvider->createTexture(dims, desc.fFormat, desc.fRenderable,
Brian Salomon40a40622020-07-21 10:32:07 -0400352 desc.fSampleCnt, desc.fMipmapped,
Brian Salomon63410e92020-03-23 18:32:50 -0400353 desc.fBudgeted, desc.fProtected);
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500354 },
Greg Daniel4065d452018-11-16 15:43:41 -0500355 format,
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400356 GrRenderable::kYes,
357 1,
Brian Salomone8a766b2019-07-19 14:24:36 -0400358 GrProtected::kNo,
Brian Salomonbeb7f522019-08-30 16:19:42 -0400359 *proxyProvider->caps(),
360 GrSurfaceProxy::UseAllocator::kNo);
Robert Phillips5f78adf2019-04-22 12:41:39 -0400361
Brian Salomondf1bd6d2020-03-26 20:37:01 -0400362 GrSwizzle readSwizzle = caps->getReadSwizzle(format, GrColorType::kRGBA_8888);
Greg Danield11ae2e2020-02-10 16:36:07 -0500363 fAtlasView = {std::move(proxy), kBottomLeft_GrSurfaceOrigin, readSwizzle};
364 return fAtlasView;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400365 }
366
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400367 /*
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500368 * This callback creates the atlas and updates the AtlasedRectOps to read from it
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400369 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400370 void preFlush(GrOnFlushResourceProvider* resourceProvider,
Greg Danielf41b2bd2019-08-22 16:19:24 -0400371 const uint32_t* opsTaskIDs,
Chris Daltonc4b47352019-08-23 10:10:36 -0600372 int numOpsTaskIDs) override {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400373 // Until MDB is landed we will most-likely only have one opsTask.
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400374 SkTDArray<LinkedListHeader*> lists;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400375 for (int i = 0; i < numOpsTaskIDs; ++i) {
376 if (LinkedListHeader* list = this->getList(opsTaskIDs[i])) {
Mike Reed5edcd312018-08-08 11:23:41 -0400377 lists.push_back(list);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400378 }
379 }
380
381 if (!lists.count()) {
382 return; // nothing to atlas
383 }
384
Greg Danield11ae2e2020-02-10 16:36:07 -0500385 if (!resourceProvider->instatiateProxy(fAtlasView.proxy())) {
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500386 return;
387 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400388
Greg Danield11ae2e2020-02-10 16:36:07 -0500389 // At this point 'fAtlasView' proxy should be instantiated and have:
390 // 1 ref from the 'fAtlasView' proxy sk_sp
Robert Phillips3d4cac52019-06-11 08:08:08 -0400391 // 9 refs from the 9 AtlasedRectOps
Robert Phillipse5f73282019-06-18 17:15:04 -0400392 // The backing GrSurface should have only 1 though bc there is only one proxy
Greg Danield11ae2e2020-02-10 16:36:07 -0500393 CheckSingleThreadedProxyRefs(fReporter, fAtlasView.proxy(), 10, 1);
394 auto rtc = resourceProvider->makeRenderTargetContext(
395 fAtlasView.refProxy(), fAtlasView.origin(), GrColorType::kRGBA_8888, nullptr,
396 nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400397
Chris Dalton344e9032017-12-11 15:42:09 -0700398 // clear the atlas
Michael Ludwig81d41722020-05-26 16:57:38 -0400399 rtc->clear(SK_PMColor4fTRANSPARENT);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400400
401 int blocksInAtlas = 0;
402 for (int i = 0; i < lists.count(); ++i) {
403 for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
404 SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
405 kAtlasTileSize, kAtlasTileSize);
406
407 // For now, we avoid the resource buffer issues and just use clears
408#if 1
Michael Ludwig81d41722020-05-26 16:57:38 -0400409 rtc->clear(r, op->color());
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400410#else
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400411 GrPaint paint;
Brian Osman9a9baae2018-11-05 15:06:26 -0500412 paint.setColor4f(op->color());
Brian Salomon9a036422017-07-13 17:04:43 -0400413 std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
414 SkRect::Make(r)));
415 rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400416#endif
417 blocksInAtlas++;
418
419 // Set the atlased Op's color to white (so we know we're not using it for
420 // the final draw).
Brian Osmancf860852018-10-31 14:04:39 -0400421 op->setColor(SK_PMColor4fWHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400422
423 // Set the atlased Op's localRect to point to where it landed in the atlas
424 op->setLocalRect(SkRect::Make(r));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400425 }
426
427 // We've updated all these ops and we certainly don't want to process them again
428 this->clearOpsFor(lists[i]);
429 }
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400430 }
431
432private:
433 typedef struct {
434 uint32_t fID;
435 AtlasedRectOp* fHead;
436 } LinkedListHeader;
437
Greg Danielf41b2bd2019-08-22 16:19:24 -0400438 LinkedListHeader* getList(uint32_t opsTaskID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400439 for (int i = 0; i < fOps.count(); ++i) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400440 if (opsTaskID == fOps[i].fID) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400441 return &(fOps[i]);
442 }
443 }
444 return nullptr;
445 }
446
447 void clearOpsFor(LinkedListHeader* header) {
448 // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
449 // forget about them in the laziest way possible.
450 header->fHead = nullptr;
Greg Danielf41b2bd2019-08-22 16:19:24 -0400451 header->fID = 0; // invalid opsTask ID
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400452 }
453
Greg Danielf41b2bd2019-08-22 16:19:24 -0400454 // Each opsTask containing AtlasedRectOps gets its own internal singly-linked list
Greg Danield11ae2e2020-02-10 16:36:07 -0500455 SkTDArray<LinkedListHeader> fOps;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400456
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500457 // The fully lazy proxy for the atlas
Greg Danield11ae2e2020-02-10 16:36:07 -0500458 GrSurfaceProxyView fAtlasView;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400459
460 // Set to true when the testing harness expects this object to be no longer used
Greg Danield11ae2e2020-02-10 16:36:07 -0500461 bool fDone;
Brian Salomon557e8122019-10-24 10:37:08 -0400462
Greg Danield11ae2e2020-02-10 16:36:07 -0500463 skiatest::Reporter* fReporter;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400464};
465
466// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
Robert Phillips58adb342020-07-23 09:41:57 -0400467static GrSurfaceProxyView make_upstream_image(GrRecordingContext* rContext,
468 AtlasObject* object,
469 int start,
Greg Danield11ae2e2020-02-10 16:36:07 -0500470 GrSurfaceProxyView atlasView,
471 SkAlphaType atlasAlphaType) {
Greg Daniele20fcad2020-01-08 11:52:34 -0500472 auto rtc = GrRenderTargetContext::Make(
Robert Phillips58adb342020-07-23 09:41:57 -0400473 rContext, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox,
Greg Daniele20fcad2020-01-08 11:52:34 -0500474 {3 * kDrawnTileSize, kDrawnTileSize});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400475
Michael Ludwig81d41722020-05-26 16:57:38 -0400476 rtc->clear({ 1, 0, 0, 1 });
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400477
478 for (int i = 0; i < 3; ++i) {
479 SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
480
Greg Danield2ccbb52020-02-05 10:45:39 -0500481 auto fp = GrTextureEffect::Make(atlasView, atlasAlphaType);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400482 GrPaint paint;
John Stiles5933d7d2020-07-21 12:28:35 -0400483 paint.setColorFragmentProcessor(std::move(fp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400484 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Robert Phillips58adb342020-07-23 09:41:57 -0400485 std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(rContext,
Robert Phillips7c525e62018-06-12 10:11:12 -0400486 std::move(paint), r, start + i));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400487
488 AtlasedRectOp* sparePtr = op.get();
489
Greg Danielf41b2bd2019-08-22 16:19:24 -0400490 uint32_t opsTaskID;
Michael Ludwig7c12e282020-05-29 09:54:07 -0400491 rtc->priv().testingOnly_addDrawOp(nullptr, std::move(op),
Greg Danielf41b2bd2019-08-22 16:19:24 -0400492 [&opsTaskID](GrOp* op, uint32_t id) { opsTaskID = id; });
493 SkASSERT(SK_InvalidUniqueID != opsTaskID);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400494
Greg Danielf41b2bd2019-08-22 16:19:24 -0400495 object->addOp(opsTaskID, sparePtr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400496 }
497
Greg Danield11ae2e2020-02-10 16:36:07 -0500498 return rtc->readSurfaceView();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400499}
500
501// Enable this if you want to debug the final draws w/o having the atlasCallback create the
502// atlas
503#if 0
504#include "SkGrPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500505#include "include/core/SkImageEncoder.h"
506#include "tools/ToolUtils.h"
Chris Dalton12658942017-10-05 19:45:25 -0600507
508static void save_bm(const SkBitmap& bm, const char name[]) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500509 bool result = ToolUtils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
Chris Dalton12658942017-10-05 19:45:25 -0600510 SkASSERT(result);
511}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400512
Robert Phillips58adb342020-07-23 09:41:57 -0400513sk_sp<GrTextureProxy> pre_create_atlas(GrRecordingContext* rContext) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400514 SkBitmap bm;
515 bm.allocN32Pixels(18, 2, true);
516 bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2));
517 bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2));
518 bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2));
519 bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2));
520 bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
521 bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2));
522 bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2));
523 bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2));
524 bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2));
525
526#if 1
527 save_bm(bm, "atlas-fake.png");
528#endif
529
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400530 desc.fFlags |= kRenderTarget_GrSurfaceFlag;
531
Robert Phillips58adb342020-07-23 09:41:57 -0400532 sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*rContext->caps(),
533 rContext->textureProvider(),
Brian Salomona56a7462020-02-07 14:17:25 -0500534 dm.dimensions(), SkBudgeted::kYes,
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400535 bm.getPixels(), bm.rowBytes());
536
537 return sk_ref_sp(tmp->asTextureProxy());
538}
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400539#endif
540
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500541
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400542static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
543 SkColor readback = bm.getColor(x, kDrawnTileSize/2);
544 REPORTER_ASSERT(reporter, expected == readback);
545 if (expected != readback) {
546 SkDebugf("Color mismatch: %x %x\n", expected, readback);
547 }
548}
549
550/*
551 * For the atlasing test we make a DAG that looks like:
552 *
553 * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8
554 * \ /
555 * \ /
556 * RT4
557 * We then flush RT4 and expect only ops 0-5 to be atlased together.
558 * Each op is just a solid colored rect so both the atlas and the final image should appear as:
559 * R G B C M Y
560 * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
561 *
Robert Phillips7d79e7b2018-02-14 11:09:57 -0500562 * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize
563 * and look like:
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400564 * R G B C M Y K Grey White
565 */
Chris Daltonfe199b72017-05-05 11:26:15 -0400566DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
Greg Danield11ae2e2020-02-10 16:36:07 -0500567 static const int kNumViews = 3;
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400568
Adlai Hollerc95b5892020-08-11 12:02:22 -0400569 auto dContext = ctxInfo.directContext();
570 auto proxyProvider = dContext->priv().proxyProvider();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400571
Brian Salomon557e8122019-10-24 10:37:08 -0400572 AtlasObject object(reporter);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400573
Adlai Hollerc95b5892020-08-11 12:02:22 -0400574 dContext->priv().addOnFlushCallbackObject(&object);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400575
Greg Danield11ae2e2020-02-10 16:36:07 -0500576 GrSurfaceProxyView views[kNumViews];
577 for (int i = 0; i < kNumViews; ++i) {
Adlai Hollerc95b5892020-08-11 12:02:22 -0400578 views[i] = make_upstream_image(dContext, &object, i * 3,
579 object.getAtlasView(proxyProvider, dContext->priv().caps()),
Greg Danield11ae2e2020-02-10 16:36:07 -0500580 kPremul_SkAlphaType);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400581 }
582
583 static const int kFinalWidth = 6*kDrawnTileSize;
584 static const int kFinalHeight = kDrawnTileSize;
585
Greg Daniele20fcad2020-01-08 11:52:34 -0500586 auto rtc = GrRenderTargetContext::Make(
Adlai Hollerc95b5892020-08-11 12:02:22 -0400587 dContext, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox,
Greg Daniele20fcad2020-01-08 11:52:34 -0500588 {kFinalWidth, kFinalHeight});
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400589
Michael Ludwig81d41722020-05-26 16:57:38 -0400590 rtc->clear(SK_PMColor4fWHITE);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400591
592 // Note that this doesn't include the third texture proxy
Greg Danield11ae2e2020-02-10 16:36:07 -0500593 for (int i = 0; i < kNumViews - 1; ++i) {
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400594 SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
595
Mike Reed1f607332020-05-21 12:11:27 -0400596 SkMatrix t = SkMatrix::Translate(-i*3*kDrawnTileSize, 0);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400597
598 GrPaint paint;
Greg Danield11ae2e2020-02-10 16:36:07 -0500599 auto fp = GrTextureEffect::Make(std::move(views[i]), kPremul_SkAlphaType, t);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400600 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
John Stiles5933d7d2020-07-21 12:28:35 -0400601 paint.setColorFragmentProcessor(std::move(fp));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400602
Michael Ludwig7c12e282020-05-29 09:54:07 -0400603 rtc->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), r);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400604 }
605
Greg Daniel9efe3862020-06-11 11:51:06 -0400606 rtc->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo(), nullptr);
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400607
608 SkBitmap readBack;
609 readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
610
Adlai Hollerc95b5892020-08-11 12:02:22 -0400611 SkAssertResult(rtc->readPixels(dContext, readBack.info(), readBack.getPixels(),
612 readBack.rowBytes(), {0, 0}));
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400613
Adlai Hollerc95b5892020-08-11 12:02:22 -0400614 dContext->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
Chris Daltonfe199b72017-05-05 11:26:15 -0400615
616 object.markAsDone();
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400617
Robert Phillipseb35f4d2017-03-21 07:56:47 -0400618 int x = kDrawnTileSize/2;
619 test_color(reporter, readBack, x, SK_ColorRED);
620 x += kDrawnTileSize;
621 test_color(reporter, readBack, x, SK_ColorGREEN);
622 x += kDrawnTileSize;
623 test_color(reporter, readBack, x, SK_ColorBLUE);
624 x += kDrawnTileSize;
625 test_color(reporter, readBack, x, SK_ColorCYAN);
626 x += kDrawnTileSize;
627 test_color(reporter, readBack, x, SK_ColorMAGENTA);
628 x += kDrawnTileSize;
629 test_color(reporter, readBack, x, SK_ColorYELLOW);
630}