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