aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar herb <herb@google.com>2015-12-07 12:12:29 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-12-07 12:12:29 -0800
commitd4c24f67496ff2e5e83bc7ce7945cbb85484bfa6 (patch)
tree45d549ae162159aa0100652ab2759acd305ebc05 /src/core
parentba923d38a5ea092aaa37967c5367ae19e2e4f017 (diff)
Simplify D1G so that it can inline DrawOneGlyph, and fix a bug in codegen
that only happens on ARM64 using GCC 4.9. Review URL: https://codereview.chromium.org/1507633004
Diffstat (limited to 'src/core')
-rw-r--r--src/core/SkDraw.cpp269
-rw-r--r--src/core/SkFindAndPlaceGlyph.h25
2 files changed, 127 insertions, 167 deletions
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index e1a49d39b4..ca6c2dee08 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -40,6 +40,9 @@
//#define TRACE_BITMAP_DRAWS
+// Helper function to fix code gen bug on ARM64.
+// See SkFindAndPlaceGlyph.h for more details.
+void FixGCC49Arm64Bug(int v) { }
/** Helper for allocating small blitters on the stack.
*/
@@ -1423,170 +1426,120 @@ void SkDraw::drawText_asPaths(const char text[], size_t byteLength,
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
-struct SkDraw1Glyph {
- const SkDraw* fDraw;
- const SkRegion* fClip;
- const SkAAClip* fAAClip;
- SkBlitter* fBlitter;
- SkGlyphCache* fCache;
- const SkPaint* fPaint;
- SkIRect fClipBounds;
- /** Half the sampling frequency of the rasterized glyph in x. */
- SkScalar fHalfSampleX;
- /** Half the sampling frequency of the rasterized glyph in y. */
- SkScalar fHalfSampleY;
-
- /** Draws one glyph.
- *
- * The x and y are pre-biased, so implementations may just truncate them.
- * i.e. half the sampling frequency has been added.
- * e.g. 1/2 or 1/(2^(SkGlyph::kSubBits+1)) has already been added.
- * This added bias can be found in fHalfSampleX,Y.
- */
- typedef void (*Proc)(const SkDraw1Glyph&, Sk48Dot16 x, Sk48Dot16 y, const SkGlyph&);
-
- Proc init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache,
- const SkPaint&);
-
- // call this instead of fBlitter->blitMask() since this wrapper will handle
- // the case when the mask is ARGB32_Format
- //
- void blitMask(const SkMask& mask, const SkIRect& clip) const {
- if (SkMask::kARGB32_Format == mask.fFormat) {
- this->blitMaskAsSprite(mask);
- } else {
- fBlitter->blitMask(mask, clip);
- }
- }
-
- // mask must be kARGB32_Format
- void blitMaskAsSprite(const SkMask& mask) const;
-};
-static void D1G_RectClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy,
- const SkGlyph& glyph) {
- // Prevent glyphs from being drawn outside of or straddling the edge of device space.
- if ((fx >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) ||
- (fx >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) ||
- (fy >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) ||
- (fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/))
- {
- return;
- }
+class DrawOneGlyph {
+public:
+ DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache, SkBlitter* blitter)
+ : fUseRegionToDraw(UsingRegionToDraw(draw.fRC))
+ , fGlyphCache(cache)
+ , fBlitter(blitter)
+ , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr)
+ , fDraw(draw)
+ , fPaint(paint)
+ , fClipBounds(PickClipBounds(draw)) { }
+
+ void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
+ position += rounding;
+ Sk48Dot16 fx = SkScalarTo48Dot16(position.fX);
+ Sk48Dot16 fy = SkScalarTo48Dot16(position.fY);
+ // Prevent glyphs from being drawn outside of or straddling the edge of device space.
+ if ((fx >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) ||
+ (fx >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) ||
+ (fy >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) ||
+ (fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) {
+ return;
+ }
- int left = Sk48Dot16FloorToInt(fx);
- int top = Sk48Dot16FloorToInt(fy);
- SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
- SkASSERT((nullptr == state.fClip && state.fAAClip) ||
- (state.fClip && nullptr == state.fAAClip && state.fClip->isRect()));
+ int left = Sk48Dot16FloorToInt(fx);
+ int top = Sk48Dot16FloorToInt(fy);
+ SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
- left += glyph.fLeft;
- top += glyph.fTop;
+ left += glyph.fLeft;
+ top += glyph.fTop;
- int right = left + glyph.fWidth;
- int bottom = top + glyph.fHeight;
+ int right = left + glyph.fWidth;
+ int bottom = top + glyph.fHeight;
- SkMask mask;
- SkIRect storage;
- SkIRect* bounds = &mask.fBounds;
+ SkMask mask;
+ mask.fBounds.set(left, top, right, bottom);
- mask.fBounds.set(left, top, right, bottom);
+ if (fUseRegionToDraw) {
+ SkRegion::Cliperator clipper(*fClip, mask.fBounds);
- // this extra test is worth it, assuming that most of the time it succeeds
- // since we can avoid writing to storage
- if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) {
- if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds))
- return;
- bounds = &storage;
- }
+ if (!clipper.done() && this->getImageData(glyph, &mask)) {
+ const SkIRect& cr = clipper.rect();
+ do {
+ this->blitMask(mask, cr);
+ clipper.next();
+ } while (!clipper.done());
+ }
+ } else {
+ SkIRect storage;
+ SkIRect* bounds = &mask.fBounds;
+
+ // this extra test is worth it, assuming that most of the time it succeeds
+ // since we can avoid writing to storage
+ if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) {
+ if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds))
+ return;
+ bounds = &storage;
+ }
- uint8_t* aa = (uint8_t*)glyph.fImage;
- if (nullptr == aa) {
- aa = (uint8_t*)state.fCache->findImage(glyph);
- if (nullptr == aa) {
- return; // can't rasterize glyph
+ if (this->getImageData(glyph, &mask)) {
+ this->blitMask(mask, *bounds);
+ }
}
}
- mask.fRowBytes = glyph.rowBytes();
- mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
- mask.fImage = aa;
- state.blitMask(mask, *bounds);
-}
-
-static void D1G_RgnClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy,
- const SkGlyph& glyph) {
- int left = Sk48Dot16FloorToInt(fx);
- int top = Sk48Dot16FloorToInt(fy);
- SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
- SkASSERT(!state.fClip->isRect());
-
- SkMask mask;
-
- left += glyph.fLeft;
- top += glyph.fTop;
+private:
+ static bool UsingRegionToDraw(const SkRasterClip* rClip) {
+ return rClip->isBW() && !rClip->isRect();
+ }
- mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
- SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
+ static SkIRect PickClipBounds(const SkDraw& draw) {
+ const SkRasterClip& rasterClip = *draw.fRC;
- if (!clipper.done()) {
- const SkIRect& cr = clipper.rect();
- const uint8_t* aa = (uint8_t*)state.fCache->findImage(glyph);
- if (nullptr == aa) {
- return;
+ if (rasterClip.isBW()) {
+ return rasterClip.bwRgn().getBounds();
+ } else {
+ return rasterClip.aaRgn().getBounds();
}
-
- mask.fRowBytes = glyph.rowBytes();
- mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
- mask.fImage = (uint8_t*)aa;
- do {
- state.blitMask(mask, cr);
- clipper.next();
- } while (!clipper.done());
}
-}
-
-SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache,
- const SkPaint& pnt) {
- fDraw = draw;
- fBlitter = blitter;
- fCache = cache;
- fPaint = &pnt;
- if (cache->isSubpixel()) {
- fHalfSampleX = fHalfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound);
- } else {
- fHalfSampleX = fHalfSampleY = SK_ScalarHalf;
+ bool getImageData(const SkGlyph& glyph, SkMask* mask) {
+ uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph));
+ if (nullptr == bits) {
+ return false; // can't rasterize glyph
+ }
+ mask->fImage = bits;
+ mask->fRowBytes = glyph.rowBytes();
+ mask->fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
+ return true;
}
- if (draw->fRC->isBW()) {
- fAAClip = nullptr;
- fClip = &draw->fRC->bwRgn();
- fClipBounds = fClip->getBounds();
- if (fClip->isRect()) {
- return D1G_RectClip;
+ void blitMask(const SkMask& mask, const SkIRect& clip) const {
+ if (SkMask::kARGB32_Format == mask.fFormat) {
+ SkBitmap bm;
+ bm.installPixels(
+ SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()),
+ (SkPMColor*)mask.fImage, mask.fRowBytes);
+
+ fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint);
} else {
- return D1G_RgnClip;
+ fBlitter->blitMask(mask, clip);
}
- } else { // aaclip
- fAAClip = &draw->fRC->aaRgn();
- fClip = nullptr;
- fClipBounds = fAAClip->getBounds();
- return D1G_RectClip;
}
-}
-
-void SkDraw1Glyph::blitMaskAsSprite(const SkMask& mask) const {
- SkASSERT(SkMask::kARGB32_Format == mask.fFormat);
- SkBitmap bm;
- bm.installPixels(SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()),
- (SkPMColor*)mask.fImage, mask.fRowBytes);
-
- fDraw->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), *fPaint);
-}
+ const bool fUseRegionToDraw;
+ SkGlyphCache * const fGlyphCache;
+ SkBlitter * const fBlitter;
+ const SkRegion* const fClip;
+ const SkDraw& fDraw;
+ const SkPaint& fPaint;
+ const SkIRect fClipBounds;
+};
-///////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////
void SkDraw::drawText(const char text[], size_t byteLength,
SkScalar x, SkScalar y, const SkPaint& paint) const {
@@ -1606,25 +1559,17 @@ void SkDraw::drawText(const char text[], size_t byteLength,
return;
}
- SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix);
- SkGlyphCache* cache = autoCache.getCache();
-
+ SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix);
+ SkGlyphCache* cache = autoCache.getCache();
// The Blitter Choose needs to be live while using the blitter below.
SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
-
- SkDraw1Glyph d1g;
- SkDraw1Glyph::Proc proc = d1g.init(this, wrapper.getBlitter(), cache, paint);
+ DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter());
SkFindAndPlaceGlyph::ProcessText(
paint.getTextEncoding(), text, byteLength,
- {x, y}, *fMatrix, paint.getTextAlign(), cache,
- [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
- position += rounding;
- proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position.fY), glyph);
- }
- );
+ {x, y}, *fMatrix, paint.getTextAlign(), cache, drawOneGlyph);
}
//////////////////////////////////////////////////////////////////////////////
@@ -1696,24 +1641,18 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
return;
}
+ SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix);
+ SkGlyphCache* cache = autoCache.getCache();
+
// The Blitter Choose needs to be live while using the blitter below.
SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
-
- SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix);
- SkGlyphCache* cache = autoCache.getCache();
- SkDraw1Glyph d1g;
- SkDraw1Glyph::Proc proc = d1g.init(this, wrapper.getBlitter(), cache, paint);
- SkPaint::Align textAlignment = paint.getTextAlign();
+ DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter());
+ SkPaint::Align textAlignment = paint.getTextAlign();
SkFindAndPlaceGlyph::ProcessPosText(
paint.getTextEncoding(), text, byteLength,
- offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache,
- [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
- position += rounding;
- proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position.fY), glyph);
- }
- );
+ offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache, drawOneGlyph);
}
#if defined _WIN32 && _MSC_VER >= 1300
diff --git a/src/core/SkFindAndPlaceGlyph.h b/src/core/SkFindAndPlaceGlyph.h
index 278be07e0b..bd6338d587 100644
--- a/src/core/SkFindAndPlaceGlyph.h
+++ b/src/core/SkFindAndPlaceGlyph.h
@@ -30,6 +30,16 @@ struct SkMaxSizeOf<H, Ts...> {
sizeof(H) >= SkMaxSizeOf<Ts...>::value ? sizeof(H) : SkMaxSizeOf<Ts...>::value;
};
+
+// This is a temporary helper function to work around a bug in the code generation
+// for aarch64 (arm) on GCC 4.9. This bug does not show up on other platforms, so it
+// seems to be an aarch64 backend problem.
+//
+// GCC 4.9 on ARM64 does not generate the proper constructor code for PositionReader or
+// GlyphFindAndPlace. The vtable is not set properly without adding the fixme code.
+// The implementation is in SkDraw.cpp.
+extern void FixGCC49Arm64Bug(int v);
+
class SkFindAndPlaceGlyph {
public:
template<typename ProcessOneGlyph>
@@ -229,6 +239,9 @@ private:
public:
virtual ~PositionReaderInterface() { }
virtual SkPoint nextPoint() = 0;
+ // This is only here to fix a GCC 4.9 aarch64 code gen bug.
+ // See comment at the top of the file.
+ virtual int forceUseForBug() = 0;
};
class HorizontalPositions final : public PositionReaderInterface {
@@ -241,6 +254,8 @@ private:
return {x, 0};
}
+ int forceUseForBug() override { return 1; }
+
private:
const SkScalar* fPositions;
};
@@ -256,6 +271,8 @@ private:
return to_return;
}
+ int forceUseForBug() override { return 2; }
+
private:
const SkScalar* fPositions;
};
@@ -410,7 +427,9 @@ private:
class GlyphFindAndPlaceSubpixel final : public GlyphFindAndPlaceInterface<ProcessOneGlyph> {
public:
GlyphFindAndPlaceSubpixel(LookupGlyph& glyphFinder)
- : fGlyphFinder(glyphFinder) { }
+ : fGlyphFinder(glyphFinder) {
+ FixGCC49Arm64Bug(1);
+ }
SkPoint findAndPositionGlyph(
const char** text, SkPoint position, ProcessOneGlyph&& processOneGlyph) override {
@@ -464,6 +483,7 @@ private:
public:
GlyphFindAndPlaceFullPixel(LookupGlyph& glyphFinder)
: fGlyphFinder(glyphFinder) {
+ FixGCC49Arm64Bug(2);
// Kerning can only be used with SkPaint::kLeft_Align
static_assert(!kUseKerning || SkPaint::kLeft_Align == kTextAlignment,
"Kerning can only be used with left aligned text.");
@@ -601,6 +621,7 @@ inline void SkFindAndPlaceGlyph::ProcessPosText(
} else {
to_init->initialize<HorizontalPositions>(pos);
}
+ positionReader->forceUseForBug();
}
};
@@ -617,7 +638,7 @@ inline void SkFindAndPlaceGlyph::ProcessPosText(
}
};
- GlyphFindAndPlace<ProcessOneGlyph> findAndPosition{
+ GlyphFindAndPlace<ProcessOneGlyph> findAndPosition {
[&](typename GlyphFindAndPlace<ProcessOneGlyph>::Variants* to_init) {
if (cache->isSubpixel()) {
switch (textAlignment) {