Bug 1530471 - remove SkiaGL Canvas2D functionality r=jrmuizel

Depends on D21050

Differential Revision: https://phabricator.services.mozilla.com/D21051

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Lee Salzman 2019-02-28 14:58:19 +00:00
Родитель 5092fbb7ef
Коммит f5b37f6034
6 изменённых файлов: 41 добавлений и 563 удалений

Просмотреть файл

@ -27,12 +27,10 @@ using namespace gfx;
* due to CORS security.
*/
struct ImageCacheKey {
ImageCacheKey(imgIContainer* aImage, HTMLCanvasElement* aCanvas,
bool aIsAccelerated)
: mImage(aImage), mCanvas(aCanvas), mIsAccelerated(aIsAccelerated) {}
ImageCacheKey(imgIContainer* aImage, HTMLCanvasElement* aCanvas)
: mImage(aImage), mCanvas(aCanvas) {}
nsCOMPtr<imgIContainer> mImage;
HTMLCanvasElement* mCanvas;
bool mIsAccelerated;
};
/**
@ -43,13 +41,11 @@ struct ImageCacheEntryData {
ImageCacheEntryData(const ImageCacheEntryData& aOther)
: mImage(aOther.mImage),
mCanvas(aOther.mCanvas),
mIsAccelerated(aOther.mIsAccelerated),
mSourceSurface(aOther.mSourceSurface),
mSize(aOther.mSize) {}
explicit ImageCacheEntryData(const ImageCacheKey& aKey)
: mImage(aKey.mImage),
mCanvas(aKey.mCanvas),
mIsAccelerated(aKey.mIsAccelerated) {}
mCanvas(aKey.mCanvas) {}
nsExpirationState* GetExpirationState() { return &mState; }
size_t SizeInBytes() { return mSize.width * mSize.height * 4; }
@ -57,7 +53,6 @@ struct ImageCacheEntryData {
// Key
nsCOMPtr<imgIContainer> mImage;
HTMLCanvasElement* mCanvas;
bool mIsAccelerated;
// Value
RefPtr<SourceSurface> mSourceSurface;
IntSize mSize;
@ -76,13 +71,12 @@ class ImageCacheEntry : public PLDHashEntryHdr {
~ImageCacheEntry() {}
bool KeyEquals(KeyTypePointer key) const {
return mData->mImage == key->mImage && mData->mCanvas == key->mCanvas &&
mData->mIsAccelerated == key->mIsAccelerated;
return mData->mImage == key->mImage && mData->mCanvas == key->mCanvas;
}
static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
static PLDHashNumber HashKey(KeyTypePointer key) {
return HashGeneric(key->mImage.get(), key->mCanvas, key->mIsAccelerated);
return HashGeneric(key->mImage.get(), key->mCanvas);
}
enum { ALLOW_MEMMOVE = true };
@ -93,11 +87,10 @@ class ImageCacheEntry : public PLDHashEntryHdr {
* Used for all images across all canvases.
*/
struct AllCanvasImageCacheKey {
AllCanvasImageCacheKey(imgIContainer* aImage, bool aIsAccelerated)
: mImage(aImage), mIsAccelerated(aIsAccelerated) {}
explicit AllCanvasImageCacheKey(imgIContainer* aImage)
: mImage(aImage) {}
nsCOMPtr<imgIContainer> mImage;
bool mIsAccelerated;
};
class AllCanvasImageCacheEntry : public PLDHashEntryHdr {
@ -106,27 +99,25 @@ class AllCanvasImageCacheEntry : public PLDHashEntryHdr {
typedef const AllCanvasImageCacheKey* KeyTypePointer;
explicit AllCanvasImageCacheEntry(const KeyType* aKey)
: mImage(aKey->mImage), mIsAccelerated(aKey->mIsAccelerated) {}
: mImage(aKey->mImage) {}
AllCanvasImageCacheEntry(const AllCanvasImageCacheEntry& toCopy)
: mImage(toCopy.mImage),
mIsAccelerated(toCopy.mIsAccelerated),
mSourceSurface(toCopy.mSourceSurface) {}
~AllCanvasImageCacheEntry() {}
bool KeyEquals(KeyTypePointer key) const {
return mImage == key->mImage && mIsAccelerated == key->mIsAccelerated;
return mImage == key->mImage;
}
static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
static PLDHashNumber HashKey(KeyTypePointer key) {
return HashGeneric(key->mImage.get(), key->mIsAccelerated);
return HashGeneric(key->mImage.get());
}
enum { ALLOW_MEMMOVE = true };
nsCOMPtr<imgIContainer> mImage;
bool mIsAccelerated;
RefPtr<SourceSurface> mSourceSurface;
};
@ -149,11 +140,10 @@ class ImageCache final : public nsExpirationTracker<ImageCacheEntryData, 4> {
// Remove from the all canvas cache entry first since nsExpirationTracker
// will delete aObject.
mAllCanvasCache.RemoveEntry(
AllCanvasImageCacheKey(aObject->mImage, aObject->mIsAccelerated));
AllCanvasImageCacheKey(aObject->mImage));
// Deleting the entry will delete aObject since the entry owns aObject.
mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas,
aObject->mIsAccelerated));
mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas));
}
nsTHashtable<ImageCacheEntry> mCache;
@ -273,8 +263,7 @@ static already_AddRefed<imgIContainer> GetImageContainer(dom::Element* aImage) {
void CanvasImageCache::NotifyDrawImage(Element* aImage,
HTMLCanvasElement* aCanvas,
SourceSurface* aSource,
const IntSize& aSize,
bool aIsAccelerated) {
const IntSize& aSize) {
if (!gImageCache) {
gImageCache = new ImageCache();
nsContentUtils::RegisterShutdownObserver(
@ -286,8 +275,8 @@ void CanvasImageCache::NotifyDrawImage(Element* aImage,
return;
}
AllCanvasImageCacheKey allCanvasCacheKey(imgContainer, aIsAccelerated);
ImageCacheKey canvasCacheKey(imgContainer, aCanvas, aIsAccelerated);
AllCanvasImageCacheKey allCanvasCacheKey(imgContainer);
ImageCacheKey canvasCacheKey(imgContainer, aCanvas);
ImageCacheEntry* entry = gImageCache->mCache.PutEntry(canvasCacheKey);
if (entry) {
@ -317,8 +306,7 @@ void CanvasImageCache::NotifyDrawImage(Element* aImage,
gImageCache->AgeOneGeneration();
}
SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage,
bool aIsAccelerated) {
SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage) {
if (!gImageCache) {
return nullptr;
}
@ -329,7 +317,7 @@ SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage,
}
AllCanvasImageCacheEntry* entry = gImageCache->mAllCanvasCache.GetEntry(
AllCanvasImageCacheKey(imgContainer, aIsAccelerated));
AllCanvasImageCacheKey(imgContainer));
if (!entry) {
return nullptr;
}
@ -339,8 +327,7 @@ SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage,
SourceSurface* CanvasImageCache::LookupCanvas(Element* aImage,
HTMLCanvasElement* aCanvas,
IntSize* aSizeOut,
bool aIsAccelerated) {
IntSize* aSizeOut) {
if (!gImageCache) {
return nullptr;
}
@ -351,7 +338,7 @@ SourceSurface* CanvasImageCache::LookupCanvas(Element* aImage,
}
ImageCacheEntry* entry = gImageCache->mCache.GetEntry(
ImageCacheKey(imgContainer, aCanvas, aIsAccelerated));
ImageCacheKey(imgContainer, aCanvas));
if (!entry) {
return nullptr;
}

Просмотреть файл

@ -33,15 +33,13 @@ class CanvasImageCache {
*/
static void NotifyDrawImage(dom::Element* aImage,
dom::HTMLCanvasElement* aCanvas,
SourceSurface* aSource, const gfx::IntSize& aSize,
bool aIsAccelerated);
SourceSurface* aSource, const gfx::IntSize& aSize);
/**
* Check whether aImage has recently been drawn any canvas. If we return
* a non-null surface, then the same image was recently drawn into a canvas.
*/
static SourceSurface* LookupAllCanvas(dom::Element* aImage,
bool aIsAccelerated);
static SourceSurface* LookupAllCanvas(dom::Element* aImage);
/**
* Like the top above, but restricts the lookup to only aCanvas. This is
@ -49,8 +47,7 @@ class CanvasImageCache {
*/
static SourceSurface* LookupCanvas(dom::Element* aImage,
dom::HTMLCanvasElement* aCanvas,
gfx::IntSize* aSizeOut,
bool aIsAccelerated);
gfx::IntSize* aSizeOut);
};
} // namespace mozilla

Просмотреть файл

@ -106,8 +106,6 @@
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/FloatingPoint.h"
#include "nsGlobalWindow.h"
#include "GLContext.h"
#include "GLContextProvider.h"
#include "nsIScreenManager.h"
#include "nsFilterInstance.h"
#include "nsSVGLength2.h"
@ -125,16 +123,6 @@
#undef free // apparently defined by some windows header, clashing with a
// free() method in SkTypes.h
#include "SkiaGLGlue.h"
#ifdef USE_SKIA
# include "SurfaceTypes.h"
# include "GLBlitHelper.h"
# include "ScopedGLHelpers.h"
#endif
using mozilla::gl::GLContext;
using mozilla::gl::GLContextProvider;
using mozilla::gl::SkiaGLGlue;
#ifdef XP_WIN
# include "gfxWindowsPlatform.h"
@ -760,105 +748,6 @@ CanvasShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
return NS_OK;
}
class CanvasDrawObserver {
public:
explicit CanvasDrawObserver(CanvasRenderingContext2D* aCanvasContext);
// Only enumerate draw calls that could affect the heuristic
enum DrawCallType { PutImageData, GetImageData, DrawImage };
// This is the one that we call on relevant draw calls and count
// GPU vs. CPU preferrable calls...
void DidDrawCall(DrawCallType aType);
// When this returns true, the observer is done making the decisions.
// Right now, we expect to get rid of the observer after the FrameEnd
// returns true, though the decision could eventually change if the
// function calls shift. If we change to monitor the functions called
// and make decisions to change more than once, we would probably want
// FrameEnd to reset the timer and counters as it returns true.
bool FrameEnd();
private:
// These values will be picked up from preferences:
int32_t mMinFramesBeforeDecision;
float mMinSecondsBeforeDecision;
int32_t mMinCallsBeforeDecision;
CanvasRenderingContext2D* mCanvasContext;
int32_t mSoftwarePreferredCalls;
int32_t mGPUPreferredCalls;
int32_t mFramesRendered;
TimeStamp mCreationTime;
};
// We are not checking for the validity of the preference values. For example,
// negative values will have an effect of a quick exit, so no harm done.
CanvasDrawObserver::CanvasDrawObserver(CanvasRenderingContext2D* aCanvasContext)
: mMinFramesBeforeDecision(gfxPrefs::CanvasAutoAccelerateMinFrames()),
mMinSecondsBeforeDecision(gfxPrefs::CanvasAutoAccelerateMinSeconds()),
mMinCallsBeforeDecision(gfxPrefs::CanvasAutoAccelerateMinCalls()),
mCanvasContext(aCanvasContext),
mSoftwarePreferredCalls(0),
mGPUPreferredCalls(0),
mFramesRendered(0),
mCreationTime(TimeStamp::NowLoRes()) {}
void CanvasDrawObserver::DidDrawCall(DrawCallType aType) {
switch (aType) {
case PutImageData:
case GetImageData:
if (mGPUPreferredCalls == 0 && mSoftwarePreferredCalls == 0) {
mCreationTime = TimeStamp::NowLoRes();
}
mSoftwarePreferredCalls++;
break;
case DrawImage:
if (mGPUPreferredCalls == 0 && mSoftwarePreferredCalls == 0) {
mCreationTime = TimeStamp::NowLoRes();
}
mGPUPreferredCalls++;
break;
}
}
// If we return true, the observer is done making the decisions...
bool CanvasDrawObserver::FrameEnd() {
mFramesRendered++;
// We log the first mMinFramesBeforeDecision frames of any
// canvas object then make a call to determine whether it should
// be GPU or CPU backed
if ((mFramesRendered >= mMinFramesBeforeDecision) ||
((TimeStamp::NowLoRes() - mCreationTime).ToSeconds()) >
mMinSecondsBeforeDecision) {
// If we don't have enough data, don't bother changing...
if (mGPUPreferredCalls > mMinCallsBeforeDecision ||
mSoftwarePreferredCalls > mMinCallsBeforeDecision) {
CanvasRenderingContext2D::RenderingMode switchToMode;
if (mGPUPreferredCalls >= mSoftwarePreferredCalls) {
switchToMode =
CanvasRenderingContext2D::RenderingMode::OpenGLBackendMode;
} else {
switchToMode =
CanvasRenderingContext2D::RenderingMode::SoftwareBackendMode;
}
if (switchToMode != mCanvasContext->mRenderingMode) {
if (!mCanvasContext->SwitchRenderingMode(switchToMode)) {
gfxDebug() << "Canvas acceleration failed mode switch to "
<< switchToMode;
}
}
}
// If we ever redesign this class to constantly monitor the functions
// and keep making decisions, we would probably want to reset the counters
// and the timers here...
return true;
}
return false;
}
class CanvasRenderingContext2DUserData : public LayerUserData {
public:
explicit CanvasRenderingContext2DUserData(CanvasRenderingContext2D* aContext)
@ -884,12 +773,6 @@ class CanvasRenderingContext2DUserData : public LayerUserData {
static_cast<CanvasRenderingContext2D*>(aData);
if (context) {
context->MarkContextClean();
if (context->mDrawObserver) {
if (context->mDrawObserver->FrameEnd()) {
// Note that this call deletes and nulls out mDrawObserver:
context->RemoveDrawObserver();
}
}
}
}
bool IsForContext(CanvasRenderingContext2D* aContext) {
@ -909,7 +792,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(CanvasRenderingContext2D)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CanvasRenderingContext2D)
// Make sure we remove ourselves from the list of demotable contexts (raw
// pointers), since we're logically destructed at this point.
CanvasRenderingContext2D::RemoveDemotableContext(tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCanvasElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
for (uint32_t i = 0; i < tmp->mStyleStack.Length(); i++) {
@ -1000,15 +882,10 @@ NS_INTERFACE_MAP_END
// Initialize our static variables.
uintptr_t CanvasRenderingContext2D::sNumLivingContexts = 0;
DrawTarget* CanvasRenderingContext2D::sErrorTarget = nullptr;
static bool sMaxContextsInitialized = false;
static int32_t sMaxContexts = 0;
CanvasRenderingContext2D::CanvasRenderingContext2D(
layers::LayersBackend aCompositorBackend)
: mRenderingMode(RenderingMode::OpenGLBackendMode),
mCompositorBackend(aCompositorBackend)
// these are the default values from the Canvas spec
,
: // these are the default values from the Canvas spec
mWidth(0),
mHeight(0),
mZero(false),
@ -1017,35 +894,21 @@ CanvasRenderingContext2D::CanvasRenderingContext2D(
mOpaque(false),
mResetLayer(true),
mIPC(false),
mIsSkiaGL(false),
mHasPendingStableStateCallback(false),
mDrawObserver(nullptr),
mIsEntireFrameInvalid(false),
mPredictManyRedrawCalls(false),
mIsCapturedFrameInvalid(false),
mPathTransformWillUpdate(false),
mInvalidateCount(0),
mWriteOnly(false) {
if (!sMaxContextsInitialized) {
sMaxContexts = gfxPrefs::CanvasAzureAcceleratedLimit();
sMaxContextsInitialized = true;
}
sNumLivingContexts++;
mShutdownObserver = new CanvasShutdownObserver(this);
nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
// The default is to use OpenGL mode
if (AllowOpenGLCanvas()) {
mDrawObserver = new CanvasDrawObserver(this);
} else {
mRenderingMode = RenderingMode::SoftwareBackendMode;
}
}
CanvasRenderingContext2D::~CanvasRenderingContext2D() {
RemoveDrawObserver();
RemovePostRefreshObserver();
RemoveShutdownObserver();
Reset();
@ -1057,7 +920,6 @@ CanvasRenderingContext2D::~CanvasRenderingContext2D() {
if (!sNumLivingContexts) {
NS_IF_RELEASE(sErrorTarget);
}
RemoveDemotableContext(this);
}
JSObject* CanvasRenderingContext2D::WrapObject(
@ -1228,13 +1090,6 @@ void CanvasRenderingContext2D::Redraw(const gfx::Rect& aR) {
}
void CanvasRenderingContext2D::DidRefresh() {
if (IsTargetValid() && mIsSkiaGL) {
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
MOZ_ASSERT(glue);
auto gl = glue->GetGLContext();
gl->FlushIfHeavyGLCallsSinceLastFlush();
}
}
void CanvasRenderingContext2D::RedrawUser(const gfxRect& aR) {
@ -1249,70 +1104,6 @@ void CanvasRenderingContext2D::RedrawUser(const gfxRect& aR) {
Redraw(newr);
}
bool CanvasRenderingContext2D::AllowOpenGLCanvas() const {
// If we somehow didn't have the correct compositor in the constructor,
// we could do something like this to get it:
//
// HTMLCanvasElement* el = GetCanvas();
// if (el) {
// mCompositorBackend = el->GetCompositorBackendType();
// }
//
// We could have LAYERS_NONE if there was no widget at the time of
// canvas creation, but in that case the
// HTMLCanvasElement::GetCompositorBackendType would return LAYERS_NONE
// as well, so it wouldn't help much.
//
// XXX Disable SkiaGL on WebRender, since there is a case that R8G8B8X8
// is used, but WebRender does not support R8G8B8X8.
return (mCompositorBackend == LayersBackend::LAYERS_OPENGL) &&
gfxPlatform::GetPlatform()->AllowOpenGLCanvas();
}
bool CanvasRenderingContext2D::SwitchRenderingMode(
RenderingMode aRenderingMode) {
if (!(IsTargetValid() || mBufferProvider) ||
mRenderingMode == aRenderingMode) {
return false;
}
MOZ_ASSERT(mBufferProvider);
#ifdef USE_SKIA_GPU
// Do not attempt to switch into GL mode if the platform doesn't allow it.
if ((aRenderingMode == RenderingMode::OpenGLBackendMode) &&
!AllowOpenGLCanvas()) {
return false;
}
#endif
RefPtr<PersistentBufferProvider> oldBufferProvider = mBufferProvider;
// Return the old target to the buffer provider.
// We need to do this before calling EnsureTarget.
ReturnTarget();
mTarget = nullptr;
mBufferProvider = nullptr;
mResetLayer = true;
// Recreate mTarget using the new rendering mode
RenderingMode attemptedMode = EnsureTarget(nullptr, aRenderingMode);
if (!IsTargetValid()) {
return false;
}
if (oldBufferProvider && mTarget) {
CopyBufferProvider(*oldBufferProvider, *mTarget,
IntRect(0, 0, mWidth, mHeight));
}
// We succeeded, so update mRenderingMode to reflect reality
mRenderingMode = attemptedMode;
return true;
}
bool CanvasRenderingContext2D::CopyBufferProvider(
PersistentBufferProvider& aOld, DrawTarget& aTarget, IntRect aCopyRect) {
// Borrowing the snapshot must be done after ReturnTarget.
@ -1328,119 +1119,6 @@ bool CanvasRenderingContext2D::CopyBufferProvider(
}
void CanvasRenderingContext2D::Demote() {
if (SwitchRenderingMode(RenderingMode::SoftwareBackendMode)) {
RemoveDemotableContext(this);
}
}
std::vector<CanvasRenderingContext2D*>&
CanvasRenderingContext2D::DemotableContexts() {
// This is a list of raw pointers to cycle-collected objects. We need to
// ensure that we remove elements from it during UNLINK (which can happen
// considerably before the actual destructor) since the object is logically
// destroyed at that point and will be in an inconsistant state.
static std::vector<CanvasRenderingContext2D*> contexts;
return contexts;
}
void CanvasRenderingContext2D::DemoteOldestContextIfNecessary() {
MOZ_ASSERT(sMaxContextsInitialized);
if (sMaxContexts <= 0) {
return;
}
std::vector<CanvasRenderingContext2D*>& contexts = DemotableContexts();
if (contexts.size() < (size_t)sMaxContexts) return;
CanvasRenderingContext2D* oldest = contexts.front();
if (oldest->SwitchRenderingMode(RenderingMode::SoftwareBackendMode)) {
RemoveDemotableContext(oldest);
}
}
void CanvasRenderingContext2D::AddDemotableContext(
CanvasRenderingContext2D* aContext) {
MOZ_ASSERT(sMaxContextsInitialized);
if (sMaxContexts <= 0) return;
std::vector<CanvasRenderingContext2D*>::iterator iter = std::find(
DemotableContexts().begin(), DemotableContexts().end(), aContext);
if (iter != DemotableContexts().end()) return;
DemotableContexts().push_back(aContext);
}
void CanvasRenderingContext2D::RemoveDemotableContext(
CanvasRenderingContext2D* aContext) {
MOZ_ASSERT(sMaxContextsInitialized);
if (sMaxContexts <= 0) return;
std::vector<CanvasRenderingContext2D*>::iterator iter = std::find(
DemotableContexts().begin(), DemotableContexts().end(), aContext);
if (iter != DemotableContexts().end()) DemotableContexts().erase(iter);
}
#define MIN_SKIA_GL_DIMENSION 16
bool CanvasRenderingContext2D::CheckSizeForSkiaGL(IntSize aSize) {
MOZ_ASSERT(NS_IsMainThread());
int minsize = Preferences::GetInt("gfx.canvas.min-size-for-skia-gl", 128);
if (aSize.width < MIN_SKIA_GL_DIMENSION ||
aSize.height < MIN_SKIA_GL_DIMENSION ||
(aSize.width * aSize.height < minsize * minsize)) {
return false;
}
// Maximum pref allows 3 different options:
// 0 means unlimited size
// > 0 means use value as an absolute threshold
// < 0 means use the number of screen pixels as a threshold
int maxsize = Preferences::GetInt("gfx.canvas.max-size-for-skia-gl", 0);
// unlimited max size
if (!maxsize) {
return true;
}
// absolute max size threshold
if (maxsize > 0) {
return aSize.width <= maxsize && aSize.height <= maxsize;
}
// Cache the number of pixels on the primary screen
static int32_t gScreenPixels = -1;
if (gScreenPixels < 0) {
// Default to historical mobile screen size of 980x480, like FishIEtank.
// In addition, allow skia use up to this size even if the screen is
// smaller. A lot content expects this size to work well. See Bug 999841
if (gfxPlatform::GetPlatform()->HasEnoughTotalSystemMemoryForSkiaGL()) {
gScreenPixels = 980 * 480;
}
nsCOMPtr<nsIScreenManager> screenManager =
do_GetService("@mozilla.org/gfx/screenmanager;1");
if (screenManager) {
nsCOMPtr<nsIScreen> primaryScreen;
screenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen));
if (primaryScreen) {
int32_t x, y, width, height;
primaryScreen->GetRect(&x, &y, &width, &height);
gScreenPixels = std::max(gScreenPixels, width * height);
}
}
}
// Just always use a scale of 1.0. It can be changed if a lot of contents need
// it.
static double gDefaultScale = 1.0;
double scale = gDefaultScale > 0 ? gDefaultScale : 1.0;
int32_t threshold = ceil(scale * scale * gScreenPixels);
// screen size acts as max threshold
return threshold < 0 || (aSize.width * aSize.height) <= threshold;
}
void CanvasRenderingContext2D::ScheduleStableStateCallback() {
@ -1489,30 +1167,22 @@ void CanvasRenderingContext2D::RestoreClipsAndTransformToTarget() {
}
}
CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(
const gfx::Rect* aCoveredRect, RenderingMode aRenderingMode) {
bool CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect) {
if (AlreadyShutDown()) {
gfxCriticalError() << "Attempt to render into a Canvas2d after shutdown.";
SetErrorState();
return aRenderingMode;
return false;
}
// This would make no sense, so make sure we don't get ourselves in a mess
MOZ_ASSERT(mRenderingMode != RenderingMode::DefaultBackendMode);
RenderingMode mode = (aRenderingMode == RenderingMode::DefaultBackendMode)
? mRenderingMode
: aRenderingMode;
if (mTarget && mode == mRenderingMode) {
return mRenderingMode;
if (mTarget) {
return true;
}
// Check that the dimensions are sane
if (mWidth > gfxPrefs::MaxCanvasSize() ||
mHeight > gfxPrefs::MaxCanvasSize() || mWidth < 0 || mHeight < 0) {
SetErrorState();
return aRenderingMode;
return false;
}
// If the next drawing command covers the entire canvas, we can skip copying
@ -1542,7 +1212,7 @@ CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(
IntRect persistedRect =
canDiscardContent ? IntRect() : IntRect(0, 0, mWidth, mHeight);
if (mBufferProvider && mode == mRenderingMode) {
if (mBufferProvider) {
mTarget = mBufferProvider->BorrowDrawTarget(persistedRect);
if (mTarget && !mBufferProvider->PreservesDrawingState()) {
@ -1550,28 +1220,21 @@ CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(
}
if (mTarget) {
return mode;
return true;
}
}
RefPtr<DrawTarget> newTarget;
RefPtr<PersistentBufferProvider> newProvider;
if (mode == RenderingMode::OpenGLBackendMode &&
!TrySkiaGLTarget(newTarget, newProvider)) {
// Fall back to software.
mode = RenderingMode::SoftwareBackendMode;
}
if (mode == RenderingMode::SoftwareBackendMode &&
!TrySharedTarget(newTarget, newProvider) &&
if (!TrySharedTarget(newTarget, newProvider) &&
!TryBasicTarget(newTarget, newProvider)) {
gfxCriticalError(
CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(GetSize())))
<< "Failed borrow shared and basic targets.";
SetErrorState();
return mode;
return false;
}
MOZ_ASSERT(newTarget);
@ -1612,7 +1275,7 @@ CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(
// canvas is already invalid, which can speed up future drawing.
Redraw();
return mode;
return true;
}
void CanvasRenderingContext2D::SetInitialState() {
@ -1672,57 +1335,6 @@ static already_AddRefed<LayerManager> LayerManagerFromCanvasElement(
aCanvasElement->OwnerDoc());
}
bool CanvasRenderingContext2D::TrySkiaGLTarget(
RefPtr<gfx::DrawTarget>& aOutDT,
RefPtr<layers::PersistentBufferProvider>& aOutProvider) {
aOutDT = nullptr;
aOutProvider = nullptr;
mIsSkiaGL = false;
IntSize size(mWidth, mHeight);
if (!AllowOpenGLCanvas() || !CheckSizeForSkiaGL(size)) {
return false;
}
RefPtr<LayerManager> layerManager =
LayerManagerFromCanvasElement(mCanvasElement);
if (!layerManager) {
return false;
}
DemoteOldestContextIfNecessary();
mBufferProvider = nullptr;
#ifdef USE_SKIA_GPU
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
if (!glue || !glue->GetGrContext() || !glue->GetGLContext()) {
return false;
}
SurfaceFormat format = GetSurfaceFormat();
aOutDT = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(),
size, format);
if (!aOutDT) {
gfxCriticalNote
<< "Failed to create a SkiaGL DrawTarget, falling back to software\n";
return false;
}
MOZ_ASSERT(aOutDT->GetType() == DrawTargetType::HARDWARE_RASTER);
AddDemotableContext(this);
aOutProvider = new PersistentBufferProviderBasic(aOutDT);
mIsSkiaGL = true;
// Drop a note in the debug builds if we ever use accelerated Skia canvas.
gfxWarningOnce() << "Using SkiaGL canvas.";
#endif
// could still be null if USE_SKIA_GPU is not #defined.
return !!aOutDT;
}
bool CanvasRenderingContext2D::TrySharedTarget(
RefPtr<gfx::DrawTarget>& aOutDT,
RefPtr<layers::PersistentBufferProvider>& aOutProvider) {
@ -1912,16 +1524,6 @@ CanvasRenderingContext2D::SetContextOptions(JSContext* aCx,
return NS_ERROR_UNEXPECTED;
}
if (Preferences::GetBool("gfx.canvas.willReadFrequently.enable", false)) {
// Use software when there is going to be a lot of readback
if (attributes.mWillReadFrequently) {
// We want to lock into software, so remove the observer that
// may potentially change that...
RemoveDrawObserver();
mRenderingMode = RenderingMode::SoftwareBackendMode;
}
}
mContextAttributesHasAlpha = attributes.mAlpha;
UpdateIsOpaque();
@ -4537,7 +4139,7 @@ CanvasRenderingContext2D::CachedSurfaceFromElement(Element* aElement) {
return res;
}
res.mSourceSurface = CanvasImageCache::LookupAllCanvas(aElement, mIsSkiaGL);
res.mSourceSurface = CanvasImageCache::LookupAllCanvas(aElement);
if (!res.mSourceSurface) {
return res;
}
@ -4576,10 +4178,6 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
double aDw, double aDh,
uint8_t aOptional_argc,
ErrorResult& aError) {
if (mDrawObserver) {
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::DrawImage);
}
MOZ_ASSERT(aOptional_argc == 0 || aOptional_argc == 2 || aOptional_argc == 6);
if (!ValidateRect(aDx, aDy, aDw, aDh, true)) {
@ -4640,8 +4238,7 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
element = video;
}
srcSurf = CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize,
mIsSkiaGL);
srcSurf = CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize);
}
nsLayoutUtils::DirectDrawInfo drawInfo;
@ -4692,7 +4289,7 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
if (res.mSourceSurface) {
if (res.mImageRequest) {
CanvasImageCache::NotifyDrawImage(
element, mCanvasElement, res.mSourceSurface, imgSize, mIsSkiaGL);
element, mCanvasElement, res.mSourceSurface, imgSize);
}
srcSurf = res.mSourceSurface;
} else {
@ -5118,10 +4715,6 @@ void CanvasRenderingContext2D::DrawWindow(nsGlobalWindowInner& aWindow,
already_AddRefed<ImageData> CanvasRenderingContext2D::GetImageData(
JSContext* aCx, double aSx, double aSy, double aSw, double aSh,
nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) {
if (mDrawObserver) {
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::GetImageData);
}
if (!mCanvasElement && !mDocShell) {
NS_ERROR("No canvas element and no docshell in GetImageData!!!");
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
@ -5190,10 +4783,6 @@ already_AddRefed<ImageData> CanvasRenderingContext2D::GetImageData(
nsresult CanvasRenderingContext2D::GetImageDataArray(
JSContext* aCx, int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight,
nsIPrincipal& aSubjectPrincipal, JSObject** aRetval) {
if (mDrawObserver) {
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::GetImageData);
}
MOZ_ASSERT(aWidth && aHeight);
CheckedInt<uint32_t> len = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
@ -5349,10 +4938,6 @@ nsresult CanvasRenderingContext2D::PutImageData_explicit(
int32_t aX, int32_t aY, uint32_t aW, uint32_t aH,
dom::Uint8ClampedArray* aArray, bool aHasDirtyRect, int32_t aDirtyX,
int32_t aDirtyY, int32_t aDirtyWidth, int32_t aDirtyHeight) {
if (mDrawObserver) {
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::PutImageData);
}
if (aW == 0 || aH == 0) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
@ -5520,29 +5105,11 @@ already_AddRefed<ImageData> CanvasRenderingContext2D::CreateImageData(
static uint8_t g2DContextLayerUserData;
uint32_t CanvasRenderingContext2D::SkiaGLTex() const {
if (!mTarget) {
return 0;
}
MOZ_ASSERT(IsTargetValid());
return (uint32_t)(uintptr_t)mTarget->GetNativeSurface(
NativeSurfaceType::OPENGL_TEXTURE);
}
void CanvasRenderingContext2D::RemoveDrawObserver() {
if (mDrawObserver) {
delete mDrawObserver;
mDrawObserver = nullptr;
}
}
already_AddRefed<Layer> CanvasRenderingContext2D::GetCanvasLayer(
nsDisplayListBuilder* aBuilder, Layer* aOldLayer, LayerManager* aManager) {
if (mOpaque || mIsSkiaGL) {
if (mOpaque) {
// If we're opaque then make sure we have a surface so we paint black
// instead of transparent.
// If we're using SkiaGL, then SkiaGLTex() below needs the target to
// be accessible.
EnsureTarget();
}
@ -5563,16 +5130,6 @@ already_AddRefed<Layer> CanvasRenderingContext2D::GetCanvasLayer(
CanvasInitializeData data;
if (mIsSkiaGL) {
GLuint skiaGLTex = SkiaGLTex();
if (skiaGLTex) {
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
MOZ_ASSERT(glue);
data.mGLContext = glue->GetGLContext();
data.mFrontbufferGLTex = skiaGLTex;
}
}
data.mBufferProvider = mBufferProvider;
if (userData && userData->IsForContext(this) &&
@ -5619,11 +5176,9 @@ already_AddRefed<Layer> CanvasRenderingContext2D::GetCanvasLayer(
bool CanvasRenderingContext2D::UpdateWebRenderCanvasData(
nsDisplayListBuilder* aBuilder, WebRenderCanvasData* aCanvasData) {
if (mOpaque || mIsSkiaGL) {
if (mOpaque) {
// If we're opaque then make sure we have a surface so we paint black
// instead of transparent.
// If we're using SkiaGL, then SkiaGLTex() below needs the target to
// be accessible.
EnsureTarget();
}
@ -5645,15 +5200,6 @@ bool CanvasRenderingContext2D::UpdateWebRenderCanvasData(
if (!mResetLayer && renderer) {
CanvasInitializeData data;
if (mIsSkiaGL) {
GLuint skiaGLTex = SkiaGLTex();
if (skiaGLTex) {
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
MOZ_ASSERT(glue);
data.mGLContext = glue->GetGLContext();
data.mFrontbufferGLTex = skiaGLTex;
}
}
data.mBufferProvider = mBufferProvider;
if (renderer->IsDataValid(data)) {
@ -5695,16 +5241,6 @@ bool CanvasRenderingContext2D::InitializeCanvasRenderer(
}
}
if (mIsSkiaGL) {
GLuint skiaGLTex = SkiaGLTex();
if (skiaGLTex) {
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
MOZ_ASSERT(glue);
data.mGLContext = glue->GetGLContext();
data.mFrontbufferGLTex = skiaGLTex;
}
}
data.mBufferProvider = mBufferProvider;
aRenderer->Initialize(data);

Просмотреть файл

@ -376,14 +376,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
double aH, const nsAString& aBgColor, uint32_t aFlags,
mozilla::ErrorResult& aError);
enum RenderingMode {
SoftwareBackendMode,
OpenGLBackendMode,
DefaultBackendMode
};
bool SwitchRenderingMode(RenderingMode aRenderingMode);
// Eventually this should be deprecated. Keeping for now to keep the binding
// functional.
void Demote();
@ -509,9 +501,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
void OnShutdown();
// Check the global setup, as well as the compositor type:
bool AllowOpenGLCanvas() const;
/**
* Update CurrentState().filter with the filter description for
* CurrentState().filterChain.
@ -616,17 +605,12 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
* is in turn an error in creating the sErrorTarget then they would both
* be null so IsTargetValid() would still return null.
*
* Returns the actual rendering mode being used by the created target.
* Returns true on success.
*/
RenderingMode EnsureTarget(
const gfx::Rect* aCoveredRect = nullptr,
RenderingMode aRenderMode = RenderingMode::DefaultBackendMode);
bool EnsureTarget(const gfx::Rect* aCoveredRect = nullptr);
void RestoreClipsAndTransformToTarget();
bool TrySkiaGLTarget(RefPtr<gfx::DrawTarget>& aOutDT,
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
bool TrySharedTarget(RefPtr<gfx::DrawTarget>& aOutDT,
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
@ -704,19 +688,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
return CurrentState().font;
}
// This function maintains a list of raw pointers to cycle-collected
// objects. We need to ensure that no entries persist beyond unlink,
// since the objects are logically destructed at that point.
static std::vector<CanvasRenderingContext2D*>& DemotableContexts();
static void DemoteOldestContextIfNecessary();
static void AddDemotableContext(CanvasRenderingContext2D* aContext);
static void RemoveDemotableContext(CanvasRenderingContext2D* aContext);
RenderingMode mRenderingMode;
layers::LayersBackend mCompositorBackend;
// Member vars
int32_t mWidth, mHeight;
@ -742,9 +713,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
bool mResetLayer;
// This is needed for drawing in drawAsyncXULElement
bool mIPC;
// True if the current DrawTarget is using skia-gl, used so we can avoid
// requesting the DT from mBufferProvider to check.
bool mIsSkiaGL;
bool mHasPendingStableStateCallback;
@ -760,14 +728,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
RefPtr<mozilla::layers::PersistentBufferProvider> mBufferProvider;
uint32_t SkiaGLTex() const;
// This observes our draw calls at the beginning of the canvas
// lifetime and switches to software or GPU mode depending on
// what it thinks is best
CanvasDrawObserver* mDrawObserver;
void RemoveDrawObserver();
RefPtr<CanvasShutdownObserver> mShutdownObserver;
void RemoveShutdownObserver();
bool AlreadyShutDown() const { return !mShutdownObserver; }
@ -919,8 +879,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
const Optional<double>& aMaxWidth,
TextDrawOperation aOp, float* aWidth);
bool CheckSizeForSkiaGL(mozilla::gfx::IntSize aSize);
// A clip or a transform, recorded and restored in order.
struct ClipState {
explicit ClipState(mozilla::gfx::Path* aClip) : clip(aClip) {}

Просмотреть файл

@ -16,6 +16,7 @@
#include "mozilla/Telemetry.h"
#include "CanvasRenderingContext2D.h"
#include "CanvasUtils.h"
#include "GLContext.h"
#include "GLScreenBuffer.h"
#include "WebGL1Context.h"
#include "WebGL2Context.h"

Просмотреть файл

@ -26,7 +26,6 @@
("%s: " arg, __func__, ##__VA_ARGS__))
using namespace mozilla;
using namespace mozilla::gl;
using namespace mozilla::java::sdk;
using media::TimeUnit;