| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 1 | /* | 
|  | 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 |  | 
|  | 8 | #include "Test.h" | 
|  | 9 |  | 
| Greg Daniel | a5cb781 | 2017-06-16 09:45:32 -0400 | [diff] [blame] | 10 | #include "GrBackendSemaphore.h" | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 11 | #include "GrClip.h" | 
|  | 12 | #include "GrContextPriv.h" | 
|  | 13 | #include "GrDefaultGeoProcFactory.h" | 
| Chris Dalton | fe199b7 | 2017-05-05 11:26:15 -0400 | [diff] [blame] | 14 | #include "GrOnFlushResourceProvider.h" | 
| Robert Phillips | 0bd24dc | 2018-01-16 08:06:32 -0500 | [diff] [blame] | 15 | #include "GrProxyProvider.h" | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 16 | #include "GrQuad.h" | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 17 | #include "GrRenderTargetContextPriv.h" | 
|  | 18 | #include "GrResourceProvider.h" | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 19 | #include "GrTexture.h" | 
|  | 20 |  | 
| Mike Reed | 75ae421 | 2018-01-23 11:24:08 -0500 | [diff] [blame] | 21 | #include "SkBitmap.h" | 
| Cary Clark | 74f623d | 2017-11-06 20:02:02 -0500 | [diff] [blame] | 22 | #include "SkPointPriv.h" | 
| Ethan Nicholas | 21a9b56 | 2019-04-10 12:06:19 -0400 | [diff] [blame] | 23 | #include "effects/generated/GrSimpleTextureEffect.h" | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 24 | #include "ops/GrSimpleMeshDrawOpHelper.h" | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 25 |  | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 26 | namespace { | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 27 | // This is a simplified mesh drawing op that can be used in the atlas generation test. | 
|  | 28 | // Please see AtlasedRectOp below. | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 29 | class NonAARectOp : public GrMeshDrawOp { | 
|  | 30 | protected: | 
|  | 31 | using Helper = GrSimpleMeshDrawOpHelper; | 
|  | 32 |  | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 33 | public: | 
|  | 34 | DEFINE_OP_CLASS_ID | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 35 |  | 
|  | 36 | // This creates an instance of a simple non-AA solid color rect-drawing Op | 
| Robert Phillips | b97da53 | 2019-02-12 15:24:12 -0500 | [diff] [blame] | 37 | static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context, | 
| Robert Phillips | 7c525e6 | 2018-06-12 10:11:12 -0400 | [diff] [blame] | 38 | GrPaint&& paint, | 
|  | 39 | const SkRect& r) { | 
|  | 40 | return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, nullptr, ClassID()); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 41 | } | 
|  | 42 |  | 
|  | 43 | // This creates an instance of a simple non-AA textured rect-drawing Op | 
| Robert Phillips | b97da53 | 2019-02-12 15:24:12 -0500 | [diff] [blame] | 44 | static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context, | 
| Robert Phillips | 7c525e6 | 2018-06-12 10:11:12 -0400 | [diff] [blame] | 45 | GrPaint&& paint, | 
|  | 46 | const SkRect& r, | 
|  | 47 | const SkRect& local) { | 
|  | 48 | return Helper::FactoryHelper<NonAARectOp>(context, std::move(paint), r, &local, ClassID()); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 49 | } | 
|  | 50 |  | 
| Brian Osman | cf86085 | 2018-10-31 14:04:39 -0400 | [diff] [blame] | 51 | const SkPMColor4f& color() const { return fColor; } | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 52 |  | 
| Brian Osman | cf86085 | 2018-10-31 14:04:39 -0400 | [diff] [blame] | 53 | NonAARectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r, | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 54 | 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 Salomon | a33b67c | 2018-05-17 10:42:14 -0400 | [diff] [blame] | 61 | fLocalQuad = GrQuad(*localRect); | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 62 | } | 
|  | 63 | // Choose some conservative values for aa bloat and zero area. | 
|  | 64 | this->setBounds(r, HasAABloat::kYes, IsZeroArea::kYes); | 
|  | 65 | } | 
|  | 66 |  | 
| Robert Phillips | b493eeb | 2017-09-13 13:10:52 -0400 | [diff] [blame] | 67 | const char* name() const override { return "NonAARectOp"; } | 
|  | 68 |  | 
| Brian Salomon | 7d94bb5 | 2018-10-12 14:37:19 -0400 | [diff] [blame] | 69 | void visitProxies(const VisitProxyFunc& func, VisitorType) const override { | 
| Robert Phillips | b493eeb | 2017-09-13 13:10:52 -0400 | [diff] [blame] | 70 | fHelper.visitProxies(func); | 
|  | 71 | } | 
|  | 72 |  | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 73 | FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } | 
|  | 74 |  | 
| Brian Osman | 5ced0bf | 2019-03-15 10:15:29 -0400 | [diff] [blame] | 75 | GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip*, | 
|  | 76 | GrFSAAType fsaaType, GrClampType clampType) override { | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 77 | // Set the color to unknown because the subclass may change the color later. | 
|  | 78 | GrProcessorAnalysisColor gpColor; | 
|  | 79 | gpColor.setToUnknown(); | 
|  | 80 | // We ignore the clip so pass this rather than the GrAppliedClip param. | 
|  | 81 | static GrAppliedClip kNoClip; | 
| Chris Dalton | b8fff0d | 2019-03-05 10:11:58 -0700 | [diff] [blame] | 82 | return fHelper.finalizeProcessors( | 
| Brian Osman | 5ced0bf | 2019-03-15 10:15:29 -0400 | [diff] [blame] | 83 | caps, &kNoClip, fsaaType, clampType, GrProcessorAnalysisCoverage::kNone, &gpColor); | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 84 | } | 
|  | 85 |  | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 86 | protected: | 
| Brian Osman | cf86085 | 2018-10-31 14:04:39 -0400 | [diff] [blame] | 87 | SkPMColor4f fColor; | 
|  | 88 | bool        fHasLocalRect; | 
|  | 89 | GrQuad      fLocalQuad; | 
|  | 90 | SkRect      fRect; | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 91 |  | 
|  | 92 | private: | 
| Brian Salomon | 91326c3 | 2017-08-09 16:02:19 -0400 | [diff] [blame] | 93 | void onPrepareDraws(Target* target) override { | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 94 | using namespace GrDefaultGeoProcFactory; | 
|  | 95 |  | 
|  | 96 | // The vertex attrib order is always pos, color, local coords. | 
|  | 97 | static const int kColorOffset = sizeof(SkPoint); | 
|  | 98 | static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); | 
|  | 99 |  | 
|  | 100 | sk_sp<GrGeometryProcessor> gp = | 
| Ruiqi Mao | b609e6d | 2018-07-17 10:19:38 -0400 | [diff] [blame] | 101 | GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(), | 
|  | 102 | Color::kPremulGrColorAttribute_Type, | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 103 | Coverage::kSolid_Type, | 
|  | 104 | fHasLocalRect ? LocalCoords::kHasExplicit_Type | 
|  | 105 | : LocalCoords::kUnused_Type, | 
|  | 106 | SkMatrix::I()); | 
|  | 107 | if (!gp) { | 
|  | 108 | SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n"); | 
|  | 109 | return; | 
|  | 110 | } | 
|  | 111 |  | 
| Brian Osman | f04fb3c | 2018-11-12 15:34:00 -0500 | [diff] [blame] | 112 | size_t vertexStride = gp->vertexStride(); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 113 |  | 
| Brian Salomon | 12d2264 | 2019-01-29 14:38:50 -0500 | [diff] [blame] | 114 | sk_sp<const GrBuffer> indexBuffer; | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 115 | int firstIndex; | 
|  | 116 | uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex); | 
|  | 117 | if (!indices) { | 
|  | 118 | SkDebugf("Indices could not be allocated for GrAtlasedOp.\n"); | 
|  | 119 | return; | 
|  | 120 | } | 
|  | 121 |  | 
| Brian Salomon | 12d2264 | 2019-01-29 14:38:50 -0500 | [diff] [blame] | 122 | sk_sp<const GrBuffer> vertexBuffer; | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 123 | int firstVertex; | 
|  | 124 | void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex); | 
|  | 125 | if (!vertices) { | 
|  | 126 | SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n"); | 
|  | 127 | return; | 
|  | 128 | } | 
|  | 129 |  | 
|  | 130 | // Setup indices | 
|  | 131 | indices[0] = 0; | 
|  | 132 | indices[1] = 1; | 
|  | 133 | indices[2] = 2; | 
| Brian Salomon | 57caa66 | 2017-10-18 12:21:05 +0000 | [diff] [blame] | 134 | indices[3] = 2; | 
|  | 135 | indices[4] = 1; | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 136 | indices[5] = 3; | 
|  | 137 |  | 
|  | 138 | // Setup positions | 
|  | 139 | SkPoint* position = (SkPoint*) vertices; | 
| Brian Salomon | ec42e15 | 2018-05-18 12:52:22 -0400 | [diff] [blame] | 140 | SkPointPriv::SetRectTriStrip(position, fRect, vertexStride); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 141 |  | 
|  | 142 | // Setup vertex colors | 
|  | 143 | GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset); | 
|  | 144 | for (int i = 0; i < 4; ++i) { | 
| Brian Osman | cf86085 | 2018-10-31 14:04:39 -0400 | [diff] [blame] | 145 | *color = fColor.toBytes_RGBA(); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 146 | color = (GrColor*)((intptr_t)color + vertexStride); | 
|  | 147 | } | 
|  | 148 |  | 
|  | 149 | // Setup local coords | 
|  | 150 | if (fHasLocalRect) { | 
|  | 151 | SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset); | 
|  | 152 | for (int i = 0; i < 4; i++) { | 
|  | 153 | *coords = fLocalQuad.point(i); | 
|  | 154 | coords = (SkPoint*)((intptr_t) coords + vertexStride); | 
|  | 155 | } | 
|  | 156 | } | 
|  | 157 |  | 
| Brian Salomon | 7eae3e0 | 2018-08-07 14:02:38 +0000 | [diff] [blame] | 158 | GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles); | 
|  | 159 | mesh->setIndexed(indexBuffer, 6, firstIndex, 0, 3, GrPrimitiveRestart::kNo); | 
|  | 160 | mesh->setVertexData(vertexBuffer, firstVertex); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 161 |  | 
| Chris Dalton | 07cdcfc9 | 2019-02-26 11:13:22 -0700 | [diff] [blame] | 162 | target->recordDraw(std::move(gp), mesh); | 
|  | 163 | } | 
|  | 164 |  | 
|  | 165 | void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override { | 
|  | 166 | fHelper.executeDrawsAndUploads(this, flushState, chainBounds); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 167 | } | 
|  | 168 |  | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 169 | Helper fHelper; | 
|  | 170 |  | 
|  | 171 | typedef GrMeshDrawOp INHERITED; | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 172 | }; | 
|  | 173 |  | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 174 | }  // anonymous namespace | 
|  | 175 |  | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 176 | static constexpr SkRect kEmptyRect = SkRect::MakeEmpty(); | 
|  | 177 |  | 
|  | 178 | namespace { | 
|  | 179 |  | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 180 | /* | 
|  | 181 | * Atlased ops just draw themselves as textured rects with the texture pixels being | 
|  | 182 | * pulled out of the atlas. Their color is based on their ID. | 
|  | 183 | */ | 
|  | 184 | class AtlasedRectOp final : public NonAARectOp { | 
|  | 185 | public: | 
|  | 186 | DEFINE_OP_CLASS_ID | 
|  | 187 |  | 
|  | 188 | ~AtlasedRectOp() override { | 
|  | 189 | fID = -1; | 
|  | 190 | } | 
|  | 191 |  | 
|  | 192 | const char* name() const override { return "AtlasedRectOp"; } | 
|  | 193 |  | 
|  | 194 | int id() const { return fID; } | 
|  | 195 |  | 
| Robert Phillips | 7c525e6 | 2018-06-12 10:11:12 -0400 | [diff] [blame] | 196 | static std::unique_ptr<AtlasedRectOp> Make(GrContext* context, | 
|  | 197 | GrPaint&& paint, | 
|  | 198 | const SkRect& r, | 
|  | 199 | int id) { | 
|  | 200 | GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(context, std::move(paint), | 
|  | 201 | r, id).release(); | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 202 | return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op)); | 
|  | 203 | } | 
|  | 204 |  | 
|  | 205 | // We set the initial color of the NonAARectOp based on the ID. | 
|  | 206 | // Note that we force creation of a NonAARectOp that has local coords in anticipation of | 
|  | 207 | // pulling from the atlas. | 
| Brian Osman | cf86085 | 2018-10-31 14:04:39 -0400 | [diff] [blame] | 208 | AtlasedRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkRect& r, | 
| Brian Osman | 936fe7d | 2018-10-30 15:30:35 -0400 | [diff] [blame] | 209 | int id) | 
| Brian Osman | cf86085 | 2018-10-31 14:04:39 -0400 | [diff] [blame] | 210 | : INHERITED(helperArgs, SkPMColor4f::FromBytes_RGBA(kColors[id]), r, &kEmptyRect, | 
|  | 211 | ClassID()) | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 212 | , fID(id) | 
|  | 213 | , fNext(nullptr) { | 
|  | 214 | SkASSERT(fID < kMaxIDs); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 215 | } | 
|  | 216 |  | 
| Brian Osman | cf86085 | 2018-10-31 14:04:39 -0400 | [diff] [blame] | 217 | void setColor(const SkPMColor4f& color) { fColor = color; } | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 218 | void setLocalRect(const SkRect& localRect) { | 
|  | 219 | SkASSERT(fHasLocalRect);    // This should've been created to anticipate this | 
| Brian Salomon | a33b67c | 2018-05-17 10:42:14 -0400 | [diff] [blame] | 220 | fLocalQuad = GrQuad(localRect); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 221 | } | 
|  | 222 |  | 
|  | 223 | AtlasedRectOp* next() const { return fNext; } | 
|  | 224 | void setNext(AtlasedRectOp* next) { | 
|  | 225 | fNext = next; | 
|  | 226 | } | 
|  | 227 |  | 
|  | 228 | private: | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 229 |  | 
|  | 230 | static const int kMaxIDs = 9; | 
| Brian Osman | 1be2b7c | 2018-10-29 16:07:15 -0400 | [diff] [blame] | 231 | static const GrColor kColors[kMaxIDs]; | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 232 |  | 
|  | 233 | int            fID; | 
|  | 234 | // The Atlased ops have an internal singly-linked list of ops that land in the same opList | 
|  | 235 | AtlasedRectOp* fNext; | 
|  | 236 |  | 
|  | 237 | typedef NonAARectOp INHERITED; | 
|  | 238 | }; | 
|  | 239 |  | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 240 | }  // anonymous namespace | 
|  | 241 |  | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 242 | const GrColor AtlasedRectOp::kColors[kMaxIDs] = { | 
|  | 243 | GrColorPackRGBA(255, 0, 0, 255), | 
|  | 244 | GrColorPackRGBA(0, 255, 0, 255), | 
|  | 245 | GrColorPackRGBA(0, 0, 255, 255), | 
|  | 246 | GrColorPackRGBA(0, 255, 255, 255), | 
|  | 247 | GrColorPackRGBA(255, 0, 255, 255), | 
|  | 248 | GrColorPackRGBA(255, 255, 0, 255), | 
|  | 249 | GrColorPackRGBA(0, 0, 0, 255), | 
|  | 250 | GrColorPackRGBA(128, 128, 128, 255), | 
|  | 251 | GrColorPackRGBA(255, 255, 255, 255) | 
|  | 252 | }; | 
|  | 253 |  | 
|  | 254 | static const int kDrawnTileSize = 16; | 
|  | 255 |  | 
|  | 256 | /* | 
|  | 257 | * Rather than performing any rect packing, this atlaser just lays out constant-sized | 
|  | 258 | * tiles in an Nx1 row | 
|  | 259 | */ | 
|  | 260 | static const int kAtlasTileSize = 2; | 
|  | 261 |  | 
|  | 262 | /* | 
|  | 263 | * This class aggregates the op information required for atlasing | 
|  | 264 | */ | 
| Chris Dalton | fe199b7 | 2017-05-05 11:26:15 -0400 | [diff] [blame] | 265 | class AtlasObject final : public GrOnFlushCallbackObject { | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 266 | public: | 
|  | 267 | AtlasObject() : fDone(false) { } | 
|  | 268 |  | 
|  | 269 | ~AtlasObject() override { | 
|  | 270 | SkASSERT(fDone); | 
|  | 271 | } | 
|  | 272 |  | 
|  | 273 | void markAsDone() { | 
|  | 274 | fDone = true; | 
|  | 275 | } | 
|  | 276 |  | 
|  | 277 | // Insert the new op in an internal singly-linked list for 'opListID' | 
|  | 278 | void addOp(uint32_t opListID, AtlasedRectOp* op) { | 
|  | 279 | LinkedListHeader* header = nullptr; | 
|  | 280 | for (int i = 0; i < fOps.count(); ++i) { | 
|  | 281 | if (opListID == fOps[i].fID) { | 
|  | 282 | header = &(fOps[i]); | 
|  | 283 | } | 
|  | 284 | } | 
|  | 285 |  | 
|  | 286 | if (!header) { | 
| Mike Reed | 5edcd31 | 2018-08-08 11:23:41 -0400 | [diff] [blame] | 287 | fOps.push_back({opListID, nullptr}); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 288 | header = &(fOps[fOps.count()-1]); | 
|  | 289 | } | 
|  | 290 |  | 
|  | 291 | op->setNext(header->fHead); | 
|  | 292 | header->fHead = op; | 
|  | 293 | } | 
|  | 294 |  | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 295 | int numOps() const { return fOps.count(); } | 
|  | 296 |  | 
|  | 297 | // Get the fully lazy proxy that is backing the atlas. Its actual width isn't | 
|  | 298 | // known until flush time. | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 299 | sk_sp<GrTextureProxy> getAtlasProxy(GrProxyProvider* proxyProvider, const GrCaps* caps) { | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 300 | if (fAtlasProxy) { | 
|  | 301 | return fAtlasProxy; | 
|  | 302 | } | 
|  | 303 |  | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 304 | const GrBackendFormat format = caps->getBackendFormatFromColorType(kRGBA_8888_SkColorType); | 
|  | 305 |  | 
| Chris Dalton | 4c458b1 | 2018-06-16 17:22:59 -0600 | [diff] [blame] | 306 | fAtlasProxy = GrProxyProvider::MakeFullyLazyProxy( | 
| Brian Salomon | b6a3a3b | 2019-04-01 12:29:34 -0400 | [diff] [blame] | 307 | [](GrResourceProvider* resourceProvider) | 
|  | 308 | -> GrSurfaceProxy::LazyInstantiationResult { | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 309 | GrSurfaceDesc desc; | 
|  | 310 | desc.fFlags = kRenderTarget_GrSurfaceFlag; | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 311 | // TODO: until partial flushes in MDB lands we're stuck having | 
|  | 312 | // all 9 atlas draws occur | 
|  | 313 | desc.fWidth = 9 /*this->numOps()*/ * kAtlasTileSize; | 
|  | 314 | desc.fHeight = kAtlasTileSize; | 
|  | 315 | desc.fConfig = kRGBA_8888_GrPixelConfig; | 
|  | 316 |  | 
| Brian Salomon | b6a3a3b | 2019-04-01 12:29:34 -0400 | [diff] [blame] | 317 | auto texture = resourceProvider->createTexture( | 
|  | 318 | desc, SkBudgeted::kYes, GrResourceProvider::Flags::kNoPendingIO); | 
|  | 319 | return std::move(texture); | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 320 | }, | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 321 | format, | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 322 | GrProxyProvider::Renderable::kYes, | 
|  | 323 | kBottomLeft_GrSurfaceOrigin, | 
| Chris Dalton | 4c458b1 | 2018-06-16 17:22:59 -0600 | [diff] [blame] | 324 | kRGBA_8888_GrPixelConfig, | 
|  | 325 | *proxyProvider->caps()); | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 326 | return fAtlasProxy; | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 327 | } | 
|  | 328 |  | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 329 | /* | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 330 | * This callback creates the atlas and updates the AtlasedRectOps to read from it | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 331 | */ | 
| Chris Dalton | fe199b7 | 2017-05-05 11:26:15 -0400 | [diff] [blame] | 332 | void preFlush(GrOnFlushResourceProvider* resourceProvider, | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 333 | const uint32_t* opListIDs, int numOpListIDs, | 
|  | 334 | SkTArray<sk_sp<GrRenderTargetContext>>* results) override { | 
|  | 335 | SkASSERT(!results->count()); | 
|  | 336 |  | 
|  | 337 | // Until MDB is landed we will most-likely only have one opList. | 
|  | 338 | SkTDArray<LinkedListHeader*> lists; | 
|  | 339 | for (int i = 0; i < numOpListIDs; ++i) { | 
|  | 340 | if (LinkedListHeader* list = this->getList(opListIDs[i])) { | 
| Mike Reed | 5edcd31 | 2018-08-08 11:23:41 -0400 | [diff] [blame] | 341 | lists.push_back(list); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 342 | } | 
|  | 343 | } | 
|  | 344 |  | 
|  | 345 | if (!lists.count()) { | 
|  | 346 | return; // nothing to atlas | 
|  | 347 | } | 
|  | 348 |  | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 349 | if (!resourceProvider->instatiateProxy(fAtlasProxy.get())) { | 
|  | 350 | return; | 
|  | 351 | } | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 352 |  | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 353 | // At this point all the GrAtlasedOp's should have lined up to read from 'atlasDest' and | 
|  | 354 | // there should either be two writes to clear it or no writes. | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 355 | SkASSERT(9 == fAtlasProxy->getPendingReadCnt_TestOnly()); | 
|  | 356 | SkASSERT(2 == fAtlasProxy->getPendingWriteCnt_TestOnly() || | 
|  | 357 | 0 == fAtlasProxy->getPendingWriteCnt_TestOnly()); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 358 | sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext( | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 359 | fAtlasProxy, | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 360 | nullptr, nullptr); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 361 |  | 
| Chris Dalton | 344e903 | 2017-12-11 15:42:09 -0700 | [diff] [blame] | 362 | // clear the atlas | 
| Brian Osman | 9a9baae | 2018-11-05 15:06:26 -0500 | [diff] [blame] | 363 | rtc->clear(nullptr, SK_PMColor4fTRANSPARENT, | 
|  | 364 | GrRenderTargetContext::CanClearFullscreen::kYes); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 365 |  | 
|  | 366 | int blocksInAtlas = 0; | 
|  | 367 | for (int i = 0; i < lists.count(); ++i) { | 
|  | 368 | for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) { | 
|  | 369 | SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0, | 
|  | 370 | kAtlasTileSize, kAtlasTileSize); | 
|  | 371 |  | 
|  | 372 | // For now, we avoid the resource buffer issues and just use clears | 
|  | 373 | #if 1 | 
| Brian Osman | 9a9baae | 2018-11-05 15:06:26 -0500 | [diff] [blame] | 374 | rtc->clear(&r, op->color(), GrRenderTargetContext::CanClearFullscreen::kNo); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 375 | #else | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 376 | GrPaint paint; | 
| Brian Osman | 9a9baae | 2018-11-05 15:06:26 -0500 | [diff] [blame] | 377 | paint.setColor4f(op->color()); | 
| Brian Salomon | 9a03642 | 2017-07-13 17:04:43 -0400 | [diff] [blame] | 378 | std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint), | 
|  | 379 | SkRect::Make(r))); | 
|  | 380 | rtc->priv().testingOnly_addDrawOp(std::move(drawOp)); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 381 | #endif | 
|  | 382 | blocksInAtlas++; | 
|  | 383 |  | 
|  | 384 | // Set the atlased Op's color to white (so we know we're not using it for | 
|  | 385 | // the final draw). | 
| Brian Osman | cf86085 | 2018-10-31 14:04:39 -0400 | [diff] [blame] | 386 | op->setColor(SK_PMColor4fWHITE); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 387 |  | 
|  | 388 | // Set the atlased Op's localRect to point to where it landed in the atlas | 
|  | 389 | op->setLocalRect(SkRect::Make(r)); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 390 | } | 
|  | 391 |  | 
|  | 392 | // We've updated all these ops and we certainly don't want to process them again | 
|  | 393 | this->clearOpsFor(lists[i]); | 
|  | 394 | } | 
|  | 395 |  | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 396 | results->push_back(std::move(rtc)); | 
|  | 397 | } | 
|  | 398 |  | 
|  | 399 | private: | 
|  | 400 | typedef struct { | 
|  | 401 | uint32_t       fID; | 
|  | 402 | AtlasedRectOp* fHead; | 
|  | 403 | } LinkedListHeader; | 
|  | 404 |  | 
|  | 405 | LinkedListHeader* getList(uint32_t opListID) { | 
|  | 406 | for (int i = 0; i < fOps.count(); ++i) { | 
|  | 407 | if (opListID == fOps[i].fID) { | 
|  | 408 | return &(fOps[i]); | 
|  | 409 | } | 
|  | 410 | } | 
|  | 411 | return nullptr; | 
|  | 412 | } | 
|  | 413 |  | 
|  | 414 | void clearOpsFor(LinkedListHeader* header) { | 
|  | 415 | // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just | 
|  | 416 | // forget about them in the laziest way possible. | 
|  | 417 | header->fHead = nullptr; | 
|  | 418 | header->fID = 0;            // invalid opList ID | 
|  | 419 | } | 
|  | 420 |  | 
|  | 421 | // Each opList containing AtlasedRectOps gets its own internal singly-linked list | 
|  | 422 | SkTDArray<LinkedListHeader>  fOps; | 
|  | 423 |  | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 424 | // The fully lazy proxy for the atlas | 
|  | 425 | sk_sp<GrTextureProxy>        fAtlasProxy; | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 426 |  | 
|  | 427 | // Set to true when the testing harness expects this object to be no longer used | 
|  | 428 | bool                         fDone; | 
|  | 429 | }; | 
|  | 430 |  | 
|  | 431 | // This creates an off-screen rendertarget whose ops which eventually pull from the atlas. | 
|  | 432 | static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start, | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 433 | sk_sp<GrTextureProxy> atlasProxy) { | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 434 | const GrBackendFormat format = | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 435 | context->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType); | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 436 |  | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 437 | sk_sp<GrRenderTargetContext> rtc(context->priv().makeDeferredRenderTargetContext( | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 438 | format, | 
| Robert Phillips | dd3b3f4 | 2017-04-24 10:57:28 -0400 | [diff] [blame] | 439 | SkBackingFit::kApprox, | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 440 | 3*kDrawnTileSize, | 
|  | 441 | kDrawnTileSize, | 
|  | 442 | kRGBA_8888_GrPixelConfig, | 
|  | 443 | nullptr)); | 
|  | 444 |  | 
| Brian Osman | 9a9baae | 2018-11-05 15:06:26 -0500 | [diff] [blame] | 445 | rtc->clear(nullptr, { 1, 0, 0, 1 }, GrRenderTargetContext::CanClearFullscreen::kYes); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 446 |  | 
|  | 447 | for (int i = 0; i < 3; ++i) { | 
|  | 448 | SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize); | 
|  | 449 |  | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 450 | auto fp = GrSimpleTextureEffect::Make(atlasProxy, SkMatrix::I()); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 451 | GrPaint paint; | 
|  | 452 | paint.addColorFragmentProcessor(std::move(fp)); | 
|  | 453 | paint.setPorterDuffXPFactory(SkBlendMode::kSrc); | 
| Robert Phillips | 7c525e6 | 2018-06-12 10:11:12 -0400 | [diff] [blame] | 454 | std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(context, | 
|  | 455 | std::move(paint), r, start + i)); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 456 |  | 
|  | 457 | AtlasedRectOp* sparePtr = op.get(); | 
|  | 458 |  | 
| Brian Salomon | 348a037 | 2018-10-31 10:42:18 -0400 | [diff] [blame] | 459 | uint32_t opListID; | 
|  | 460 | rtc->priv().testingOnly_addDrawOp(GrNoClip(), std::move(op), | 
|  | 461 | [&opListID](GrOp* op, uint32_t id) { opListID = id; }); | 
| Chris Dalton | f104fec | 2018-05-22 16:17:48 -0600 | [diff] [blame] | 462 | SkASSERT(SK_InvalidUniqueID != opListID); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 463 |  | 
|  | 464 | object->addOp(opListID, sparePtr); | 
|  | 465 | } | 
|  | 466 |  | 
|  | 467 | return rtc->asTextureProxyRef(); | 
|  | 468 | } | 
|  | 469 |  | 
|  | 470 | // Enable this if you want to debug the final draws w/o having the atlasCallback create the | 
|  | 471 | // atlas | 
|  | 472 | #if 0 | 
|  | 473 | #include "SkGrPriv.h" | 
| Mike Klein | ea3f014 | 2019-03-20 11:12:10 -0500 | [diff] [blame] | 474 | #include "SkImageEncoder.h" | 
|  | 475 | #include "ToolUtils.h" | 
| Chris Dalton | 1265894 | 2017-10-05 19:45:25 -0600 | [diff] [blame] | 476 |  | 
|  | 477 | static void save_bm(const SkBitmap& bm, const char name[]) { | 
| Mike Klein | ea3f014 | 2019-03-20 11:12:10 -0500 | [diff] [blame] | 478 | bool result = ToolUtils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100); | 
| Chris Dalton | 1265894 | 2017-10-05 19:45:25 -0600 | [diff] [blame] | 479 | SkASSERT(result); | 
|  | 480 | } | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 481 |  | 
|  | 482 | sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) { | 
|  | 483 | SkBitmap bm; | 
|  | 484 | bm.allocN32Pixels(18, 2, true); | 
|  | 485 | bm.erase(SK_ColorRED,     SkIRect::MakeXYWH(0, 0, 2, 2)); | 
|  | 486 | bm.erase(SK_ColorGREEN,   SkIRect::MakeXYWH(2, 0, 2, 2)); | 
|  | 487 | bm.erase(SK_ColorBLUE,    SkIRect::MakeXYWH(4, 0, 2, 2)); | 
|  | 488 | bm.erase(SK_ColorCYAN,    SkIRect::MakeXYWH(6, 0, 2, 2)); | 
|  | 489 | bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2)); | 
|  | 490 | bm.erase(SK_ColorYELLOW,  SkIRect::MakeXYWH(10, 0, 2, 2)); | 
|  | 491 | bm.erase(SK_ColorBLACK,   SkIRect::MakeXYWH(12, 0, 2, 2)); | 
|  | 492 | bm.erase(SK_ColorGRAY,    SkIRect::MakeXYWH(14, 0, 2, 2)); | 
|  | 493 | bm.erase(SK_ColorWHITE,   SkIRect::MakeXYWH(16, 0, 2, 2)); | 
|  | 494 |  | 
|  | 495 | #if 1 | 
|  | 496 | save_bm(bm, "atlas-fake.png"); | 
|  | 497 | #endif | 
|  | 498 |  | 
| Brian Osman | 2b23c4b | 2018-06-01 12:25:08 -0400 | [diff] [blame] | 499 | GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info()); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 500 | desc.fFlags |= kRenderTarget_GrSurfaceFlag; | 
|  | 501 |  | 
|  | 502 | sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(), | 
|  | 503 | context->textureProvider(), | 
|  | 504 | desc, SkBudgeted::kYes, | 
|  | 505 | bm.getPixels(), bm.rowBytes()); | 
|  | 506 |  | 
|  | 507 | return sk_ref_sp(tmp->asTextureProxy()); | 
|  | 508 | } | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 509 | #endif | 
|  | 510 |  | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 511 |  | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 512 | static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) { | 
|  | 513 | SkColor readback = bm.getColor(x, kDrawnTileSize/2); | 
|  | 514 | REPORTER_ASSERT(reporter, expected == readback); | 
|  | 515 | if (expected != readback) { | 
|  | 516 | SkDebugf("Color mismatch: %x %x\n", expected, readback); | 
|  | 517 | } | 
|  | 518 | } | 
|  | 519 |  | 
|  | 520 | /* | 
|  | 521 | * For the atlasing test we make a DAG that looks like: | 
|  | 522 | * | 
|  | 523 | *    RT1 with ops: 0,1,2       RT2 with ops: 3,4,5       RT3 with ops: 6,7,8 | 
|  | 524 | *                     \         / | 
|  | 525 | *                      \       / | 
|  | 526 | *                         RT4 | 
|  | 527 | * We then flush RT4 and expect only ops 0-5 to be atlased together. | 
|  | 528 | * Each op is just a solid colored rect so both the atlas and the final image should appear as: | 
|  | 529 | *           R G B C M Y | 
|  | 530 | * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize. | 
|  | 531 | * | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 532 | * Note: until partial flushes in MDB lands, the atlas will actually have width= 9*kAtlasTileSize | 
|  | 533 | * and look like: | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 534 | *           R G B C M Y K Grey White | 
|  | 535 | */ | 
| Chris Dalton | fe199b7 | 2017-05-05 11:26:15 -0400 | [diff] [blame] | 536 | DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) { | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 537 | static const int kNumProxies = 3; | 
|  | 538 |  | 
|  | 539 | GrContext* context = ctxInfo.grContext(); | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 540 | auto proxyProvider = context->priv().proxyProvider(); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 541 |  | 
| Chris Dalton | fe199b7 | 2017-05-05 11:26:15 -0400 | [diff] [blame] | 542 | AtlasObject object; | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 543 |  | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 544 | context->priv().addOnFlushCallbackObject(&object); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 545 |  | 
|  | 546 | sk_sp<GrTextureProxy> proxies[kNumProxies]; | 
|  | 547 | for (int i = 0; i < kNumProxies; ++i) { | 
| Robert Phillips | 7d79e7b | 2018-02-14 11:09:57 -0500 | [diff] [blame] | 548 | proxies[i] = make_upstream_image(context, &object, i*3, | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 549 | object.getAtlasProxy(proxyProvider, | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 550 | context->priv().caps())); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 551 | } | 
|  | 552 |  | 
|  | 553 | static const int kFinalWidth = 6*kDrawnTileSize; | 
|  | 554 | static const int kFinalHeight = kDrawnTileSize; | 
|  | 555 |  | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 556 | const GrBackendFormat format = | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 557 | context->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType); | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 558 |  | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 559 | sk_sp<GrRenderTargetContext> rtc(context->priv().makeDeferredRenderTargetContext( | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 560 | format, | 
| Robert Phillips | dd3b3f4 | 2017-04-24 10:57:28 -0400 | [diff] [blame] | 561 | SkBackingFit::kApprox, | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 562 | kFinalWidth, | 
|  | 563 | kFinalHeight, | 
|  | 564 | kRGBA_8888_GrPixelConfig, | 
|  | 565 | nullptr)); | 
|  | 566 |  | 
| Brian Osman | 9a9baae | 2018-11-05 15:06:26 -0500 | [diff] [blame] | 567 | rtc->clear(nullptr, SK_PMColor4fWHITE, GrRenderTargetContext::CanClearFullscreen::kYes); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 568 |  | 
|  | 569 | // Note that this doesn't include the third texture proxy | 
|  | 570 | for (int i = 0; i < kNumProxies-1; ++i) { | 
|  | 571 | SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize); | 
|  | 572 |  | 
|  | 573 | SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0); | 
|  | 574 |  | 
|  | 575 | GrPaint paint; | 
| Brian Osman | 2240be9 | 2017-10-18 13:15:13 -0400 | [diff] [blame] | 576 | auto fp = GrSimpleTextureEffect::Make(std::move(proxies[i]), t); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 577 | paint.setPorterDuffXPFactory(SkBlendMode::kSrc); | 
|  | 578 | paint.addColorFragmentProcessor(std::move(fp)); | 
|  | 579 |  | 
|  | 580 | rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r); | 
|  | 581 | } | 
|  | 582 |  | 
| Greg Daniel | bae7121 | 2019-03-01 15:24:35 -0500 | [diff] [blame] | 583 | rtc->prepareForExternalIO(SkSurface::BackendSurfaceAccess::kNoAccess, | 
| Greg Daniel | b9990e4 | 2019-04-10 16:28:52 -0400 | [diff] [blame^] | 584 | kNone_GrFlushFlags, 0, nullptr); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 585 |  | 
|  | 586 | SkBitmap readBack; | 
|  | 587 | readBack.allocN32Pixels(kFinalWidth, kFinalHeight); | 
|  | 588 |  | 
|  | 589 | SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(), | 
|  | 590 | readBack.rowBytes(), 0, 0); | 
|  | 591 | SkASSERT(result); | 
|  | 592 |  | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 593 | context->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object); | 
| Chris Dalton | fe199b7 | 2017-05-05 11:26:15 -0400 | [diff] [blame] | 594 |  | 
|  | 595 | object.markAsDone(); | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 596 |  | 
| Robert Phillips | eb35f4d | 2017-03-21 07:56:47 -0400 | [diff] [blame] | 597 | int x = kDrawnTileSize/2; | 
|  | 598 | test_color(reporter, readBack, x, SK_ColorRED); | 
|  | 599 | x += kDrawnTileSize; | 
|  | 600 | test_color(reporter, readBack, x, SK_ColorGREEN); | 
|  | 601 | x += kDrawnTileSize; | 
|  | 602 | test_color(reporter, readBack, x, SK_ColorBLUE); | 
|  | 603 | x += kDrawnTileSize; | 
|  | 604 | test_color(reporter, readBack, x, SK_ColorCYAN); | 
|  | 605 | x += kDrawnTileSize; | 
|  | 606 | test_color(reporter, readBack, x, SK_ColorMAGENTA); | 
|  | 607 | x += kDrawnTileSize; | 
|  | 608 | test_color(reporter, readBack, x, SK_ColorYELLOW); | 
|  | 609 | } |