Bug 1365876. Blur text shadows on the CPU. r=lsalzman

This commit is contained in:
Mason Chang 2017-07-24 13:48:14 -07:00
parent bd32331e0f
commit b4e1afb9e9
6 changed files with 29 additions and 14 deletions

View File

@ -36,14 +36,16 @@ gfxAlphaBoxBlur::Init(gfxContext* aDestinationCtx,
const IntSize& aSpreadRadius,
const IntSize& aBlurRadius,
const gfxRect* aDirtyRect,
const gfxRect* aSkipRect)
const gfxRect* aSkipRect,
bool aUseHardwareAccel)
{
DrawTarget* refDT = aDestinationCtx->GetDrawTarget();
Maybe<Rect> dirtyRect = aDirtyRect ? Some(ToRect(*aDirtyRect)) : Nothing();
Maybe<Rect> skipRect = aSkipRect ? Some(ToRect(*aSkipRect)) : Nothing();
RefPtr<DrawTarget> dt =
InitDrawTarget(refDT, ToRect(aRect), aSpreadRadius, aBlurRadius,
dirtyRect.ptrOr(nullptr), skipRect.ptrOr(nullptr));
dirtyRect.ptrOr(nullptr), skipRect.ptrOr(nullptr),
aUseHardwareAccel);
if (!dt) {
return nullptr;
}
@ -60,7 +62,8 @@ gfxAlphaBoxBlur::InitDrawTarget(const DrawTarget* aReferenceDT,
const IntSize& aSpreadRadius,
const IntSize& aBlurRadius,
const Rect* aDirtyRect,
const Rect* aSkipRect)
const Rect* aSkipRect,
bool aUseHardwareAccel)
{
mBlur.Init(aRect, aSpreadRadius, aBlurRadius, aDirtyRect, aSkipRect);
size_t blurDataSize = mBlur.GetSurfaceAllocationSize();
@ -75,10 +78,10 @@ gfxAlphaBoxBlur::InitDrawTarget(const DrawTarget* aReferenceDT,
// Otherwise, DrawSurfaceWithShadow only supports square blurs without spread.
// When blurring small draw targets such as short spans text, the cost of
// creating and flushing an accelerated draw target may exceed the speedup
// gained from the faster blur, so we also make sure the blurred data exceeds
// a sufficient number of pixels to offset this cost.
// gained from the faster blur. It's up to the users of this blur
// to determine whether they want to use hardware acceleration.
if (aBlurRadius.IsSquare() && aSpreadRadius.IsEmpty() &&
blurDataSize >= 8192 &&
aUseHardwareAccel &&
backend == BackendType::DIRECT2D1_1) {
mAccelerated = true;
mDrawTarget =

View File

@ -74,6 +74,9 @@ public:
* @param aSkipRect A pointer to a rect, measured in device units, that
* represents an area where blurring is unnecessary and shouldn't be done
* for speed reasons. It is safe to pass nullptr here.
*
* @param aUseHardwareAccel Flag to state whether or not we can use hardware
* acceleration to speed up this blur.
*/
already_AddRefed<gfxContext>
Init(gfxContext* aDestinationCtx,
@ -81,7 +84,8 @@ public:
const mozilla::gfx::IntSize& aSpreadRadius,
const mozilla::gfx::IntSize& aBlurRadius,
const gfxRect* aDirtyRect,
const gfxRect* aSkipRect);
const gfxRect* aSkipRect,
bool aUseHardwareAccel = true);
already_AddRefed<DrawTarget>
InitDrawTarget(const mozilla::gfx::DrawTarget* aReferenceDT,
@ -89,7 +93,8 @@ public:
const mozilla::gfx::IntSize& aSpreadRadius,
const mozilla::gfx::IntSize& aBlurRadius,
const mozilla::gfx::Rect* aDirtyRect = nullptr,
const mozilla::gfx::Rect* aSkipRect = nullptr);
const mozilla::gfx::Rect* aSkipRect = nullptr,
bool aUseHardwareAccel = true);
/**
* Performs the blur and optionally colors the result if aShadowColor is not null.

View File

@ -6025,7 +6025,8 @@ nsLayoutUtils::PaintTextShadow(const nsIFrame* aFrame,
nsContextBoxBlur contextBoxBlur;
gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, 0, blurRadius,
presCtx->AppUnitsPerDevPixel(),
aDestCtx, aDirtyRect, nullptr);
aDestCtx, aDirtyRect, nullptr,
nsContextBoxBlur::DISABLE_HARDWARE_ACCELERATION_BLUR);
if (!shadowContext)
continue;

View File

@ -6972,12 +6972,14 @@ nsTextFrame::PaintShadows(nsCSSShadowArray* aShadow,
// If the textrun uses any color or SVG fonts, we need to force use of a mask
// for shadow rendering even if blur radius is zero.
uint32_t blurFlags = 0;
// Force disable hardware acceleration for text shadows since it's usually
// more expensive than just doing it on the CPU.
uint32_t blurFlags = nsContextBoxBlur::DISABLE_HARDWARE_ACCELERATION_BLUR;
uint32_t numGlyphRuns;
const gfxTextRun::GlyphRun* run = mTextRun->GetGlyphRuns(&numGlyphRuns);
while (numGlyphRuns-- > 0) {
if (run->mFont->AlwaysNeedsMaskForShadow()) {
blurFlags = nsContextBoxBlur::FORCE_MASK;
blurFlags |= nsContextBoxBlur::FORCE_MASK;
break;
}
run++;

View File

@ -4292,13 +4292,16 @@ nsContextBoxBlur::Init(const nsRect& aRect, nscoord aSpreadRadius,
// Create the temporary surface for blurring
dirtyRect = transform.TransformBounds(dirtyRect);
bool useHardwareAccel = !(aFlags & DISABLE_HARDWARE_ACCELERATION_BLUR);
if (aSkipRect) {
gfxRect skipRect = transform.TransformBounds(*aSkipRect);
mContext = mAlphaBoxBlur.Init(aDestinationCtx, rect, spreadRadius,
blurRadius, &dirtyRect, &skipRect);
blurRadius, &dirtyRect, &skipRect,
useHardwareAccel);
} else {
mContext = mAlphaBoxBlur.Init(aDestinationCtx, rect, spreadRadius,
blurRadius, &dirtyRect, nullptr);
blurRadius, &dirtyRect, nullptr,
useHardwareAccel);
}
if (mContext) {

View File

@ -715,7 +715,8 @@ class nsContextBoxBlur {
public:
enum {
FORCE_MASK = 0x01
FORCE_MASK = 0x01,
DISABLE_HARDWARE_ACCELERATION_BLUR = 0x02
};
/**
* Prepares a gfxContext to draw on. Do not call this twice; if you want