GrBatchAtlas* GrResourceProvider::createAtlas(GrPixelConfig config, int width, int height, int numPlotsX, int numPlotsY, GrBatchAtlas::EvictionFunc func, void* data) { GrSurfaceDesc desc; desc.fFlags = kNone_GrSurfaceFlags; desc.fWidth = width; desc.fHeight = height; desc.fConfig = config; // We don't want to flush the context so we claim we're in the middle of flushing so as to // guarantee we do not recieve a texture with pending IO // TODO: Determine how to avoid having to do this. (https://bug.skia.org/4156) static const uint32_t kFlags = GrResourceProvider::kNoPendingIO_Flag; GrTexture* texture = this->createApproxTexture(desc, kFlags); if (!texture) { return nullptr; } GrBatchAtlas* atlas = new GrBatchAtlas(texture, numPlotsX, numPlotsY); atlas->registerEvictionCallback(func, data); return atlas; }
void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override { int instanceCount = fGeoData.count(); SkMatrix invert; if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) { SkDebugf("Could not invert viewmatrix\n"); return; } uint32_t flags = 0; flags |= this->viewMatrix().isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode); // Setup GrGeometryProcessor GrBatchAtlas* atlas = fAtlas; SkAutoTUnref<GrGeometryProcessor> dfProcessor( GrDistanceFieldPathGeoProc::Create(this->color(), this->viewMatrix(), atlas->getTexture(), params, flags, this->usesLocalCoords())); batchTarget->initDraw(dfProcessor, pipeline); FlushInfo flushInfo; // allocate vertices size_t vertexStride = dfProcessor->getVertexStride(); SkASSERT(vertexStride == 2 * sizeof(SkPoint)); const GrVertexBuffer* vertexBuffer; void* vertices = batchTarget->makeVertSpace(vertexStride, kVerticesPerQuad * instanceCount, &vertexBuffer, &flushInfo.fVertexOffset); flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer)); flushInfo.fIndexBuffer.reset(batchTarget->resourceProvider()->refQuadIndexBuffer()); if (!vertices || !flushInfo.fIndexBuffer) { SkDebugf("Could not allocate vertices\n"); return; } flushInfo.fInstancesToFlush = 0; for (int i = 0; i < instanceCount; i++) { Geometry& args = fGeoData[i]; // get mip level SkScalar maxScale = this->viewMatrix().getMaxScale(); const SkRect& bounds = args.fPath.getBounds(); SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); SkScalar size = maxScale * maxDim; uint32_t desiredDimension; if (size <= kSmallMIP) { desiredDimension = kSmallMIP; } else if (size <= kMediumMIP) { desiredDimension = kMediumMIP; } else { desiredDimension = kLargeMIP; } // check to see if path is cached // TODO: handle stroked vs. filled version of same path PathData::Key key = { args.fPath.getGenerationID(), desiredDimension }; args.fPathData = fPathCache->find(key); if (NULL == args.fPathData || !atlas->hasID(args.fPathData->fID)) { // Remove the stale cache entry if (args.fPathData) { fPathCache->remove(args.fPathData->fKey); fPathList->remove(args.fPathData); SkDELETE(args.fPathData); } SkScalar scale = desiredDimension/maxDim; args.fPathData = SkNEW(PathData); if (!this->addPathToAtlas(batchTarget, dfProcessor, pipeline, &flushInfo, atlas, args.fPathData, args.fPath, args.fStroke, args.fAntiAlias, desiredDimension, scale)) { SkDebugf("Can't rasterize path\n"); return; } } atlas->setLastUseToken(args.fPathData->fID, batchTarget->currentToken()); // Now set vertices intptr_t offset = reinterpret_cast<intptr_t>(vertices); offset += i * kVerticesPerQuad * vertexStride; SkPoint* positions = reinterpret_cast<SkPoint*>(offset); this->writePathVertices(batchTarget, atlas, pipeline, dfProcessor, positions, vertexStride, this->viewMatrix(), args.fPath, args.fPathData); flushInfo.fInstancesToFlush++; } this->flush(batchTarget, &flushInfo); }
void onPrepareDraws(Target* target) const override { int instanceCount = fGeoData.count(); SkMatrix invert; if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) { SkDebugf("Could not invert viewmatrix\n"); return; } const SkMatrix& ctm = this->viewMatrix(); uint32_t flags = 0; flags |= ctm.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0; flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; flags |= fGammaCorrect ? kGammaCorrect_DistanceFieldEffectFlag : 0; GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode); FlushInfo flushInfo; // Setup GrGeometryProcessor GrBatchAtlas* atlas = fAtlas; flushInfo.fGeometryProcessor = GrDistanceFieldPathGeoProc::Make(this->color(), this->viewMatrix(), atlas->getTexture(), params, flags, this->usesLocalCoords()); // allocate vertices size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride(); SkASSERT(vertexStride == 2 * sizeof(SkPoint) + sizeof(GrColor)); const GrBuffer* vertexBuffer; void* vertices = target->makeVertexSpace(vertexStride, kVerticesPerQuad * instanceCount, &vertexBuffer, &flushInfo.fVertexOffset); flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer)); flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer()); if (!vertices || !flushInfo.fIndexBuffer) { SkDebugf("Could not allocate vertices\n"); return; } flushInfo.fInstancesToFlush = 0; // Pointer to the next set of vertices to write. intptr_t offset = reinterpret_cast<intptr_t>(vertices); for (int i = 0; i < instanceCount; i++) { const Geometry& args = fGeoData[i]; // get mip level SkScalar maxScale = this->viewMatrix().getMaxScale(); const SkRect& bounds = args.fShape.bounds(); SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); SkScalar size = maxScale * maxDim; uint32_t desiredDimension; if (size <= kSmallMIP) { desiredDimension = kSmallMIP; } else if (size <= kMediumMIP) { desiredDimension = kMediumMIP; } else { desiredDimension = kLargeMIP; } // check to see if path is cached ShapeData::Key key(args.fShape, desiredDimension); ShapeData* shapeData = fShapeCache->find(key); if (nullptr == shapeData || !atlas->hasID(shapeData->fID)) { // Remove the stale cache entry if (shapeData) { fShapeCache->remove(shapeData->fKey); fShapeList->remove(shapeData); delete shapeData; } SkScalar scale = desiredDimension/maxDim; shapeData = new ShapeData; if (!this->addPathToAtlas(target, &flushInfo, atlas, shapeData, args.fShape, args.fAntiAlias, desiredDimension, scale)) { delete shapeData; SkDebugf("Can't rasterize path\n"); continue; } } atlas->setLastUseToken(shapeData->fID, target->nextDrawToken()); this->writePathVertices(target, atlas, offset, args.fColor, vertexStride, this->viewMatrix(), shapeData); offset += kVerticesPerQuad * vertexStride; flushInfo.fInstancesToFlush++; } this->flush(target, &flushInfo); }