зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1298345 - Refactor CanvasRenderingContext2D's texture allocation code. r=Bas
This commit is contained in:
Родитель
d056325bfe
Коммит
47e7bc67f9
|
@ -1546,8 +1546,7 @@ CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect,
|
|||
{
|
||||
if (AlreadyShutDown()) {
|
||||
gfxCriticalError() << "Attempt to render into a Canvas2d after shutdown.";
|
||||
EnsureErrorTarget();
|
||||
mTarget = sErrorTarget;
|
||||
SetErrorState();
|
||||
return aRenderingMode;
|
||||
}
|
||||
|
||||
|
@ -1560,6 +1559,15 @@ CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect,
|
|||
return mRenderingMode;
|
||||
}
|
||||
|
||||
// Check that the dimensions are sane
|
||||
if (mWidth > gfxPrefs::MaxCanvasSize() ||
|
||||
mHeight > gfxPrefs::MaxCanvasSize() ||
|
||||
mWidth < 0 || mHeight < 0) {
|
||||
|
||||
SetErrorState();
|
||||
return aRenderingMode;
|
||||
}
|
||||
|
||||
// If the next drawing command covers the entire canvas, we can skip copying
|
||||
// from the previous frame and/or clearing the canvas.
|
||||
gfx::Rect canvasRect(0, 0, mWidth, mHeight);
|
||||
|
@ -1582,13 +1590,10 @@ CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect,
|
|||
|
||||
ScheduleStableStateCallback();
|
||||
|
||||
// we'll do a few extra things at the end of this method if we changed the
|
||||
// buffer provider.
|
||||
RefPtr<PersistentBufferProvider> oldBufferProvider = mBufferProvider;
|
||||
IntRect persistedRect = canDiscardContent ? IntRect()
|
||||
: IntRect(0, 0, mWidth, mHeight);
|
||||
|
||||
if (mBufferProvider && mode == mRenderingMode) {
|
||||
auto persistedRect = canDiscardContent ? IntRect()
|
||||
: IntRect(0, 0, mWidth, mHeight);
|
||||
mTarget = mBufferProvider->BorrowDrawTarget(persistedRect);
|
||||
|
||||
if (mTarget && !mBufferProvider->PreservesDrawingState()) {
|
||||
|
@ -1600,112 +1605,211 @@ CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect,
|
|||
}
|
||||
}
|
||||
|
||||
mIsSkiaGL = false;
|
||||
RefPtr<DrawTarget> newTarget;
|
||||
RefPtr<PersistentBufferProvider> newProvider;
|
||||
|
||||
// Check that the dimensions are sane
|
||||
IntSize size(mWidth, mHeight);
|
||||
if (!mTarget &&
|
||||
size.width <= gfxPrefs::MaxCanvasSize() &&
|
||||
size.height <= gfxPrefs::MaxCanvasSize() &&
|
||||
size.width >= 0 && size.height >= 0) {
|
||||
SurfaceFormat format = GetSurfaceFormat();
|
||||
nsIDocument* ownerDoc = nullptr;
|
||||
if (mCanvasElement) {
|
||||
ownerDoc = mCanvasElement->OwnerDoc();
|
||||
}
|
||||
|
||||
RefPtr<LayerManager> layerManager = nullptr;
|
||||
|
||||
if (ownerDoc) {
|
||||
layerManager =
|
||||
nsContentUtils::PersistentLayerManagerForDocument(ownerDoc);
|
||||
}
|
||||
|
||||
if (layerManager) {
|
||||
if (mode == RenderingMode::OpenGLBackendMode &&
|
||||
gfxPlatform::GetPlatform()->UseAcceleratedCanvas() &&
|
||||
CheckSizeForSkiaGL(size)) {
|
||||
DemoteOldestContextIfNecessary();
|
||||
mBufferProvider = nullptr;
|
||||
|
||||
#if USE_SKIA_GPU
|
||||
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
|
||||
|
||||
if (glue && glue->GetGrContext() && glue->GetGLContext()) {
|
||||
mTarget = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(), size, format);
|
||||
if (mTarget) {
|
||||
AddDemotableContext(this);
|
||||
mBufferProvider = new PersistentBufferProviderBasic(mTarget);
|
||||
mIsSkiaGL = true;
|
||||
} else {
|
||||
gfxCriticalNote << "Failed to create a SkiaGL DrawTarget, falling back to software " << size << ", " << format;
|
||||
mode = RenderingMode::SoftwareBackendMode;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!mBufferProvider) {
|
||||
mTarget = nullptr;
|
||||
mBufferProvider = layerManager->CreatePersistentBufferProvider(size, format);
|
||||
}
|
||||
}
|
||||
|
||||
if (mBufferProvider) {
|
||||
mTarget = mBufferProvider->BorrowDrawTarget(IntRect(IntPoint(), IntSize(mWidth, mHeight)));
|
||||
} else if (!mTarget) {
|
||||
mTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format);
|
||||
mode = RenderingMode::SoftwareBackendMode;
|
||||
}
|
||||
if (mode == RenderingMode::OpenGLBackendMode &&
|
||||
!TrySkiaGLTarget(newTarget, newProvider)) {
|
||||
// Fall back to software.
|
||||
mode = RenderingMode::SoftwareBackendMode;
|
||||
}
|
||||
|
||||
if (mTarget) {
|
||||
// We changed the buffer provider.
|
||||
// XXX - It would make more sense to track the allocation in
|
||||
// PeristentBufferProvider, rather than here.
|
||||
if (mBufferProvider != oldBufferProvider) {
|
||||
static bool registered = false;
|
||||
if (!registered) {
|
||||
registered = true;
|
||||
RegisterStrongMemoryReporter(new Canvas2dPixelsReporter());
|
||||
}
|
||||
|
||||
gCanvasAzureMemoryUsed += mWidth * mHeight * 4;
|
||||
JSContext* context = nsContentUtils::GetCurrentJSContext();
|
||||
if (context) {
|
||||
JS_updateMallocCounter(context, mWidth * mHeight * 4);
|
||||
}
|
||||
|
||||
mTarget->ClearRect(canvasRect);
|
||||
|
||||
// Force a full layer transaction since we didn't have a layer before
|
||||
// and now we might need one.
|
||||
if (mCanvasElement) {
|
||||
mCanvasElement->InvalidateCanvas();
|
||||
}
|
||||
// Calling Redraw() tells our invalidation machinery that the entire
|
||||
// canvas is already invalid, which can speed up future drawing.
|
||||
Redraw();
|
||||
}
|
||||
|
||||
if (mBufferProvider != oldBufferProvider || !mBufferProvider ||
|
||||
!mBufferProvider->PreservesDrawingState()) {
|
||||
RestoreClipsAndTransformToTarget();
|
||||
}
|
||||
} else {
|
||||
EnsureErrorTarget();
|
||||
mTarget = sErrorTarget;
|
||||
mBufferProvider = nullptr;
|
||||
if (mode == RenderingMode::SoftwareBackendMode &&
|
||||
!TrySharedTarget(newTarget, newProvider) &&
|
||||
!TryBasicTarget(newTarget, newProvider)) {
|
||||
SetErrorState();
|
||||
return mode;
|
||||
}
|
||||
|
||||
// Drop a note in the debug builds if we ever use accelerated Skia canvas.
|
||||
if (mIsSkiaGL && mTarget && mTarget->GetType() == DrawTargetType::HARDWARE_RASTER) {
|
||||
gfxWarningOnce() << "Using SkiaGL canvas.";
|
||||
MOZ_ASSERT(newTarget);
|
||||
MOZ_ASSERT(newProvider);
|
||||
|
||||
mTarget = newTarget.forget();
|
||||
mBufferProvider = newProvider.forget();
|
||||
|
||||
RegisterAllocation();
|
||||
|
||||
// Skia expects the unused X channel to contains 0 even for opaque operations
|
||||
// so we can't skip clearing in that case, even if we are going to cover the
|
||||
// entire canvas in the next drawing operation.
|
||||
if (!canDiscardContent || mTarget->GetBackendType() == gfx::BackendType::SKIA) {
|
||||
mTarget->ClearRect(canvasRect);
|
||||
}
|
||||
|
||||
RestoreClipsAndTransformToTarget();
|
||||
|
||||
// Force a full layer transaction since we didn't have a layer before
|
||||
// and now we might need one.
|
||||
if (mCanvasElement) {
|
||||
mCanvasElement->InvalidateCanvas();
|
||||
}
|
||||
// Calling Redraw() tells our invalidation machinery that the entire
|
||||
// canvas is already invalid, which can speed up future drawing.
|
||||
Redraw();
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::SetInitialState()
|
||||
{
|
||||
// Set up the initial canvas defaults
|
||||
mPathBuilder = nullptr;
|
||||
mPath = nullptr;
|
||||
mDSPathBuilder = nullptr;
|
||||
|
||||
mStyleStack.Clear();
|
||||
ContextState *state = mStyleStack.AppendElement();
|
||||
state->globalAlpha = 1.0;
|
||||
|
||||
state->colorStyles[Style::FILL] = NS_RGB(0,0,0);
|
||||
state->colorStyles[Style::STROKE] = NS_RGB(0,0,0);
|
||||
state->shadowColor = NS_RGBA(0,0,0,0);
|
||||
}
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::SetErrorState()
|
||||
{
|
||||
EnsureErrorTarget();
|
||||
|
||||
if (mTarget && mTarget != sErrorTarget) {
|
||||
gCanvasAzureMemoryUsed -= mWidth * mHeight * 4;
|
||||
}
|
||||
|
||||
mTarget = sErrorTarget;
|
||||
mBufferProvider = nullptr;
|
||||
|
||||
// clear transforms, clips, etc.
|
||||
SetInitialState();
|
||||
}
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::RegisterAllocation()
|
||||
{
|
||||
// XXX - It would make more sense to track the allocation in
|
||||
// PeristentBufferProvider, rather than here.
|
||||
static bool registered = false;
|
||||
if (!registered) {
|
||||
registered = true;
|
||||
RegisterStrongMemoryReporter(new Canvas2dPixelsReporter());
|
||||
}
|
||||
|
||||
gCanvasAzureMemoryUsed += mWidth * mHeight * 4;
|
||||
JSContext* context = nsContentUtils::GetCurrentJSContext();
|
||||
if (context) {
|
||||
JS_updateMallocCounter(context, mWidth * mHeight * 4);
|
||||
}
|
||||
}
|
||||
|
||||
static already_AddRefed<LayerManager>
|
||||
LayerManagerFromCanvasElement(nsINode* aCanvasElement)
|
||||
{
|
||||
if (!aCanvasElement || !aCanvasElement->OwnerDoc()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nsContentUtils::PersistentLayerManagerForDocument(aCanvasElement->OwnerDoc());
|
||||
}
|
||||
|
||||
bool
|
||||
CanvasRenderingContext2D::TrySkiaGLTarget(RefPtr<gfx::DrawTarget>& aOutDT,
|
||||
RefPtr<layers::PersistentBufferProvider>& aOutProvider)
|
||||
{
|
||||
aOutDT = nullptr;
|
||||
aOutProvider = nullptr;
|
||||
|
||||
|
||||
mIsSkiaGL = false;
|
||||
|
||||
IntSize size(mWidth, mHeight);
|
||||
if (!gfxPlatform::GetPlatform()->UseAcceleratedCanvas() ||
|
||||
!CheckSizeForSkiaGL(size)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
RefPtr<LayerManager> layerManager = LayerManagerFromCanvasElement(mCanvasElement);
|
||||
|
||||
if (!layerManager) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DemoteOldestContextIfNecessary();
|
||||
mBufferProvider = nullptr;
|
||||
|
||||
#if 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) {
|
||||
return false;
|
||||
gfxCriticalNote << "Failed to create a SkiaGL DrawTarget, falling back to software\n";
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
aOutDT = nullptr;
|
||||
aOutProvider = nullptr;
|
||||
|
||||
if (!mCanvasElement || !mCanvasElement->OwnerDoc()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<LayerManager> layerManager = LayerManagerFromCanvasElement(mCanvasElement);
|
||||
|
||||
if (!layerManager) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aOutProvider = layerManager->CreatePersistentBufferProvider(GetSize(), GetSurfaceFormat());
|
||||
|
||||
if (!aOutProvider) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can pass an empty persisted rect since we just created the buffer
|
||||
// provider (nothing to restore).
|
||||
aOutDT = aOutProvider->BorrowDrawTarget(IntRect());
|
||||
MOZ_ASSERT(aOutDT);
|
||||
|
||||
return !!aOutDT;
|
||||
}
|
||||
|
||||
bool
|
||||
CanvasRenderingContext2D::TryBasicTarget(RefPtr<gfx::DrawTarget>& aOutDT,
|
||||
RefPtr<layers::PersistentBufferProvider>& aOutProvider)
|
||||
{
|
||||
aOutDT = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(GetSize(),
|
||||
GetSurfaceFormat());
|
||||
if (!aOutDT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aOutProvider = new PersistentBufferProviderBasic(aOutDT);
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t
|
||||
CanvasRenderingContext2D::GetWidth() const
|
||||
{
|
||||
|
@ -1763,18 +1867,7 @@ CanvasRenderingContext2D::ClearTarget(bool aRetainBuffer)
|
|||
|
||||
mResetLayer = true;
|
||||
|
||||
// set up the initial canvas defaults
|
||||
mStyleStack.Clear();
|
||||
mPathBuilder = nullptr;
|
||||
mPath = nullptr;
|
||||
mDSPathBuilder = nullptr;
|
||||
|
||||
ContextState *state = mStyleStack.AppendElement();
|
||||
state->globalAlpha = 1.0;
|
||||
|
||||
state->colorStyles[Style::FILL] = NS_RGB(0,0,0);
|
||||
state->colorStyles[Style::STROKE] = NS_RGB(0,0,0);
|
||||
state->shadowColor = NS_RGBA(0,0,0,0);
|
||||
SetInitialState();
|
||||
|
||||
// For vertical writing-mode, unless text-orientation is sideways,
|
||||
// we'll modify the initial value of textBaseline to 'middle'.
|
||||
|
@ -1789,7 +1882,7 @@ CanvasRenderingContext2D::ClearTarget(bool aRetainBuffer)
|
|||
if (canvasStyle) {
|
||||
WritingMode wm(canvasStyle);
|
||||
if (wm.IsVertical() && !wm.IsSideways()) {
|
||||
state->textBaseline = TextBaseline::MIDDLE;
|
||||
CurrentState().textBaseline = TextBaseline::MIDDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1920,7 +2013,7 @@ CanvasRenderingContext2D::GetImageBuffer(int32_t* aFormat)
|
|||
|
||||
if (snapshot) {
|
||||
RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
|
||||
if (data && data->GetSize() == IntSize(mWidth, mHeight)) {
|
||||
if (data && data->GetSize() == GetSize()) {
|
||||
*aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB;
|
||||
ret = SurfaceToPackedBGRA(data);
|
||||
}
|
||||
|
@ -2762,7 +2855,7 @@ CanvasRenderingContext2D::UpdateFilter()
|
|||
CurrentState().filter =
|
||||
nsFilterInstance::GetFilterDescription(mCanvasElement,
|
||||
CurrentState().filterChain,
|
||||
CanvasUserSpaceMetrics(IntSize(mWidth, mHeight),
|
||||
CanvasUserSpaceMetrics(GetSize(),
|
||||
CurrentState().fontFont,
|
||||
CurrentState().fontLanguage,
|
||||
CurrentState().fontExplicitLanguage,
|
||||
|
@ -5798,30 +5891,6 @@ void CanvasRenderingContext2D::RemoveDrawObserver()
|
|||
}
|
||||
}
|
||||
|
||||
PersistentBufferProvider*
|
||||
CanvasRenderingContext2D::GetBufferProvider(LayerManager* aManager)
|
||||
{
|
||||
if (AlreadyShutDown()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mBufferProvider) {
|
||||
return mBufferProvider;
|
||||
}
|
||||
|
||||
if (mTarget) {
|
||||
mBufferProvider = new PersistentBufferProviderBasic(mTarget);
|
||||
return mBufferProvider;
|
||||
}
|
||||
|
||||
if (aManager && !mIsSkiaGL) {
|
||||
mBufferProvider = aManager->CreatePersistentBufferProvider(gfx::IntSize(mWidth, mHeight),
|
||||
GetSurfaceFormat());
|
||||
}
|
||||
|
||||
return mBufferProvider;
|
||||
}
|
||||
|
||||
already_AddRefed<Layer>
|
||||
CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||
Layer *aOldLayer,
|
||||
|
@ -5869,8 +5938,7 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
}
|
||||
|
||||
PersistentBufferProvider *provider = GetBufferProvider(aManager);
|
||||
data.mBufferProvider = provider;
|
||||
data.mBufferProvider = mBufferProvider;
|
||||
|
||||
if (userData &&
|
||||
userData->IsForContext(this) &&
|
||||
|
@ -5906,7 +5974,7 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
|||
canvasLayer->SetUserData(&g2DContextLayerUserData, userData);
|
||||
|
||||
CanvasLayer::Data data;
|
||||
data.mSize = nsIntSize(mWidth, mHeight);
|
||||
data.mSize = GetSize();
|
||||
data.mHasAlpha = !mOpaque;
|
||||
|
||||
canvasLayer->SetPreTransactionCallback(
|
||||
|
@ -5923,8 +5991,7 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
}
|
||||
|
||||
PersistentBufferProvider *provider = GetBufferProvider(aManager);
|
||||
data.mBufferProvider = provider;
|
||||
data.mBufferProvider = mBufferProvider;
|
||||
|
||||
canvasLayer->Initialize(data);
|
||||
uint32_t flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
|
||||
|
@ -5961,7 +6028,7 @@ CanvasRenderingContext2D::IsContextCleanForFrameCapture()
|
|||
bool
|
||||
CanvasRenderingContext2D::ShouldForceInactiveLayer(LayerManager* aManager)
|
||||
{
|
||||
return !aManager->CanUseCanvasLayerForSize(IntSize(mWidth, mHeight));
|
||||
return !aManager->CanUseCanvasLayerForSize(GetSize());
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CanvasPath, AddRef)
|
||||
|
|
|
@ -429,6 +429,7 @@ public:
|
|||
|
||||
virtual int32_t GetWidth() const override;
|
||||
virtual int32_t GetHeight() const override;
|
||||
gfx::IntSize GetSize() const { return gfx::IntSize(mWidth, mHeight); }
|
||||
|
||||
// nsICanvasRenderingContextInternal
|
||||
/**
|
||||
|
@ -463,7 +464,6 @@ public:
|
|||
NS_IMETHOD SetIsOpaque(bool aIsOpaque) override;
|
||||
bool GetIsOpaque() override { return mOpaque; }
|
||||
NS_IMETHOD Reset() override;
|
||||
mozilla::layers::PersistentBufferProvider* GetBufferProvider(mozilla::layers::LayerManager* aManager);
|
||||
already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||
Layer* aOldLayer,
|
||||
LayerManager* aManager,
|
||||
|
@ -645,6 +645,21 @@ protected:
|
|||
|
||||
void RestoreClipsAndTransformToTarget();
|
||||
|
||||
bool TrySkiaGLTarget(RefPtr<gfx::DrawTarget>& aOutDT,
|
||||
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
|
||||
|
||||
bool TrySharedTarget(RefPtr<gfx::DrawTarget>& aOutDT,
|
||||
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
|
||||
|
||||
bool TryBasicTarget(RefPtr<gfx::DrawTarget>& aOutDT,
|
||||
RefPtr<layers::PersistentBufferProvider>& aOutProvider);
|
||||
|
||||
void RegisterAllocation();
|
||||
|
||||
void SetInitialState();
|
||||
|
||||
void SetErrorState();
|
||||
|
||||
/**
|
||||
* This method is run at the end of the event-loop spin where
|
||||
* ScheduleStableStateCallback was called.
|
||||
|
|
Загрузка…
Ссылка в новой задаче