1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/layers/CompositableClient.h"
8 #include <stdint.h>       // for uint64_t, uint32_t
9 #include "gfxPlatform.h"  // for gfxPlatform
10 #include "mozilla/layers/CompositableForwarder.h"
11 #include "mozilla/layers/ImageBridgeChild.h"
12 #include "mozilla/layers/TextureClient.h"  // for TextureClient, etc
13 #include "mozilla/layers/TextureClientOGL.h"
14 #include "mozilla/mozalloc.h"  // for operator delete, etc
15 #include "mozilla/layers/TextureClientRecycleAllocator.h"
16 #ifdef XP_WIN
17 #include "gfxWindowsPlatform.h"  // for gfxWindowsPlatform
18 #include "mozilla/layers/TextureD3D11.h"
19 #endif
20 #include "gfxUtils.h"
21 #include "IPDLActor.h"
22 
23 namespace mozilla {
24 namespace layers {
25 
26 using namespace mozilla::gfx;
27 
InitIPDL(const CompositableHandle & aHandle)28 void CompositableClient::InitIPDL(const CompositableHandle& aHandle) {
29   MOZ_ASSERT(aHandle);
30 
31   mForwarder->AssertInForwarderThread();
32 
33   mHandle = aHandle;
34   mIsAsync = !NS_IsMainThread();
35 }
36 
CompositableClient(CompositableForwarder * aForwarder,TextureFlags aTextureFlags)37 CompositableClient::CompositableClient(CompositableForwarder* aForwarder,
38                                        TextureFlags aTextureFlags)
39     : mForwarder(aForwarder), mTextureFlags(aTextureFlags), mIsAsync(false) {}
40 
~CompositableClient()41 CompositableClient::~CompositableClient() { Destroy(); }
42 
GetCompositorBackendType() const43 LayersBackend CompositableClient::GetCompositorBackendType() const {
44   return mForwarder->GetCompositorBackendType();
45 }
46 
Connect(ImageContainer * aImageContainer)47 bool CompositableClient::Connect(ImageContainer* aImageContainer) {
48   MOZ_ASSERT(!mHandle);
49   if (!GetForwarder() || mHandle) {
50     return false;
51   }
52 
53   GetForwarder()->AssertInForwarderThread();
54   GetForwarder()->Connect(this, aImageContainer);
55   return true;
56 }
57 
IsConnected() const58 bool CompositableClient::IsConnected() const {
59   // CanSend() is only reliable in the same thread as the IPDL channel.
60   mForwarder->AssertInForwarderThread();
61   return !!mHandle;
62 }
63 
Destroy()64 void CompositableClient::Destroy() {
65   if (mTextureClientRecycler) {
66     mTextureClientRecycler->Destroy();
67   }
68 
69   if (mHandle) {
70     mForwarder->ReleaseCompositable(mHandle);
71     mHandle = CompositableHandle();
72   }
73 }
74 
GetAsyncHandle() const75 CompositableHandle CompositableClient::GetAsyncHandle() const {
76   if (mIsAsync) {
77     return mHandle;
78   }
79   return CompositableHandle();
80 }
81 
CreateBufferTextureClient(gfx::SurfaceFormat aFormat,gfx::IntSize aSize,gfx::BackendType aMoz2DBackend,TextureFlags aTextureFlags)82 already_AddRefed<TextureClient> CompositableClient::CreateBufferTextureClient(
83     gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
84     gfx::BackendType aMoz2DBackend, TextureFlags aTextureFlags) {
85   return TextureClient::CreateForRawBufferAccess(GetForwarder(), aFormat, aSize,
86                                                  aMoz2DBackend,
87                                                  aTextureFlags | mTextureFlags);
88 }
89 
90 already_AddRefed<TextureClient>
CreateTextureClientForDrawing(gfx::SurfaceFormat aFormat,gfx::IntSize aSize,BackendSelector aSelector,TextureFlags aTextureFlags,TextureAllocationFlags aAllocFlags)91 CompositableClient::CreateTextureClientForDrawing(
92     gfx::SurfaceFormat aFormat, gfx::IntSize aSize, BackendSelector aSelector,
93     TextureFlags aTextureFlags, TextureAllocationFlags aAllocFlags) {
94   return TextureClient::CreateForDrawing(
95       GetForwarder(), aFormat, aSize, aSelector, aTextureFlags | mTextureFlags,
96       aAllocFlags);
97 }
98 
99 already_AddRefed<TextureClient>
CreateTextureClientFromSurface(gfx::SourceSurface * aSurface,BackendSelector aSelector,TextureFlags aTextureFlags,TextureAllocationFlags aAllocFlags)100 CompositableClient::CreateTextureClientFromSurface(
101     gfx::SourceSurface* aSurface, BackendSelector aSelector,
102     TextureFlags aTextureFlags, TextureAllocationFlags aAllocFlags) {
103   return TextureClient::CreateFromSurface(GetForwarder(), aSurface, aSelector,
104                                           aTextureFlags | mTextureFlags,
105                                           aAllocFlags);
106 }
107 
AddTextureClient(TextureClient * aClient)108 bool CompositableClient::AddTextureClient(TextureClient* aClient) {
109   if (!aClient) {
110     return false;
111   }
112   aClient->SetAddedToCompositableClient();
113   return aClient->InitIPDLActor(mForwarder);
114 }
115 
ClearCachedResources()116 void CompositableClient::ClearCachedResources() {
117   if (mTextureClientRecycler) {
118     mTextureClientRecycler->ShrinkToMinimumSize();
119   }
120 }
121 
HandleMemoryPressure()122 void CompositableClient::HandleMemoryPressure() {
123   if (mTextureClientRecycler) {
124     mTextureClientRecycler->ShrinkToMinimumSize();
125   }
126 }
127 
RemoveTexture(TextureClient * aTexture)128 void CompositableClient::RemoveTexture(TextureClient* aTexture) {
129   mForwarder->RemoveTextureFromCompositable(this, aTexture);
130 }
131 
GetTextureClientRecycler()132 TextureClientRecycleAllocator* CompositableClient::GetTextureClientRecycler() {
133   if (mTextureClientRecycler) {
134     return mTextureClientRecycler;
135   }
136 
137   if (!mForwarder) {
138     return nullptr;
139   }
140 
141   if (!mForwarder->GetTextureForwarder()->UsesImageBridge()) {
142     MOZ_ASSERT(NS_IsMainThread());
143     mTextureClientRecycler =
144         new layers::TextureClientRecycleAllocator(mForwarder);
145     return mTextureClientRecycler;
146   }
147 
148   // Handle a case that mForwarder is ImageBridge
149 
150   if (InImageBridgeChildThread()) {
151     mTextureClientRecycler =
152         new layers::TextureClientRecycleAllocator(mForwarder);
153     return mTextureClientRecycler;
154   }
155 
156   ReentrantMonitor barrier("CompositableClient::GetTextureClientRecycler");
157   ReentrantMonitorAutoEnter mainThreadAutoMon(barrier);
158   bool done = false;
159 
160   RefPtr<Runnable> runnable = NS_NewRunnableFunction(
161       "layers::CompositableClient::GetTextureClientRecycler", [&]() {
162         if (!mTextureClientRecycler) {
163           mTextureClientRecycler =
164               new layers::TextureClientRecycleAllocator(mForwarder);
165         }
166         ReentrantMonitorAutoEnter childThreadAutoMon(barrier);
167         done = true;
168         barrier.NotifyAll();
169       });
170 
171   ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
172       runnable.forget());
173 
174   // should stop the thread until done.
175   while (!done) {
176     barrier.Wait();
177   }
178 
179   return mTextureClientRecycler;
180 }
181 
DumpTextureClient(std::stringstream & aStream,TextureClient * aTexture,TextureDumpMode aCompress)182 void CompositableClient::DumpTextureClient(std::stringstream& aStream,
183                                            TextureClient* aTexture,
184                                            TextureDumpMode aCompress) {
185   if (!aTexture) {
186     return;
187   }
188   RefPtr<gfx::DataSourceSurface> dSurf = aTexture->GetAsSurface();
189   if (!dSurf) {
190     return;
191   }
192   if (aCompress == TextureDumpMode::Compress) {
193     aStream << gfxUtils::GetAsLZ4Base64Str(dSurf).get();
194   } else {
195     aStream << gfxUtils::GetAsDataURI(dSurf).get();
196   }
197 }
198 
~AutoRemoveTexture()199 AutoRemoveTexture::~AutoRemoveTexture() {
200   if (mCompositable && mTexture && mCompositable->IsConnected()) {
201     mCompositable->RemoveTexture(mTexture);
202   }
203 }
204 
205 }  // namespace layers
206 }  // namespace mozilla
207