Bug 772726: Factor out pixel-aligned clip handling in DrawTargetD2D. r=jrmuizel

This commit is contained in:
Bas Schouten 2012-09-18 23:04:42 +00:00
parent 7980e436fe
commit 6ab8e308dd
4 changed files with 151 additions and 33 deletions

View File

@ -100,7 +100,19 @@ public:
gfxWarning() << "Failed to create shared bitmap for old surface.";
}
mClippedArea = mDT->GetClippedGeometry();
IntRect clipBounds;
mClippedArea = mDT->GetClippedGeometry(&clipBounds);
if (!clipBounds.IsEqualEdges(IntRect(IntPoint(0, 0), mDT->mSize))) {
// We still need to take into account clipBounds if it contains additional
// clipping information.
RefPtr<ID2D1RectangleGeometry> rectGeom;
factory()->CreateRectangleGeometry(D2D1::Rect(clipBounds.x, clipBounds.y,
clipBounds.XMost(), clipBounds.YMost()),
byRef(rectGeom));
mClippedArea = mDT->Intersect(mClippedArea, rectGeom);
}
}
ID2D1Factory *factory() { return mDT->factory(); }
@ -325,6 +337,8 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface,
return;
}
SetScissorToRect(nullptr);
// XXX - This function is way too long, it should be split up soon to make
// it more graspable!
@ -357,8 +371,9 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface,
RefPtr<ID3D10Texture2D> maskTexture;
RefPtr<ID3D10ShaderResourceView> maskSRView;
IntRect clipBounds;
if (mPushedClips.size()) {
EnsureClipMaskTexture();
EnsureClipMaskTexture(&clipBounds);
mDevice->CreateShaderResourceView(mCurrentClipMaskTexture, nullptr, byRef(maskSRView));
}
@ -614,6 +629,7 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface,
Float(aSurface->GetSize().height) / mSize.height));
mPrivateData->mEffect->GetTechniqueByName("SampleTextureWithShadow")->
GetPassByIndex(2)->Apply(0);
SetScissorToRect(&clipBounds);
} else {
mPrivateData->mEffect->GetTechniqueByName("SampleTextureWithShadow")->
GetPassByIndex(1)->Apply(0);
@ -639,6 +655,7 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface,
Float(aSurface->GetSize().height) / mSize.height));
mPrivateData->mEffect->GetTechniqueByName("SampleMaskedTexture")->
GetPassByIndex(0)->Apply(0);
// We've set the scissor rect here for the previous draw call.
} else {
mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->
GetPassByIndex(0)->Apply(0);
@ -1006,15 +1023,20 @@ DrawTargetD2D::PushClipRect(const Rect &aRect)
}
PushedClip clip;
Rect rect = mTransform.TransformBounds(aRect);
IntRect intRect;
clip.mIsPixelAligned = rect.ToIntRect(&intRect);
// Do not store the transform, just store the device space rectangle directly.
clip.mBounds = D2DRect(mTransform.TransformBounds(aRect));
clip.mBounds = D2DRect(rect);
mPushedClips.push_back(clip);
mRT->SetTransform(D2D1::IdentityMatrix());
mTransformDirty = true;
if (mClipsArePushed) {
mRT->PushAxisAlignedClip(clip.mBounds, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
mRT->PushAxisAlignedClip(clip.mBounds, clip.mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
}
}
@ -1575,6 +1597,7 @@ DrawTargetD2D::FinalizeRTForOperation(CompositionOp aOperator, const Pattern &aP
mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), nullptr, 0xffffffff);
SetScissorToRect(nullptr);
mDevice->Draw(4, 0);
}
@ -1586,6 +1609,32 @@ DrawTargetD2D::ConvertRectToGeometry(const D2D1_RECT_F& aRect)
return rectGeom.forget();
}
TemporaryRef<ID2D1Geometry>
DrawTargetD2D::GetTransformedGeometry(ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform)
{
RefPtr<ID2D1PathGeometry> tmpGeometry;
factory()->CreatePathGeometry(byRef(tmpGeometry));
RefPtr<ID2D1GeometrySink> currentSink;
tmpGeometry->Open(byRef(currentSink));
aGeometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
aTransform, currentSink);
currentSink->Close();
return tmpGeometry;
}
TemporaryRef<ID2D1Geometry>
DrawTargetD2D::Intersect(ID2D1Geometry *aGeometryA, ID2D1Geometry *aGeometryB)
{
RefPtr<ID2D1PathGeometry> pathGeom;
factory()->CreatePathGeometry(byRef(pathGeom));
RefPtr<ID2D1GeometrySink> sink;
pathGeom->Open(byRef(sink));
aGeometryA->CombineWithGeometry(aGeometryB, D2D1_COMBINE_MODE_INTERSECT, nullptr, sink);
sink->Close();
return pathGeom;
}
static D2D1_RECT_F
IntersectRect(const D2D1_RECT_F& aRect1, const D2D1_RECT_F& aRect2)
{
@ -1598,36 +1647,56 @@ IntersectRect(const D2D1_RECT_F& aRect1, const D2D1_RECT_F& aRect2)
}
TemporaryRef<ID2D1Geometry>
DrawTargetD2D::GetClippedGeometry()
DrawTargetD2D::GetClippedGeometry(IntRect *aClipBounds)
{
if (mCurrentClippedGeometry) {
*aClipBounds = mCurrentClipBounds;
return mCurrentClippedGeometry;
}
mCurrentClipBounds = IntRect(IntPoint(0, 0), mSize);
// if pathGeom is null then pathRect represents the path.
RefPtr<ID2D1Geometry> pathGeom;
D2D1_RECT_F pathRect;
bool pathRectIsAxisAligned = false;
std::vector<DrawTargetD2D::PushedClip>::iterator iter = mPushedClips.begin();
if (iter->mPath) {
RefPtr<ID2D1PathGeometry> tmpGeometry;
factory()->CreatePathGeometry(byRef(tmpGeometry));
RefPtr<ID2D1GeometrySink> currentSink;
tmpGeometry->Open(byRef(currentSink));
iter->mPath->GetGeometry()->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
iter->mTransform, currentSink);
currentSink->Close();
pathGeom = tmpGeometry.forget();
pathGeom = GetTransformedGeometry(iter->mPath->GetGeometry(), iter->mTransform);
} else {
pathRect = iter->mBounds;
pathRectIsAxisAligned = iter->mIsPixelAligned;
}
iter++;
for (;iter != mPushedClips.end(); iter++) {
// Do nothing but add it to the current clip bounds.
if (!iter->mPath && iter->mIsPixelAligned) {
mCurrentClipBounds.IntersectRect(mCurrentClipBounds,
IntRect(iter->mBounds.left, iter->mBounds.top,
int32_t(iter->mBounds.right - iter->mBounds.left),
int32_t(iter->mBounds.bottom - iter->mBounds.top)));
continue;
}
if (!pathGeom) {
if (pathRectIsAxisAligned) {
mCurrentClipBounds.IntersectRect(mCurrentClipBounds,
IntRect(pathRect.left, pathRect.top,
int32_t(pathRect.right - pathRect.left),
int32_t(pathRect.bottom - pathRect.top)));
}
if (iter->mPath) {
pathGeom = ConvertRectToGeometry(pathRect);
// See if pathRect needs to go into the path geometry.
if (!pathRectIsAxisAligned) {
pathGeom = ConvertRectToGeometry(pathRect);
} else {
pathGeom = GetTransformedGeometry(iter->mPath->GetGeometry(), iter->mTransform);
}
} else {
pathRect = IntersectRect(pathRect, iter->mBounds);
pathRectIsAxisAligned = false;
continue;
}
}
@ -1652,10 +1721,15 @@ DrawTargetD2D::GetClippedGeometry()
pathGeom = newGeom.forget();
}
// For now we need mCurrentClippedGeometry to always be non-NULL. This method
// might seem a little strange but it is just fine, if pathGeom is NULL
// pathRect will always still contain 1 clip unaccounted for regardless of
// mCurrentClipBounds.
if (!pathGeom) {
pathGeom = ConvertRectToGeometry(pathRect);
}
mCurrentClippedGeometry = pathGeom.forget();
*aClipBounds = mCurrentClipBounds;
return mCurrentClippedGeometry;
}
@ -1759,7 +1833,7 @@ DrawTargetD2D::PushClipsToRT(ID2D1RenderTarget *aRT)
iter->mTransform, 1.0f, nullptr,
options), iter->mLayer);
} else {
aRT->PushAxisAlignedClip(iter->mBounds, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
aRT->PushAxisAlignedClip(iter->mBounds, iter->mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
}
}
}
@ -1777,12 +1851,15 @@ DrawTargetD2D::PopClipsFromRT(ID2D1RenderTarget *aRT)
}
void
DrawTargetD2D::EnsureClipMaskTexture()
DrawTargetD2D::EnsureClipMaskTexture(IntRect *aBounds)
{
if (mCurrentClipMaskTexture || mPushedClips.empty()) {
*aBounds = mCurrentClipBounds;
return;
}
RefPtr<ID2D1Geometry> geometry = GetClippedGeometry(aBounds);
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_A8_UNORM,
mSize.width,
mSize.height,
@ -1806,8 +1883,6 @@ DrawTargetD2D::EnsureClipMaskTexture()
RefPtr<ID2D1SolidColorBrush> brush;
rt->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), byRef(brush));
RefPtr<ID2D1Geometry> geometry = GetClippedGeometry();
rt->BeginDraw();
rt->Clear(D2D1::ColorF(0, 0));
rt->FillGeometry(geometry, brush);
@ -1940,8 +2015,12 @@ DrawTargetD2D::FillGlyphsManual(ScaledFontDWrite *aFont,
bool isMasking = false;
IntRect clipBoundsStorage;
IntRect *clipBounds = nullptr;
if (!mPushedClips.empty()) {
RefPtr<ID2D1Geometry> geom = GetClippedGeometry();
clipBounds = &clipBoundsStorage;
RefPtr<ID2D1Geometry> geom = GetClippedGeometry(clipBounds);
RefPtr<ID2D1RectangleGeometry> rectGeom;
factory()->CreateRectangleGeometry(D2D1::RectF(rectBounds.x, rectBounds.y,
@ -1951,13 +2030,14 @@ DrawTargetD2D::FillGlyphsManual(ScaledFontDWrite *aFont,
D2D1_GEOMETRY_RELATION relation;
if (FAILED(geom->CompareWithGeometry(rectGeom, D2D1::IdentityMatrix(), &relation)) ||
relation != D2D1_GEOMETRY_RELATION_CONTAINS) {
relation != D2D1_GEOMETRY_RELATION_CONTAINS ) {
isMasking = true;
}
}
if (isMasking) {
EnsureClipMaskTexture();
clipBounds = &clipBoundsStorage;
EnsureClipMaskTexture(clipBounds);
RefPtr<ID3D10ShaderResourceView> srViewMask;
hr = mDevice->CreateShaderResourceView(mCurrentClipMaskTexture, nullptr, byRef(srViewMask));
@ -1983,7 +2063,7 @@ DrawTargetD2D::FillGlyphsManual(ScaledFontDWrite *aFont,
rtViews = rtView;
mDevice->OMSetRenderTargets(1, &rtViews, nullptr);
SetScissorToRect(clipBounds);
mDevice->Draw(4, 0);
return true;
}
@ -2613,5 +2693,22 @@ DrawTargetD2D::GetDWriteFactory()
return mDWriteFactory;
}
void
DrawTargetD2D::SetScissorToRect(IntRect *aRect)
{
D3D10_RECT rect;
if (aRect) {
rect.left = aRect->x;
rect.right = aRect->XMost();
rect.top = aRect->y;
rect.bottom = aRect->YMost();
} else {
rect.left = rect.left = INT32_MIN;
rect.right = rect.top = INT32_MAX;
}
mDevice->RSSetScissorRects(1, &rect);
}
}
}

View File

@ -172,8 +172,9 @@ private:
void PopClipsFromRT(ID2D1RenderTarget *aRT);
// This function ensures mCurrentClipMaskTexture contains a texture containing
// a mask corresponding with the current DrawTarget clip.
void EnsureClipMaskTexture();
// a mask corresponding with the current DrawTarget clip. See
// GetClippedGeometry for a description of aClipBounds.
void EnsureClipMaskTexture(IntRect *aClipBounds);
bool FillGlyphsManual(ScaledFontDWrite *aFont,
const GlyphBuffer &aBuffer,
@ -183,7 +184,14 @@ private:
TemporaryRef<ID2D1RenderTarget> CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat);
TemporaryRef<ID2D1Geometry> ConvertRectToGeometry(const D2D1_RECT_F& aRect);
TemporaryRef<ID2D1Geometry> GetClippedGeometry();
TemporaryRef<ID2D1Geometry> GetTransformedGeometry(ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform);
TemporaryRef<ID2D1Geometry> Intersect(ID2D1Geometry *aGeometryA, ID2D1Geometry *aGeometryB);
// This returns the clipped geometry, in addition it returns aClipBounds which
// represents the intersection of all pixel-aligned rectangular clips that
// are currently set. The returned clipped geometry must be clipped by these
// bounds to correctly reflect the total clip. This is in device space.
TemporaryRef<ID2D1Geometry> GetClippedGeometry(IntRect *aClipBounds);
TemporaryRef<ID2D1Brush> CreateBrushForPattern(const Pattern &aPattern, Float aAlpha = 1.0f);
@ -199,6 +207,10 @@ private:
void SetupEffectForRadialGradient(const RadialGradientPattern *aPattern);
void SetupStateForRendering();
// Set the scissor rect to a certain IntRects, resets the scissor rect to
// surface bounds when NULL is specified.
void SetScissorToRect(IntRect *aRect);
static const uint32_t test = 4;
IntSize mSize;
@ -207,6 +219,10 @@ private:
RefPtr<ID3D10Texture2D> mTexture;
RefPtr<ID3D10Texture2D> mCurrentClipMaskTexture;
RefPtr<ID2D1Geometry> mCurrentClippedGeometry;
// This is only valid if mCurrentClippedGeometry is non-null. And will
// only be the intersection of all pixel-aligned retangular clips. This is in
// device space.
IntRect mCurrentClipBounds;
mutable RefPtr<ID2D1RenderTarget> mRT;
// We store this to prevent excessive SetTextRenderingParams calls.
@ -224,7 +240,12 @@ private:
{
RefPtr<ID2D1Layer> mLayer;
D2D1_RECT_F mBounds;
D2D1_MATRIX_3X2_F mTransform;
union {
// If mPath is non-NULL, the mTransform member will be used, otherwise
// the mIsPixelAligned member is valid.
D2D1_MATRIX_3X2_F mTransform;
bool mIsPixelAligned;
};
RefPtr<PathD2D> mPath;
};
std::vector<PushedClip> mPushedClips;

View File

@ -98,7 +98,7 @@ sampler sShadowSampler = sampler_state {
RasterizerState TextureRast
{
ScissorEnable = False;
ScissorEnable = True;
CullMode = None;
};

View File

@ -75,7 +75,7 @@ SamplerState sShadowSampler
};
RasterizerState TextureRast
{
ScissorEnable = bool(FALSE /* 0 */);
ScissorEnable = bool(TRUE /* 1 */);
CullMode = uint(NONE /* 1 */);
};
BlendState ShadowBlendH
@ -3057,10 +3057,10 @@ technique10 SampleTextTexture
const BYTE d2deffect[] =
{
68, 88, 66, 67, 180, 92,
99, 8, 31, 243, 141, 10,
239, 43, 71, 236, 45, 138,
71, 112, 1, 0, 0, 0,
68, 88, 66, 67, 162, 185,
42, 249, 229, 2, 50, 89,
3, 159, 21, 149, 11, 251,
62, 135, 1, 0, 0, 0,
144, 191, 0, 0, 1, 0,
0, 0, 36, 0, 0, 0,
70, 88, 49, 48, 100, 191,
@ -3212,7 +3212,7 @@ const BYTE d2deffect[] =
0, 0, 84, 101, 120, 116,
117, 114, 101, 82, 97, 115,
116, 0, 1, 0, 0, 0,
2, 0, 0, 0, 0, 0,
2, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0,
2, 0, 0, 0, 1, 0,
0, 0, 66, 108, 101, 110,