Reland: Allow DFPathRenderer to store bitmaps at low resolutions
BUG=chromium:682918 Change-Id: Ieadb41229227a20d41b8e932ba0770fe72479898 Reviewed-on: https://skia-review.googlesource.com/9068 Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
parent
3c322e23a0
commit
33632d8eda
@ -224,6 +224,54 @@ static void make_accessibility(SkPath* path) {
|
||||
path->close();
|
||||
}
|
||||
|
||||
// test case for http://crbug.com/695196
|
||||
static void make_visualizer(SkPath* path) {
|
||||
path->moveTo(1.9520f, 2.0000f);
|
||||
path->conicTo(1.5573f, 1.9992f, 1.2782f, 2.2782f, 0.9235f);
|
||||
path->conicTo(0.9992f, 2.5573f, 1.0000f, 2.9520f, 0.9235f);
|
||||
path->lineTo(1.0000f, 5.4300f);
|
||||
path->lineTo(17.0000f, 5.4300f);
|
||||
path->lineTo(17.0000f, 2.9520f);
|
||||
path->conicTo(17.0008f, 2.5573f, 16.7218f, 2.2782f, 0.9235f);
|
||||
path->conicTo(16.4427f, 1.9992f, 16.0480f, 2.0000f, 0.9235f);
|
||||
path->lineTo(1.9520f, 2.0000f);
|
||||
path->close();
|
||||
path->moveTo(2.7140f, 3.1430f);
|
||||
path->conicTo(3.0547f, 3.1287f, 3.2292f, 3.4216f, 0.8590f);
|
||||
path->conicTo(3.4038f, 3.7145f, 3.2292f, 4.0074f, 0.8590f);
|
||||
path->conicTo(3.0547f, 4.3003f, 2.7140f, 4.2860f, 0.8590f);
|
||||
path->conicTo(2.1659f, 4.2631f, 2.1659f, 3.7145f, 0.7217f);
|
||||
path->conicTo(2.1659f, 3.1659f, 2.7140f, 3.1430f, 0.7217f);
|
||||
path->lineTo(2.7140f, 3.1430f);
|
||||
path->close();
|
||||
path->moveTo(5.0000f, 3.1430f);
|
||||
path->conicTo(5.3407f, 3.1287f, 5.5152f, 3.4216f, 0.8590f);
|
||||
path->conicTo(5.6898f, 3.7145f, 5.5152f, 4.0074f, 0.8590f);
|
||||
path->conicTo(5.3407f, 4.3003f, 5.0000f, 4.2860f, 0.8590f);
|
||||
path->conicTo(4.4519f, 4.2631f, 4.4519f, 3.7145f, 0.7217f);
|
||||
path->conicTo(4.4519f, 3.1659f, 5.0000f, 3.1430f, 0.7217f);
|
||||
path->lineTo(5.0000f, 3.1430f);
|
||||
path->close();
|
||||
path->moveTo(7.2860f, 3.1430f);
|
||||
path->conicTo(7.6267f, 3.1287f, 7.8012f, 3.4216f, 0.8590f);
|
||||
path->conicTo(7.9758f, 3.7145f, 7.8012f, 4.0074f, 0.8590f);
|
||||
path->conicTo(7.6267f, 4.3003f, 7.2860f, 4.2860f, 0.8590f);
|
||||
path->conicTo(6.7379f, 4.2631f, 6.7379f, 3.7145f, 0.7217f);
|
||||
path->conicTo(6.7379f, 3.1659f, 7.2860f, 3.1430f, 0.7217f);
|
||||
path->close();
|
||||
path->moveTo(1.0000f, 6.1900f);
|
||||
path->lineTo(1.0000f, 14.3810f);
|
||||
path->conicTo(0.9992f, 14.7757f, 1.2782f, 15.0548f, 0.9235f);
|
||||
path->conicTo(1.5573f, 15.3338f, 1.9520f, 15.3330f, 0.9235f);
|
||||
path->lineTo(16.0480f, 15.3330f);
|
||||
path->conicTo(16.4427f, 15.3338f, 16.7218f, 15.0548f, 0.9235f);
|
||||
path->conicTo(17.0008f, 14.7757f, 17.0000f, 14.3810f, 0.9235f);
|
||||
path->lineTo(17.0000f, 6.1910f);
|
||||
path->lineTo(1.0000f, 6.1910f);
|
||||
path->lineTo(1.0000f, 6.1900f);
|
||||
path->close();
|
||||
}
|
||||
|
||||
constexpr MakePathProc gProcs[] = {
|
||||
make_frame,
|
||||
make_triangle,
|
||||
@ -244,6 +292,7 @@ class PathFillGM : public skiagm::GM {
|
||||
SkScalar fDY[N];
|
||||
SkPath fInfoPath;
|
||||
SkPath fAccessibilityPath;
|
||||
SkPath fVisualizerPath;
|
||||
protected:
|
||||
void onOnceBeforeDraw() override {
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
@ -252,6 +301,7 @@ protected:
|
||||
|
||||
make_info(&fInfoPath);
|
||||
make_accessibility(&fAccessibilityPath);
|
||||
make_visualizer(&fVisualizerPath);
|
||||
}
|
||||
|
||||
|
||||
@ -281,6 +331,10 @@ protected:
|
||||
canvas->scale(2, 2);
|
||||
canvas->translate(5, 15);
|
||||
canvas->drawPath(fAccessibilityPath, paint);
|
||||
|
||||
canvas->scale(0.5f, 0.5f);
|
||||
canvas->translate(5, 50);
|
||||
canvas->drawPath(fVisualizerPath, paint);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -518,7 +518,7 @@ GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(
|
||||
fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
|
||||
kHigh_GrSLPrecision);
|
||||
fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType);
|
||||
fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kVec2f_GrVertexAttribType);
|
||||
fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kVec2us_GrVertexAttribType);
|
||||
this->addTextureSampler(&fTextureSampler);
|
||||
}
|
||||
|
||||
@ -542,7 +542,7 @@ GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(
|
||||
fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
|
||||
kHigh_GrSLPrecision);
|
||||
fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType);
|
||||
fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kVec2f_GrVertexAttribType);
|
||||
fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kVec2us_GrVertexAttribType);
|
||||
this->addTextureSampler(&fTextureSampler);
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "GrSWMaskHelper.h"
|
||||
#include "GrSurfacePriv.h"
|
||||
#include "GrTexturePriv.h"
|
||||
#include "effects/GrBitmapTextGeoProc.h"
|
||||
#include "effects/GrDistanceFieldGeoProc.h"
|
||||
#include "ops/GrMeshDrawOp.h"
|
||||
|
||||
@ -165,16 +166,36 @@ private:
|
||||
bool gammaCorrect)
|
||||
: INHERITED(ClassID()) {
|
||||
SkASSERT(shape.hasUnstyledKey());
|
||||
// Compute bounds
|
||||
this->setTransformedBounds(shape.bounds(), viewMatrix, HasAABloat::kYes, IsZeroArea::kNo);
|
||||
|
||||
#ifdef SK_BUILD_FOR_ANDROID
|
||||
fUsesDistanceField = true;
|
||||
#else
|
||||
// only use distance fields on desktop to save space in the atlas
|
||||
fUsesDistanceField = this->bounds().width() > kMaxMIP || this->bounds().height() > kMaxMIP;
|
||||
#endif
|
||||
fViewMatrix = viewMatrix;
|
||||
fShapes.emplace_back(Entry{color, shape});
|
||||
SkVector translate = SkVector::Make(0, 0);
|
||||
if (!fUsesDistanceField) {
|
||||
// In this case we don't apply a view matrix, so we need to remove the non-subpixel
|
||||
// translation and add it back when we generate the quad for the path
|
||||
SkScalar translateX = viewMatrix.getTranslateX();
|
||||
SkScalar translateY = viewMatrix.getTranslateY();
|
||||
translate = SkVector::Make(SkScalarFloorToScalar(translateX),
|
||||
SkScalarFloorToScalar(translateY));
|
||||
// Only store the fractional part of the translation in the view matrix
|
||||
fViewMatrix.setTranslateX(translateX - translate.fX);
|
||||
fViewMatrix.setTranslateY(translateY - translate.fY);
|
||||
}
|
||||
|
||||
fShapes.emplace_back(Entry{color, shape, translate});
|
||||
|
||||
fAtlas = atlas;
|
||||
fShapeCache = shapeCache;
|
||||
fShapeList = shapeList;
|
||||
fGammaCorrect = gammaCorrect;
|
||||
|
||||
// Compute bounds
|
||||
this->setTransformedBounds(shape.bounds(), viewMatrix, HasAABloat::kYes, IsZeroArea::kNo);
|
||||
}
|
||||
|
||||
void getFragmentProcessorAnalysisInputs(FragmentProcessorAnalysisInputs* input) const override {
|
||||
@ -198,34 +219,45 @@ private:
|
||||
void onPrepareDraws(Target* target) const override {
|
||||
int instanceCount = fShapes.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;
|
||||
|
||||
GrSamplerParams params(SkShader::kRepeat_TileMode, GrSamplerParams::kBilerp_FilterMode);
|
||||
|
||||
FlushInfo flushInfo;
|
||||
|
||||
// Setup GrGeometryProcessor
|
||||
GrDrawOpAtlas* atlas = fAtlas;
|
||||
flushInfo.fGeometryProcessor = GrDistanceFieldPathGeoProc::Make(this->color(),
|
||||
this->viewMatrix(),
|
||||
atlas->getTexture(),
|
||||
params,
|
||||
flags,
|
||||
if (fUsesDistanceField) {
|
||||
GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
|
||||
|
||||
uint32_t flags = 0;
|
||||
flags |= ctm.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
|
||||
flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
|
||||
flags |= fGammaCorrect ? kGammaCorrect_DistanceFieldEffectFlag : 0;
|
||||
|
||||
flushInfo.fGeometryProcessor = GrDistanceFieldPathGeoProc::Make(
|
||||
this->color(), this->viewMatrix(), atlas->getTexture(), params, flags,
|
||||
this->usesLocalCoords());
|
||||
} else {
|
||||
GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
|
||||
|
||||
SkMatrix invert;
|
||||
if (this->usesLocalCoords()) {
|
||||
if (!this->viewMatrix().invert(&invert)) {
|
||||
SkDebugf("Could not invert viewmatrix\n");
|
||||
return;
|
||||
}
|
||||
// for local coords, we need to add the translation back in that we removed
|
||||
// from the stored view matrix
|
||||
invert.preTranslate(-fShapes[0].fTranslate.fX, -fShapes[0].fTranslate.fY);
|
||||
}
|
||||
|
||||
flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
|
||||
this->color(), atlas->getTexture(), params, kA8_GrMaskFormat, invert,
|
||||
this->usesLocalCoords());
|
||||
}
|
||||
|
||||
// allocate vertices
|
||||
size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride();
|
||||
SkASSERT(vertexStride == 2 * sizeof(SkPoint) + sizeof(GrColor));
|
||||
SkASSERT(vertexStride == sizeof(SkPoint) + sizeof(GrColor) + 2*sizeof(uint16_t));
|
||||
|
||||
const GrBuffer* vertexBuffer;
|
||||
void* vertices = target->makeVertexSpace(vertexStride,
|
||||
@ -245,11 +277,14 @@ private:
|
||||
for (int i = 0; i < instanceCount; i++) {
|
||||
const Entry& args = fShapes[i];
|
||||
|
||||
ShapeData* shapeData;
|
||||
SkScalar maxScale;
|
||||
if (fUsesDistanceField) {
|
||||
// get mip level
|
||||
SkScalar maxScale = SkScalarAbs(this->viewMatrix().getMaxScale());
|
||||
maxScale = SkScalarAbs(this->viewMatrix().getMaxScale());
|
||||
const SkRect& bounds = args.fShape.bounds();
|
||||
SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
|
||||
// We try to create the DF at a power of two scaled path resolution (1/2, 1, 2, 4, etc)
|
||||
// We try to create the DF at a 2^n scaled path resolution (1/2, 1, 2, 4, etc.)
|
||||
// In the majority of cases this will yield a crisper rendering.
|
||||
SkScalar mipScale = 1.0f;
|
||||
// Our mipscale is the maxScale clamped to the next highest power of 2
|
||||
@ -280,9 +315,9 @@ private:
|
||||
}
|
||||
SkScalar desiredDimension = SkTMin(mipSize, kMaxMIP);
|
||||
|
||||
// check to see if path is cached
|
||||
// check to see if df path is cached
|
||||
ShapeData::Key key(args.fShape, SkScalarCeilToInt(desiredDimension));
|
||||
ShapeData* shapeData = fShapeCache->find(key);
|
||||
shapeData = fShapeCache->find(key);
|
||||
if (nullptr == shapeData || !atlas->hasID(shapeData->fID)) {
|
||||
// Remove the stale cache entry
|
||||
if (shapeData) {
|
||||
@ -293,7 +328,7 @@ private:
|
||||
SkScalar scale = desiredDimension / maxDim;
|
||||
|
||||
shapeData = new ShapeData;
|
||||
if (!this->addPathToAtlas(target,
|
||||
if (!this->addDFPathToAtlas(target,
|
||||
&flushInfo,
|
||||
atlas,
|
||||
shapeData,
|
||||
@ -305,6 +340,32 @@ private:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// check to see if bitmap path is cached
|
||||
ShapeData::Key key(args.fShape, this->viewMatrix());
|
||||
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;
|
||||
}
|
||||
|
||||
shapeData = new ShapeData;
|
||||
if (!this->addBMPathToAtlas(target,
|
||||
&flushInfo,
|
||||
atlas,
|
||||
shapeData,
|
||||
args.fShape,
|
||||
this->viewMatrix())) {
|
||||
delete shapeData;
|
||||
SkDebugf("Can't rasterize path\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
maxScale = 1;
|
||||
}
|
||||
|
||||
atlas->setLastUseToken(shapeData->fID, target->nextDrawToken());
|
||||
|
||||
@ -314,6 +375,7 @@ private:
|
||||
args.fColor,
|
||||
vertexStride,
|
||||
maxScale,
|
||||
args.fTranslate,
|
||||
shapeData);
|
||||
offset += kVerticesPerQuad * vertexStride;
|
||||
flushInfo.fInstancesToFlush++;
|
||||
@ -322,7 +384,7 @@ private:
|
||||
this->flush(target, &flushInfo);
|
||||
}
|
||||
|
||||
bool addPathToAtlas(GrMeshDrawOp::Target* target, FlushInfo* flushInfo, GrDrawOpAtlas* atlas,
|
||||
bool addDFPathToAtlas(GrMeshDrawOp::Target* target, FlushInfo* flushInfo, GrDrawOpAtlas* atlas,
|
||||
ShapeData* shapeData, const GrShape& shape, uint32_t dimension,
|
||||
SkScalar scale) const {
|
||||
const SkRect& bounds = shape.bounds();
|
||||
@ -439,23 +501,121 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addBMPathToAtlas(GrMeshDrawOp::Target* target, FlushInfo* flushInfo,
|
||||
GrDrawOpAtlas* atlas, ShapeData* shapeData,
|
||||
const GrShape& shape, const SkMatrix& ctm) const {
|
||||
const SkRect& bounds = shape.bounds();
|
||||
if (bounds.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
SkMatrix drawMatrix(ctm);
|
||||
drawMatrix.set(SkMatrix::kMTransX, SkScalarFraction(ctm.get(SkMatrix::kMTransX)));
|
||||
drawMatrix.set(SkMatrix::kMTransY, SkScalarFraction(ctm.get(SkMatrix::kMTransY)));
|
||||
SkRect shapeDevBounds;
|
||||
drawMatrix.mapRect(&shapeDevBounds, bounds);
|
||||
SkScalar dx = SkScalarFloorToScalar(shapeDevBounds.fLeft);
|
||||
SkScalar dy = SkScalarFloorToScalar(shapeDevBounds.fTop);
|
||||
|
||||
// get integer boundary
|
||||
SkIRect devPathBounds;
|
||||
shapeDevBounds.roundOut(&devPathBounds);
|
||||
// pad to allow room for antialiasing
|
||||
const int intPad = SkScalarCeilToInt(kAntiAliasPad);
|
||||
// place devBounds at origin
|
||||
int width = devPathBounds.width() + 2 * intPad;
|
||||
int height = devPathBounds.height() + 2 * intPad;
|
||||
devPathBounds = SkIRect::MakeWH(width, height);
|
||||
SkScalar translateX = intPad - dx;
|
||||
SkScalar translateY = intPad - dy;
|
||||
|
||||
SkASSERT(devPathBounds.fLeft == 0);
|
||||
SkASSERT(devPathBounds.fTop == 0);
|
||||
SkASSERT(devPathBounds.width() > 0);
|
||||
SkASSERT(devPathBounds.height() > 0);
|
||||
|
||||
SkPath path;
|
||||
shape.asPath(&path);
|
||||
// setup bitmap backing
|
||||
SkAutoPixmapStorage dst;
|
||||
if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(),
|
||||
devPathBounds.height()))) {
|
||||
return false;
|
||||
}
|
||||
sk_bzero(dst.writable_addr(), dst.getSafeSize());
|
||||
|
||||
// rasterize path
|
||||
SkPaint paint;
|
||||
paint.setStyle(SkPaint::kFill_Style);
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
SkDraw draw;
|
||||
sk_bzero(&draw, sizeof(draw));
|
||||
|
||||
SkRasterClip rasterClip;
|
||||
rasterClip.setRect(devPathBounds);
|
||||
draw.fRC = &rasterClip;
|
||||
drawMatrix.postTranslate(translateX, translateY);
|
||||
draw.fMatrix = &drawMatrix;
|
||||
draw.fDst = dst;
|
||||
|
||||
draw.drawPathCoverage(path, paint);
|
||||
|
||||
// add to atlas
|
||||
SkIPoint16 atlasLocation;
|
||||
GrDrawOpAtlas::AtlasID id;
|
||||
if (!atlas->addToAtlas(&id, target, dst.width(), dst.height(), dst.addr(),
|
||||
&atlasLocation)) {
|
||||
this->flush(target, flushInfo);
|
||||
if (!atlas->addToAtlas(&id, target, dst.width(), dst.height(), dst.addr(),
|
||||
&atlasLocation)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// add to cache
|
||||
shapeData->fKey.set(shape, ctm);
|
||||
shapeData->fID = id;
|
||||
|
||||
// set the bounds rect to the original bounds
|
||||
shapeData->fBounds = SkRect::Make(devPathBounds);
|
||||
shapeData->fBounds.offset(-translateX, -translateY);
|
||||
|
||||
// set up path to texture coordinate transform
|
||||
shapeData->fScale = SK_Scalar1;
|
||||
shapeData->fTranslate.fX = atlasLocation.fX + translateX;
|
||||
shapeData->fTranslate.fY = atlasLocation.fY + translateY;
|
||||
|
||||
fShapeCache->add(shapeData);
|
||||
fShapeList->addToTail(shapeData);
|
||||
#ifdef DF_PATH_TRACKING
|
||||
++g_NumCachedPaths;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void writePathVertices(GrDrawOp::Target* target,
|
||||
GrDrawOpAtlas* atlas,
|
||||
intptr_t offset,
|
||||
GrColor color,
|
||||
size_t vertexStride,
|
||||
SkScalar maxScale,
|
||||
const SkVector& preTranslate,
|
||||
const ShapeData* shapeData) const {
|
||||
SkPoint* positions = reinterpret_cast<SkPoint*>(offset);
|
||||
|
||||
// outset bounds to include ~1 pixel of AA in device space
|
||||
SkRect bounds = shapeData->fBounds;
|
||||
if (fUsesDistanceField) {
|
||||
// outset bounds to include ~1 pixel of AA in device space
|
||||
SkScalar outset = SkScalarInvert(maxScale);
|
||||
bounds.outset(outset, outset);
|
||||
}
|
||||
|
||||
// vertex positions
|
||||
// TODO make the vertex attributes a struct
|
||||
positions->setRectFan(bounds.left(), bounds.top(), bounds.right(), bounds.bottom(),
|
||||
positions->setRectFan(bounds.left() + preTranslate.fX,
|
||||
bounds.top() + preTranslate.fY,
|
||||
bounds.right() + preTranslate.fX,
|
||||
bounds.bottom() + preTranslate.fY,
|
||||
vertexStride);
|
||||
|
||||
// colors
|
||||
@ -482,15 +642,32 @@ private:
|
||||
texRight += translate.fX;
|
||||
texBottom += translate.fY;
|
||||
|
||||
// vertex texture coords
|
||||
// TODO make these int16_t
|
||||
SkPoint* textureCoords = (SkPoint*)(offset + sizeof(SkPoint) + sizeof(GrColor));
|
||||
// convert texcoords to unsigned short format
|
||||
GrTexture* texture = atlas->getTexture();
|
||||
textureCoords->setRectFan(texLeft / texture->width(),
|
||||
texTop / texture->height(),
|
||||
texRight / texture->width(),
|
||||
texBottom / texture->height(),
|
||||
vertexStride);
|
||||
SkScalar uFactor = 65535.f / texture->width();
|
||||
SkScalar vFactor = 65535.f / texture->height();
|
||||
uint16_t l = (uint16_t)(texLeft*uFactor);
|
||||
uint16_t t = (uint16_t)(texTop*vFactor);
|
||||
uint16_t r = (uint16_t)(texRight*uFactor);
|
||||
uint16_t b = (uint16_t)(texBottom*vFactor);
|
||||
|
||||
// set vertex texture coords
|
||||
intptr_t textureCoordOffset = offset + sizeof(SkPoint) + sizeof(GrColor);
|
||||
uint16_t* textureCoords = (uint16_t*) textureCoordOffset;
|
||||
textureCoords[0] = l;
|
||||
textureCoords[1] = t;
|
||||
textureCoordOffset += vertexStride;
|
||||
textureCoords = (uint16_t*)textureCoordOffset;
|
||||
textureCoords[0] = l;
|
||||
textureCoords[1] = b;
|
||||
textureCoordOffset += vertexStride;
|
||||
textureCoords = (uint16_t*)textureCoordOffset;
|
||||
textureCoords[0] = r;
|
||||
textureCoords[1] = b;
|
||||
textureCoordOffset += vertexStride;
|
||||
textureCoords = (uint16_t*)textureCoordOffset;
|
||||
textureCoords[0] = r;
|
||||
textureCoords[1] = t;
|
||||
}
|
||||
|
||||
void flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
|
||||
@ -510,6 +687,7 @@ private:
|
||||
GrColor color() const { return fShapes[0].fColor; }
|
||||
const SkMatrix& viewMatrix() const { return fViewMatrix; }
|
||||
bool usesLocalCoords() const { return fUsesLocalCoords; }
|
||||
bool usesDistanceField() const { return fUsesDistanceField; }
|
||||
|
||||
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
|
||||
AADistanceFieldPathOp* that = t->cast<AADistanceFieldPathOp>();
|
||||
@ -518,11 +696,20 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO We can position on the cpu
|
||||
if (this->usesDistanceField() != that->usesDistanceField()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO We can position on the cpu for distance field paths
|
||||
if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->usesDistanceField() && this->usesLocalCoords() &&
|
||||
!this->fShapes[0].fTranslate.equalsWithinTolerance(that->fShapes[0].fTranslate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fShapes.push_back_n(that->fShapes.count(), that->fShapes.begin());
|
||||
this->joinBounds(*that);
|
||||
return true;
|
||||
@ -530,10 +717,12 @@ private:
|
||||
|
||||
SkMatrix fViewMatrix;
|
||||
bool fUsesLocalCoords;
|
||||
bool fUsesDistanceField;
|
||||
|
||||
struct Entry {
|
||||
GrColor fColor;
|
||||
GrShape fShape;
|
||||
SkVector fTranslate;
|
||||
};
|
||||
|
||||
SkSTArray<1, Entry> fShapes;
|
||||
|
@ -38,6 +38,7 @@ private:
|
||||
Key() {}
|
||||
Key(const Key& that) { *this = that; }
|
||||
Key(const GrShape& shape, uint32_t dim) { this->set(shape, dim); }
|
||||
Key(const GrShape& shape, const SkMatrix& ctm) { this->set(shape, ctm); }
|
||||
|
||||
Key& operator=(const Key& that) {
|
||||
fKey.reset(that.fKey.count());
|
||||
@ -56,6 +57,37 @@ private:
|
||||
shape.writeUnstyledKey(&fKey[1]);
|
||||
}
|
||||
|
||||
void set(const GrShape& shape, const SkMatrix& ctm) {
|
||||
GrUniqueKey maskKey;
|
||||
struct KeyData {
|
||||
SkScalar fFractionalTranslateX;
|
||||
SkScalar fFractionalTranslateY;
|
||||
};
|
||||
|
||||
// Shapes' keys are for their pre-style geometry, but by now we shouldn't have any
|
||||
// relevant styling information.
|
||||
SkASSERT(shape.style().isSimpleFill());
|
||||
SkASSERT(shape.hasUnstyledKey());
|
||||
// We require the upper left 2x2 of the matrix to match exactly for a cache hit.
|
||||
SkScalar sx = ctm.get(SkMatrix::kMScaleX);
|
||||
SkScalar sy = ctm.get(SkMatrix::kMScaleY);
|
||||
SkScalar kx = ctm.get(SkMatrix::kMSkewX);
|
||||
SkScalar ky = ctm.get(SkMatrix::kMSkewY);
|
||||
SkScalar tx = ctm.get(SkMatrix::kMTransX);
|
||||
SkScalar ty = ctm.get(SkMatrix::kMTransY);
|
||||
// Allow 8 bits each in x and y of subpixel positioning.
|
||||
SkFixed fracX = SkScalarToFixed(SkScalarFraction(tx)) & 0x0000FF00;
|
||||
SkFixed fracY = SkScalarToFixed(SkScalarFraction(ty)) & 0x0000FF00;
|
||||
int shapeKeySize = shape.unstyledKeySize();
|
||||
fKey.reset(5 + shapeKeySize);
|
||||
fKey[0] = SkFloat2Bits(sx);
|
||||
fKey[1] = SkFloat2Bits(sy);
|
||||
fKey[2] = SkFloat2Bits(kx);
|
||||
fKey[3] = SkFloat2Bits(ky);
|
||||
fKey[4] = fracX | (fracY >> 8);
|
||||
shape.writeUnstyledKey(&fKey[5]);
|
||||
}
|
||||
|
||||
bool operator==(const Key& that) const {
|
||||
return fKey.count() == that.fKey.count() &&
|
||||
0 == memcmp(fKey.get(), that.fKey.get(), sizeof(uint32_t) * fKey.count());
|
||||
@ -65,8 +97,9 @@ private:
|
||||
const uint32_t* data() const { return fKey.get(); }
|
||||
|
||||
private:
|
||||
// The key is composed of the dimensions of the DF generated for the path (32x32 max,
|
||||
// 64x64 max, 128x128 max) and the GrShape's key.
|
||||
// The key is composed of the GrShape's key, and either the dimensions of the DF
|
||||
// generated for the path (32x32 max, 64x64 max, 128x128 max) if an SDF image or
|
||||
// the matrix for the path with only fractional translation.
|
||||
SkAutoSTArray<24, uint32_t> fKey;
|
||||
};
|
||||
Key fKey;
|
||||
|
Loading…
Reference in New Issue
Block a user