1eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips/*
2eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips * Copyright 2017 Google Inc.
3eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips *
4eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips * Use of this source code is governed by a BSD-style license that can be
5eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips * found in the LICENSE file.
6eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips */
7eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
8eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#include "Test.h"
9eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
10eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#if SK_SUPPORT_GPU
11eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
12a5cb781c17c09e01655defd0a84b431996b6a015Greg Daniel#include "GrBackendSemaphore.h"
13eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#include "GrClip.h"
14eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#include "GrContextPriv.h"
15eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#include "GrDefaultGeoProcFactory.h"
16fe199b7d512a7cfc56deaaa134260e1d47a1e7e0Chris Dalton#include "GrOnFlushResourceProvider.h"
17eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#include "GrRenderTargetContextPriv.h"
18eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#include "GrResourceProvider.h"
19eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#include "GrQuad.h"
20eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#include "effects/GrSimpleTextureEffect.h"
219a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon#include "ops/GrSimpleMeshDrawOpHelper.h"
22eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
239a03642ad2fce5805642783f68078a0a6bf03554Brian Salomonnamespace {
24eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips// This is a simplified mesh drawing op that can be used in the atlas generation test.
25eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips// Please see AtlasedRectOp below.
269a03642ad2fce5805642783f68078a0a6bf03554Brian Salomonclass NonAARectOp : public GrMeshDrawOp {
279a03642ad2fce5805642783f68078a0a6bf03554Brian Salomonprotected:
289a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    using Helper = GrSimpleMeshDrawOpHelper;
299a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon
30eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipspublic:
31eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    DEFINE_OP_CLASS_ID
32eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    const char* name() const override { return "NonAARectOp"; }
33eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
34eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    // This creates an instance of a simple non-AA solid color rect-drawing Op
359a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& r) {
369a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        return Helper::FactoryHelper<NonAARectOp>(std::move(paint), r, nullptr, ClassID());
37eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
38eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
39eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    // This creates an instance of a simple non-AA textured rect-drawing Op
409a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkRect& r, const SkRect& local) {
419a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        return Helper::FactoryHelper<NonAARectOp>(std::move(paint), r, &local, ClassID());
42eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
43eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
44eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrColor color() const { return fColor; }
45eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
469a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    NonAARectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r,
479a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon                const SkRect* localRect, int32_t classID)
489a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon            : INHERITED(classID)
499a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon            , fColor(color)
509a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon            , fHasLocalRect(SkToBool(localRect))
519a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon            , fRect(r)
529a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon            , fHelper(helperArgs, GrAAType::kNone) {
539a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        if (fHasLocalRect) {
549a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon            fLocalQuad.set(*localRect);
559a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        }
56eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // Choose some conservative values for aa bloat and zero area.
57eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        this->setBounds(r, HasAABloat::kYes, IsZeroArea::kYes);
58eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
59eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
609a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
619a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon
629a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip*) override {
639a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        // Set the color to unknown because the subclass may change the color later.
649a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        GrProcessorAnalysisColor gpColor;
659a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        gpColor.setToUnknown();
669a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        // We ignore the clip so pass this rather than the GrAppliedClip param.
679a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        static GrAppliedClip kNoClip;
689a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        return fHelper.xpRequiresDstTexture(caps, &kNoClip, GrProcessorAnalysisCoverage::kNone,
699a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon                                            &gpColor);
70eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
71eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
729a03642ad2fce5805642783f68078a0a6bf03554Brian Salomonprotected:
73eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrColor fColor;
74eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bool    fHasLocalRect;
75eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrQuad  fLocalQuad;
76eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    SkRect  fRect;
77eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
78eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipsprivate:
79eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
80eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
81eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    void onPrepareDraws(Target* target) const override {
82eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        using namespace GrDefaultGeoProcFactory;
83eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
84eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // The vertex attrib order is always pos, color, local coords.
85eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        static const int kColorOffset = sizeof(SkPoint);
86eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
87eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
88eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        sk_sp<GrGeometryProcessor> gp =
89eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
90eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                              Coverage::kSolid_Type,
91eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                              fHasLocalRect ? LocalCoords::kHasExplicit_Type
92eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                            : LocalCoords::kUnused_Type,
93eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                              SkMatrix::I());
94eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        if (!gp) {
95eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n");
96eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            return;
97eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        }
98eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
99eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        size_t vertexStride = gp->getVertexStride();
100eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
101eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkASSERT(fHasLocalRect
102eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                    ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
103eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                    : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
104eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
105eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        const GrBuffer* indexBuffer;
106eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        int firstIndex;
107eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex);
108eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        if (!indices) {
109eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            SkDebugf("Indices could not be allocated for GrAtlasedOp.\n");
110eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            return;
111eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        }
112eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
113eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        const GrBuffer* vertexBuffer;
114eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        int firstVertex;
115eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex);
116eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        if (!vertices) {
117eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n");
118eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            return;
119eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        }
120eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
121eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // Setup indices
122eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        indices[0] = 0;
123eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        indices[1] = 1;
124eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        indices[2] = 2;
125eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        indices[3] = 0;
126eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        indices[4] = 2;
127eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        indices[5] = 3;
128eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
129eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // Setup positions
130eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkPoint* position = (SkPoint*) vertices;
131eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        position->setRectFan(fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom, vertexStride);
132eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
133eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // Setup vertex colors
134eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset);
135eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        for (int i = 0; i < 4; ++i) {
136eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            *color = fColor;
137eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            color = (GrColor*)((intptr_t)color + vertexStride);
138eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        }
139eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
140eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // Setup local coords
141eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        if (fHasLocalRect) {
142eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset);
143eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            for (int i = 0; i < 4; i++) {
144eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                *coords = fLocalQuad.point(i);
145eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                coords = (SkPoint*)((intptr_t) coords + vertexStride);
146eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            }
147eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        }
148eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
1493809bab7ed344ad140346c38e149dabf10bd525fChris Dalton        GrMesh mesh(GrPrimitiveType::kTriangles);
150114a3c0b2b26c84b9d0907a99fd8ab7938631246Chris Dalton        mesh.setIndexed(indexBuffer, 6, firstIndex, 0, 3);
151114a3c0b2b26c84b9d0907a99fd8ab7938631246Chris Dalton        mesh.setVertexData(vertexBuffer, firstVertex);
152eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
1539a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        target->draw(gp.get(), fHelper.makePipeline(target), mesh);
154eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
155eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
1569a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    Helper fHelper;
1579a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon
1589a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    typedef GrMeshDrawOp INHERITED;
159eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips};
160eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
1619a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon}  // anonymous namespace
1629a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon
163eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#ifdef SK_DEBUG
164eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#include "SkImageEncoder.h"
165eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#include "sk_tool_utils.h"
166eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
167eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipsstatic void save_bm(const SkBitmap& bm, const char name[]) {
168eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bool result = sk_tool_utils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100);
169eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    SkASSERT(result);
170eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips}
171eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#endif
172eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
1739a03642ad2fce5805642783f68078a0a6bf03554Brian Salomonstatic constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
1749a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon
1759a03642ad2fce5805642783f68078a0a6bf03554Brian Salomonnamespace {
1769a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon
177eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips/*
178eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips * Atlased ops just draw themselves as textured rects with the texture pixels being
179eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips * pulled out of the atlas. Their color is based on their ID.
180eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips */
181eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipsclass AtlasedRectOp final : public NonAARectOp {
182eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipspublic:
183eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    DEFINE_OP_CLASS_ID
184eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
185eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    ~AtlasedRectOp() override {
186eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        fID = -1;
187eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
188eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
189eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    const char* name() const override { return "AtlasedRectOp"; }
190eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
191eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    int id() const { return fID; }
192eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
1939a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    static std::unique_ptr<AtlasedRectOp> Make(GrPaint&& paint, const SkRect& r, int id) {
1949a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        GrDrawOp* op = Helper::FactoryHelper<AtlasedRectOp>(std::move(paint), r, id).release();
1959a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        return std::unique_ptr<AtlasedRectOp>(static_cast<AtlasedRectOp*>(op));
1969a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    }
1979a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon
1989a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    // We set the initial color of the NonAARectOp based on the ID.
1999a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    // Note that we force creation of a NonAARectOp that has local coords in anticipation of
2009a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    // pulling from the atlas.
2019a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon    AtlasedRectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkRect& r, int id)
2029a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon            : INHERITED(helperArgs, kColors[id], r, &kEmptyRect, ClassID())
2039a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon            , fID(id)
2049a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon            , fNext(nullptr) {
2059a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        SkASSERT(fID < kMaxIDs);
206eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
207eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
208eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    void setColor(GrColor color) { fColor = color; }
209eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    void setLocalRect(const SkRect& localRect) {
210eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkASSERT(fHasLocalRect);    // This should've been created to anticipate this
211eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        fLocalQuad.set(localRect);
212eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
213eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
214eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    AtlasedRectOp* next() const { return fNext; }
215eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    void setNext(AtlasedRectOp* next) {
216eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        fNext = next;
217eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
218eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
219eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipsprivate:
220eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
221eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    static const int kMaxIDs = 9;
222eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    static const SkColor kColors[kMaxIDs];
223eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
224eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    int            fID;
225eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    // The Atlased ops have an internal singly-linked list of ops that land in the same opList
226eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    AtlasedRectOp* fNext;
227eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
228eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    typedef NonAARectOp INHERITED;
229eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips};
230eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
2319a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon}  // anonymous namespace
2329a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon
233eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipsconst GrColor AtlasedRectOp::kColors[kMaxIDs] = {
234eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrColorPackRGBA(255, 0, 0, 255),
235eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrColorPackRGBA(0, 255, 0, 255),
236eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrColorPackRGBA(0, 0, 255, 255),
237eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrColorPackRGBA(0, 255, 255, 255),
238eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrColorPackRGBA(255, 0, 255, 255),
239eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrColorPackRGBA(255, 255, 0, 255),
240eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrColorPackRGBA(0, 0, 0, 255),
241eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrColorPackRGBA(128, 128, 128, 255),
242eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrColorPackRGBA(255, 255, 255, 255)
243eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips};
244eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
245eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipsstatic const int kDrawnTileSize = 16;
246eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
247eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips/*
248eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips * Rather than performing any rect packing, this atlaser just lays out constant-sized
249eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips * tiles in an Nx1 row
250eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips */
251eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipsstatic const int kAtlasTileSize = 2;
252eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
253eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips/*
254eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips * This class aggregates the op information required for atlasing
255eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips */
256fe199b7d512a7cfc56deaaa134260e1d47a1e7e0Chris Daltonclass AtlasObject final : public GrOnFlushCallbackObject {
257eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipspublic:
258eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    AtlasObject() : fDone(false) { }
259eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
260eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    ~AtlasObject() override {
261eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkASSERT(fDone);
262eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
263eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
264eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    void markAsDone() {
265eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        fDone = true;
266eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
267eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
268eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    // Insert the new op in an internal singly-linked list for 'opListID'
269eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    void addOp(uint32_t opListID, AtlasedRectOp* op) {
270eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        LinkedListHeader* header = nullptr;
271eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        for (int i = 0; i < fOps.count(); ++i) {
272eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            if (opListID == fOps[i].fID) {
273eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                header = &(fOps[i]);
274eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            }
275eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        }
276eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
277eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        if (!header) {
278eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            fOps.push({opListID, nullptr});
279eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            header = &(fOps[fOps.count()-1]);
280eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        }
281eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
282eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        op->setNext(header->fHead);
283eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        header->fHead = op;
284eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
285eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
286eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    // For the time being we need to pre-allocate the atlas.
287eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    void setAtlasDest(sk_sp<GrTextureProxy> atlasDest) {
288eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        fAtlasDest = atlasDest;
289eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
290eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
291eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    void saveRTC(sk_sp<GrRenderTargetContext> rtc) {
292eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkASSERT(!fRTC);
293eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        fRTC = rtc;
294eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
295eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
296eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#ifdef SK_DEBUG
297eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    void saveAtlasToDisk() {
298eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkBitmap readBack;
299eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        readBack.allocN32Pixels(fRTC->width(), fRTC->height());
300eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
301eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        bool result = fRTC->readPixels(readBack.info(),
302eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                       readBack.getPixels(), readBack.rowBytes(), 0, 0);
303eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkASSERT(result);
304eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        save_bm(readBack, "atlas-real.png");
305eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
306eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#endif
307eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
308eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    /*
309eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips     * This callback back creates the atlas and updates the AtlasedRectOps to read from it
310eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips     */
311fe199b7d512a7cfc56deaaa134260e1d47a1e7e0Chris Dalton    void preFlush(GrOnFlushResourceProvider* resourceProvider,
312eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                  const uint32_t* opListIDs, int numOpListIDs,
313eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                  SkTArray<sk_sp<GrRenderTargetContext>>* results) override {
314eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkASSERT(!results->count());
315eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
316eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // Until MDB is landed we will most-likely only have one opList.
317eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkTDArray<LinkedListHeader*> lists;
318eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        for (int i = 0; i < numOpListIDs; ++i) {
319eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            if (LinkedListHeader* list = this->getList(opListIDs[i])) {
320eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                lists.push(list);
321eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            }
322eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        }
323eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
324eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        if (!lists.count()) {
325eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            return; // nothing to atlas
326eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        }
327eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
328eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // TODO: right now we have to pre-allocate the atlas bc the TextureSamplers need a
329eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // hard GrTexture
330eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#if 0
331eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        GrSurfaceDesc desc;
332eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        desc.fFlags = kRenderTarget_GrSurfaceFlag;
333eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        desc.fWidth = this->numOps() * kAtlasTileSize;
334eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        desc.fHeight = kAtlasTileSize;
335eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        desc.fConfig = kRGBA_8888_GrPixelConfig;
336eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
337eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(desc,
338eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                                     nullptr,
339eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                                     nullptr);
340eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#else
341eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // At this point all the GrAtlasedOp's should have lined up to read from 'atlasDest' and
342eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // there should either be two writes to clear it or no writes.
343eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkASSERT(9 == fAtlasDest->getPendingReadCnt_TestOnly());
344eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkASSERT(2 == fAtlasDest->getPendingWriteCnt_TestOnly() ||
345eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                 0 == fAtlasDest->getPendingWriteCnt_TestOnly());
346eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(
347eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                           fAtlasDest,
348eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                           nullptr, nullptr);
349eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#endif
350eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
351eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        rtc->clear(nullptr, 0xFFFFFFFF, true); // clear the atlas
352eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
353eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        int blocksInAtlas = 0;
354eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        for (int i = 0; i < lists.count(); ++i) {
355eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) {
356eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0,
357eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                              kAtlasTileSize, kAtlasTileSize);
358eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
359eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                // For now, we avoid the resource buffer issues and just use clears
360eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#if 1
361eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                rtc->clear(&r, op->color(), false);
362eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#else
363eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                GrPaint paint;
3649a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon                paint.setColor4f(GrColor4f::FromGrColor(op->color()));
3659a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon                std::unique_ptr<GrDrawOp> drawOp(NonAARectOp::Make(std::move(paint),
3669a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon                                                                   SkRect::Make(r)));
3679a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon                rtc->priv().testingOnly_addDrawOp(std::move(drawOp));
368eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#endif
369eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                blocksInAtlas++;
370eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
371eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                // Set the atlased Op's color to white (so we know we're not using it for
372eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                // the final draw).
373eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                op->setColor(0xFFFFFFFF);
374eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
375eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                // Set the atlased Op's localRect to point to where it landed in the atlas
376eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                op->setLocalRect(SkRect::Make(r));
377eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
378eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                // TODO: we also need to set the op's GrSuperDeferredSimpleTextureEffect to point
379eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                // to the rtc's proxy!
380eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            }
381eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
382eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            // We've updated all these ops and we certainly don't want to process them again
383eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            this->clearOpsFor(lists[i]);
384eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        }
385eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
386eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // Hide a ref to the RTC in AtlasData so we can check on it later
387eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        this->saveRTC(rtc);
388eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
389eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        results->push_back(std::move(rtc));
390eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
391eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
392eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipsprivate:
393eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    typedef struct {
394eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        uint32_t       fID;
395eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        AtlasedRectOp* fHead;
396eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    } LinkedListHeader;
397eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
398eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    LinkedListHeader* getList(uint32_t opListID) {
399eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        for (int i = 0; i < fOps.count(); ++i) {
400eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            if (opListID == fOps[i].fID) {
401eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                return &(fOps[i]);
402eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips            }
403eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        }
404eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        return nullptr;
405eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
406eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
407eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    void clearOpsFor(LinkedListHeader* header) {
408eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just
409eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // forget about them in the laziest way possible.
410eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        header->fHead = nullptr;
411eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        header->fID = 0;            // invalid opList ID
412eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
413eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
414eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    // Each opList containing AtlasedRectOps gets its own internal singly-linked list
415eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    SkTDArray<LinkedListHeader>  fOps;
416eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
417eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    // The RTC used to create the atlas
418eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    sk_sp<GrRenderTargetContext> fRTC;
419eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
420eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    // For the time being we need to pre-allocate the atlas bc the TextureSamplers require
421eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    // a GrTexture
422eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    sk_sp<GrTextureProxy>        fAtlasDest;
423eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
424eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    // Set to true when the testing harness expects this object to be no longer used
425eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bool                         fDone;
426eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips};
427eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
428eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips// This creates an off-screen rendertarget whose ops which eventually pull from the atlas.
429eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipsstatic sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start,
430eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                 sk_sp<GrTextureProxy> fakeAtlas) {
431dd3b3f41829d32d7eaf3eb4903570d49c2ba9ff8Robert Phillips    sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContext(
432dd3b3f41829d32d7eaf3eb4903570d49c2ba9ff8Robert Phillips                                                                      SkBackingFit::kApprox,
433eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                      3*kDrawnTileSize,
434eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                      kDrawnTileSize,
435eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                      kRGBA_8888_GrPixelConfig,
436eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                      nullptr));
437eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
438eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    rtc->clear(nullptr, GrColorPackRGBA(255, 0, 0, 255), true);
439eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
440eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    for (int i = 0; i < 3; ++i) {
441eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize);
442eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
443eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // TODO: here is the blocker for deferring creation of the atlas. The TextureSamplers
444eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // created here currently require a hard GrTexture.
445fbcef6eb8abad142daf45418516550f7635b4a52Robert Phillips        sk_sp<GrFragmentProcessor> fp = GrSimpleTextureEffect::Make(fakeAtlas,
446eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                    nullptr, SkMatrix::I());
447eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        GrPaint paint;
448eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        paint.addColorFragmentProcessor(std::move(fp));
449eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
4509a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(std::move(paint), r, start + i));
451eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
452eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        AtlasedRectOp* sparePtr = op.get();
453eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
4549a03642ad2fce5805642783f68078a0a6bf03554Brian Salomon        uint32_t opListID = rtc->priv().testingOnly_addDrawOp(std::move(op));
455eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
456eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        object->addOp(opListID, sparePtr);
457eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
458eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
459eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    return rtc->asTextureProxyRef();
460eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips}
461eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
462eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips// Enable this if you want to debug the final draws w/o having the atlasCallback create the
463eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips// atlas
464eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#if 0
465eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#include "SkGrPriv.h"
466eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
467eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipssk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
468eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    SkBitmap bm;
469eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bm.allocN32Pixels(18, 2, true);
470eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bm.erase(SK_ColorRED,     SkIRect::MakeXYWH(0, 0, 2, 2));
471eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bm.erase(SK_ColorGREEN,   SkIRect::MakeXYWH(2, 0, 2, 2));
472eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bm.erase(SK_ColorBLUE,    SkIRect::MakeXYWH(4, 0, 2, 2));
473eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bm.erase(SK_ColorCYAN,    SkIRect::MakeXYWH(6, 0, 2, 2));
474eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2));
475eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bm.erase(SK_ColorYELLOW,  SkIRect::MakeXYWH(10, 0, 2, 2));
476eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bm.erase(SK_ColorBLACK,   SkIRect::MakeXYWH(12, 0, 2, 2));
477eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bm.erase(SK_ColorGRAY,    SkIRect::MakeXYWH(14, 0, 2, 2));
478eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    bm.erase(SK_ColorWHITE,   SkIRect::MakeXYWH(16, 0, 2, 2));
479eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
480eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#if 1
481eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    save_bm(bm, "atlas-fake.png");
482eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#endif
483eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
484eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info(), *context->caps());
485eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    desc.fFlags |= kRenderTarget_GrSurfaceFlag;
486eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
487eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(),
488eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                             context->textureProvider(),
489eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                             desc, SkBudgeted::kYes,
490eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                             bm.getPixels(), bm.rowBytes());
491eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
492eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    return sk_ref_sp(tmp->asTextureProxy());
493eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips}
494eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#else
495eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips// TODO: this is unfortunate and must be removed. We want the atlas to be created later.
496eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipssk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) {
497eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrSurfaceDesc desc;
498eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    desc.fFlags = kRenderTarget_GrSurfaceFlag;
499eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    desc.fConfig = kSkia8888_GrPixelConfig;
500eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
501eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    desc.fWidth = 32;
502eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    desc.fHeight = 16;
503eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    sk_sp<GrSurfaceProxy> atlasDest = GrSurfaceProxy::MakeDeferred(
504eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                            context->resourceProvider(),
505eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                            desc, SkBackingFit::kExact,
506eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                            SkBudgeted::kYes,
507eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                            GrResourceProvider::kNoPendingIO_Flag);
508eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    return sk_ref_sp(atlasDest->asTextureProxy());
509eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips}
510eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#endif
511eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
512eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillipsstatic void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) {
513eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    SkColor readback = bm.getColor(x, kDrawnTileSize/2);
514eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    REPORTER_ASSERT(reporter, expected == readback);
515eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    if (expected != readback) {
516eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkDebugf("Color mismatch: %x %x\n", expected, readback);
517eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
518eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips}
519eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
520eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips/*
521eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips * For the atlasing test we make a DAG that looks like:
522eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips *
523eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips *    RT1 with ops: 0,1,2       RT2 with ops: 3,4,5       RT3 with ops: 6,7,8
524eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips *                     \         /
525eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips *                      \       /
526eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips *                         RT4
527eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips * We then flush RT4 and expect only ops 0-5 to be atlased together.
528eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips * Each op is just a solid colored rect so both the atlas and the final image should appear as:
529eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips *           R G B C M Y
530eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize.
531eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips *
532eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips * Note: until MDB lands, the atlas will actually have width= 9*kAtlasTileSize and look like:
533eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips *           R G B C M Y K Grey White
534eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips */
535fe199b7d512a7cfc56deaaa134260e1d47a1e7e0Chris DaltonDEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
536eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    static const int kNumProxies = 3;
537eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
538eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    GrContext* context = ctxInfo.grContext();
539eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
540eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    if (context->caps()->useDrawInsteadOfClear()) {
541eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        // TODO: fix the buffer issues so this can run on all devices
542eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        return;
543eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
544eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
545fe199b7d512a7cfc56deaaa134260e1d47a1e7e0Chris Dalton    AtlasObject object;
546eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
547eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    // For now (until we add a GrSuperDeferredSimpleTextureEffect), we create the final atlas
548eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    // proxy ahead of time.
549eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    sk_sp<GrTextureProxy> atlasDest = pre_create_atlas(context);
550eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
551fe199b7d512a7cfc56deaaa134260e1d47a1e7e0Chris Dalton    object.setAtlasDest(atlasDest);
552eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
553fe199b7d512a7cfc56deaaa134260e1d47a1e7e0Chris Dalton    context->contextPriv().addOnFlushCallbackObject(&object);
554eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
555eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    sk_sp<GrTextureProxy> proxies[kNumProxies];
556eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    for (int i = 0; i < kNumProxies; ++i) {
557fe199b7d512a7cfc56deaaa134260e1d47a1e7e0Chris Dalton        proxies[i] = make_upstream_image(context, &object, i*3, atlasDest);
558eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
559eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
560eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    static const int kFinalWidth = 6*kDrawnTileSize;
561eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    static const int kFinalHeight = kDrawnTileSize;
562eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
563dd3b3f41829d32d7eaf3eb4903570d49c2ba9ff8Robert Phillips    sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContext(
564dd3b3f41829d32d7eaf3eb4903570d49c2ba9ff8Robert Phillips                                                                      SkBackingFit::kApprox,
565eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                      kFinalWidth,
566eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                      kFinalHeight,
567eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                      kRGBA_8888_GrPixelConfig,
568eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                      nullptr));
569eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
570eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    rtc->clear(nullptr, 0xFFFFFFFF, true);
571eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
572eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    // Note that this doesn't include the third texture proxy
573eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    for (int i = 0; i < kNumProxies-1; ++i) {
574eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize);
575eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
576eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0);
577eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
578eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        GrPaint paint;
579fbcef6eb8abad142daf45418516550f7635b4a52Robert Phillips        sk_sp<GrFragmentProcessor> fp(GrSimpleTextureEffect::Make(std::move(proxies[i]),
580eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                                                  nullptr, t));
581eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
582eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        paint.addColorFragmentProcessor(std::move(fp));
583eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
584eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips        rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
585eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    }
586eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
587a5cb781c17c09e01655defd0a84b431996b6a015Greg Daniel    rtc->prepareForExternalIO(0, nullptr);
588eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
589eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    SkBitmap readBack;
590eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
591eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
592eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(),
593eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips                                               readBack.rowBytes(), 0, 0);
594eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    SkASSERT(result);
595eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
596fe199b7d512a7cfc56deaaa134260e1d47a1e7e0Chris Dalton    context->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);
597fe199b7d512a7cfc56deaaa134260e1d47a1e7e0Chris Dalton
598fe199b7d512a7cfc56deaaa134260e1d47a1e7e0Chris Dalton    object.markAsDone();
599eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
600eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#if 0
601eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    save_bm(readBack, "atlas-final-image.png");
602eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    data.saveAtlasToDisk();
603eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#endif
604eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
605eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    int x = kDrawnTileSize/2;
606eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    test_color(reporter, readBack, x, SK_ColorRED);
607eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    x += kDrawnTileSize;
608eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    test_color(reporter, readBack, x, SK_ColorGREEN);
609eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    x += kDrawnTileSize;
610eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    test_color(reporter, readBack, x, SK_ColorBLUE);
611eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    x += kDrawnTileSize;
612eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    test_color(reporter, readBack, x, SK_ColorCYAN);
613eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    x += kDrawnTileSize;
614eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    test_color(reporter, readBack, x, SK_ColorMAGENTA);
615eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    x += kDrawnTileSize;
616eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips    test_color(reporter, readBack, x, SK_ColorYELLOW);
617eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips}
618eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips
619eb35f4dfaa10b9d751abbc9a1406456eb3b1649dRobert Phillips#endif
620