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