michael@0: /* -*- Mode: C++; tab-width: 2; 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 "ClientCanvasLayer.h" michael@0: #include "GLContext.h" // for GLContext michael@0: #include "GLScreenBuffer.h" // for GLScreenBuffer michael@0: #include "GeckoProfiler.h" // for PROFILER_LABEL michael@0: #include "SharedSurfaceEGL.h" // for SurfaceFactory_EGLImage michael@0: #include "SharedSurfaceGL.h" // for SurfaceFactory_GLTexture, etc michael@0: #include "SurfaceStream.h" // for SurfaceStream, etc michael@0: #include "SurfaceTypes.h" // for SurfaceStreamType michael@0: #include "ClientLayerManager.h" // for ClientLayerManager, etc michael@0: #include "mozilla/gfx/Point.h" // for IntSize michael@0: #include "mozilla/layers/CompositorTypes.h" michael@0: #include "mozilla/layers/LayersTypes.h" michael@0: #include "nsCOMPtr.h" // for already_AddRefed michael@0: #include "nsISupportsImpl.h" // for Layer::AddRef, etc michael@0: #include "nsRect.h" // for nsIntRect 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: #ifdef XP_MACOSX michael@0: #include "SharedSurfaceIO.h" michael@0: #endif michael@0: #include "gfxPrefs.h" // for WebGLForceLayersReadback 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: ClientCanvasLayer::~ClientCanvasLayer() michael@0: { michael@0: MOZ_COUNT_DTOR(ClientCanvasLayer); michael@0: if (mCanvasClient) { michael@0: mCanvasClient->OnDetach(); michael@0: mCanvasClient = nullptr; michael@0: } michael@0: if (mTextureSurface) { michael@0: delete mTextureSurface; michael@0: } michael@0: } michael@0: michael@0: void michael@0: ClientCanvasLayer::Initialize(const Data& aData) michael@0: { michael@0: CopyableCanvasLayer::Initialize(aData); michael@0: michael@0: mCanvasClient = nullptr; michael@0: michael@0: if (mGLContext) { michael@0: GLScreenBuffer* screen = mGLContext->Screen(); michael@0: michael@0: SurfaceCaps caps = screen->Caps(); michael@0: if (mStream) { michael@0: // The screen caps are irrelevant if we're using a separate stream michael@0: caps = GetContentFlags() & CONTENT_OPAQUE ? SurfaceCaps::ForRGB() : SurfaceCaps::ForRGBA(); michael@0: } michael@0: michael@0: SurfaceStreamType streamType = michael@0: SurfaceStream::ChooseGLStreamType(SurfaceStream::OffMainThread, michael@0: screen->PreserveBuffer()); michael@0: SurfaceFactory_GL* factory = nullptr; michael@0: if (!gfxPrefs::WebGLForceLayersReadback()) { michael@0: if (ClientManager()->AsShadowForwarder()->GetCompositorBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) { michael@0: if (mGLContext->GetContextType() == GLContextType::EGL) { michael@0: bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default); michael@0: michael@0: if (!isCrossProcess) { michael@0: // [Basic/OGL Layers, OMTC] WebGL layer init. michael@0: factory = SurfaceFactory_EGLImage::Create(mGLContext, caps); michael@0: } else { michael@0: // [Basic/OGL Layers, OOPC] WebGL layer init. (Out Of Process Compositing) michael@0: #ifdef MOZ_WIDGET_GONK michael@0: factory = new SurfaceFactory_Gralloc(mGLContext, caps, ClientManager()->AsShadowForwarder()); michael@0: #else michael@0: // we could do readback here maybe michael@0: NS_NOTREACHED("isCrossProcess but not on native B2G!"); michael@0: #endif michael@0: } michael@0: } else { michael@0: // [Basic Layers, OMTC] WebGL layer init. michael@0: // Well, this *should* work... michael@0: #ifdef XP_MACOSX michael@0: factory = new SurfaceFactory_IOSurface(mGLContext, caps); michael@0: #else michael@0: factory = new SurfaceFactory_GLTexture(mGLContext, nullptr, caps); michael@0: #endif michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (mStream) { michael@0: // We're using a stream other than the one in the default screen michael@0: mFactory = factory; michael@0: if (!mFactory) { michael@0: // Absolutely must have a factory here, so create a basic one michael@0: mFactory = new SurfaceFactory_Basic(mGLContext, caps); michael@0: } michael@0: michael@0: gfx::IntSize size = gfx::IntSize(aData.mSize.width, aData.mSize.height); michael@0: mTextureSurface = SharedSurface_GLTexture::Create(mGLContext, mGLContext, michael@0: mGLContext->GetGLFormats(), michael@0: size, caps.alpha, aData.mTexID); michael@0: SharedSurface* producer = mStream->SwapProducer(mFactory, size); michael@0: if (!producer) { michael@0: // Fallback to basic factory michael@0: delete mFactory; michael@0: mFactory = new SurfaceFactory_Basic(mGLContext, caps); michael@0: producer = mStream->SwapProducer(mFactory, size); michael@0: MOZ_ASSERT(producer, "Failed to create initial canvas surface with basic factory"); michael@0: } michael@0: } else if (factory) { michael@0: screen->Morph(factory, streamType); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: ClientCanvasLayer::RenderLayer() michael@0: { michael@0: PROFILER_LABEL("ClientCanvasLayer", "Paint"); michael@0: if (!IsDirty()) { michael@0: return; michael@0: } michael@0: michael@0: if (GetMaskLayer()) { michael@0: ToClientLayer(GetMaskLayer())->RenderLayer(); michael@0: } michael@0: michael@0: if (!mCanvasClient) { michael@0: TextureFlags flags = TEXTURE_IMMEDIATE_UPLOAD; michael@0: if (mNeedsYFlip) { michael@0: flags |= TEXTURE_NEEDS_Y_FLIP; michael@0: } michael@0: michael@0: if (!mGLContext) { michael@0: // We don't support locking for buffer surfaces currently michael@0: flags |= TEXTURE_IMMEDIATE_UPLOAD; michael@0: } else { michael@0: // GLContext's SurfaceStream handles ownership itself, michael@0: // and doesn't require layers to do any deallocation. michael@0: flags |= TEXTURE_DEALLOCATE_CLIENT; michael@0: } michael@0: mCanvasClient = CanvasClient::CreateCanvasClient(GetCanvasClientType(), michael@0: ClientManager()->AsShadowForwarder(), flags); michael@0: if (!mCanvasClient) { michael@0: return; michael@0: } michael@0: if (HasShadow()) { michael@0: mCanvasClient->Connect(); michael@0: ClientManager()->AsShadowForwarder()->Attach(mCanvasClient, this); michael@0: } michael@0: } michael@0: michael@0: FirePreTransactionCallback(); michael@0: mCanvasClient->Update(gfx::IntSize(mBounds.width, mBounds.height), this); michael@0: michael@0: FireDidTransactionCallback(); michael@0: michael@0: ClientManager()->Hold(this); michael@0: mCanvasClient->Updated(); michael@0: mCanvasClient->OnTransaction(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: ClientLayerManager::CreateCanvasLayer() michael@0: { michael@0: NS_ASSERTION(InConstruction(), "Only allowed in construction phase"); michael@0: nsRefPtr layer = michael@0: new ClientCanvasLayer(this); michael@0: CREATE_SHADOW(Canvas); michael@0: return layer.forget(); michael@0: } michael@0: michael@0: } michael@0: }