From 11de23359f94add7848e1e1fb83d9e94b1f9599d Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Wed, 28 Jan 2015 00:54:19 +0000 Subject: [PATCH] Bug 1089454: Prevent usage of incompatible graphics objects after device reset. r=jrmuizel --- gfx/2d/2D.h | 1 + gfx/2d/DrawTargetD2D.cpp | 2 +- gfx/2d/DrawTargetD2D1.cpp | 15 ++++++++++++++- gfx/2d/GradientStopsD2D.h | 6 +++++- gfx/thebes/gfxGradientCache.cpp | 10 +++++++++- gfx/thebes/gfxPlatform.h | 3 ++- gfx/thebes/gfxWindowsPlatform.cpp | 7 +++++++ 7 files changed, 39 insertions(+), 5 deletions(-) diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index b38f66f986e6..30d7104a5242 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -162,6 +162,7 @@ public: virtual ~GradientStops() {} virtual BackendType GetBackendType() const = 0; + virtual bool IsValid() const { return true; } protected: GradientStops() {} diff --git a/gfx/2d/DrawTargetD2D.cpp b/gfx/2d/DrawTargetD2D.cpp index 7b619cc4d096..8db4f2ef27cb 100644 --- a/gfx/2d/DrawTargetD2D.cpp +++ b/gfx/2d/DrawTargetD2D.cpp @@ -1300,7 +1300,7 @@ DrawTargetD2D::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops, E return nullptr; } - return new GradientStopsD2D(stopCollection); + return new GradientStopsD2D(stopCollection, Factory::GetDirect3D11Device()); } TemporaryRef diff --git a/gfx/2d/DrawTargetD2D1.cpp b/gfx/2d/DrawTargetD2D1.cpp index 484a5b7a1fc0..e21c58fbe071 100644 --- a/gfx/2d/DrawTargetD2D1.cpp +++ b/gfx/2d/DrawTargetD2D1.cpp @@ -725,7 +725,7 @@ DrawTargetD2D1::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops, return nullptr; } - return new GradientStopsD2D(stopCollection); + return new GradientStopsD2D(stopCollection, Factory::GetDirect3D11Device()); } TemporaryRef @@ -1228,6 +1228,12 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)), stops->mStopCollection, byRef(gradBrush)); + + if (!gradBrush) { + gfxWarning() << "Couldn't create gradient brush."; + return CreateTransparentBlackBrush(); + } + return gradBrush.forget(); } if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) { @@ -1251,6 +1257,11 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) stops->mStopCollection, byRef(gradBrush)); + if (!gradBrush) { + gfxWarning() << "Couldn't create gradient brush."; + return CreateTransparentBlackBrush(); + } + return gradBrush.forget(); } if (aPattern.GetType() == PatternType::SURFACE) { @@ -1279,6 +1290,8 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) Float(pat->mSurface->GetSize().height)); } + MOZ_ASSERT(pat->mSurface->IsValid()); + RefPtr imageBrush; RefPtr image = GetImageForSurface(pat->mSurface, mat, pat->mExtendMode, !pat->mSamplingRect.IsEmpty() ? &pat->mSamplingRect : nullptr); diff --git a/gfx/2d/GradientStopsD2D.h b/gfx/2d/GradientStopsD2D.h index e06bfa05e17b..b86151b55757 100644 --- a/gfx/2d/GradientStopsD2D.h +++ b/gfx/2d/GradientStopsD2D.h @@ -17,17 +17,21 @@ class GradientStopsD2D : public GradientStops { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsD2D) - GradientStopsD2D(ID2D1GradientStopCollection *aStopCollection) + GradientStopsD2D(ID2D1GradientStopCollection *aStopCollection, ID3D11Device *aDevice) : mStopCollection(aStopCollection) + , mDevice(aDevice) {} virtual BackendType GetBackendType() const { return BackendType::DIRECT2D; } + virtual bool IsValid() const MOZ_FINAL{ return mDevice == Factory::GetDirect3D11Device(); } + private: friend class DrawTargetD2D; friend class DrawTargetD2D1; mutable RefPtr mStopCollection; + RefPtr mDevice; }; } diff --git a/gfx/thebes/gfxGradientCache.cpp b/gfx/thebes/gfxGradientCache.cpp index bb15913d696e..7e1e40c4c86c 100644 --- a/gfx/thebes/gfxGradientCache.cpp +++ b/gfx/thebes/gfxGradientCache.cpp @@ -185,7 +185,15 @@ gfxGradientCache::GetGradientStops(const DrawTarget *aDT, nsTArray } GradientCacheData* cached = gGradientCache->Lookup(aStops, aExtend, aDT->GetBackendType()); - return cached ? cached->mStops : nullptr; + if (cached && cached->mStops) { + if (!cached->mStops->IsValid()) { + gGradientCache->NotifyExpired(cached); + } else { + return cached->mStops; + } + } + + return nullptr; } GradientStops * diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index d99ab3a4f90a..495e6f797ae5 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -673,6 +673,8 @@ protected: // Hardware vsync source. Only valid on parent process nsRefPtr mVsyncSource; + mozilla::RefPtr mScreenReferenceDrawTarget; + private: /** * Start up Thebes. @@ -688,7 +690,6 @@ private: virtual void GetPlatformCMSOutputProfile(void *&mem, size_t &size); nsRefPtr mScreenReferenceSurface; - mozilla::RefPtr mScreenReferenceDrawTarget; nsTArray mCJKPrefLangs; nsCOMPtr mSRGBOverrideObserver; nsCOMPtr mFontPrefsObserver; diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 133d50e46d53..317cc3d5b98c 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -386,6 +386,7 @@ gfxWindowsPlatform::UpdateRenderMode() /* Pick the default render mode for * desktop. */ + bool didReset = false; if (DidRenderingDeviceReset()) { mD3D11DeviceInitialized = false; mD3D11Device = nullptr; @@ -395,6 +396,8 @@ gfxWindowsPlatform::UpdateRenderMode() imgLoader::Singleton()->ClearCache(true); imgLoader::Singleton()->ClearCache(false); Factory::SetDirect3D11Device(nullptr); + + didReset = true; } mRenderMode = RENDER_GDI; @@ -512,6 +515,10 @@ gfxWindowsPlatform::UpdateRenderMode() contentMask |= BackendTypeBit(BackendType::SKIA); InitBackendPrefs(canvasMask, defaultBackend, contentMask, defaultBackend); + + if (didReset) { + mScreenReferenceDrawTarget = CreateOffscreenContentDrawTarget(IntSize(1, 1), SurfaceFormat::B8G8R8A8); + } } #ifdef CAIRO_HAS_D2D_SURFACE