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