Reland "direct mask biased to (0,0)"
This is a reland of 56cde4923f
Original change's description:
> direct mask biased to (0,0)
>
> Create mask rectangles in device space.
> But, instead of offsetting to the drawing text blob origin
> offset to 0,0 to simplify mapping from source space to
> device space.
>
> Bug: skia:10251
>
> Change-Id: Ic637eb78879bcfae7e7944053d67d9eaef8490cc
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/290133
> Commit-Queue: Herb Derby <herb@google.com>
> Reviewed-by: Robert Phillips <robertphillips@google.com>
Bug: skia:10251
Change-Id: I622ed5c3c16379b06989bf737e74a7752984c158
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/290441
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
parent
39decdbe35
commit
e7825ff7e3
@ -40,7 +40,7 @@ void SkDrawableGlyphBuffer::startSource(const SkZip<const SkGlyphID, const SkPoi
|
||||
SkDEBUGCODE(fPhase = kInput);
|
||||
}
|
||||
|
||||
void SkDrawableGlyphBuffer::startDevice(
|
||||
void SkDrawableGlyphBuffer::startBitmapDevice(
|
||||
const SkZip<const SkGlyphID, const SkPoint>& source,
|
||||
SkPoint origin, const SkMatrix& viewMatrix,
|
||||
const SkGlyphPositionRoundingSpec& roundingSpec) {
|
||||
@ -68,6 +68,44 @@ void SkDrawableGlyphBuffer::startDevice(
|
||||
SkDEBUGCODE(fPhase = kInput);
|
||||
}
|
||||
|
||||
void SkDrawableGlyphBuffer::startGPUDevice(
|
||||
const SkZip<const SkGlyphID, const SkPoint>& source,
|
||||
SkPoint origin, const SkMatrix& viewMatrix,
|
||||
const SkGlyphPositionRoundingSpec& roundingSpec) {
|
||||
fInputSize = source.size();
|
||||
fDrawableSize = 0;
|
||||
|
||||
// Map the positions including subpixel position.
|
||||
auto positions = source.get<1>();
|
||||
SkMatrix matrix = viewMatrix;
|
||||
matrix.preTranslate(origin.x(), origin.y());
|
||||
|
||||
// Q = [M][T](0,0).
|
||||
SkPoint Q = matrix.mapXY(0, 0);
|
||||
SkPoint halfSampleFreq = roundingSpec.halfAxisSampleFreq;
|
||||
matrix.postTranslate(halfSampleFreq.x(), halfSampleFreq.y());
|
||||
matrix.mapPoints(fPositions, positions.data(), positions.size());
|
||||
|
||||
// Mask for controlling axis alignment.
|
||||
SkIPoint mask = roundingSpec.ignorePositionFieldMask;
|
||||
|
||||
// Convert glyph ids and positions to packed glyph ids.
|
||||
SkZip<const SkGlyphID, const SkPoint> withMappedPos =
|
||||
SkMakeZip(source.get<0>(), fPositions.get());
|
||||
SkGlyphVariant* packedIDCursor = fMultiBuffer;
|
||||
for (auto [glyphID, pos] : withMappedPos) {
|
||||
*packedIDCursor++ = SkPackedGlyphID{glyphID, pos, mask};
|
||||
}
|
||||
|
||||
for (SkPoint& pos : SkSpan<SkPoint>(fPositions, source.size())) {
|
||||
SkPoint P = SkPoint::Make(SkScalarFloorToScalar(pos.x()), SkScalarFloorToScalar(pos.y()));
|
||||
pos = P - Q;
|
||||
}
|
||||
|
||||
SkDEBUGCODE(fPhase = kInput);
|
||||
}
|
||||
|
||||
|
||||
void SkDrawableGlyphBuffer::reset() {
|
||||
SkDEBUGCODE(fPhase = kReset);
|
||||
if (fMaxSize > 200) {
|
||||
|
@ -148,7 +148,29 @@ public:
|
||||
void startSource(const SkZip<const SkGlyphID, const SkPoint>& source);
|
||||
|
||||
// Load the buffer with SkPackedGlyphIDs and positions using the device transform.
|
||||
void startDevice(
|
||||
void startBitmapDevice(
|
||||
const SkZip<const SkGlyphID, const SkPoint>& source,
|
||||
SkPoint origin, const SkMatrix& viewMatrix,
|
||||
const SkGlyphPositionRoundingSpec& roundingSpec);
|
||||
|
||||
// Load the buffer with SkPackedGlyphIDs, calculating positions so they can be constant.
|
||||
//
|
||||
// A final device position is computed in the following manner:
|
||||
// [x,y] = Floor[M][T][x',y']^t
|
||||
// M is complicated but includes the rounding offsets for subpixel positioning.
|
||||
// T is the translation matrix derived from the text blob origin.
|
||||
// The final position is {Floor(x), Floor(y)}. If we want to move this position around in
|
||||
// device space given a start origin T in source space and a end position T' in source space
|
||||
// and new device matrix M', we need to calculate a suitable device space translation V. We
|
||||
// know that V must be integer.
|
||||
// V = [M'][T'](0,0)^t - [M][T](0,0)^t.
|
||||
// V = Q' - Q
|
||||
// So all the positions Ps are translated by V to translate from T to T' in source space. We can
|
||||
// generate Ps such that we just need to add any Q' to the constant Ps to get a final positions.
|
||||
// So, a single point P = {Floor(x)-Q_x, Floor(y)-Q_y}; this does not have to be integer.
|
||||
// This allows positioning to be P + Q', which given ideal numbers would be an integer. Since
|
||||
// the addition is done with floating point, it must be rounded.
|
||||
void startGPUDevice(
|
||||
const SkZip<const SkGlyphID, const SkPoint>& source,
|
||||
SkPoint origin, const SkMatrix& viewMatrix,
|
||||
const SkGlyphPositionRoundingSpec& roundingSpec);
|
||||
|
@ -124,7 +124,7 @@ void SkGlyphRunListPainter::drawForBitmapDevice(
|
||||
|
||||
auto strike = strikeSpec.findOrCreateStrike();
|
||||
|
||||
fDrawable.startDevice(
|
||||
fDrawable.startBitmapDevice(
|
||||
fRejects.source(), drawOrigin, deviceMatrix, strike->roundingSpec());
|
||||
strike->prepareForDrawingMasksCPU(&fDrawable);
|
||||
bitmapDevice->paintMasks(&fDrawable, runPaint);
|
||||
@ -189,7 +189,7 @@ void SkGlyphRunListPainter::processGlyphRunList(const SkGlyphRunList& glyphRunLi
|
||||
|
||||
SkScopedStrikeForGPU strike = strikeSpec.findOrCreateScopedStrike(fStrikeCache);
|
||||
|
||||
fDrawable.startDevice(fRejects.source(), origin, drawMatrix, strike->roundingSpec());
|
||||
fDrawable.startGPUDevice(fRejects.source(), origin, drawMatrix, strike->roundingSpec());
|
||||
strike->prepareForMaskDrawing(&fDrawable, &fRejects);
|
||||
fRejects.flipRejectsToSource();
|
||||
|
||||
|
@ -50,7 +50,7 @@ GrTextBlob::SubRun::SubRun(SubRunType type, GrTextBlob* textBlob, const SkStrike
|
||||
, fVertexData{vertexData}
|
||||
, fStrikeSpec{strikeSpec}
|
||||
, fCurrentColor{textBlob->fColor}
|
||||
, fCurrentOrigin{this->needsTransform() ? SkPoint{0, 0} : textBlob->fInitialOrigin}
|
||||
, fCurrentOrigin{0,0}
|
||||
, fCurrentMatrix{textBlob->fInitialMatrix} {
|
||||
SkASSERT(type != kTransformedPath);
|
||||
textBlob->insertSubRun(this);
|
||||
@ -111,7 +111,6 @@ void GrTextBlob::SubRun::appendGlyphs(const SkZip<SkGlyphVariant, SkPoint>& draw
|
||||
// Only floor the device coordinates.
|
||||
SkRect dstRect;
|
||||
if (!this->needsTransform()) {
|
||||
pos = {SkScalarFloorToScalar(pos.x()), SkScalarFloorToScalar(pos.y())};
|
||||
dstRect = dest_rect(*skGlyph, pos);
|
||||
} else {
|
||||
dstRect = dest_rect(*skGlyph, pos, strikeToSource);
|
||||
@ -142,15 +141,6 @@ void GrTextBlob::SubRun::appendGlyphs(const SkZip<SkGlyphVariant, SkPoint>& draw
|
||||
packedIDCursor->fPackedGlyphID = skGlyph->getPackedID();
|
||||
packedIDCursor++;
|
||||
}
|
||||
|
||||
if (!this->needsTransform()) {
|
||||
// Use the negative initial origin to make the fVertexBounds {0, 0} based.
|
||||
SkPoint pt = fBlob->fInitialOrigin;
|
||||
|
||||
// If the box is in device space, then transform the source space origin to device space.
|
||||
pt = fBlob->fInitialMatrix.mapXY(pt.x(), pt.y());
|
||||
fVertexBounds.offset(-pt);
|
||||
}
|
||||
}
|
||||
|
||||
void GrTextBlob::SubRun::resetBulkUseToken() { fBulkUseToken.reset(); }
|
||||
@ -228,19 +218,12 @@ void GrTextBlob::SubRun::translateVerticesIfNeeded(
|
||||
// If transform is needed, then the vertices are in source space, calculate the source
|
||||
// space translation.
|
||||
translation = drawOrigin - fCurrentOrigin;
|
||||
fCurrentOrigin = drawOrigin;
|
||||
} else {
|
||||
// Calculate the translation in source space to a translation in device space. Calculate
|
||||
// the translation by mapping (0, 0) through both the current matrix, and the draw
|
||||
// matrix, and taking the difference.
|
||||
SkMatrix currentMatrix{fCurrentMatrix};
|
||||
currentMatrix.preTranslate(fCurrentOrigin.x(), fCurrentOrigin.y());
|
||||
SkPoint currentDeviceOrigin{0, 0};
|
||||
currentMatrix.mapPoints(¤tDeviceOrigin, 1);
|
||||
SkMatrix completeDrawMatrix{drawMatrix};
|
||||
completeDrawMatrix.preTranslate(drawOrigin.x(), drawOrigin.y());
|
||||
SkPoint drawDeviceOrigin{0, 0};
|
||||
completeDrawMatrix.mapPoints(&drawDeviceOrigin, 1);
|
||||
translation = drawDeviceOrigin - currentDeviceOrigin;
|
||||
// Calculate the translation in destination space.
|
||||
SkPoint newOrigin = drawMatrix.mapXY(drawOrigin.x(), drawOrigin.y());
|
||||
translation = newOrigin - fCurrentOrigin;
|
||||
fCurrentOrigin = newOrigin;
|
||||
}
|
||||
|
||||
if (translation != SkPoint{0, 0}) {
|
||||
@ -248,12 +231,18 @@ void GrTextBlob::SubRun::translateVerticesIfNeeded(
|
||||
for (size_t quad = 0; quad < fGlyphs.size(); quad++) {
|
||||
SkPoint* vertexCursor = reinterpret_cast<SkPoint*>(quadStart(quad));
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
*vertexCursor += translation;
|
||||
if (this->needsTransform()) {
|
||||
*vertexCursor += translation;
|
||||
} else {
|
||||
// This should result in an integer, but floating point is not accurate. This
|
||||
// result should be very close to an integer; round to an integer.
|
||||
*vertexCursor = {SkScalarRoundToScalar(vertexCursor->x() + translation.x()),
|
||||
SkScalarRoundToScalar(vertexCursor->y() + translation.y())};
|
||||
}
|
||||
vertexCursor = SkTAddOffset<SkPoint>(vertexCursor, vertexStride);
|
||||
}
|
||||
}
|
||||
fCurrentMatrix = drawMatrix;
|
||||
fCurrentOrigin = drawOrigin;
|
||||
}
|
||||
}
|
||||
|
||||
@ -529,7 +518,7 @@ void GrTextBlob::addOp(GrTextTarget* target,
|
||||
if (!needsExactCTM) {
|
||||
for (const auto& pathPos : subRun->fPaths) {
|
||||
const SkPath& path = pathPos.fPath;
|
||||
const SkPoint pos = pathPos.fOrigin; // Transform the glyph to source space.
|
||||
const SkPoint pos = pathPos.fOrigin; // Transform the glyph to source space.
|
||||
SkMatrix pathMatrix = strikeToSource;
|
||||
pathMatrix.postTranslate(pos.x(), pos.y());
|
||||
SkPreConcatMatrixProvider strikeToDevice(deviceMatrix, pathMatrix);
|
||||
|
@ -393,6 +393,8 @@ public:
|
||||
GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken;
|
||||
uint64_t fAtlasGeneration{GrDrawOpAtlas::kInvalidAtlasGeneration};
|
||||
GrColor fCurrentColor;
|
||||
// If the vertex data needTransform(), then fCurrentOrigin is in source space else it is in
|
||||
// device space.
|
||||
SkPoint fCurrentOrigin;
|
||||
SkMatrix fCurrentMatrix;
|
||||
std::vector<PathGlyph> fPaths;
|
||||
|
@ -172,7 +172,7 @@ DEF_TEST(SkDrawableGlyphBufferBasic, reporter) {
|
||||
drawable.ensureSize(100);
|
||||
SkMatrix matrix = SkMatrix::MakeScale(0.5);
|
||||
SkGlyphPositionRoundingSpec rounding{true, kX_SkAxisAlignment};
|
||||
drawable.startDevice(source, {100, 100}, matrix, rounding);
|
||||
drawable.startBitmapDevice(source, {100, 100}, matrix, rounding);
|
||||
for (auto [i, packedID, pos] : SkMakeEnumerate(drawable.input())) {
|
||||
REPORTER_ASSERT(reporter, glyphIDs[i] == packedID.packedID().glyphID());
|
||||
REPORTER_ASSERT(reporter,
|
||||
|
@ -72,8 +72,8 @@ DEF_TEST(SkScalerCacheMultiThread, Reporter) {
|
||||
drawable.ensureSize(glyphCount);
|
||||
rejects.setSource(local);
|
||||
|
||||
drawable.startDevice(rejects.source(), {0, 0}, SkMatrix::I(),
|
||||
scalerCache.roundingSpec());
|
||||
drawable.startBitmapDevice(rejects.source(), {0, 0}, SkMatrix::I(),
|
||||
scalerCache.roundingSpec());
|
||||
scalerCache.prepareForMaskDrawing(&drawable, &rejects);
|
||||
rejects.flipRejectsToSource();
|
||||
drawable.reset();
|
||||
|
Loading…
Reference in New Issue
Block a user