Bug 1022167 - Ensure fence delivery of thebes layer in b2g process r=nical
[gecko.git] / gfx / layers / client / CanvasClient.cpp
blob75c14ca09aaed0b80a5fbb92ecca3fafa5daf7f8
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/layers/CanvasClient.h"
7 #include "ClientCanvasLayer.h" // for ClientCanvasLayer
8 #include "CompositorChild.h" // for CompositorChild
9 #include "GLContext.h" // for GLContext
10 #include "GLScreenBuffer.h" // for GLScreenBuffer
11 #include "SurfaceStream.h" // for SurfaceStream
12 #include "SurfaceTypes.h" // for SurfaceStreamHandle
13 #include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat
14 #include "gfxPlatform.h" // for gfxPlatform
15 #include "mozilla/gfx/BaseSize.h" // for BaseSize
16 #include "mozilla/layers/CompositableForwarder.h"
17 #include "mozilla/layers/GrallocTextureClient.h"
18 #include "mozilla/layers/LayersTypes.h"
19 #include "mozilla/layers/TextureClient.h" // for TextureClient, etc
20 #include "mozilla/layers/TextureClientOGL.h"
21 #include "nsAutoPtr.h" // for nsRefPtr
22 #include "nsDebug.h" // for printf_stderr, NS_ASSERTION
23 #include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
24 #ifdef MOZ_WIDGET_GONK
25 #include "SharedSurfaceGralloc.h"
26 #endif
28 using namespace mozilla::gfx;
29 using namespace mozilla::gl;
31 namespace mozilla {
32 namespace layers {
34 /* static */ TemporaryRef<CanvasClient>
35 CanvasClient::CreateCanvasClient(CanvasClientType aType,
36 CompositableForwarder* aForwarder,
37 TextureFlags aFlags)
39 #ifndef MOZ_WIDGET_GONK
40 if (XRE_GetProcessType() != GeckoProcessType_Default) {
41 NS_WARNING("Most platforms still need an optimized way to share GL cross process.");
42 return new CanvasClient2D(aForwarder, aFlags);
44 #endif
45 if (aType == CanvasClientGLContext &&
46 aForwarder->GetCompositorBackendType() == LayersBackend::LAYERS_OPENGL) {
47 aFlags |= TextureFlags::DEALLOCATE_CLIENT;
48 return new CanvasClientSurfaceStream(aForwarder, aFlags);
50 return new CanvasClient2D(aForwarder, aFlags);
53 void
54 CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
56 AutoRemoveTexture autoRemove(this);
57 if (mBuffer &&
58 (mBuffer->IsImmutable() || mBuffer->GetSize() != aSize)) {
59 autoRemove.mTexture = mBuffer;
60 mBuffer = nullptr;
63 bool bufferCreated = false;
64 if (!mBuffer) {
65 bool isOpaque = (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE);
66 gfxContentType contentType = isOpaque
67 ? gfxContentType::COLOR
68 : gfxContentType::COLOR_ALPHA;
69 gfxImageFormat format
70 = gfxPlatform::GetPlatform()->OptimalFormatForContent(contentType);
71 TextureFlags flags = TextureFlags::DEFAULT;
72 if (mTextureFlags & TextureFlags::NEEDS_Y_FLIP) {
73 flags |= TextureFlags::NEEDS_Y_FLIP;
76 gfx::SurfaceFormat surfaceFormat = gfx::ImageFormatToSurfaceFormat(format);
77 mBuffer = CreateTextureClientForCanvas(surfaceFormat, aSize, flags, aLayer);
78 MOZ_ASSERT(mBuffer->CanExposeDrawTarget());
79 mBuffer->AllocateForSurface(aSize);
81 bufferCreated = true;
84 if (!mBuffer->Lock(OpenMode::OPEN_WRITE_ONLY)) {
85 mBuffer = nullptr;
86 return;
89 bool updated = false;
91 // Restrict drawTarget to a scope so that terminates before Unlock.
92 RefPtr<DrawTarget> target =
93 mBuffer->BorrowDrawTarget();
94 if (target) {
95 aLayer->UpdateTarget(target);
96 updated = true;
99 mBuffer->Unlock();
101 if (bufferCreated && !AddTextureClient(mBuffer)) {
102 mBuffer = nullptr;
103 return;
106 if (updated) {
107 GetForwarder()->UpdatedTexture(this, mBuffer, nullptr);
108 GetForwarder()->UseTexture(this, mBuffer);
112 TemporaryRef<TextureClient>
113 CanvasClient2D::CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
114 gfx::IntSize aSize,
115 TextureFlags aFlags,
116 ClientCanvasLayer* aLayer)
118 if (aLayer->IsGLLayer()) {
119 // We want a cairo backend here as we don't want to be copying into
120 // an accelerated backend and we like LockBits to work. This is currently
121 // the most effective way to make this work.
122 return CreateBufferTextureClient(aFormat, aFlags, BackendType::CAIRO);
125 gfx::BackendType backend = gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
126 #ifdef XP_WIN
127 return CreateTextureClientForDrawing(aFormat, aFlags, backend, aSize);
128 #else
129 // XXX - We should use CreateTextureClientForDrawing, but we first need
130 // to use double buffering.
131 return CreateBufferTextureClient(aFormat, aFlags, backend);
132 #endif
135 CanvasClientSurfaceStream::CanvasClientSurfaceStream(CompositableForwarder* aLayerForwarder,
136 TextureFlags aFlags)
137 : CanvasClient(aLayerForwarder, aFlags)
141 void
142 CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
144 aLayer->mGLContext->MakeCurrent();
145 GLScreenBuffer* screen = aLayer->mGLContext->Screen();
146 SurfaceStream* stream = nullptr;
148 if (aLayer->mStream) {
149 stream = aLayer->mStream;
151 // Copy our current surface to the current producer surface in our stream, then
152 // call SwapProducer to make a new buffer ready.
153 stream->CopySurfaceToProducer(aLayer->mTextureSurface, aLayer->mFactory);
154 stream->SwapProducer(aLayer->mFactory, gfx::IntSize(aSize.width, aSize.height));
155 } else {
156 stream = screen->Stream();
159 bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
160 bool bufferCreated = false;
161 if (isCrossProcess) {
162 #ifdef MOZ_WIDGET_GONK
163 SharedSurface* surf = stream->SwapConsumer();
164 if (!surf) {
165 printf_stderr("surf is null post-SwapConsumer!\n");
166 return;
169 if (surf->Type() != SharedSurfaceType::Gralloc) {
170 printf_stderr("Unexpected non-Gralloc SharedSurface in IPC path!");
171 MOZ_ASSERT(false);
172 return;
175 SharedSurface_Gralloc* grallocSurf = SharedSurface_Gralloc::Cast(surf);
177 RefPtr<GrallocTextureClientOGL> grallocTextureClient =
178 static_cast<GrallocTextureClientOGL*>(grallocSurf->GetTextureClient());
180 // If IPDLActor is null means this TextureClient didn't AddTextureClient yet
181 if (!grallocTextureClient->GetIPDLActor()) {
182 grallocTextureClient->SetTextureFlags(mTextureInfo.mTextureFlags);
183 AddTextureClient(grallocTextureClient);
186 if (grallocTextureClient->GetIPDLActor()) {
187 UseTexture(grallocTextureClient);
190 if (mBuffer) {
191 // remove old buffer from CompositableHost
192 RefPtr<AsyncTransactionTracker> tracker = new RemoveTextureFromCompositableTracker();
193 // Hold TextureClient until transaction complete.
194 tracker->SetTextureClient(mBuffer);
195 mBuffer->SetRemoveFromCompositableTracker(tracker);
196 // RemoveTextureFromCompositableAsync() expects CompositorChild's presence.
197 GetForwarder()->RemoveTextureFromCompositableAsync(tracker, this, mBuffer);
199 mBuffer = grallocTextureClient;
200 #else
201 printf_stderr("isCrossProcess, but not MOZ_WIDGET_GONK! Someone needs to write some code!");
202 MOZ_ASSERT(false);
203 #endif
204 } else {
205 if (!mBuffer) {
206 StreamTextureClientOGL* textureClient =
207 new StreamTextureClientOGL(mTextureInfo.mTextureFlags);
208 textureClient->InitWith(stream);
209 mBuffer = textureClient;
210 bufferCreated = true;
213 if (bufferCreated && !AddTextureClient(mBuffer)) {
214 mBuffer = nullptr;
217 if (mBuffer) {
218 GetForwarder()->UseTexture(this, mBuffer);
222 aLayer->Painted();