зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1736177
- Part 10. Add OffscreenCanvasDisplayHelper implementation. r=jgilbert
This helper class manages the necessary state to facilitate the display pipeline for an OffscreenCanvas created through HTMLCanvasElement's transferControlToOffscreen. Differential Revision: https://phabricator.services.mozilla.com/D130786
This commit is contained in:
Родитель
8077b44a0c
Коммит
54b53f8b76
|
@ -0,0 +1,208 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "OffscreenCanvasDisplayHelper.h"
|
||||
#include "mozilla/gfx/CanvasManagerChild.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "mozilla/layers/TextureClientSharedSurface.h"
|
||||
#include "mozilla/layers/TextureWrapperImage.h"
|
||||
#include "mozilla/SVGObserverUtils.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
OffscreenCanvasDisplayHelper::OffscreenCanvasDisplayHelper(
|
||||
HTMLCanvasElement* aCanvasElement, uint32_t aWidth, uint32_t aHeight)
|
||||
: mMutex("mozilla::dom::OffscreenCanvasDisplayHelper"),
|
||||
mCanvasElement(aCanvasElement),
|
||||
mWidth(aWidth),
|
||||
mHeight(aHeight),
|
||||
mImageProducerID(layers::ImageContainer::AllocateProducerID()) {}
|
||||
|
||||
OffscreenCanvasDisplayHelper::~OffscreenCanvasDisplayHelper() = default;
|
||||
|
||||
void OffscreenCanvasDisplayHelper::Destroy() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
mCanvasElement = nullptr;
|
||||
}
|
||||
|
||||
CanvasContextType OffscreenCanvasDisplayHelper::GetContextType() const {
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mType;
|
||||
}
|
||||
|
||||
RefPtr<layers::ImageContainer> OffscreenCanvasDisplayHelper::GetImageContainer()
|
||||
const {
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mImageContainer;
|
||||
}
|
||||
|
||||
void OffscreenCanvasDisplayHelper::UpdateContext(
|
||||
layers::ImageContainer* aContainer, CanvasContextType aType,
|
||||
int32_t aChildId) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
mImageContainer = aContainer;
|
||||
mType = aType;
|
||||
|
||||
if (aChildId) {
|
||||
mContextManagerId = gfx::CanvasManagerChild::Get()->Id();
|
||||
mContextChildId = aChildId;
|
||||
}
|
||||
|
||||
MaybeQueueInvalidateElement();
|
||||
}
|
||||
|
||||
bool OffscreenCanvasDisplayHelper::UpdateParameters(uint32_t aWidth,
|
||||
uint32_t aHeight,
|
||||
bool aHasAlpha,
|
||||
bool aIsPremultiplied) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mCanvasElement) {
|
||||
// Our weak reference to the canvas element has been cleared, so we cannot
|
||||
// present directly anymore.
|
||||
return false;
|
||||
}
|
||||
|
||||
mWidth = aWidth;
|
||||
mHeight = aHeight;
|
||||
mHasAlpha = aHasAlpha;
|
||||
mIsPremultiplied = aIsPremultiplied;
|
||||
|
||||
MaybeQueueInvalidateElement();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OffscreenCanvasDisplayHelper::CommitFrameToCompositor(
|
||||
nsICanvasRenderingContextInternal* aContext,
|
||||
layers::TextureType aTextureType) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
|
||||
layers::TextureFlags flags = layers::TextureFlags::NO_FLAGS;
|
||||
|
||||
if (!mCanvasElement) {
|
||||
// Our weak reference to the canvas element has been cleared, so we cannot
|
||||
// present directly anymore.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mHasAlpha) {
|
||||
format = gfx::SurfaceFormat::B8G8R8X8;
|
||||
} else if (!mIsPremultiplied) {
|
||||
flags |= layers::TextureFlags::NON_PREMULTIPLIED;
|
||||
}
|
||||
|
||||
auto imageBridge = layers::ImageBridgeChild::GetSingleton();
|
||||
if (!imageBridge) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<layers::Image> image;
|
||||
RefPtr<gfx::SourceSurface> surface;
|
||||
|
||||
Maybe<layers::SurfaceDescriptor> desc =
|
||||
aContext->PresentFrontBuffer(nullptr, aTextureType);
|
||||
if (desc) {
|
||||
RefPtr<layers::TextureClient> texture =
|
||||
layers::SharedSurfaceTextureData::CreateTextureClient(
|
||||
*desc, format, gfx::IntSize(mWidth, mHeight), flags, imageBridge);
|
||||
if (texture) {
|
||||
image = new layers::TextureWrapperImage(
|
||||
texture, gfx::IntRect(0, 0, mWidth, mHeight));
|
||||
}
|
||||
} else {
|
||||
surface = aContext->GetFrontBufferSnapshot(/* requireAlphaPremult */ true);
|
||||
if (surface) {
|
||||
image = new layers::SourceSurfaceImage(surface);
|
||||
}
|
||||
}
|
||||
|
||||
AutoTArray<layers::ImageContainer::NonOwningImage, 1> imageList;
|
||||
imageList.AppendElement(layers::ImageContainer::NonOwningImage(
|
||||
image, TimeStamp(), mLastFrameID++, mImageProducerID));
|
||||
mImageContainer->SetCurrentImages(imageList);
|
||||
|
||||
mFrontBufferDesc = std::move(desc);
|
||||
mFrontBufferSurface = std::move(surface);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OffscreenCanvasDisplayHelper::MaybeQueueInvalidateElement() {
|
||||
if (!mPendingInvalidate) {
|
||||
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
|
||||
"OffscreenCanvasDisplayHelper::InvalidateElement",
|
||||
[self = RefPtr{this}]() { self->InvalidateElement(); });
|
||||
NS_DispatchToMainThread(runnable.forget());
|
||||
mPendingInvalidate = true;
|
||||
}
|
||||
}
|
||||
|
||||
void OffscreenCanvasDisplayHelper::InvalidateElement() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
HTMLCanvasElement* canvasElement;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(mPendingInvalidate);
|
||||
mPendingInvalidate = false;
|
||||
canvasElement = mCanvasElement;
|
||||
}
|
||||
|
||||
if (canvasElement) {
|
||||
SVGObserverUtils::InvalidateDirectRenderingObservers(canvasElement);
|
||||
canvasElement->InvalidateCanvasContent(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<layers::SurfaceDescriptor> OffscreenCanvasDisplayHelper::GetFrontBuffer(
|
||||
WebGLFramebufferJS*, const bool webvr) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mFrontBufferDesc;
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::SourceSurface>
|
||||
OffscreenCanvasDisplayHelper::GetSurfaceSnapshot(gfxAlphaType* out_alphaType) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
Maybe<layers::SurfaceDescriptor> desc;
|
||||
|
||||
bool hasAlpha;
|
||||
uint32_t managerId;
|
||||
int32_t childId;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mFrontBufferSurface) {
|
||||
RefPtr<gfx::SourceSurface> surface = mFrontBufferSurface;
|
||||
return surface.forget();
|
||||
}
|
||||
|
||||
hasAlpha = mHasAlpha;
|
||||
managerId = mContextManagerId;
|
||||
childId = mContextChildId;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!managerId || !childId)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return gfx::CanvasManagerChild::Get()->GetSnapshot(managerId, childId,
|
||||
hasAlpha);
|
||||
}
|
||||
|
||||
already_AddRefed<layers::Image> OffscreenCanvasDisplayHelper::GetAsImage() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<gfx::SourceSurface> surface = GetSurfaceSnapshot();
|
||||
if (!surface) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeAndAddRef<layers::SourceSurfaceImage>(surface);
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
|
@ -0,0 +1,77 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_DOM_OFFSCREENCANVASDISPLAYHELPER_H_
|
||||
#define MOZILLA_DOM_OFFSCREENCANVASDISPLAYHELPER_H_
|
||||
|
||||
#include "CanvasRenderingContextHelper.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsICanvasRenderingContextInternal.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
class HTMLCanvasElement;
|
||||
|
||||
class OffscreenCanvasDisplayHelper final {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OffscreenCanvasDisplayHelper)
|
||||
|
||||
public:
|
||||
explicit OffscreenCanvasDisplayHelper(HTMLCanvasElement* aCanvasElement,
|
||||
uint32_t aWidth, uint32_t aHeight);
|
||||
|
||||
CanvasContextType GetContextType() const;
|
||||
|
||||
RefPtr<layers::ImageContainer> GetImageContainer() const;
|
||||
|
||||
void UpdateContext(layers::ImageContainer* aContainer,
|
||||
CanvasContextType aType, int32_t aChildId);
|
||||
|
||||
bool UpdateParameters(uint32_t aWidth, uint32_t aHeight, bool aHasAlpha,
|
||||
bool aIsPremultiplied);
|
||||
|
||||
bool CommitFrameToCompositor(nsICanvasRenderingContextInternal* aContext,
|
||||
layers::TextureType aTextureType);
|
||||
|
||||
void Destroy();
|
||||
|
||||
mozilla::Maybe<mozilla::layers::SurfaceDescriptor> GetFrontBuffer(
|
||||
mozilla::WebGLFramebufferJS*, const bool webvr = false);
|
||||
|
||||
already_AddRefed<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(
|
||||
gfxAlphaType* out_alphaType = nullptr);
|
||||
|
||||
already_AddRefed<mozilla::layers::Image> GetAsImage();
|
||||
|
||||
private:
|
||||
~OffscreenCanvasDisplayHelper();
|
||||
void MaybeQueueInvalidateElement();
|
||||
void InvalidateElement();
|
||||
|
||||
mutable Mutex mMutex;
|
||||
HTMLCanvasElement* MOZ_NON_OWNING_REF mCanvasElement;
|
||||
RefPtr<layers::ImageContainer> mImageContainer;
|
||||
RefPtr<gfx::SourceSurface> mFrontBufferSurface;
|
||||
Maybe<layers::SurfaceDescriptor> mFrontBufferDesc;
|
||||
|
||||
CanvasContextType mType = CanvasContextType::NoContext;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
uint32_t mContextManagerId = 0;
|
||||
int32_t mContextChildId = 0;
|
||||
mozilla::layers::ImageContainer::ProducerID mImageProducerID;
|
||||
mozilla::layers::ImageContainer::FrameID mLastFrameID = 0;
|
||||
bool mPendingInvalidate = false;
|
||||
bool mHasAlpha = false;
|
||||
bool mIsPremultiplied = false;
|
||||
};
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // MOZILLA_DOM_OFFSCREENCANVASDISPLAYHELPER_H_
|
|
@ -60,6 +60,7 @@ EXPORTS.mozilla.dom += [
|
|||
"ImageData.h",
|
||||
"ImageUtils.h",
|
||||
"OffscreenCanvas.h",
|
||||
"OffscreenCanvasDisplayHelper.h",
|
||||
"QueueParamTraits.h",
|
||||
"TextMetrics.h",
|
||||
"WebGLChild.h",
|
||||
|
@ -88,6 +89,7 @@ UNIFIED_SOURCES += [
|
|||
"ImageData.cpp",
|
||||
"nsICanvasRenderingContextInternal.cpp",
|
||||
"OffscreenCanvas.cpp",
|
||||
"OffscreenCanvasDisplayHelper.cpp",
|
||||
"XRWebGLLayer.cpp",
|
||||
]
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче