/src/mozilla-central/gfx/layers/composite/TextureHost.cpp
Line | Count | Source (jump to first uncovered line) |
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 "TextureHost.h" |
8 | | |
9 | | #include "CompositableHost.h" // for CompositableHost |
10 | | #include "LayerScope.h" |
11 | | #include "LayersLogging.h" // for AppendToString |
12 | | #include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory |
13 | | #include "mozilla/gfx/gfxVars.h" |
14 | | #include "mozilla/ipc/Shmem.h" // for Shmem |
15 | | #include "mozilla/layers/CompositableTransactionParent.h" // for CompositableParentManager |
16 | | #include "mozilla/layers/CompositorBridgeParent.h" |
17 | | #include "mozilla/layers/Compositor.h" // for Compositor |
18 | | #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator |
19 | | #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc |
20 | | #include "mozilla/layers/TextureHostBasic.h" |
21 | | #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL |
22 | | #include "mozilla/layers/ImageDataSerializer.h" |
23 | | #include "mozilla/layers/TextureClient.h" |
24 | | #ifdef XP_DARWIN |
25 | | #include "mozilla/layers/TextureSync.h" |
26 | | #endif |
27 | | #include "mozilla/layers/GPUVideoTextureHost.h" |
28 | | #include "mozilla/layers/WebRenderTextureHost.h" |
29 | | #include "mozilla/webrender/RenderBufferTextureHost.h" |
30 | | #include "mozilla/webrender/RenderThread.h" |
31 | | #include "mozilla/webrender/WebRenderAPI.h" |
32 | | #include "nsAString.h" |
33 | | #include "mozilla/RefPtr.h" // for nsRefPtr |
34 | | #include "nsPrintfCString.h" // for nsPrintfCString |
35 | | #include "mozilla/layers/PTextureParent.h" |
36 | | #include "mozilla/Unused.h" |
37 | | #include <limits> |
38 | | #include "../opengl/CompositorOGL.h" |
39 | | #include "gfxPrefs.h" |
40 | | #include "gfxUtils.h" |
41 | | #include "IPDLActor.h" |
42 | | |
43 | | #ifdef MOZ_ENABLE_D3D10_LAYER |
44 | | #include "../d3d11/CompositorD3D11.h" |
45 | | #endif |
46 | | |
47 | | #ifdef MOZ_X11 |
48 | | #include "mozilla/layers/X11TextureHost.h" |
49 | | #endif |
50 | | |
51 | | #ifdef XP_MACOSX |
52 | | #include "../opengl/MacIOSurfaceTextureHostOGL.h" |
53 | | #endif |
54 | | |
55 | | #ifdef XP_WIN |
56 | | #include "mozilla/layers/TextureDIB.h" |
57 | | #endif |
58 | | |
59 | | #if 0 |
60 | | #define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__) |
61 | | #else |
62 | | #define RECYCLE_LOG(...) do { } while (0) |
63 | | #endif |
64 | | |
65 | | namespace mozilla { |
66 | | namespace layers { |
67 | | |
68 | | /** |
69 | | * TextureParent is the host-side IPDL glue between TextureClient and TextureHost. |
70 | | * It is an IPDL actor just like LayerParent, CompositableParent, etc. |
71 | | */ |
72 | | class TextureParent : public ParentActor<PTextureParent> |
73 | | { |
74 | | public: |
75 | | explicit TextureParent(HostIPCAllocator* aAllocator, uint64_t aSerial, const wr::MaybeExternalImageId& aExternalImageId); |
76 | | |
77 | | ~TextureParent(); |
78 | | |
79 | | bool Init(const SurfaceDescriptor& aSharedData, |
80 | | const ReadLockDescriptor& aReadLock, |
81 | | const LayersBackend& aLayersBackend, |
82 | | const TextureFlags& aFlags); |
83 | | |
84 | | void NotifyNotUsed(uint64_t aTransactionId); |
85 | | |
86 | | virtual mozilla::ipc::IPCResult RecvRecycleTexture(const TextureFlags& aTextureFlags) override; |
87 | | |
88 | 0 | TextureHost* GetTextureHost() { return mTextureHost; } |
89 | | |
90 | | virtual void Destroy() override; |
91 | | |
92 | 0 | uint64_t GetSerial() const { return mSerial; } |
93 | | |
94 | | HostIPCAllocator* mSurfaceAllocator; |
95 | | RefPtr<TextureHost> mTextureHost; |
96 | | // mSerial is unique in TextureClient's process. |
97 | | const uint64_t mSerial; |
98 | | wr::MaybeExternalImageId mExternalImageId; |
99 | | }; |
100 | | |
101 | | static bool |
102 | | WrapWithWebRenderTextureHost(ISurfaceAllocator* aDeallocator, |
103 | | LayersBackend aBackend, |
104 | | TextureFlags aFlags) |
105 | 0 | { |
106 | 0 | if ((aFlags & TextureFlags::SNAPSHOT) || |
107 | 0 | (aBackend != LayersBackend::LAYERS_WR) || |
108 | 0 | (!aDeallocator->UsesImageBridge() && !aDeallocator->AsCompositorBridgeParentBase())) { |
109 | 0 | return false; |
110 | 0 | } |
111 | 0 | return true; |
112 | 0 | } |
113 | | |
114 | | //////////////////////////////////////////////////////////////////////////////// |
115 | | PTextureParent* |
116 | | TextureHost::CreateIPDLActor(HostIPCAllocator* aAllocator, |
117 | | const SurfaceDescriptor& aSharedData, |
118 | | const ReadLockDescriptor& aReadLock, |
119 | | LayersBackend aLayersBackend, |
120 | | TextureFlags aFlags, |
121 | | uint64_t aSerial, |
122 | | const wr::MaybeExternalImageId& aExternalImageId) |
123 | 0 | { |
124 | 0 | TextureParent* actor = new TextureParent(aAllocator, aSerial, aExternalImageId); |
125 | 0 | if (!actor->Init(aSharedData, aReadLock, aLayersBackend, aFlags)) { |
126 | 0 | actor->ActorDestroy(ipc::IProtocol::ActorDestroyReason::FailedConstructor); |
127 | 0 | delete actor; |
128 | 0 | return nullptr; |
129 | 0 | } |
130 | 0 | return actor; |
131 | 0 | } |
132 | | |
133 | | // static |
134 | | bool |
135 | | TextureHost::DestroyIPDLActor(PTextureParent* actor) |
136 | 0 | { |
137 | 0 | delete actor; |
138 | 0 | return true; |
139 | 0 | } |
140 | | |
141 | | // static |
142 | | bool |
143 | | TextureHost::SendDeleteIPDLActor(PTextureParent* actor) |
144 | 0 | { |
145 | 0 | return PTextureParent::Send__delete__(actor); |
146 | 0 | } |
147 | | |
148 | | // static |
149 | | TextureHost* |
150 | | TextureHost::AsTextureHost(PTextureParent* actor) |
151 | 0 | { |
152 | 0 | if (!actor) { |
153 | 0 | return nullptr; |
154 | 0 | } |
155 | 0 | return static_cast<TextureParent*>(actor)->mTextureHost; |
156 | 0 | } |
157 | | |
158 | | // static |
159 | | uint64_t |
160 | | TextureHost::GetTextureSerial(PTextureParent* actor) |
161 | 0 | { |
162 | 0 | if (!actor) { |
163 | 0 | return UINT64_MAX; |
164 | 0 | } |
165 | 0 | return static_cast<TextureParent*>(actor)->mSerial; |
166 | 0 | } |
167 | | |
168 | | PTextureParent* |
169 | | TextureHost::GetIPDLActor() |
170 | 0 | { |
171 | 0 | return mActor; |
172 | 0 | } |
173 | | |
174 | | void |
175 | | TextureHost::SetLastFwdTransactionId(uint64_t aTransactionId) |
176 | 0 | { |
177 | 0 | MOZ_ASSERT(mFwdTransactionId <= aTransactionId); |
178 | 0 | mFwdTransactionId = aTransactionId; |
179 | 0 | } |
180 | | |
181 | | // implemented in TextureHostOGL.cpp |
182 | | already_AddRefed<TextureHost> CreateTextureHostOGL(const SurfaceDescriptor& aDesc, |
183 | | ISurfaceAllocator* aDeallocator, |
184 | | LayersBackend aBackend, |
185 | | TextureFlags aFlags); |
186 | | |
187 | | // implemented in TextureHostBasic.cpp |
188 | | already_AddRefed<TextureHost> CreateTextureHostBasic(const SurfaceDescriptor& aDesc, |
189 | | ISurfaceAllocator* aDeallocator, |
190 | | LayersBackend aBackend, |
191 | | TextureFlags aFlags); |
192 | | |
193 | | // implemented in TextureD3D11.cpp |
194 | | already_AddRefed<TextureHost> CreateTextureHostD3D11(const SurfaceDescriptor& aDesc, |
195 | | ISurfaceAllocator* aDeallocator, |
196 | | LayersBackend aBackend, |
197 | | TextureFlags aFlags); |
198 | | |
199 | | already_AddRefed<TextureHost> |
200 | | TextureHost::Create(const SurfaceDescriptor& aDesc, |
201 | | const ReadLockDescriptor& aReadLock, |
202 | | ISurfaceAllocator* aDeallocator, |
203 | | LayersBackend aBackend, |
204 | | TextureFlags aFlags, |
205 | | wr::MaybeExternalImageId& aExternalImageId) |
206 | 0 | { |
207 | 0 | RefPtr<TextureHost> result; |
208 | 0 |
|
209 | 0 | switch (aDesc.type()) { |
210 | 0 | case SurfaceDescriptor::TSurfaceDescriptorBuffer: |
211 | 0 | case SurfaceDescriptor::TSurfaceDescriptorDIB: |
212 | 0 | case SurfaceDescriptor::TSurfaceDescriptorFileMapping: |
213 | 0 | case SurfaceDescriptor::TSurfaceDescriptorGPUVideo: |
214 | 0 | result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aBackend, aFlags); |
215 | 0 | break; |
216 | 0 |
|
217 | 0 | case SurfaceDescriptor::TEGLImageDescriptor: |
218 | 0 | case SurfaceDescriptor::TSurfaceTextureDescriptor: |
219 | 0 | case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture: |
220 | 0 | result = CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags); |
221 | 0 | break; |
222 | 0 |
|
223 | 0 | case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: |
224 | 0 | if (aBackend == LayersBackend::LAYERS_OPENGL || |
225 | 0 | aBackend == LayersBackend::LAYERS_WR) { |
226 | 0 | result = CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags); |
227 | 0 | break; |
228 | 0 | } else { |
229 | 0 | result = CreateTextureHostBasic(aDesc, aDeallocator, aBackend, aFlags); |
230 | 0 | break; |
231 | 0 | } |
232 | 0 | |
233 | 0 | #ifdef MOZ_X11 |
234 | 0 | case SurfaceDescriptor::TSurfaceDescriptorX11: { |
235 | 0 | if (!aDeallocator->IsSameProcess()) { |
236 | 0 | NS_ERROR("A client process is trying to peek at our address space using a X11Texture!"); |
237 | 0 | return nullptr; |
238 | 0 | } |
239 | 0 |
|
240 | 0 | const SurfaceDescriptorX11& desc = aDesc.get_SurfaceDescriptorX11(); |
241 | 0 | result = MakeAndAddRef<X11TextureHost>(aFlags, desc); |
242 | 0 | break; |
243 | 0 | } |
244 | 0 | #endif |
245 | 0 |
|
246 | | #ifdef XP_WIN |
247 | | case SurfaceDescriptor::TSurfaceDescriptorD3D10: |
248 | | case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr: |
249 | | result = CreateTextureHostD3D11(aDesc, aDeallocator, aBackend, aFlags); |
250 | | break; |
251 | | #endif |
252 | 0 | default: |
253 | 0 | MOZ_CRASH("GFX: Unsupported Surface type host"); |
254 | 0 | } |
255 | 0 |
|
256 | 0 | if (result && WrapWithWebRenderTextureHost(aDeallocator, aBackend, aFlags)) { |
257 | 0 | MOZ_ASSERT(aExternalImageId.isSome()); |
258 | 0 | result = new WebRenderTextureHost(aDesc, aFlags, result, aExternalImageId.ref()); |
259 | 0 | } |
260 | 0 |
|
261 | 0 | if (result) { |
262 | 0 | result->DeserializeReadLock(aReadLock, aDeallocator); |
263 | 0 | } |
264 | 0 |
|
265 | 0 | return result.forget(); |
266 | 0 | } |
267 | | |
268 | | already_AddRefed<TextureHost> |
269 | | CreateBackendIndependentTextureHost(const SurfaceDescriptor& aDesc, |
270 | | ISurfaceAllocator* aDeallocator, |
271 | | LayersBackend aBackend, |
272 | | TextureFlags aFlags) |
273 | 0 | { |
274 | 0 | RefPtr<TextureHost> result; |
275 | 0 | switch (aDesc.type()) { |
276 | 0 | case SurfaceDescriptor::TSurfaceDescriptorBuffer: { |
277 | 0 | const SurfaceDescriptorBuffer& bufferDesc = aDesc.get_SurfaceDescriptorBuffer(); |
278 | 0 | const MemoryOrShmem& data = bufferDesc.data(); |
279 | 0 | switch (data.type()) { |
280 | 0 | case MemoryOrShmem::TShmem: { |
281 | 0 | const ipc::Shmem& shmem = data.get_Shmem(); |
282 | 0 | const BufferDescriptor& desc = bufferDesc.desc(); |
283 | 0 | if (!shmem.IsReadable()) { |
284 | 0 | // We failed to map the shmem so we can't verify its size. This |
285 | 0 | // should not be a fatal error, so just create the texture with |
286 | 0 | // nothing backing it. |
287 | 0 | result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags); |
288 | 0 | break; |
289 | 0 | } |
290 | 0 | |
291 | 0 | size_t bufSize = shmem.Size<char>(); |
292 | 0 | size_t reqSize = SIZE_MAX; |
293 | 0 | switch (desc.type()) { |
294 | 0 | case BufferDescriptor::TYCbCrDescriptor: { |
295 | 0 | const YCbCrDescriptor& ycbcr = desc.get_YCbCrDescriptor(); |
296 | 0 | reqSize = |
297 | 0 | ImageDataSerializer::ComputeYCbCrBufferSize(ycbcr.ySize(), ycbcr.yStride(), |
298 | 0 | ycbcr.cbCrSize(), ycbcr.cbCrStride(), |
299 | 0 | ycbcr.yOffset(), ycbcr.cbOffset(), |
300 | 0 | ycbcr.crOffset()); |
301 | 0 | break; |
302 | 0 | } |
303 | 0 | case BufferDescriptor::TRGBDescriptor: { |
304 | 0 | const RGBDescriptor& rgb = desc.get_RGBDescriptor(); |
305 | 0 | reqSize = ImageDataSerializer::ComputeRGBBufferSize(rgb.size(), rgb.format()); |
306 | 0 | break; |
307 | 0 | } |
308 | 0 | default: |
309 | 0 | gfxCriticalError() << "Bad buffer host descriptor " << (int)desc.type(); |
310 | 0 | MOZ_CRASH("GFX: Bad descriptor"); |
311 | 0 | } |
312 | 0 |
|
313 | 0 | if (reqSize == 0 || bufSize < reqSize) { |
314 | 0 | NS_ERROR("A client process gave a shmem too small to fit for its descriptor!"); |
315 | 0 | return nullptr; |
316 | 0 | } |
317 | 0 |
|
318 | 0 | result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags); |
319 | 0 | break; |
320 | 0 | } |
321 | 0 | case MemoryOrShmem::Tuintptr_t: { |
322 | 0 | if (!aDeallocator->IsSameProcess()) { |
323 | 0 | NS_ERROR("A client process is trying to peek at our address space using a MemoryTexture!"); |
324 | 0 | return nullptr; |
325 | 0 | } |
326 | 0 |
|
327 | 0 | result = new MemoryTextureHost(reinterpret_cast<uint8_t*>(data.get_uintptr_t()), |
328 | 0 | bufferDesc.desc(), |
329 | 0 | aFlags); |
330 | 0 | break; |
331 | 0 | } |
332 | 0 | default: |
333 | 0 | gfxCriticalError() << "Failed texture host for backend " << (int)data.type(); |
334 | 0 | MOZ_CRASH("GFX: No texture host for backend"); |
335 | 0 | } |
336 | 0 | break; |
337 | 0 | } |
338 | 0 | case SurfaceDescriptor::TSurfaceDescriptorGPUVideo: { |
339 | 0 | result = GPUVideoTextureHost::CreateFromDescriptor( |
340 | 0 | aFlags, aDesc.get_SurfaceDescriptorGPUVideo()); |
341 | 0 | break; |
342 | 0 | } |
343 | | #ifdef XP_WIN |
344 | | case SurfaceDescriptor::TSurfaceDescriptorDIB: { |
345 | | if (!aDeallocator->IsSameProcess()) { |
346 | | NS_ERROR("A client process is trying to peek at our address space using a DIBTexture!"); |
347 | | return nullptr; |
348 | | } |
349 | | |
350 | | result = new DIBTextureHost(aFlags, aDesc); |
351 | | break; |
352 | | } |
353 | | case SurfaceDescriptor::TSurfaceDescriptorFileMapping: { |
354 | | result = new TextureHostFileMapping(aFlags, aDesc); |
355 | | break; |
356 | | } |
357 | | #endif |
358 | 0 | default: { |
359 | 0 | NS_WARNING("No backend independent TextureHost for this descriptor type"); |
360 | 0 | } |
361 | 0 | } |
362 | 0 | return result.forget(); |
363 | 0 | } |
364 | | |
365 | | TextureHost::TextureHost(TextureFlags aFlags) |
366 | | : AtomicRefCountedWithFinalize("TextureHost") |
367 | | , mActor(nullptr) |
368 | | , mFlags(aFlags) |
369 | | , mCompositableCount(0) |
370 | | , mFwdTransactionId(0) |
371 | | , mReadLocked(false) |
372 | 0 | { |
373 | 0 | } |
374 | | |
375 | | TextureHost::~TextureHost() |
376 | 0 | { |
377 | 0 | if (mReadLocked) { |
378 | 0 | // If we still have a ReadLock, unlock it. At this point we don't care about |
379 | 0 | // the texture client being written into on the other side since it should be |
380 | 0 | // destroyed by now. But we will hit assertions if we don't ReadUnlock before |
381 | 0 | // destroying the lock itself. |
382 | 0 | ReadUnlock(); |
383 | 0 | MaybeNotifyUnlocked(); |
384 | 0 | } |
385 | 0 | } |
386 | | |
387 | | void TextureHost::Finalize() |
388 | 0 | { |
389 | 0 | if (!(GetFlags() & TextureFlags::DEALLOCATE_CLIENT)) { |
390 | 0 | DeallocateSharedData(); |
391 | 0 | DeallocateDeviceData(); |
392 | 0 | } |
393 | 0 | } |
394 | | |
395 | | void |
396 | | TextureHost::UnbindTextureSource() |
397 | 0 | { |
398 | 0 | if (mReadLocked) { |
399 | 0 | // This TextureHost is not used anymore. Since most compositor backends are |
400 | 0 | // working asynchronously under the hood a compositor could still be using |
401 | 0 | // this texture, so it is generally best to wait until the end of the next |
402 | 0 | // composition before calling ReadUnlock. We ask the compositor to take care |
403 | 0 | // of that for us. |
404 | 0 | if (mProvider) { |
405 | 0 | mProvider->UnlockAfterComposition(this); |
406 | 0 | } else { |
407 | 0 | // GetCompositor returned null which means no compositor can be using this |
408 | 0 | // texture. We can ReadUnlock right away. |
409 | 0 | ReadUnlock(); |
410 | 0 | MaybeNotifyUnlocked(); |
411 | 0 | } |
412 | 0 | } |
413 | 0 | } |
414 | | |
415 | | void |
416 | | TextureHost::RecycleTexture(TextureFlags aFlags) |
417 | 0 | { |
418 | 0 | MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE); |
419 | 0 | MOZ_ASSERT(aFlags & TextureFlags::RECYCLE); |
420 | 0 | mFlags = aFlags; |
421 | 0 | } |
422 | | |
423 | | void |
424 | | TextureHost::NotifyNotUsed() |
425 | 0 | { |
426 | 0 | if (!mActor) { |
427 | 0 | return; |
428 | 0 | } |
429 | 0 | |
430 | 0 | // Do not need to call NotifyNotUsed() if TextureHost does not have |
431 | 0 | // TextureFlags::RECYCLE flag. |
432 | 0 | if (!(GetFlags() & TextureFlags::RECYCLE)) { |
433 | 0 | return; |
434 | 0 | } |
435 | 0 | |
436 | 0 | // The following cases do not need to defer NotifyNotUsed until next Composite. |
437 | 0 | // - TextureHost does not have Compositor. |
438 | 0 | // - Compositor is BasicCompositor. |
439 | 0 | // - TextureHost has intermediate buffer. |
440 | 0 | // end of buffer usage. |
441 | 0 | if (!mProvider || |
442 | 0 | HasIntermediateBuffer() || |
443 | 0 | !mProvider->NotifyNotUsedAfterComposition(this)) |
444 | 0 | { |
445 | 0 | static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId); |
446 | 0 | return; |
447 | 0 | } |
448 | 0 | } |
449 | | |
450 | | void |
451 | | TextureHost::CallNotifyNotUsed() |
452 | 0 | { |
453 | 0 | if (!mActor) { |
454 | 0 | return; |
455 | 0 | } |
456 | 0 | static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId); |
457 | 0 | } |
458 | | |
459 | | void |
460 | | TextureHost::PrintInfo(std::stringstream& aStream, const char* aPrefix) |
461 | 0 | { |
462 | 0 | aStream << aPrefix; |
463 | 0 | aStream << nsPrintfCString("%s (0x%p)", Name(), this).get(); |
464 | 0 | // Note: the TextureHost needs to be locked before it is safe to call |
465 | 0 | // GetSize() and GetFormat() on it. |
466 | 0 | if (Lock()) { |
467 | 0 | AppendToString(aStream, GetSize(), " [size=", "]"); |
468 | 0 | AppendToString(aStream, GetFormat(), " [format=", "]"); |
469 | 0 | Unlock(); |
470 | 0 | } |
471 | 0 | AppendToString(aStream, mFlags, " [flags=", "]"); |
472 | | #ifdef MOZ_DUMP_PAINTING |
473 | | if (gfxPrefs::LayersDumpTexture()) { |
474 | | nsAutoCString pfx(aPrefix); |
475 | | pfx += " "; |
476 | | |
477 | | aStream << "\n" << pfx.get() << "Surface: "; |
478 | | RefPtr<gfx::DataSourceSurface> dSurf = GetAsSurface(); |
479 | | if (dSurf) { |
480 | | aStream << gfxUtils::GetAsLZ4Base64Str(dSurf).get(); |
481 | | } |
482 | | } |
483 | | #endif |
484 | | } |
485 | | |
486 | | void |
487 | | TextureHost::Updated(const nsIntRegion* aRegion) |
488 | 0 | { |
489 | 0 | LayerScope::ContentChanged(this); |
490 | 0 | UpdatedInternal(aRegion); |
491 | 0 | } |
492 | | |
493 | | TextureSource::TextureSource() |
494 | | : mCompositableCount(0) |
495 | 0 | { |
496 | 0 | } |
497 | | |
498 | | TextureSource::~TextureSource() |
499 | 0 | { |
500 | 0 | } |
501 | | |
502 | | const char* |
503 | | TextureSource::Name() const |
504 | 0 | { |
505 | 0 | MOZ_CRASH("GFX: TextureSource without class name"); |
506 | 0 | return "TextureSource"; |
507 | 0 | } |
508 | | |
509 | | BufferTextureHost::BufferTextureHost(const BufferDescriptor& aDesc, |
510 | | TextureFlags aFlags) |
511 | | : TextureHost(aFlags) |
512 | | , mUpdateSerial(1) |
513 | | , mLocked(false) |
514 | | , mNeedsFullUpdate(false) |
515 | 0 | { |
516 | 0 | mDescriptor = aDesc; |
517 | 0 | switch (mDescriptor.type()) { |
518 | 0 | case BufferDescriptor::TYCbCrDescriptor: { |
519 | 0 | const YCbCrDescriptor& ycbcr = mDescriptor.get_YCbCrDescriptor(); |
520 | 0 | mSize = ycbcr.ySize(); |
521 | 0 | mFormat = gfx::SurfaceFormat::YUV; |
522 | 0 | mHasIntermediateBuffer = ycbcr.hasIntermediateBuffer(); |
523 | 0 | break; |
524 | 0 | } |
525 | 0 | case BufferDescriptor::TRGBDescriptor: { |
526 | 0 | const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor(); |
527 | 0 | mSize = rgb.size(); |
528 | 0 | mFormat = rgb.format(); |
529 | 0 | mHasIntermediateBuffer = rgb.hasIntermediateBuffer(); |
530 | 0 | break; |
531 | 0 | } |
532 | 0 | default: |
533 | 0 | gfxCriticalError() << "Bad buffer host descriptor " << (int)mDescriptor.type(); |
534 | 0 | MOZ_CRASH("GFX: Bad descriptor"); |
535 | 0 | } |
536 | 0 | if (aFlags & TextureFlags::COMPONENT_ALPHA) { |
537 | 0 | // One texture of a component alpha texture pair will start out all white. |
538 | 0 | // This hack allows us to easily make sure that white will be uploaded. |
539 | 0 | // See bug 1138934 |
540 | 0 | mNeedsFullUpdate = true; |
541 | 0 | } |
542 | 0 | } |
543 | | |
544 | | BufferTextureHost::~BufferTextureHost() |
545 | 0 | {} |
546 | | |
547 | | void |
548 | | BufferTextureHost::UpdatedInternal(const nsIntRegion* aRegion) |
549 | 0 | { |
550 | 0 | ++mUpdateSerial; |
551 | 0 | // If the last frame wasn't uploaded yet, and we -don't- have a partial update, |
552 | 0 | // we still need to update the full surface. |
553 | 0 | if (aRegion && !mNeedsFullUpdate) { |
554 | 0 | mMaybeUpdatedRegion.OrWith(*aRegion); |
555 | 0 | } else { |
556 | 0 | mNeedsFullUpdate = true; |
557 | 0 | } |
558 | 0 | if (GetFlags() & TextureFlags::IMMEDIATE_UPLOAD) { |
559 | 0 | DebugOnly<bool> result = MaybeUpload(!mNeedsFullUpdate ? &mMaybeUpdatedRegion : nullptr); |
560 | 0 | NS_WARNING_ASSERTION(result, "Failed to upload a texture"); |
561 | 0 | } |
562 | 0 | } |
563 | | |
564 | | void |
565 | | BufferTextureHost::SetTextureSourceProvider(TextureSourceProvider* aProvider) |
566 | 0 | { |
567 | 0 | if (mProvider == aProvider) { |
568 | 0 | return; |
569 | 0 | } |
570 | 0 | if (mFirstSource && mFirstSource->IsOwnedBy(this)) { |
571 | 0 | mFirstSource->SetOwner(nullptr); |
572 | 0 | } |
573 | 0 | if (mFirstSource) { |
574 | 0 | mFirstSource = nullptr; |
575 | 0 | mNeedsFullUpdate = true; |
576 | 0 | } |
577 | 0 | mProvider = aProvider; |
578 | 0 | } |
579 | | |
580 | | void |
581 | | BufferTextureHost::DeallocateDeviceData() |
582 | 0 | { |
583 | 0 | if (mFirstSource && mFirstSource->NumCompositableRefs() > 0) { |
584 | 0 | return; |
585 | 0 | } |
586 | 0 | |
587 | 0 | if (!mFirstSource || !mFirstSource->IsOwnedBy(this)) { |
588 | 0 | mFirstSource = nullptr; |
589 | 0 | return; |
590 | 0 | } |
591 | 0 | |
592 | 0 | mFirstSource->SetOwner(nullptr); |
593 | 0 |
|
594 | 0 | RefPtr<TextureSource> it = mFirstSource; |
595 | 0 | while (it) { |
596 | 0 | it->DeallocateDeviceData(); |
597 | 0 | it = it->GetNextSibling(); |
598 | 0 | } |
599 | 0 | } |
600 | | |
601 | | bool |
602 | | BufferTextureHost::Lock() |
603 | 0 | { |
604 | 0 | MOZ_ASSERT(!mLocked); |
605 | 0 | if (!UploadIfNeeded()) { |
606 | 0 | return false; |
607 | 0 | } |
608 | 0 | mLocked = !!mFirstSource; |
609 | 0 | return mLocked; |
610 | 0 | } |
611 | | |
612 | | void |
613 | | BufferTextureHost::Unlock() |
614 | 0 | { |
615 | 0 | MOZ_ASSERT(mLocked); |
616 | 0 | mLocked = false; |
617 | 0 | } |
618 | | |
619 | | void |
620 | | BufferTextureHost::CreateRenderTexture(const wr::ExternalImageId& aExternalImageId) |
621 | 0 | { |
622 | 0 | RefPtr<wr::RenderTextureHost> texture = |
623 | 0 | new wr::RenderBufferTextureHost(GetBuffer(), GetBufferDescriptor()); |
624 | 0 |
|
625 | 0 | wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(aExternalImageId), texture.forget()); |
626 | 0 | } |
627 | | |
628 | | uint32_t |
629 | | BufferTextureHost::NumSubTextures() const |
630 | 0 | { |
631 | 0 | if (GetFormat() == gfx::SurfaceFormat::YUV) { |
632 | 0 | return 3; |
633 | 0 | } |
634 | 0 | |
635 | 0 | return 1; |
636 | 0 | } |
637 | | |
638 | | void |
639 | | BufferTextureHost::PushResourceUpdates(wr::TransactionBuilder& aResources, |
640 | | ResourceUpdateOp aOp, |
641 | | const Range<wr::ImageKey>& aImageKeys, |
642 | | const wr::ExternalImageId& aExtID) |
643 | 0 | { |
644 | 0 | auto method = aOp == TextureHost::ADD_IMAGE ? &wr::TransactionBuilder::AddExternalImage |
645 | 0 | : &wr::TransactionBuilder::UpdateExternalImage; |
646 | 0 | auto bufferType = wr::WrExternalImageBufferType::ExternalBuffer; |
647 | 0 |
|
648 | 0 | if (GetFormat() != gfx::SurfaceFormat::YUV) { |
649 | 0 | MOZ_ASSERT(aImageKeys.length() == 1); |
650 | 0 |
|
651 | 0 | wr::ImageDescriptor descriptor(GetSize(), |
652 | 0 | ImageDataSerializer::ComputeRGBStride(GetFormat(), GetSize().width), |
653 | 0 | GetFormat()); |
654 | 0 | (aResources.*method)(aImageKeys[0], descriptor, aExtID, bufferType, 0); |
655 | 0 | } else { |
656 | 0 | MOZ_ASSERT(aImageKeys.length() == 3); |
657 | 0 |
|
658 | 0 | const layers::YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); |
659 | 0 | wr::ImageDescriptor yDescriptor(desc.ySize(), desc.yStride(), gfx::SurfaceFormat::A8); |
660 | 0 | wr::ImageDescriptor cbcrDescriptor(desc.cbCrSize(), desc.cbCrStride(), gfx::SurfaceFormat::A8); |
661 | 0 | (aResources.*method)(aImageKeys[0], yDescriptor, aExtID, bufferType, 0); |
662 | 0 | (aResources.*method)(aImageKeys[1], cbcrDescriptor, aExtID, bufferType, 1); |
663 | 0 | (aResources.*method)(aImageKeys[2], cbcrDescriptor, aExtID, bufferType, 2); |
664 | 0 | } |
665 | 0 | } |
666 | | |
667 | | void |
668 | | BufferTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder, |
669 | | const wr::LayoutRect& aBounds, |
670 | | const wr::LayoutRect& aClip, |
671 | | wr::ImageRendering aFilter, |
672 | | const Range<wr::ImageKey>& aImageKeys) |
673 | 0 | { |
674 | 0 | if (GetFormat() != gfx::SurfaceFormat::YUV) { |
675 | 0 | MOZ_ASSERT(aImageKeys.length() == 1); |
676 | 0 | aBuilder.PushImage(aBounds, aClip, true, aFilter, aImageKeys[0], !(mFlags & TextureFlags::NON_PREMULTIPLIED)); |
677 | 0 | } else { |
678 | 0 | MOZ_ASSERT(aImageKeys.length() == 3); |
679 | 0 | const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); |
680 | 0 | aBuilder.PushYCbCrPlanarImage(aBounds, |
681 | 0 | aClip, |
682 | 0 | true, |
683 | 0 | aImageKeys[0], |
684 | 0 | aImageKeys[1], |
685 | 0 | aImageKeys[2], |
686 | 0 | wr::ToWrYuvColorSpace(desc.yUVColorSpace()), |
687 | 0 | aFilter); |
688 | 0 | } |
689 | 0 | } |
690 | | |
691 | | void |
692 | | TextureHost::DeserializeReadLock(const ReadLockDescriptor& aDesc, |
693 | | ISurfaceAllocator* aAllocator) |
694 | 0 | { |
695 | 0 | if (mReadLock) { |
696 | 0 | return; |
697 | 0 | } |
698 | 0 | |
699 | 0 | mReadLock = TextureReadLock::Deserialize(aDesc, aAllocator); |
700 | 0 | } |
701 | | |
702 | | void |
703 | | TextureHost::SetReadLocked() |
704 | 0 | { |
705 | 0 | if (!mReadLock) { |
706 | 0 | return; |
707 | 0 | } |
708 | 0 | // If mReadLocked is true it means we haven't read unlocked yet and the content |
709 | 0 | // side should not have been able to write into this texture and read lock again! |
710 | 0 | MOZ_ASSERT(!mReadLocked); |
711 | 0 | mReadLocked = true; |
712 | 0 | if (mProvider) { |
713 | 0 | mProvider->MaybeUnlockBeforeNextComposition(this); |
714 | 0 | } |
715 | 0 | } |
716 | | |
717 | | void |
718 | | TextureHost::ReadUnlock() |
719 | 0 | { |
720 | 0 | if (mReadLock && mReadLocked) { |
721 | 0 | mReadLock->ReadUnlock(); |
722 | 0 | mReadLocked = false; |
723 | 0 | } |
724 | 0 | } |
725 | | |
726 | | bool |
727 | | BufferTextureHost::EnsureWrappingTextureSource() |
728 | 0 | { |
729 | 0 | MOZ_ASSERT(!mHasIntermediateBuffer); |
730 | 0 |
|
731 | 0 | if (mFirstSource && mFirstSource->IsOwnedBy(this)) { |
732 | 0 | return true; |
733 | 0 | } |
734 | 0 | // We don't own it, apparently. |
735 | 0 | if (mFirstSource) { |
736 | 0 | mNeedsFullUpdate = true; |
737 | 0 | mFirstSource = nullptr; |
738 | 0 | } |
739 | 0 |
|
740 | 0 | if (!mProvider) { |
741 | 0 | return false; |
742 | 0 | } |
743 | 0 | |
744 | 0 | if (mFormat == gfx::SurfaceFormat::YUV) { |
745 | 0 | mFirstSource = mProvider->CreateDataTextureSourceAroundYCbCr(this); |
746 | 0 | } else { |
747 | 0 | RefPtr<gfx::DataSourceSurface> surf = |
748 | 0 | gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(), |
749 | 0 | ImageDataSerializer::ComputeRGBStride(mFormat, mSize.width), mSize, mFormat); |
750 | 0 | if (!surf) { |
751 | 0 | return false; |
752 | 0 | } |
753 | 0 | mFirstSource = mProvider->CreateDataTextureSourceAround(surf); |
754 | 0 | } |
755 | 0 |
|
756 | 0 | if (!mFirstSource) { |
757 | 0 | // BasicCompositor::CreateDataTextureSourceAround never returns null |
758 | 0 | // and we don't expect to take this branch if we are using another backend. |
759 | 0 | // Returning false is fine but if we get into this situation it probably |
760 | 0 | // means something fishy is going on, like a texture being used with |
761 | 0 | // several compositor backends. |
762 | 0 | NS_WARNING("Failed to use a BufferTextureHost without intermediate buffer"); |
763 | 0 | return false; |
764 | 0 | } |
765 | 0 |
|
766 | 0 | mFirstSource->SetUpdateSerial(mUpdateSerial); |
767 | 0 | mFirstSource->SetOwner(this); |
768 | 0 |
|
769 | 0 | return true; |
770 | 0 | } |
771 | | |
772 | | static |
773 | | bool IsCompatibleTextureSource(TextureSource* aTexture, |
774 | | const BufferDescriptor& aDescriptor, |
775 | | TextureSourceProvider* aProvider) |
776 | 0 | { |
777 | 0 | if (!aProvider) { |
778 | 0 | return false; |
779 | 0 | } |
780 | 0 | |
781 | 0 | switch (aDescriptor.type()) { |
782 | 0 | case BufferDescriptor::TYCbCrDescriptor: { |
783 | 0 | const YCbCrDescriptor& ycbcr = aDescriptor.get_YCbCrDescriptor(); |
784 | 0 |
|
785 | 0 | if (!aProvider->SupportsEffect(EffectTypes::YCBCR)) { |
786 | 0 | return aTexture->GetFormat() == gfx::SurfaceFormat::B8G8R8X8 |
787 | 0 | && aTexture->GetSize() == ycbcr.ySize(); |
788 | 0 | } |
789 | 0 |
|
790 | 0 | if (aTexture->GetFormat() != gfx::SurfaceFormat::A8 |
791 | 0 | || aTexture->GetSize() != ycbcr.ySize()) { |
792 | 0 | return false; |
793 | 0 | } |
794 | 0 | |
795 | 0 | auto cbTexture = aTexture->GetSubSource(1); |
796 | 0 | if (!cbTexture |
797 | 0 | || cbTexture->GetFormat() != gfx::SurfaceFormat::A8 |
798 | 0 | || cbTexture->GetSize() != ycbcr.cbCrSize()) { |
799 | 0 | return false; |
800 | 0 | } |
801 | 0 | |
802 | 0 | auto crTexture = aTexture->GetSubSource(2); |
803 | 0 | if (!crTexture |
804 | 0 | || crTexture->GetFormat() != gfx::SurfaceFormat::A8 |
805 | 0 | || crTexture->GetSize() != ycbcr.cbCrSize()) { |
806 | 0 | return false; |
807 | 0 | } |
808 | 0 | |
809 | 0 | return true; |
810 | 0 | } |
811 | 0 | case BufferDescriptor::TRGBDescriptor: { |
812 | 0 | const RGBDescriptor& rgb = aDescriptor.get_RGBDescriptor(); |
813 | 0 | return aTexture->GetFormat() == rgb.format() |
814 | 0 | && aTexture->GetSize() == rgb.size(); |
815 | 0 | } |
816 | 0 | default: { |
817 | 0 | return false; |
818 | 0 | } |
819 | 0 | } |
820 | 0 | } |
821 | | |
822 | | void |
823 | | BufferTextureHost::PrepareTextureSource(CompositableTextureSourceRef& aTexture) |
824 | 0 | { |
825 | 0 | // Reuse WrappingTextureSourceYCbCrBasic to reduce memory consumption. |
826 | 0 | if (mFormat == gfx::SurfaceFormat::YUV && |
827 | 0 | !mHasIntermediateBuffer && |
828 | 0 | aTexture.get() && |
829 | 0 | aTexture->AsWrappingTextureSourceYCbCrBasic() && |
830 | 0 | aTexture->NumCompositableRefs() <= 1 && |
831 | 0 | aTexture->GetSize() == GetSize()) { |
832 | 0 | aTexture->AsSourceBasic()->SetBufferTextureHost(this); |
833 | 0 | aTexture->AsDataTextureSource()->SetOwner(this); |
834 | 0 | mFirstSource = aTexture->AsDataTextureSource(); |
835 | 0 | mNeedsFullUpdate = true; |
836 | 0 | } |
837 | 0 |
|
838 | 0 | if (!mHasIntermediateBuffer) { |
839 | 0 | EnsureWrappingTextureSource(); |
840 | 0 | } |
841 | 0 |
|
842 | 0 | if (mFirstSource && mFirstSource->IsOwnedBy(this)) { |
843 | 0 | // We are already attached to a TextureSource, nothing to do except tell |
844 | 0 | // the compositable to use it. |
845 | 0 | aTexture = mFirstSource.get(); |
846 | 0 | return; |
847 | 0 | } |
848 | 0 | |
849 | 0 | // We don't own it, apparently. |
850 | 0 | if (mFirstSource) { |
851 | 0 | mNeedsFullUpdate = true; |
852 | 0 | mFirstSource = nullptr; |
853 | 0 | } |
854 | 0 |
|
855 | 0 | DataTextureSource* texture = aTexture.get() ? aTexture->AsDataTextureSource() : nullptr; |
856 | 0 |
|
857 | 0 | bool compatibleFormats = texture && IsCompatibleTextureSource(texture, |
858 | 0 | mDescriptor, |
859 | 0 | mProvider); |
860 | 0 |
|
861 | 0 | bool shouldCreateTexture = !compatibleFormats |
862 | 0 | || texture->NumCompositableRefs() > 1 |
863 | 0 | || texture->HasOwner(); |
864 | 0 |
|
865 | 0 | if (!shouldCreateTexture) { |
866 | 0 | mFirstSource = texture; |
867 | 0 | mFirstSource->SetOwner(this); |
868 | 0 | mNeedsFullUpdate = true; |
869 | 0 |
|
870 | 0 | // It's possible that texture belonged to a different compositor, |
871 | 0 | // so make sure we update it (and all of its siblings) to the |
872 | 0 | // current one. |
873 | 0 | RefPtr<TextureSource> it = mFirstSource; |
874 | 0 | while (it) { |
875 | 0 | it->SetTextureSourceProvider(mProvider); |
876 | 0 | it = it->GetNextSibling(); |
877 | 0 | } |
878 | 0 | } |
879 | 0 | } |
880 | | |
881 | | bool |
882 | | BufferTextureHost::BindTextureSource(CompositableTextureSourceRef& aTexture) |
883 | 0 | { |
884 | 0 | MOZ_ASSERT(mLocked); |
885 | 0 | MOZ_ASSERT(mFirstSource); |
886 | 0 | aTexture = mFirstSource; |
887 | 0 | return !!aTexture; |
888 | 0 | } |
889 | | |
890 | | bool |
891 | | BufferTextureHost::AcquireTextureSource(CompositableTextureSourceRef& aTexture) |
892 | 0 | { |
893 | 0 | if (!UploadIfNeeded()) { |
894 | 0 | return false; |
895 | 0 | } |
896 | 0 | aTexture = mFirstSource; |
897 | 0 | return !!mFirstSource; |
898 | 0 | } |
899 | | |
900 | | void |
901 | | BufferTextureHost::ReadUnlock() |
902 | 0 | { |
903 | 0 | if (mFirstSource) { |
904 | 0 | mFirstSource->Sync(true); |
905 | 0 | } |
906 | 0 |
|
907 | 0 | TextureHost::ReadUnlock(); |
908 | 0 | } |
909 | | |
910 | | void |
911 | | BufferTextureHost::MaybeNotifyUnlocked() |
912 | 0 | { |
913 | | #ifdef XP_DARWIN |
914 | | auto actor = GetIPDLActor(); |
915 | | if (actor) { |
916 | | AutoTArray<uint64_t, 1> serials; |
917 | | serials.AppendElement(TextureHost::GetTextureSerial(actor)); |
918 | | TextureSync::SetTexturesUnlocked(actor->OtherPid(), serials); |
919 | | } |
920 | | #endif |
921 | | } |
922 | | |
923 | | void |
924 | | BufferTextureHost::UnbindTextureSource() |
925 | 0 | { |
926 | 0 | if (mFirstSource && mFirstSource->IsOwnedBy(this)) { |
927 | 0 | mFirstSource->Unbind(); |
928 | 0 | } |
929 | 0 |
|
930 | 0 | if (mFirstSource && mFirstSource->IsDirectMap() && mProvider) { |
931 | 0 | mProvider->ReferenceUntilAfterComposition(mFirstSource); |
932 | 0 | } |
933 | 0 |
|
934 | 0 | // This texture is not used by any layer anymore. |
935 | 0 | // If the texture doesn't have an intermediate buffer, it means we are |
936 | 0 | // compositing synchronously on the CPU, so we don't need to wait until |
937 | 0 | // the end of the next composition to ReadUnlock (which other textures do |
938 | 0 | // by default). |
939 | 0 | // If the texture has an intermediate buffer we don't care either because |
940 | 0 | // texture uploads are also performed synchronously for BufferTextureHost. |
941 | 0 | ReadUnlock(); |
942 | 0 | MaybeNotifyUnlocked(); |
943 | 0 | } |
944 | | |
945 | | gfx::SurfaceFormat |
946 | | BufferTextureHost::GetFormat() const |
947 | 0 | { |
948 | 0 | // mFormat is the format of the data that we share with the content process. |
949 | 0 | // GetFormat, on the other hand, expects the format that we present to the |
950 | 0 | // Compositor (it is used to choose the effect type). |
951 | 0 | // if the compositor does not support YCbCr effects, we give it a RGBX texture |
952 | 0 | // instead (see BufferTextureHost::Upload) |
953 | 0 | if (mFormat == gfx::SurfaceFormat::YUV && |
954 | 0 | mProvider && |
955 | 0 | !mProvider->SupportsEffect(EffectTypes::YCBCR)) { |
956 | 0 | return gfx::SurfaceFormat::R8G8B8X8; |
957 | 0 | } |
958 | 0 | return mFormat; |
959 | 0 | } |
960 | | |
961 | | YUVColorSpace |
962 | | BufferTextureHost::GetYUVColorSpace() const |
963 | 0 | { |
964 | 0 | if (mFormat == gfx::SurfaceFormat::YUV) { |
965 | 0 | const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); |
966 | 0 | return desc.yUVColorSpace(); |
967 | 0 | } |
968 | 0 | return YUVColorSpace::UNKNOWN; |
969 | 0 | } |
970 | | |
971 | | uint32_t |
972 | | BufferTextureHost::GetBitDepth() const |
973 | 0 | { |
974 | 0 | if (mFormat == gfx::SurfaceFormat::YUV) { |
975 | 0 | const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); |
976 | 0 | return desc.bitDepth(); |
977 | 0 | } |
978 | 0 | return 8; |
979 | 0 | } |
980 | | |
981 | | bool |
982 | | BufferTextureHost::UploadIfNeeded() |
983 | 0 | { |
984 | 0 | return MaybeUpload(!mNeedsFullUpdate ? &mMaybeUpdatedRegion : nullptr); |
985 | 0 | } |
986 | | |
987 | | bool |
988 | | BufferTextureHost::MaybeUpload(nsIntRegion *aRegion) |
989 | 0 | { |
990 | 0 | auto serial = mFirstSource ? mFirstSource->GetUpdateSerial() : 0; |
991 | 0 |
|
992 | 0 | if (serial == mUpdateSerial) { |
993 | 0 | return true; |
994 | 0 | } |
995 | 0 | |
996 | 0 | if (serial == 0) { |
997 | 0 | // 0 means the source has no valid content |
998 | 0 | aRegion = nullptr; |
999 | 0 | } |
1000 | 0 |
|
1001 | 0 | if (!Upload(aRegion)) { |
1002 | 0 | return false; |
1003 | 0 | } |
1004 | 0 | |
1005 | 0 | if (mHasIntermediateBuffer) { |
1006 | 0 | // We just did the texture upload, the content side can now freely write |
1007 | 0 | // into the shared buffer. |
1008 | 0 | ReadUnlock(); |
1009 | 0 | MaybeNotifyUnlocked(); |
1010 | 0 | } |
1011 | 0 |
|
1012 | 0 | // We no longer have an invalid region. |
1013 | 0 | mNeedsFullUpdate = false; |
1014 | 0 | mMaybeUpdatedRegion.SetEmpty(); |
1015 | 0 |
|
1016 | 0 | // If upload returns true we know mFirstSource is not null |
1017 | 0 | mFirstSource->SetUpdateSerial(mUpdateSerial); |
1018 | 0 | return true; |
1019 | 0 | } |
1020 | | |
1021 | | bool |
1022 | | BufferTextureHost::Upload(nsIntRegion *aRegion) |
1023 | 0 | { |
1024 | 0 | uint8_t* buf = GetBuffer(); |
1025 | 0 | if (!buf) { |
1026 | 0 | // We don't have a buffer; a possible cause is that the IPDL actor |
1027 | 0 | // is already dead. This inevitably happens as IPDL actors can die |
1028 | 0 | // at any time, so we want to silently return in this case. |
1029 | 0 | // another possible cause is that IPDL failed to map the shmem when |
1030 | 0 | // deserializing it. |
1031 | 0 | return false; |
1032 | 0 | } |
1033 | 0 | if (!mProvider) { |
1034 | 0 | // This can happen if we send textures to a compositable that isn't yet |
1035 | 0 | // attached to a layer. |
1036 | 0 | return false; |
1037 | 0 | } |
1038 | 0 | if (!mHasIntermediateBuffer && EnsureWrappingTextureSource()) { |
1039 | 0 | if (!mFirstSource || !mFirstSource->IsDirectMap()) { |
1040 | 0 | return true; |
1041 | 0 | } |
1042 | 0 | } |
1043 | 0 | |
1044 | 0 | if (mFormat == gfx::SurfaceFormat::UNKNOWN) { |
1045 | 0 | NS_WARNING("BufferTextureHost: unsupported format!"); |
1046 | 0 | return false; |
1047 | 0 | } else if (mFormat == gfx::SurfaceFormat::YUV) { |
1048 | 0 | const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor(); |
1049 | 0 |
|
1050 | 0 | if (!mProvider->SupportsEffect(EffectTypes::YCBCR)) { |
1051 | 0 | RefPtr<gfx::DataSourceSurface> surf = |
1052 | 0 | ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(buf, mDescriptor.get_YCbCrDescriptor()); |
1053 | 0 | if (NS_WARN_IF(!surf)) { |
1054 | 0 | return false; |
1055 | 0 | } |
1056 | 0 | if (!mFirstSource) { |
1057 | 0 | mFirstSource = mProvider->CreateDataTextureSource(mFlags|TextureFlags::RGB_FROM_YCBCR); |
1058 | 0 | mFirstSource->SetOwner(this); |
1059 | 0 | } |
1060 | 0 | return mFirstSource->Update(surf, aRegion); |
1061 | 0 | } |
1062 | 0 |
|
1063 | 0 | RefPtr<DataTextureSource> srcY; |
1064 | 0 | RefPtr<DataTextureSource> srcU; |
1065 | 0 | RefPtr<DataTextureSource> srcV; |
1066 | 0 | if (!mFirstSource) { |
1067 | 0 | // We don't support BigImages for YCbCr compositing. |
1068 | 0 | srcY = mProvider->CreateDataTextureSource(mFlags|TextureFlags::DISALLOW_BIGIMAGE); |
1069 | 0 | srcU = mProvider->CreateDataTextureSource(mFlags|TextureFlags::DISALLOW_BIGIMAGE); |
1070 | 0 | srcV = mProvider->CreateDataTextureSource(mFlags|TextureFlags::DISALLOW_BIGIMAGE); |
1071 | 0 | mFirstSource = srcY; |
1072 | 0 | mFirstSource->SetOwner(this); |
1073 | 0 | srcY->SetNextSibling(srcU); |
1074 | 0 | srcU->SetNextSibling(srcV); |
1075 | 0 | } else { |
1076 | 0 | // mFormat never changes so if this was created as a YCbCr host and already |
1077 | 0 | // contains a source it should already have 3 sources. |
1078 | 0 | // BufferTextureHost only uses DataTextureSources so it is safe to assume |
1079 | 0 | // all 3 sources are DataTextureSource. |
1080 | 0 | MOZ_ASSERT(mFirstSource->GetNextSibling()); |
1081 | 0 | MOZ_ASSERT(mFirstSource->GetNextSibling()->GetNextSibling()); |
1082 | 0 | srcY = mFirstSource; |
1083 | 0 | srcU = mFirstSource->GetNextSibling()->AsDataTextureSource(); |
1084 | 0 | srcV = mFirstSource->GetNextSibling()->GetNextSibling()->AsDataTextureSource(); |
1085 | 0 | } |
1086 | 0 |
|
1087 | 0 | RefPtr<gfx::DataSourceSurface> tempY = |
1088 | 0 | gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetYChannel(buf, desc), |
1089 | 0 | desc.yStride(), |
1090 | 0 | desc.ySize(), |
1091 | 0 | SurfaceFormatForAlphaBitDepth(desc.bitDepth())); |
1092 | 0 | RefPtr<gfx::DataSourceSurface> tempCb = |
1093 | 0 | gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetCbChannel(buf, desc), |
1094 | 0 | desc.cbCrStride(), |
1095 | 0 | desc.cbCrSize(), |
1096 | 0 | SurfaceFormatForAlphaBitDepth(desc.bitDepth())); |
1097 | 0 | RefPtr<gfx::DataSourceSurface> tempCr = |
1098 | 0 | gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetCrChannel(buf, desc), |
1099 | 0 | desc.cbCrStride(), |
1100 | 0 | desc.cbCrSize(), |
1101 | 0 | SurfaceFormatForAlphaBitDepth(desc.bitDepth())); |
1102 | 0 | // We don't support partial updates for Y U V textures |
1103 | 0 | NS_ASSERTION(!aRegion, "Unsupported partial updates for YCbCr textures"); |
1104 | 0 | if (!tempY || |
1105 | 0 | !tempCb || |
1106 | 0 | !tempCr || |
1107 | 0 | !srcY->Update(tempY) || |
1108 | 0 | !srcU->Update(tempCb) || |
1109 | 0 | !srcV->Update(tempCr)) { |
1110 | 0 | NS_WARNING("failed to update the DataTextureSource"); |
1111 | 0 | return false; |
1112 | 0 | } |
1113 | 0 | } else { |
1114 | 0 | // non-YCbCr case |
1115 | 0 | nsIntRegion* regionToUpdate = aRegion; |
1116 | 0 | if (!mFirstSource) { |
1117 | 0 | mFirstSource = mProvider->CreateDataTextureSource(mFlags); |
1118 | 0 | mFirstSource->SetOwner(this); |
1119 | 0 | if (mFlags & TextureFlags::COMPONENT_ALPHA) { |
1120 | 0 | // Update the full region the first time for component alpha textures. |
1121 | 0 | regionToUpdate = nullptr; |
1122 | 0 | } |
1123 | 0 | } |
1124 | 0 |
|
1125 | 0 | RefPtr<gfx::DataSourceSurface> surf = |
1126 | 0 | gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(), |
1127 | 0 | ImageDataSerializer::ComputeRGBStride(mFormat, mSize.width), mSize, mFormat); |
1128 | 0 | if (!surf) { |
1129 | 0 | return false; |
1130 | 0 | } |
1131 | 0 | |
1132 | 0 | if (!mFirstSource->Update(surf.get(), regionToUpdate)) { |
1133 | 0 | NS_WARNING("failed to update the DataTextureSource"); |
1134 | 0 | return false; |
1135 | 0 | } |
1136 | 0 | } |
1137 | 0 | MOZ_ASSERT(mFirstSource); |
1138 | 0 | return true; |
1139 | 0 | } |
1140 | | |
1141 | | already_AddRefed<gfx::DataSourceSurface> |
1142 | | BufferTextureHost::GetAsSurface() |
1143 | 0 | { |
1144 | 0 | RefPtr<gfx::DataSourceSurface> result; |
1145 | 0 | if (mFormat == gfx::SurfaceFormat::UNKNOWN) { |
1146 | 0 | NS_WARNING("BufferTextureHost: unsupported format!"); |
1147 | 0 | return nullptr; |
1148 | 0 | } else if (mFormat == gfx::SurfaceFormat::YUV) { |
1149 | 0 | result = ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor( |
1150 | 0 | GetBuffer(), mDescriptor.get_YCbCrDescriptor()); |
1151 | 0 | if (NS_WARN_IF(!result)) { |
1152 | 0 | return nullptr; |
1153 | 0 | } |
1154 | 0 | } else { |
1155 | 0 | result = |
1156 | 0 | gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(), |
1157 | 0 | ImageDataSerializer::GetRGBStride(mDescriptor.get_RGBDescriptor()), |
1158 | 0 | mSize, mFormat); |
1159 | 0 | } |
1160 | 0 | return result.forget(); |
1161 | 0 | } |
1162 | | |
1163 | | ShmemTextureHost::ShmemTextureHost(const ipc::Shmem& aShmem, |
1164 | | const BufferDescriptor& aDesc, |
1165 | | ISurfaceAllocator* aDeallocator, |
1166 | | TextureFlags aFlags) |
1167 | | : BufferTextureHost(aDesc, aFlags) |
1168 | | , mDeallocator(aDeallocator) |
1169 | 0 | { |
1170 | 0 | if (aShmem.IsReadable()) { |
1171 | 0 | mShmem = MakeUnique<ipc::Shmem>(aShmem); |
1172 | 0 | } else { |
1173 | 0 | // This can happen if we failed to map the shmem on this process, perhaps |
1174 | 0 | // because it was big and we didn't have enough contiguous address space |
1175 | 0 | // available, even though we did on the child process. |
1176 | 0 | // As a result this texture will be in an invalid state and Lock will |
1177 | 0 | // always fail. |
1178 | 0 |
|
1179 | 0 | gfxCriticalNote << "Failed to create a valid ShmemTextureHost"; |
1180 | 0 | } |
1181 | 0 |
|
1182 | 0 | MOZ_COUNT_CTOR(ShmemTextureHost); |
1183 | 0 | } |
1184 | | |
1185 | | ShmemTextureHost::~ShmemTextureHost() |
1186 | 0 | { |
1187 | 0 | MOZ_ASSERT(!mShmem || (mFlags & TextureFlags::DEALLOCATE_CLIENT), |
1188 | 0 | "Leaking our buffer"); |
1189 | 0 | DeallocateDeviceData(); |
1190 | 0 | MOZ_COUNT_DTOR(ShmemTextureHost); |
1191 | 0 | } |
1192 | | |
1193 | | void |
1194 | | ShmemTextureHost::DeallocateSharedData() |
1195 | 0 | { |
1196 | 0 | if (mShmem) { |
1197 | 0 | MOZ_ASSERT(mDeallocator, |
1198 | 0 | "Shared memory would leak without a ISurfaceAllocator"); |
1199 | 0 | mDeallocator->AsShmemAllocator()->DeallocShmem(*mShmem); |
1200 | 0 | mShmem = nullptr; |
1201 | 0 | } |
1202 | 0 | } |
1203 | | |
1204 | | void |
1205 | | ShmemTextureHost::ForgetSharedData() |
1206 | 0 | { |
1207 | 0 | if (mShmem) { |
1208 | 0 | mShmem = nullptr; |
1209 | 0 | } |
1210 | 0 | } |
1211 | | |
1212 | | void |
1213 | | ShmemTextureHost::OnShutdown() |
1214 | 0 | { |
1215 | 0 | mShmem = nullptr; |
1216 | 0 | } |
1217 | | |
1218 | | uint8_t* ShmemTextureHost::GetBuffer() |
1219 | 0 | { |
1220 | 0 | return mShmem ? mShmem->get<uint8_t>() : nullptr; |
1221 | 0 | } |
1222 | | |
1223 | | size_t ShmemTextureHost::GetBufferSize() |
1224 | 0 | { |
1225 | 0 | return mShmem ? mShmem->Size<uint8_t>() : 0; |
1226 | 0 | } |
1227 | | |
1228 | | MemoryTextureHost::MemoryTextureHost(uint8_t* aBuffer, |
1229 | | const BufferDescriptor& aDesc, |
1230 | | TextureFlags aFlags) |
1231 | | : BufferTextureHost(aDesc, aFlags) |
1232 | | , mBuffer(aBuffer) |
1233 | 0 | { |
1234 | 0 | MOZ_COUNT_CTOR(MemoryTextureHost); |
1235 | 0 | } |
1236 | | |
1237 | | MemoryTextureHost::~MemoryTextureHost() |
1238 | 0 | { |
1239 | 0 | MOZ_ASSERT(!mBuffer || (mFlags & TextureFlags::DEALLOCATE_CLIENT), |
1240 | 0 | "Leaking our buffer"); |
1241 | 0 | DeallocateDeviceData(); |
1242 | 0 | MOZ_COUNT_DTOR(MemoryTextureHost); |
1243 | 0 | } |
1244 | | |
1245 | | void |
1246 | | MemoryTextureHost::DeallocateSharedData() |
1247 | 0 | { |
1248 | 0 | if (mBuffer) { |
1249 | 0 | GfxMemoryImageReporter::WillFree(mBuffer); |
1250 | 0 | } |
1251 | 0 | delete[] mBuffer; |
1252 | 0 | mBuffer = nullptr; |
1253 | 0 | } |
1254 | | |
1255 | | void |
1256 | | MemoryTextureHost::ForgetSharedData() |
1257 | 0 | { |
1258 | 0 | mBuffer = nullptr; |
1259 | 0 | } |
1260 | | |
1261 | | uint8_t* MemoryTextureHost::GetBuffer() |
1262 | 0 | { |
1263 | 0 | return mBuffer; |
1264 | 0 | } |
1265 | | |
1266 | | size_t MemoryTextureHost::GetBufferSize() |
1267 | 0 | { |
1268 | 0 | // MemoryTextureHost just trusts that the buffer size is large enough to read |
1269 | 0 | // anything we need to. That's because MemoryTextureHost has to trust the buffer |
1270 | 0 | // pointer anyway, so the security model here is just that MemoryTexture's |
1271 | 0 | // are restricted to same-process clients. |
1272 | 0 | return std::numeric_limits<size_t>::max(); |
1273 | 0 | } |
1274 | | |
1275 | | TextureParent::TextureParent(HostIPCAllocator* aSurfaceAllocator, uint64_t aSerial, const wr::MaybeExternalImageId& aExternalImageId) |
1276 | | : mSurfaceAllocator(aSurfaceAllocator) |
1277 | | , mSerial(aSerial) |
1278 | | , mExternalImageId(aExternalImageId) |
1279 | 0 | { |
1280 | 0 | MOZ_COUNT_CTOR(TextureParent); |
1281 | 0 | } |
1282 | | |
1283 | | TextureParent::~TextureParent() |
1284 | 0 | { |
1285 | 0 | MOZ_COUNT_DTOR(TextureParent); |
1286 | 0 | } |
1287 | | |
1288 | | void |
1289 | | TextureParent::NotifyNotUsed(uint64_t aTransactionId) |
1290 | 0 | { |
1291 | 0 | if (!mTextureHost) { |
1292 | 0 | return; |
1293 | 0 | } |
1294 | 0 | mSurfaceAllocator->NotifyNotUsed(this, aTransactionId); |
1295 | 0 | } |
1296 | | |
1297 | | bool |
1298 | | TextureParent::Init(const SurfaceDescriptor& aSharedData, |
1299 | | const ReadLockDescriptor& aReadLock, |
1300 | | const LayersBackend& aBackend, |
1301 | | const TextureFlags& aFlags) |
1302 | 0 | { |
1303 | 0 | mTextureHost = TextureHost::Create(aSharedData, |
1304 | 0 | aReadLock, |
1305 | 0 | mSurfaceAllocator, |
1306 | 0 | aBackend, |
1307 | 0 | aFlags, |
1308 | 0 | mExternalImageId); |
1309 | 0 | if (mTextureHost) { |
1310 | 0 | mTextureHost->mActor = this; |
1311 | 0 | } |
1312 | 0 |
|
1313 | 0 | return !!mTextureHost; |
1314 | 0 | } |
1315 | | |
1316 | | void |
1317 | | TextureParent::Destroy() |
1318 | 0 | { |
1319 | 0 | if (!mTextureHost) { |
1320 | 0 | return; |
1321 | 0 | } |
1322 | 0 | |
1323 | 0 | if (mTextureHost->mReadLocked) { |
1324 | 0 | // ReadUnlock here to make sure the ReadLock's shmem does not outlive the |
1325 | 0 | // protocol that created it. |
1326 | 0 | mTextureHost->ReadUnlock(); |
1327 | 0 | mTextureHost->MaybeNotifyUnlocked(); |
1328 | 0 | } |
1329 | 0 |
|
1330 | 0 | if (mTextureHost->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) { |
1331 | 0 | mTextureHost->ForgetSharedData(); |
1332 | 0 | } |
1333 | 0 |
|
1334 | 0 | mTextureHost->mActor = nullptr; |
1335 | 0 | mTextureHost = nullptr; |
1336 | 0 | } |
1337 | | |
1338 | | void |
1339 | | TextureHost::ReceivedDestroy(PTextureParent* aActor) |
1340 | 0 | { |
1341 | 0 | static_cast<TextureParent*>(aActor)->RecvDestroy(); |
1342 | 0 | } |
1343 | | |
1344 | | mozilla::ipc::IPCResult |
1345 | | TextureParent::RecvRecycleTexture(const TextureFlags& aTextureFlags) |
1346 | 0 | { |
1347 | 0 | if (!mTextureHost) { |
1348 | 0 | return IPC_OK(); |
1349 | 0 | } |
1350 | 0 | mTextureHost->RecycleTexture(aTextureFlags); |
1351 | 0 | return IPC_OK(); |
1352 | 0 | } |
1353 | | |
1354 | | //////////////////////////////////////////////////////////////////////////////// |
1355 | | |
1356 | | } // namespace layers |
1357 | | } // namespace mozilla |