Coverage Report

Created: 2018-09-25 14:53

/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