1/* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "GrDrawAtlasOp.h" 9#include "GrDrawOpTest.h" 10#include "GrOpFlushState.h" 11#include "SkGr.h" 12#include "SkRSXform.h" 13#include "SkRandom.h" 14 15void GrDrawAtlasOp::applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) { 16 SkASSERT(fGeoData.count() == 1); 17 if (optimizations.getOverrideColorIfSet(&fGeoData[0].fColor) && fHasColors) { 18 size_t vertexStride = 19 sizeof(SkPoint) + sizeof(SkPoint) + (this->hasColors() ? sizeof(GrColor) : 0); 20 uint8_t* currVertex = fGeoData[0].fVerts.begin(); 21 for (int i = 0; i < 4 * fQuadCount; ++i) { 22 *(reinterpret_cast<GrColor*>(currVertex + sizeof(SkPoint))) = fGeoData[0].fColor; 23 currVertex += vertexStride; 24 } 25 } 26 27 fColor = fGeoData[0].fColor; 28 // We'd like to assert this, but we can't because of GLPrograms test 29 // SkASSERT(init.readsLocalCoords()); 30} 31 32static sk_sp<GrGeometryProcessor> make_gp(bool hasColors, 33 GrColor color, 34 const SkMatrix& viewMatrix) { 35 using namespace GrDefaultGeoProcFactory; 36 Color gpColor(color); 37 if (hasColors) { 38 gpColor.fType = Color::kPremulGrColorAttribute_Type; 39 } 40 41 return GrDefaultGeoProcFactory::Make(gpColor, Coverage::kSolid_Type, 42 LocalCoords::kHasExplicit_Type, viewMatrix); 43} 44 45void GrDrawAtlasOp::onPrepareDraws(Target* target) const { 46 // Setup geometry processor 47 sk_sp<GrGeometryProcessor> gp(make_gp(this->hasColors(), this->color(), this->viewMatrix())); 48 49 int instanceCount = fGeoData.count(); 50 size_t vertexStride = gp->getVertexStride(); 51 SkASSERT(vertexStride == 52 sizeof(SkPoint) + sizeof(SkPoint) + (this->hasColors() ? sizeof(GrColor) : 0)); 53 54 QuadHelper helper; 55 int numQuads = this->quadCount(); 56 void* verts = helper.init(target, vertexStride, numQuads); 57 if (!verts) { 58 SkDebugf("Could not allocate vertices\n"); 59 return; 60 } 61 62 uint8_t* vertPtr = reinterpret_cast<uint8_t*>(verts); 63 for (int i = 0; i < instanceCount; i++) { 64 const Geometry& args = fGeoData[i]; 65 66 size_t allocSize = args.fVerts.count(); 67 memcpy(vertPtr, args.fVerts.begin(), allocSize); 68 vertPtr += allocSize; 69 } 70 helper.recordDraw(target, gp.get()); 71} 72 73GrDrawAtlasOp::GrDrawAtlasOp(GrColor color, const SkMatrix& viewMatrix, int spriteCount, 74 const SkRSXform* xforms, const SkRect* rects, const SkColor* colors) 75 : INHERITED(ClassID()) { 76 SkASSERT(xforms); 77 SkASSERT(rects); 78 79 fViewMatrix = viewMatrix; 80 Geometry& installedGeo = fGeoData.push_back(); 81 installedGeo.fColor = color; 82 83 // Figure out stride and offsets 84 // Order within the vertex is: position [color] texCoord 85 size_t texOffset = sizeof(SkPoint); 86 size_t vertexStride = 2 * sizeof(SkPoint); 87 fHasColors = SkToBool(colors); 88 if (colors) { 89 texOffset += sizeof(GrColor); 90 vertexStride += sizeof(GrColor); 91 } 92 93 // Compute buffer size and alloc buffer 94 fQuadCount = spriteCount; 95 int allocSize = static_cast<int>(4 * vertexStride * spriteCount); 96 installedGeo.fVerts.reset(allocSize); 97 uint8_t* currVertex = installedGeo.fVerts.begin(); 98 99 SkRect bounds; 100 bounds.setLargestInverted(); 101 int paintAlpha = GrColorUnpackA(installedGeo.fColor); 102 for (int spriteIndex = 0; spriteIndex < spriteCount; ++spriteIndex) { 103 // Transform rect 104 SkPoint quad[4]; 105 const SkRect& currRect = rects[spriteIndex]; 106 xforms[spriteIndex].toQuad(currRect.width(), currRect.height(), quad); 107 108 // Copy colors if necessary 109 if (colors) { 110 // convert to GrColor 111 SkColor color = colors[spriteIndex]; 112 if (paintAlpha != 255) { 113 color = SkColorSetA(color, SkMulDiv255Round(SkColorGetA(color), paintAlpha)); 114 } 115 GrColor grColor = SkColorToPremulGrColor(color); 116 117 *(reinterpret_cast<GrColor*>(currVertex + sizeof(SkPoint))) = grColor; 118 *(reinterpret_cast<GrColor*>(currVertex + vertexStride + sizeof(SkPoint))) = grColor; 119 *(reinterpret_cast<GrColor*>(currVertex + 2 * vertexStride + sizeof(SkPoint))) = 120 grColor; 121 *(reinterpret_cast<GrColor*>(currVertex + 3 * vertexStride + sizeof(SkPoint))) = 122 grColor; 123 } 124 125 // Copy position and uv to verts 126 *(reinterpret_cast<SkPoint*>(currVertex)) = quad[0]; 127 *(reinterpret_cast<SkPoint*>(currVertex + texOffset)) = 128 SkPoint::Make(currRect.fLeft, currRect.fTop); 129 bounds.growToInclude(quad[0].fX, quad[0].fY); 130 currVertex += vertexStride; 131 132 *(reinterpret_cast<SkPoint*>(currVertex)) = quad[1]; 133 *(reinterpret_cast<SkPoint*>(currVertex + texOffset)) = 134 SkPoint::Make(currRect.fRight, currRect.fTop); 135 bounds.growToInclude(quad[1].fX, quad[1].fY); 136 currVertex += vertexStride; 137 138 *(reinterpret_cast<SkPoint*>(currVertex)) = quad[2]; 139 *(reinterpret_cast<SkPoint*>(currVertex + texOffset)) = 140 SkPoint::Make(currRect.fRight, currRect.fBottom); 141 bounds.growToInclude(quad[2].fX, quad[2].fY); 142 currVertex += vertexStride; 143 144 *(reinterpret_cast<SkPoint*>(currVertex)) = quad[3]; 145 *(reinterpret_cast<SkPoint*>(currVertex + texOffset)) = 146 SkPoint::Make(currRect.fLeft, currRect.fBottom); 147 bounds.growToInclude(quad[3].fX, quad[3].fY); 148 currVertex += vertexStride; 149 } 150 151 this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); 152} 153 154bool GrDrawAtlasOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { 155 GrDrawAtlasOp* that = t->cast<GrDrawAtlasOp>(); 156 157 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), 158 that->bounds(), caps)) { 159 return false; 160 } 161 162 // We currently use a uniform viewmatrix for this op. 163 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { 164 return false; 165 } 166 167 if (this->hasColors() != that->hasColors()) { 168 return false; 169 } 170 171 if (!this->hasColors() && this->color() != that->color()) { 172 return false; 173 } 174 175 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); 176 fQuadCount += that->quadCount(); 177 178 this->joinBounds(*that); 179 return true; 180} 181 182#if GR_TEST_UTILS 183 184static SkRSXform random_xform(SkRandom* random) { 185 static const SkScalar kMinExtent = -100.f; 186 static const SkScalar kMaxExtent = 100.f; 187 static const SkScalar kMinScale = 0.1f; 188 static const SkScalar kMaxScale = 100.f; 189 static const SkScalar kMinRotate = -SK_ScalarPI; 190 static const SkScalar kMaxRotate = SK_ScalarPI; 191 192 SkRSXform xform = SkRSXform::MakeFromRadians(random->nextRangeScalar(kMinScale, kMaxScale), 193 random->nextRangeScalar(kMinRotate, kMaxRotate), 194 random->nextRangeScalar(kMinExtent, kMaxExtent), 195 random->nextRangeScalar(kMinExtent, kMaxExtent), 196 random->nextRangeScalar(kMinExtent, kMaxExtent), 197 random->nextRangeScalar(kMinExtent, kMaxExtent)); 198 return xform; 199} 200 201static SkRect random_texRect(SkRandom* random) { 202 static const SkScalar kMinCoord = 0.0f; 203 static const SkScalar kMaxCoord = 1024.f; 204 205 SkRect texRect = SkRect::MakeLTRB(random->nextRangeScalar(kMinCoord, kMaxCoord), 206 random->nextRangeScalar(kMinCoord, kMaxCoord), 207 random->nextRangeScalar(kMinCoord, kMaxCoord), 208 random->nextRangeScalar(kMinCoord, kMaxCoord)); 209 texRect.sort(); 210 return texRect; 211} 212 213static void randomize_params(uint32_t count, SkRandom* random, SkTArray<SkRSXform>* xforms, 214 SkTArray<SkRect>* texRects, SkTArray<GrColor>* colors, 215 bool hasColors) { 216 for (uint32_t v = 0; v < count; v++) { 217 xforms->push_back(random_xform(random)); 218 texRects->push_back(random_texRect(random)); 219 if (hasColors) { 220 colors->push_back(GrRandomColor(random)); 221 } 222 } 223} 224 225DRAW_OP_TEST_DEFINE(GrDrawAtlasOp) { 226 uint32_t spriteCount = random->nextRangeU(1, 100); 227 228 SkTArray<SkRSXform> xforms(spriteCount); 229 SkTArray<SkRect> texRects(spriteCount); 230 SkTArray<GrColor> colors; 231 232 bool hasColors = random->nextBool(); 233 234 randomize_params(spriteCount, random, &xforms, &texRects, &colors, hasColors); 235 236 SkMatrix viewMatrix = GrTest::TestMatrix(random); 237 238 GrColor color = GrRandomColor(random); 239 return GrDrawAtlasOp::Make(color, viewMatrix, spriteCount, xforms.begin(), texRects.begin(), 240 hasColors ? colors.begin() : nullptr); 241} 242 243#endif 244