diff -r 000000000000 -r 6474c204b198 gfx/layers/client/CanvasClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/layers/client/CanvasClient.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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 "mozilla/layers/CanvasClient.h" +#include "ClientCanvasLayer.h" // for ClientCanvasLayer +#include "GLContext.h" // for GLContext +#include "GLScreenBuffer.h" // for GLScreenBuffer +#include "SurfaceStream.h" // for SurfaceStream +#include "SurfaceTypes.h" // for SurfaceStreamHandle +#include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat +#include "gfxPlatform.h" // for gfxPlatform +#include "mozilla/gfx/BaseSize.h" // for BaseSize +#include "mozilla/layers/CompositableForwarder.h" +#include "mozilla/layers/GrallocTextureClient.h" +#include "mozilla/layers/LayersTypes.h" +#include "mozilla/layers/TextureClient.h" // for TextureClient, etc +#include "mozilla/layers/TextureClientOGL.h" +#include "nsAutoPtr.h" // for nsRefPtr +#include "nsDebug.h" // for printf_stderr, NS_ASSERTION +#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc +#ifdef MOZ_WIDGET_GONK +#include "SharedSurfaceGralloc.h" +#endif + +using namespace mozilla::gfx; +using namespace mozilla::gl; + +namespace mozilla { +namespace layers { + +/* static */ TemporaryRef +CanvasClient::CreateCanvasClient(CanvasClientType aType, + CompositableForwarder* aForwarder, + TextureFlags aFlags) +{ +#ifndef MOZ_WIDGET_GONK + if (XRE_GetProcessType() != GeckoProcessType_Default) { + NS_WARNING("Most platforms still need an optimized way to share GL cross process."); + return new CanvasClient2D(aForwarder, aFlags); + } +#endif + if (aType == CanvasClientGLContext && + aForwarder->GetCompositorBackendType() == LayersBackend::LAYERS_OPENGL) { + aFlags |= TEXTURE_DEALLOCATE_CLIENT; + return new CanvasClientSurfaceStream(aForwarder, aFlags); + } + return new CanvasClient2D(aForwarder, aFlags); +} + +void +CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) +{ + if (mBuffer && + (mBuffer->IsImmutable() || mBuffer->GetSize() != aSize)) { + GetForwarder()->RemoveTextureFromCompositable(this, mBuffer); + mBuffer = nullptr; + } + + bool bufferCreated = false; + if (!mBuffer) { + bool isOpaque = (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE); + gfxContentType contentType = isOpaque + ? gfxContentType::COLOR + : gfxContentType::COLOR_ALPHA; + gfxImageFormat format + = gfxPlatform::GetPlatform()->OptimalFormatForContent(contentType); + uint32_t flags = TEXTURE_FLAGS_DEFAULT; + if (mTextureFlags & TEXTURE_NEEDS_Y_FLIP) { + flags |= TEXTURE_NEEDS_Y_FLIP; + } + mBuffer = CreateBufferTextureClient(gfx::ImageFormatToSurfaceFormat(format), + flags, + gfxPlatform::GetPlatform()->GetPreferredCanvasBackend()); + MOZ_ASSERT(mBuffer->CanExposeDrawTarget()); + mBuffer->AllocateForSurface(aSize); + + bufferCreated = true; + } + + if (!mBuffer->Lock(OPEN_WRITE_ONLY)) { + mBuffer = nullptr; + return; + } + + bool updated = false; + { + // Restrict drawTarget to a scope so that terminates before Unlock. + RefPtr target = + mBuffer->GetAsDrawTarget(); + if (target) { + aLayer->UpdateTarget(target); + updated = true; + } + } + mBuffer->Unlock(); + + if (bufferCreated && !AddTextureClient(mBuffer)) { + mBuffer = nullptr; + return; + } + + if (updated) { + GetForwarder()->UpdatedTexture(this, mBuffer, nullptr); + GetForwarder()->UseTexture(this, mBuffer); + } +} + +CanvasClientSurfaceStream::CanvasClientSurfaceStream(CompositableForwarder* aLayerForwarder, + TextureFlags aFlags) + : CanvasClient(aLayerForwarder, aFlags) +{ +} + +void +CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) +{ + aLayer->mGLContext->MakeCurrent(); + GLScreenBuffer* screen = aLayer->mGLContext->Screen(); + SurfaceStream* stream = nullptr; + + if (aLayer->mStream) { + stream = aLayer->mStream; + + // Copy our current surface to the current producer surface in our stream, then + // call SwapProducer to make a new buffer ready. + stream->CopySurfaceToProducer(aLayer->mTextureSurface, aLayer->mFactory); + stream->SwapProducer(aLayer->mFactory, gfx::IntSize(aSize.width, aSize.height)); + } else { + stream = screen->Stream(); + } + + bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default); + bool bufferCreated = false; + if (isCrossProcess) { +#ifdef MOZ_WIDGET_GONK + SharedSurface* surf = stream->SwapConsumer(); + if (!surf) { + printf_stderr("surf is null post-SwapConsumer!\n"); + return; + } + + if (surf->Type() != SharedSurfaceType::Gralloc) { + printf_stderr("Unexpected non-Gralloc SharedSurface in IPC path!"); + MOZ_ASSERT(false); + return; + } + + SharedSurface_Gralloc* grallocSurf = SharedSurface_Gralloc::Cast(surf); + + RefPtr grallocTextureClient = + static_cast(grallocSurf->GetTextureClient()); + + // If IPDLActor is null means this TextureClient didn't AddTextureClient yet + if (!grallocTextureClient->GetIPDLActor()) { + grallocTextureClient->SetTextureFlags(mTextureInfo.mTextureFlags); + AddTextureClient(grallocTextureClient); + } + + if (grallocTextureClient->GetIPDLActor()) { + GetForwarder()->UseTexture(this, grallocTextureClient); + } +#else + printf_stderr("isCrossProcess, but not MOZ_WIDGET_GONK! Someone needs to write some code!"); + MOZ_ASSERT(false); +#endif + } else { + if (!mBuffer) { + StreamTextureClientOGL* textureClient = + new StreamTextureClientOGL(mTextureInfo.mTextureFlags); + textureClient->InitWith(stream); + mBuffer = textureClient; + bufferCreated = true; + } + + if (bufferCreated && !AddTextureClient(mBuffer)) { + mBuffer = nullptr; + } + + if (mBuffer) { + GetForwarder()->UseTexture(this, mBuffer); + } + } + + aLayer->Painted(); +} + +} +}