static void tesselate(intptr_t vertices, size_t vertexStride, GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, const SkRect* localRect, const SkMatrix* localMatrix) { SkPoint* positions = reinterpret_cast<SkPoint*>(vertices); positions->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); viewMatrix.mapPointsWithStride(positions, vertexStride, BWFillRectBatchBase::kVertsPerInstance); // TODO we should only do this if local coords are being read if (localRect) { static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); SkPoint* coords = reinterpret_cast<SkPoint*>(vertices + kLocalOffset); coords->setRectFan(localRect->fLeft, localRect->fTop, localRect->fRight, localRect->fBottom, vertexStride); if (localMatrix) { localMatrix->mapPointsWithStride(coords, vertexStride, BWFillRectBatchBase::kVertsPerInstance); } } static const int kColorOffset = sizeof(SkPoint); GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset); for (int j = 0; j < 4; ++j) { *vertColor = color; vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); } }
void onPrepareDraws(Target* target) override { SkAutoTUnref<const GrGeometryProcessor> gp(create_gp(fOverrides.readsCoverage())); if (!gp) { SkDebugf("Couldn't create GrGeometryProcessor\n"); return; } target->initDraw(gp, this->pipeline()); size_t vertexStride = gp->getVertexStride(); int instanceCount = fGeoData.count(); SkAutoTUnref<const GrIndexBuffer> indexBuffer( target->resourceProvider()->refQuadIndexBuffer()); InstancedHelper helper; void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer, kVertsPerRect, kIndicesPerRect, instanceCount * kRectsPerInstance); if (!vertices || !indexBuffer) { SkDebugf("Could not allocate vertices\n"); return; } for (int i = 0; i < instanceCount; i++) { intptr_t verts = reinterpret_cast<intptr_t>(vertices) + i * kRectsPerInstance * kVertsPerRect * vertexStride; Geometry& geo = fGeoData[i]; SkNinePatchIter iter(fImageWidth, fImageHeight, geo.fCenter, geo.fDst); SkRect srcR, dstR; while (iter.next(&srcR, &dstR)) { SkPoint* positions = reinterpret_cast<SkPoint*>(verts); positions->setRectFan(dstR.fLeft, dstR.fTop, dstR.fRight, dstR.fBottom, vertexStride); SkASSERT(!geo.fViewMatrix.hasPerspective()); geo.fViewMatrix.mapPointsWithStride(positions, vertexStride, kVertsPerRect); // Setup local coords static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); SkPoint* coords = reinterpret_cast<SkPoint*>(verts + kLocalOffset); coords->setRectFan(srcR.fLeft, srcR.fTop, srcR.fRight, srcR.fBottom, vertexStride); static const int kColorOffset = sizeof(SkPoint); GrColor* vertColor = reinterpret_cast<GrColor*>(verts + kColorOffset); for (int j = 0; j < 4; ++j) { *vertColor = geo.fColor; vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); } verts += kVertsPerRect * vertexStride; } } helper.recordDraw(target); }
void generateGeometry(GrBatchTarget* batchTarget) override { SkAutoTUnref<const GrGeometryProcessor> gp(this->createRectGP()); if (!gp) { SkDebugf("Could not create GrGeometryProcessor\n"); return; } batchTarget->initDraw(gp, this->pipeline()); int instanceCount = fGeoData.count(); size_t vertexStride = gp->getVertexStride(); SkASSERT(this->hasLocalRect() ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)); QuadHelper helper; void* vertices = helper.init(batchTarget, vertexStride, instanceCount); if (!vertices) { return; } for (int i = 0; i < instanceCount; i++) { const Geometry& geom = fGeoData[i]; intptr_t offset = reinterpret_cast<intptr_t>(vertices) + kVerticesPerQuad * i * vertexStride; SkPoint* positions = reinterpret_cast<SkPoint*>(offset); positions->setRectFan(geom.fRect.fLeft, geom.fRect.fTop, geom.fRect.fRight, geom.fRect.fBottom, vertexStride); geom.fViewMatrix.mapPointsWithStride(positions, vertexStride, kVerticesPerQuad); // TODO we should only do this if local coords are being read if (geom.fHasLocalRect) { static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); SkPoint* coords = reinterpret_cast<SkPoint*>(offset + kLocalOffset); coords->setRectFan(geom.fLocalRect.fLeft, geom.fLocalRect.fTop, geom.fLocalRect.fRight, geom.fLocalRect.fBottom, vertexStride); if (geom.fHasLocalMatrix) { geom.fLocalMatrix.mapPointsWithStride(coords, vertexStride, kVerticesPerQuad); } } static const int kColorOffset = sizeof(SkPoint); GrColor* vertColor = reinterpret_cast<GrColor*>(offset + kColorOffset); for (int j = 0; j < 4; ++j) { *vertColor = geom.fColor; vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); } } helper.issueDraw(batchTarget); }
void GrDrawTarget::onDrawRect(const SkRect& rect, const SkMatrix* matrix, const SkRect* localRect, const SkMatrix* localMatrix) { GrDrawState::AutoViewMatrixRestore avmr; if (NULL != matrix) { avmr.set(this->drawState(), *matrix); } set_vertex_attributes(this->drawState(), NULL != localRect); AutoReleaseGeometry geo(this, 4, 0); if (!geo.succeeded()) { GrPrintf("Failed to get space for vertices!\n"); return; } size_t vsize = this->drawState()->getVertexSize(); geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vsize); if (NULL != localRect) { SkPoint* coords = GrTCast<SkPoint*>(GrTCast<intptr_t>(geo.vertices()) + sizeof(SkPoint)); coords->setRectFan(localRect->fLeft, localRect->fTop, localRect->fRight, localRect->fBottom, vsize); if (NULL != localMatrix) { localMatrix->mapPointsWithStride(coords, vsize, 4); } } SkRect bounds; this->getDrawState().getViewMatrix().mapRect(&bounds, rect); this->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4, &bounds); }
void GrInOrderDrawBuffer::onDrawRect(const SkRect& rect, const SkRect* localRect, const SkMatrix* localMatrix) { GrDrawState* drawState = this->drawState(); GrColor color = drawState->getColor(); set_vertex_attributes(drawState, SkToBool(localRect), color); AutoReleaseGeometry geo(this, 4, 0); if (!geo.succeeded()) { SkDebugf("Failed to get space for vertices!\n"); return; } // Go to device coords to allow batching across matrix changes SkMatrix matrix = drawState->getViewMatrix(); // When the caller has provided an explicit source rect for a stage then we don't want to // modify that stage's matrix. Otherwise if the effect is generating its source rect from // the vertex positions then we have to account for the view matrix change. GrDrawState::AutoViewMatrixRestore avmr; if (!avmr.setIdentity(drawState)) { return; } size_t vstride = drawState->getVertexStride(); geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vstride); matrix.mapPointsWithStride(geo.positions(), vstride, 4); SkRect devBounds; // since we already computed the dev verts, set the bounds hint. This will help us avoid // unnecessary clipping in our onDraw(). get_vertex_bounds(geo.vertices(), vstride, 4, &devBounds); if (localRect) { static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); SkPoint* coords = GrTCast<SkPoint*>(GrTCast<intptr_t>(geo.vertices()) + kLocalOffset); coords->setRectFan(localRect->fLeft, localRect->fTop, localRect->fRight, localRect->fBottom, vstride); if (localMatrix) { localMatrix->mapPointsWithStride(coords, vstride, 4); } } static const int kColorOffset = sizeof(SkPoint); GrColor* vertColor = GrTCast<GrColor*>(GrTCast<intptr_t>(geo.vertices()) + kColorOffset); for (int i = 0; i < 4; ++i) { *vertColor = color; vertColor = (GrColor*) ((intptr_t) vertColor + vstride); } this->setIndexSourceToBuffer(this->getContext()->getQuadIndexBuffer()); this->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &devBounds); // to ensure that stashing the drawState ptr is valid SkASSERT(this->drawState() == drawState); }
static void tesselate(intptr_t vertices, size_t vertexStride, GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, const GrQuad* localQuad) { SkPoint* positions = reinterpret_cast<SkPoint*>(vertices); positions->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); if (!viewMatrix.hasPerspective()) { viewMatrix.mapPointsWithStride(positions, vertexStride, NonAAFillRectBatchBase::kVertsPerInstance); } // Setup local coords // TODO we should only do this if local coords are being read if (localQuad) { static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); for (int i = 0; i < NonAAFillRectBatchBase::kVertsPerInstance; i++) { SkPoint* coords = reinterpret_cast<SkPoint*>(vertices + kLocalOffset + i * vertexStride); *coords = localQuad->point(i); } } static const int kColorOffset = sizeof(SkPoint); GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset); for (int j = 0; j < 4; ++j) { *vertColor = color; vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); } }
void writePathVertices(GrDrawBatch::Target* target, GrBatchAtlas* atlas, intptr_t offset, GrColor color, size_t vertexStride, const SkMatrix& viewMatrix, const ShapeData* shapeData) const { GrTexture* texture = atlas->getTexture(); SkScalar dx = shapeData->fBounds.fLeft; SkScalar dy = shapeData->fBounds.fTop; SkScalar width = shapeData->fBounds.width(); SkScalar height = shapeData->fBounds.height(); SkScalar invScale = 1.0f / shapeData->fScale; dx *= invScale; dy *= invScale; width *= invScale; height *= invScale; SkPoint* positions = reinterpret_cast<SkPoint*>(offset); // vertex positions // TODO make the vertex attributes a struct SkRect r = SkRect::MakeXYWH(dx, dy, width, height); positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertexStride); // colors for (int i = 0; i < kVerticesPerQuad; i++) { GrColor* colorPtr = (GrColor*)(offset + sizeof(SkPoint) + i * vertexStride); *colorPtr = color; } const SkScalar tx = SkIntToScalar(shapeData->fAtlasLocation.fX); const SkScalar ty = SkIntToScalar(shapeData->fAtlasLocation.fY); // vertex texture coords SkPoint* textureCoords = (SkPoint*)(offset + sizeof(SkPoint) + sizeof(GrColor)); textureCoords->setRectFan(tx / texture->width(), ty / texture->height(), (tx + shapeData->fBounds.width()) / texture->width(), (ty + shapeData->fBounds.height()) / texture->height(), vertexStride); }
static void tesselate_region(intptr_t vertices, size_t vertexStride, GrColor color, const SkRegion& region) { SkRegion::Iterator iter(region); intptr_t verts = vertices; while (!iter.done()) { SkRect rect = SkRect::Make(iter.rect()); SkPoint* position = (SkPoint*) verts; position->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); static const int kColorOffset = sizeof(SkPoint); GrColor* vertColor = reinterpret_cast<GrColor*>(verts + kColorOffset); for (int i = 0; i < kVertsPerInstance; i++) { *vertColor = color; vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); } verts += vertexStride * kVertsPerInstance; iter.next(); } }
void GrInOrderDrawBuffer::onDrawRect(const SkRect& rect, const SkMatrix* matrix, const SkRect* localRect, const SkMatrix* localMatrix) { GrDrawState::AutoColorRestore acr; GrDrawState* drawState = this->drawState(); GrColor color = drawState->getColor(); int colorOffset, localOffset; set_vertex_attributes(drawState, this->caps()->dualSourceBlendingSupport() || drawState->hasSolidCoverage(), NULL != localRect, &colorOffset, &localOffset); if (colorOffset >= 0) { // We set the draw state's color to white here. This is done so that any batching performed // in our subclass's onDraw() won't get a false from GrDrawState::op== due to a color // mismatch. TODO: Once vertex layout is owned by GrDrawState it should skip comparing the // constant color in its op== when the kColor layout bit is set and then we can remove // this. acr.set(drawState, 0xFFFFFFFF); } AutoReleaseGeometry geo(this, 4, 0); if (!geo.succeeded()) { GrPrintf("Failed to get space for vertices!\n"); return; } // Go to device coords to allow batching across matrix changes SkMatrix combinedMatrix; if (NULL != matrix) { combinedMatrix = *matrix; } else { combinedMatrix.reset(); } combinedMatrix.postConcat(drawState->getViewMatrix()); // When the caller has provided an explicit source rect for a stage then we don't want to // modify that stage's matrix. Otherwise if the effect is generating its source rect from // the vertex positions then we have to account for the view matrix change. GrDrawState::AutoViewMatrixRestore avmr; if (!avmr.setIdentity(drawState)) { return; } size_t vsize = drawState->getVertexSize(); geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vsize); combinedMatrix.mapPointsWithStride(geo.positions(), vsize, 4); SkRect devBounds; // since we already computed the dev verts, set the bounds hint. This will help us avoid // unnecessary clipping in our onDraw(). get_vertex_bounds(geo.vertices(), vsize, 4, &devBounds); if (localOffset >= 0) { SkPoint* coords = GrTCast<SkPoint*>(GrTCast<intptr_t>(geo.vertices()) + localOffset); coords->setRectFan(localRect->fLeft, localRect->fTop, localRect->fRight, localRect->fBottom, vsize); if (NULL != localMatrix) { localMatrix->mapPointsWithStride(coords, vsize, 4); } } if (colorOffset >= 0) { GrColor* vertColor = GrTCast<GrColor*>(GrTCast<intptr_t>(geo.vertices()) + colorOffset); for (int i = 0; i < 4; ++i) { *vertColor = color; vertColor = (GrColor*) ((intptr_t) vertColor + vsize); } } this->setIndexSourceToBuffer(this->getContext()->getQuadIndexBuffer()); this->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &devBounds); // to ensure that stashing the drawState ptr is valid SkASSERT(this->drawState() == drawState); }
void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override { // Go to device coords to allow batching across matrix changes SkMatrix invert = SkMatrix::I(); // if we have a local rect, then we apply the localMatrix directly to the localRect to // generate vertex local coords bool hasExplicitLocalCoords = this->hasLocalRect(); if (!hasExplicitLocalCoords) { if (!this->viewMatrix().isIdentity() && !this->viewMatrix().invert(&invert)) { SkDebugf("Could not invert\n"); return; } if (this->hasLocalMatrix()) { invert.preConcat(this->localMatrix()); } } SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(hasExplicitLocalCoords, this->color(), &invert)); batchTarget->initDraw(gp, pipeline); // TODO this is hacky, but the only way we have to initialize the GP is to use the // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch // everywhere we can remove this nastiness GrPipelineInfo init; init.fColorIgnored = fBatch.fColorIgnored; init.fOverrideColor = GrColor_ILLEGAL; init.fCoverageIgnored = fBatch.fCoverageIgnored; init.fUsesLocalCoords = this->usesLocalCoords(); gp->initBatchTracker(batchTarget->currentBatchTracker(), init); size_t vertexStride = gp->getVertexStride(); SkASSERT(hasExplicitLocalCoords ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)); int instanceCount = fGeoData.count(); int vertexCount = kVertsPerRect * instanceCount; const GrVertexBuffer* vertexBuffer; int firstVertex; void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex); if (!vertices || !batchTarget->quadIndexBuffer()) { SkDebugf("Could not allocate buffers\n"); return; } for (int i = 0; i < instanceCount; i++) { const Geometry& args = fGeoData[i]; intptr_t offset = GrTCast<intptr_t>(vertices) + kVertsPerRect * i * vertexStride; SkPoint* positions = GrTCast<SkPoint*>(offset); positions->setRectFan(args.fRect.fLeft, args.fRect.fTop, args.fRect.fRight, args.fRect.fBottom, vertexStride); args.fViewMatrix.mapPointsWithStride(positions, vertexStride, kVertsPerRect); if (args.fHasLocalRect) { static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); SkPoint* coords = GrTCast<SkPoint*>(offset + kLocalOffset); coords->setRectFan(args.fLocalRect.fLeft, args.fLocalRect.fTop, args.fLocalRect.fRight, args.fLocalRect.fBottom, vertexStride); if (args.fHasLocalMatrix) { args.fLocalMatrix.mapPointsWithStride(coords, vertexStride, kVertsPerRect); } } static const int kColorOffset = sizeof(SkPoint); GrColor* vertColor = GrTCast<GrColor*>(offset + kColorOffset); for (int j = 0; j < 4; ++j) { *vertColor = args.fColor; vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); } } const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer(); GrDrawTarget::DrawInfo drawInfo; drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType); drawInfo.setStartVertex(0); drawInfo.setStartIndex(0); drawInfo.setVerticesPerInstance(kVertsPerRect); drawInfo.setIndicesPerInstance(kIndicesPerRect); drawInfo.adjustStartVertex(firstVertex); drawInfo.setVertexBuffer(vertexBuffer); drawInfo.setIndexBuffer(quadIndexBuffer); int maxInstancesPerDraw = quadIndexBuffer->maxQuads(); while (instanceCount) { drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw)); drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance()); drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance()); batchTarget->draw(drawInfo); drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount()); instanceCount -= drawInfo.instanceCount(); } }
// Returns true if this method handled the glyph, false if needs to be passed to fallback // bool GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed, SkScalar sx, SkScalar sy, GrFontScaler* scaler) { if (NULL == fDrawTarget) { return true; } if (NULL == fStrike) { fStrike = fContext->getFontCache()->getStrike(scaler, true); } GrGlyph* glyph = fStrike->getGlyph(packed, scaler); if (NULL == glyph || glyph->fBounds.isEmpty()) { return true; } // fallback to color glyph support if (kA8_GrMaskFormat != glyph->fMaskFormat) { return false; } SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset); SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset); SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset); SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset); SkScalar scale = fTextRatio; dx *= scale; dy *= scale; sx += dx; sy += dy; width *= scale; height *= scale; SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height); // check if we clipped out SkRect dstRect; const SkMatrix& ctm = fContext->getMatrix(); (void) ctm.mapRect(&dstRect, glyphRect); if (fClipRect.quickReject(SkScalarTruncToInt(dstRect.left()), SkScalarTruncToInt(dstRect.top()), SkScalarTruncToInt(dstRect.right()), SkScalarTruncToInt(dstRect.bottom()))) { // SkCLZ(3); // so we can set a break-point in the debugger return true; } if (NULL == glyph->fPlot) { if (!fStrike->glyphTooLargeForAtlas(glyph)) { if (fStrike->addGlyphToAtlas(glyph, scaler)) { goto HAS_ATLAS; } // try to clear out an unused plot before we flush if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) && fStrike->addGlyphToAtlas(glyph, scaler)) { goto HAS_ATLAS; } if (c_DumpFontCache) { #ifdef SK_DEVELOPER fContext->getFontCache()->dump(); #endif } // before we purge the cache, we must flush any accumulated draws this->flush(); fContext->flush(); // we should have an unused plot now if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) && fStrike->addGlyphToAtlas(glyph, scaler)) { goto HAS_ATLAS; } } if (NULL == glyph->fPath) { SkPath* path = SkNEW(SkPath); if (!scaler->getGlyphPath(glyph->glyphID(), path)) { // flag the glyph as being dead? delete path; return true; } glyph->fPath = path; } // flush any accumulated draws before drawing this glyph as a path. this->flush(); GrContext::AutoMatrix am; SkMatrix ctm; ctm.setScale(fTextRatio, fTextRatio); ctm.postTranslate(sx - dx, sy - dy); GrPaint tmpPaint(fPaint); am.setPreConcat(fContext, ctm, &tmpPaint); GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo); // remove this glyph from the vertices we need to allocate fTotalVertexCount -= kVerticesPerGlyph; return true; } HAS_ATLAS: SkASSERT(glyph->fPlot); GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken(); glyph->fPlot->setDrawToken(drawToken); GrTexture* texture = glyph->fPlot->texture(); SkASSERT(texture); if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fTotalVertexCount) { this->flush(); fCurrTexture = texture; fCurrTexture->ref(); } bool useColorVerts = !fUseLCDText; if (NULL == fVertices) { int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads(); fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices); fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, useColorVerts); } SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset); SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset); SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset); SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset); fVertexBounds.joinNonEmptyArg(glyphRect); size_t vertSize = get_vertex_stride(useColorVerts); SkPoint* positions = reinterpret_cast<SkPoint*>( reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex); positions->setRectFan(glyphRect.fLeft, glyphRect.fTop, glyphRect.fRight, glyphRect.fBottom, vertSize); // The texture coords are last in both the with and without color vertex layouts. SkPoint* textureCoords = reinterpret_cast<SkPoint*>( reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint)); textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)), SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)), SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + tw)), SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + th)), vertSize); if (useColorVerts) { // color comes after position. GrColor* colors = reinterpret_cast<GrColor*>(positions + 1); for (int i = 0; i < 4; ++i) { *colors = fPaint.getColor(); colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize); } } fCurrVertex += 4; return true; }
void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override { // Go to device coords to allow batching across matrix changes SkMatrix invert = SkMatrix::I(); // if we have a local rect, then we apply the localMatrix directly to the localRect to // generate vertex local coords bool hasExplicitLocalCoords = this->hasLocalRect(); if (!hasExplicitLocalCoords) { if (!this->viewMatrix().isIdentity() && !this->viewMatrix().invert(&invert)) { SkDebugf("Could not invert\n"); return; } if (this->hasLocalMatrix()) { invert.preConcat(this->localMatrix()); } } SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(hasExplicitLocalCoords, &invert, this->usesLocalCoords(), this->coverageIgnored())); batchTarget->initDraw(gp, pipeline); int instanceCount = fGeoData.count(); size_t vertexStride = gp->getVertexStride(); SkASSERT(hasExplicitLocalCoords ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)); QuadHelper helper; void* vertices = helper.init(batchTarget, vertexStride, instanceCount); if (!vertices) { return; } for (int i = 0; i < instanceCount; i++) { const Geometry& geom = fGeoData[i]; intptr_t offset = GrTCast<intptr_t>(vertices) + kVerticesPerQuad * i * vertexStride; SkPoint* positions = GrTCast<SkPoint*>(offset); positions->setRectFan(geom.fRect.fLeft, geom.fRect.fTop, geom.fRect.fRight, geom.fRect.fBottom, vertexStride); geom.fViewMatrix.mapPointsWithStride(positions, vertexStride, kVerticesPerQuad); if (geom.fHasLocalRect) { static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); SkPoint* coords = GrTCast<SkPoint*>(offset + kLocalOffset); coords->setRectFan(geom.fLocalRect.fLeft, geom.fLocalRect.fTop, geom.fLocalRect.fRight, geom.fLocalRect.fBottom, vertexStride); if (geom.fHasLocalMatrix) { geom.fLocalMatrix.mapPointsWithStride(coords, vertexStride, kVerticesPerQuad); } } static const int kColorOffset = sizeof(SkPoint); GrColor* vertColor = GrTCast<GrColor*>(offset + kColorOffset); for (int j = 0; j < 4; ++j) { *vertColor = geom.fColor; vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); } } helper.issueDraw(batchTarget); }