Bug 1284324 - Implement Canvas Layer mirrors r=bas
- When a canvas layer is set to mirror, it copies the texture from the canvas rather than changing the texture factory with Morph(). - This is useful when a canvas content will be sent to multiple devices simultaneously, such as a VR HMD and a 2d monitor mirror. - This is used by the WebVR 1.0 API, in Bug 1250244 MozReview-Commit-ID: JfMSockO2uz
This commit is contained in:
@@ -5811,8 +5811,14 @@ CanvasRenderingContext2D::GetBufferProvider(LayerManager* aManager)
|
|||||||
already_AddRefed<Layer>
|
already_AddRefed<Layer>
|
||||||
CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||||
Layer *aOldLayer,
|
Layer *aOldLayer,
|
||||||
LayerManager *aManager)
|
LayerManager *aManager,
|
||||||
|
bool aMirror /* = false */)
|
||||||
{
|
{
|
||||||
|
if (aMirror) {
|
||||||
|
// Not supported for CanvasRenderingContext2D
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (mOpaque || mIsSkiaGL) {
|
if (mOpaque || mIsSkiaGL) {
|
||||||
// If we're opaque then make sure we have a surface so we paint black
|
// If we're opaque then make sure we have a surface so we paint black
|
||||||
// instead of transparent.
|
// instead of transparent.
|
||||||
|
|||||||
@@ -466,7 +466,8 @@ public:
|
|||||||
mozilla::layers::PersistentBufferProvider* GetBufferProvider(mozilla::layers::LayerManager* aManager);
|
mozilla::layers::PersistentBufferProvider* GetBufferProvider(mozilla::layers::LayerManager* aManager);
|
||||||
already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||||
Layer* aOldLayer,
|
Layer* aOldLayer,
|
||||||
LayerManager* aManager) override;
|
LayerManager* aManager,
|
||||||
|
bool aMirror = false) override;
|
||||||
virtual bool ShouldForceInactiveLayer(LayerManager* aManager) override;
|
virtual bool ShouldForceInactiveLayer(LayerManager* aManager) override;
|
||||||
void MarkContextClean() override;
|
void MarkContextClean() override;
|
||||||
void MarkContextCleanForFrameCapture() override;
|
void MarkContextCleanForFrameCapture() override;
|
||||||
|
|||||||
@@ -214,8 +214,14 @@ ImageBitmapRenderingContext::Reset()
|
|||||||
already_AddRefed<Layer>
|
already_AddRefed<Layer>
|
||||||
ImageBitmapRenderingContext::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
ImageBitmapRenderingContext::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||||
Layer* aOldLayer,
|
Layer* aOldLayer,
|
||||||
LayerManager* aManager)
|
LayerManager* aManager,
|
||||||
|
bool aMirror /* = false */)
|
||||||
{
|
{
|
||||||
|
if (aMirror) {
|
||||||
|
// Not supported for ImageBitmapRenderingContext
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mImage) {
|
if (!mImage) {
|
||||||
// No DidTransactionCallback will be received, so mark the context clean
|
// No DidTransactionCallback will be received, so mark the context clean
|
||||||
// now so future invalidations will be dispatched.
|
// now so future invalidations will be dispatched.
|
||||||
|
|||||||
@@ -70,7 +70,8 @@ public:
|
|||||||
NS_IMETHOD Reset() override;
|
NS_IMETHOD Reset() override;
|
||||||
virtual already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
virtual already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||||
Layer* aOldLayer,
|
Layer* aOldLayer,
|
||||||
LayerManager* aManager) override;
|
LayerManager* aManager,
|
||||||
|
bool aMirror = false) override;
|
||||||
virtual void MarkContextClean() override;
|
virtual void MarkContextClean() override;
|
||||||
|
|
||||||
NS_IMETHOD Redraw(const gfxRect& aDirty) override;
|
NS_IMETHOD Redraw(const gfxRect& aDirty) override;
|
||||||
|
|||||||
@@ -1265,6 +1265,7 @@ WebGLContext::UpdateLastUseIndex()
|
|||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t gWebGLLayerUserData;
|
static uint8_t gWebGLLayerUserData;
|
||||||
|
static uint8_t gWebGLMirrorLayerUserData;
|
||||||
|
|
||||||
class WebGLContextUserData : public LayerUserData
|
class WebGLContextUserData : public LayerUserData
|
||||||
{
|
{
|
||||||
@@ -1307,13 +1308,14 @@ private:
|
|||||||
already_AddRefed<layers::Layer>
|
already_AddRefed<layers::Layer>
|
||||||
WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder,
|
WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder,
|
||||||
Layer* oldLayer,
|
Layer* oldLayer,
|
||||||
LayerManager* manager)
|
LayerManager* manager,
|
||||||
|
bool aMirror /*= false*/)
|
||||||
{
|
{
|
||||||
if (IsContextLost())
|
if (IsContextLost())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (!mResetLayer && oldLayer &&
|
if (!mResetLayer && oldLayer &&
|
||||||
oldLayer->HasUserData(&gWebGLLayerUserData)) {
|
oldLayer->HasUserData(aMirror ? &gWebGLMirrorLayerUserData : &gWebGLLayerUserData)) {
|
||||||
RefPtr<layers::Layer> ret = oldLayer;
|
RefPtr<layers::Layer> ret = oldLayer;
|
||||||
return ret.forget();
|
return ret.forget();
|
||||||
}
|
}
|
||||||
@@ -1325,7 +1327,7 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder,
|
|||||||
}
|
}
|
||||||
|
|
||||||
WebGLContextUserData* userData = nullptr;
|
WebGLContextUserData* userData = nullptr;
|
||||||
if (builder->IsPaintingToWindow() && mCanvasElement) {
|
if (builder->IsPaintingToWindow() && mCanvasElement && !aMirror) {
|
||||||
// Make the layer tell us whenever a transaction finishes (including
|
// Make the layer tell us whenever a transaction finishes (including
|
||||||
// the current transaction), so we can clear our invalidation state and
|
// the current transaction), so we can clear our invalidation state and
|
||||||
// start invalidating again. We need to do this for the layer that is
|
// start invalidating again. We need to do this for the layer that is
|
||||||
@@ -1345,13 +1347,14 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder,
|
|||||||
WebGLContextUserData::PreTransactionCallback, userData);
|
WebGLContextUserData::PreTransactionCallback, userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
canvasLayer->SetUserData(&gWebGLLayerUserData, userData);
|
canvasLayer->SetUserData(aMirror ? &gWebGLMirrorLayerUserData : &gWebGLLayerUserData, userData);
|
||||||
|
|
||||||
CanvasLayer::Data data;
|
CanvasLayer::Data data;
|
||||||
data.mGLContext = gl;
|
data.mGLContext = gl;
|
||||||
data.mSize = nsIntSize(mWidth, mHeight);
|
data.mSize = nsIntSize(mWidth, mHeight);
|
||||||
data.mHasAlpha = gl->Caps().alpha;
|
data.mHasAlpha = gl->Caps().alpha;
|
||||||
data.mIsGLAlphaPremult = IsPremultAlpha() || !data.mHasAlpha;
|
data.mIsGLAlphaPremult = IsPremultAlpha() || !data.mHasAlpha;
|
||||||
|
data.mIsMirror = aMirror;
|
||||||
|
|
||||||
canvasLayer->Initialize(data);
|
canvasLayer->Initialize(data);
|
||||||
uint32_t flags = gl->Caps().alpha ? 0 : Layer::CONTENT_OPAQUE;
|
uint32_t flags = gl->Caps().alpha ? 0 : Layer::CONTENT_OPAQUE;
|
||||||
|
|||||||
@@ -333,7 +333,8 @@ public:
|
|||||||
|
|
||||||
already_AddRefed<Layer>
|
already_AddRefed<Layer>
|
||||||
GetCanvasLayer(nsDisplayListBuilder* builder, Layer* oldLayer,
|
GetCanvasLayer(nsDisplayListBuilder* builder, Layer* oldLayer,
|
||||||
LayerManager* manager) override;
|
LayerManager* manager,
|
||||||
|
bool aMirror = false) override;
|
||||||
|
|
||||||
// Note that 'clean' here refers to its invalidation state, not the
|
// Note that 'clean' here refers to its invalidation state, not the
|
||||||
// contents of the buffer.
|
// contents of the buffer.
|
||||||
|
|||||||
@@ -135,7 +135,8 @@ public:
|
|||||||
// one for the given layer manager if not available.
|
// one for the given layer manager if not available.
|
||||||
virtual already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* builder,
|
virtual already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* builder,
|
||||||
Layer *oldLayer,
|
Layer *oldLayer,
|
||||||
LayerManager *manager) = 0;
|
LayerManager *manager,
|
||||||
|
bool aMirror = false) = 0;
|
||||||
|
|
||||||
// Return true if the canvas should be forced to be "inactive" to ensure
|
// Return true if the canvas should be forced to be "inactive" to ensure
|
||||||
// it can be drawn to the screen even if it's too large to be blitted by
|
// it can be drawn to the screen even if it's too large to be blitted by
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ CopyableCanvasLayer::CopyableCanvasLayer(LayerManager* aLayerManager, void *aImp
|
|||||||
, mGLFrontbuffer(nullptr)
|
, mGLFrontbuffer(nullptr)
|
||||||
, mIsAlphaPremultiplied(true)
|
, mIsAlphaPremultiplied(true)
|
||||||
, mOriginPos(gl::OriginPos::TopLeft)
|
, mOriginPos(gl::OriginPos::TopLeft)
|
||||||
|
, mIsMirror(false)
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(CopyableCanvasLayer);
|
MOZ_COUNT_CTOR(CopyableCanvasLayer);
|
||||||
}
|
}
|
||||||
@@ -55,6 +56,7 @@ CopyableCanvasLayer::Initialize(const Data& aData)
|
|||||||
mGLContext = aData.mGLContext;
|
mGLContext = aData.mGLContext;
|
||||||
mIsAlphaPremultiplied = aData.mIsGLAlphaPremult;
|
mIsAlphaPremultiplied = aData.mIsGLAlphaPremult;
|
||||||
mOriginPos = gl::OriginPos::BottomLeft;
|
mOriginPos = gl::OriginPos::BottomLeft;
|
||||||
|
mIsMirror = aData.mIsMirror;
|
||||||
|
|
||||||
MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
|
MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ protected:
|
|||||||
|
|
||||||
bool mIsAlphaPremultiplied;
|
bool mIsAlphaPremultiplied;
|
||||||
gl::OriginPos mOriginPos;
|
gl::OriginPos mOriginPos;
|
||||||
|
bool mIsMirror;
|
||||||
|
|
||||||
RefPtr<gfx::DataSourceSurface> mCachedTempSurface;
|
RefPtr<gfx::DataSourceSurface> mCachedTempSurface;
|
||||||
|
|
||||||
|
|||||||
@@ -2375,6 +2375,7 @@ public:
|
|||||||
, mSize(0,0)
|
, mSize(0,0)
|
||||||
, mHasAlpha(false)
|
, mHasAlpha(false)
|
||||||
, mIsGLAlphaPremult(true)
|
, mIsGLAlphaPremult(true)
|
||||||
|
, mIsMirror(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
// One of these three must be specified for Canvas2D, but never more than one
|
// One of these three must be specified for Canvas2D, but never more than one
|
||||||
@@ -2393,6 +2394,10 @@ public:
|
|||||||
|
|
||||||
// Whether mGLContext contains data that is alpha-premultiplied.
|
// Whether mGLContext contains data that is alpha-premultiplied.
|
||||||
bool mIsGLAlphaPremult;
|
bool mIsGLAlphaPremult;
|
||||||
|
|
||||||
|
// Whether the canvas front buffer is already being rendered somewhere else.
|
||||||
|
// When true, do not swap buffers or Morph() to another factory on mGLContext
|
||||||
|
bool mIsMirror;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -411,6 +411,11 @@ CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize, Renderer& aRendere
|
|||||||
gfxCriticalError() << "Invalid canvas front buffer";
|
gfxCriticalError() << "Invalid canvas front buffer";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (layer && layer->mIsMirror) {
|
||||||
|
mShSurfClient = CloneSurface(gl->Screen()->Front()->Surf(), layer->mFactory.get());
|
||||||
|
if (!mShSurfClient) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mShSurfClient = gl->Screen()->Front();
|
mShSurfClient = gl->Screen()->Front();
|
||||||
if (mShSurfClient && mShSurfClient->GetAllocator() &&
|
if (mShSurfClient && mShSurfClient->GetAllocator() &&
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ ClientCanvasLayer::Initialize(const Data& aData)
|
|||||||
|
|
||||||
UniquePtr<SurfaceFactory> factory = GLScreenBuffer::CreateFactory(mGLContext, caps, forwarder, mFlags);
|
UniquePtr<SurfaceFactory> factory = GLScreenBuffer::CreateFactory(mGLContext, caps, forwarder, mFlags);
|
||||||
|
|
||||||
if (mGLFrontbuffer) {
|
if (mGLFrontbuffer || aData.mIsMirror) {
|
||||||
// We're using a source other than the one in the default screen.
|
// We're using a source other than the one in the default screen.
|
||||||
// (SkiaGL)
|
// (SkiaGL)
|
||||||
mFactory = Move(factory);
|
mFactory = Move(factory);
|
||||||
|
|||||||
Reference in New Issue
Block a user