gfx/layers/client/TextureClient.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/layers/TextureClient.h"
     7 #include <stdint.h>                     // for uint8_t, uint32_t, etc
     8 #include "Layers.h"                     // for Layer, etc
     9 #include "gfx2DGlue.h"
    10 #include "gfxContext.h"                 // for gfxContext, etc
    11 #include "gfxPlatform.h"                // for gfxPlatform
    12 #include "gfxPoint.h"                   // for gfxIntSize, gfxSize
    13 #include "gfxReusableSurfaceWrapper.h"  // for gfxReusableSurfaceWrapper
    14 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
    15 #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
    16 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient
    17 #include "mozilla/layers/CompositableForwarder.h"
    18 #include "mozilla/layers/ISurfaceAllocator.h"
    19 #include "mozilla/layers/ImageDataSerializer.h"
    20 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder
    21 #include "mozilla/layers/SharedPlanarYCbCrImage.h"
    22 #include "mozilla/layers/YCbCrImageDataSerializer.h"
    23 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
    24 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
    25 #include "ImageContainer.h"             // for PlanarYCbCrImage, etc
    26 #include "mozilla/gfx/2D.h"
    27 #include "mozilla/layers/TextureClientOGL.h"
    29 #ifdef XP_WIN
    30 #include "mozilla/layers/TextureD3D9.h"
    31 #include "mozilla/layers/TextureD3D11.h"
    32 #include "gfxWindowsPlatform.h"
    33 #include "gfx2DGlue.h"
    34 #endif
    35 #ifdef MOZ_X11
    36 #include "mozilla/layers/TextureClientX11.h"
    37 #ifdef GL_PROVIDER_GLX
    38 #include "GLXLibrary.h"
    39 #endif
    40 #endif
    42 #ifdef MOZ_WIDGET_GONK
    43 #include <cutils/properties.h>
    44 #include "mozilla/layers/GrallocTextureClient.h"
    45 #endif
    47 #ifdef MOZ_ANDROID_OMTC
    48 #  include "gfxReusableImageSurfaceWrapper.h"
    49 #else
    50 #  include "gfxReusableSharedImageSurfaceWrapper.h"
    51 #  include "gfxSharedImageSurface.h"
    52 #endif
    54 #if 0
    55 #define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__)
    56 #else
    57 #define RECYCLE_LOG(...) do { } while (0)
    58 #endif
    60 using namespace mozilla::gl;
    61 using namespace mozilla::gfx;
    63 namespace mozilla {
    64 namespace layers {
    66 /**
    67  * TextureChild is the content-side incarnation of the PTexture IPDL actor.
    68  *
    69  * TextureChild is used to synchronize a texture client and its corresponding
    70  * TextureHost if needed (a TextureClient that is not shared with the compositor
    71  * does not have a TextureChild)
    72  *
    73  * During the deallocation phase, a TextureChild may hold its recently destroyed
    74  * TextureClient's data until the compositor side confirmed that it is safe to
    75  * deallocte or recycle the it.
    76  */
    77 class TextureChild MOZ_FINAL : public PTextureChild
    78 {
    79 public:
    80   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureChild)
    82   TextureChild()
    83   : mForwarder(nullptr)
    84   , mTextureData(nullptr)
    85   , mTextureClient(nullptr)
    86   , mIPCOpen(false)
    87   {
    88   }
    90   bool Recv__delete__() MOZ_OVERRIDE;
    92   bool RecvCompositorRecycle(const MaybeFenceHandle& aFence)
    93   {
    94     RECYCLE_LOG("Receive recycle %p (%p)\n", mTextureClient, mWaitForRecycle.get());
    95     if (aFence.type() != aFence.Tnull_t) {
    96       FenceHandle fence = aFence.get_FenceHandle();
    97       if (fence.IsValid() && mTextureClient) {
    98         mTextureClient->SetReleaseFenceHandle(aFence);
    99         // HWC might not provide Fence.
   100         // In this case, HWC implicitly handles buffer's fence.
   101       }
   102     }
   103     mWaitForRecycle = nullptr;
   104     return true;
   105   }
   107   void WaitForCompositorRecycle()
   108   {
   109     mWaitForRecycle = mTextureClient;
   110     RECYCLE_LOG("Wait for recycle %p\n", mWaitForRecycle.get());
   111     SendClientRecycle();
   112   }
   114   /**
   115    * Only used during the deallocation phase iff we need synchronization between
   116    * the client and host side for deallocation (that is, when the data is going
   117    * to be deallocated or recycled on the client side).
   118    */
   119   void SetTextureData(TextureClientData* aData)
   120   {
   121     mTextureData = aData;
   122   }
   124   void DeleteTextureData();
   126   CompositableForwarder* GetForwarder() { return mForwarder; }
   128   ISurfaceAllocator* GetAllocator() { return mForwarder; }
   130   void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
   132   bool IPCOpen() const { return mIPCOpen; }
   134 private:
   136   // AddIPDLReference and ReleaseIPDLReference are only to be called by CreateIPDLActor
   137   // and DestroyIPDLActor, respectively. We intentionally make them private to prevent misuse.
   138   // The purpose of these methods is to be aware of when the IPC system around this
   139   // actor goes down: mIPCOpen is then set to false.
   140   void AddIPDLReference() {
   141     MOZ_ASSERT(mIPCOpen == false);
   142     mIPCOpen = true;
   143     AddRef();
   144   }
   145   void ReleaseIPDLReference() {
   146     MOZ_ASSERT(mIPCOpen == true);
   147     mIPCOpen = false;
   148     Release();
   149   }
   151   RefPtr<CompositableForwarder> mForwarder;
   152   RefPtr<TextureClient> mWaitForRecycle;
   153   TextureClientData* mTextureData;
   154   TextureClient* mTextureClient;
   155   bool mIPCOpen;
   157   friend class TextureClient;
   158 };
   160 void
   161 TextureChild::DeleteTextureData()
   162 {
   163   mWaitForRecycle = nullptr;
   164   if (mTextureData) {
   165     mTextureData->DeallocateSharedData(GetAllocator());
   166     delete mTextureData;
   167     mTextureData = nullptr;
   168   }
   169 }
   171 bool
   172 TextureChild::Recv__delete__()
   173 {
   174   DeleteTextureData();
   175   return true;
   176 }
   178 void
   179 TextureChild::ActorDestroy(ActorDestroyReason why)
   180 {
   181   if (mTextureClient) {
   182     mTextureClient->mActor = nullptr;
   183   }
   184   mWaitForRecycle = nullptr;
   185 }
   187 // static
   188 PTextureChild*
   189 TextureClient::CreateIPDLActor()
   190 {
   191   TextureChild* c = new TextureChild();
   192   c->AddIPDLReference();
   193   return c;
   194 }
   196 // static
   197 bool
   198 TextureClient::DestroyIPDLActor(PTextureChild* actor)
   199 {
   200   static_cast<TextureChild*>(actor)->ReleaseIPDLReference();
   201   return true;
   202 }
   204 // static
   205 TextureClient*
   206 TextureClient::AsTextureClient(PTextureChild* actor)
   207 {
   208   return actor ? static_cast<TextureChild*>(actor)->mTextureClient : nullptr;
   209 }
   211 void
   212 TextureClient::WaitForCompositorRecycle()
   213 {
   214   mActor->WaitForCompositorRecycle();
   215 }
   217 bool
   218 TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
   219 {
   220   MOZ_ASSERT(aForwarder);
   221   if (mActor && mActor->GetForwarder() == aForwarder) {
   222     return true;
   223   }
   224   MOZ_ASSERT(!mActor, "Cannot use a texture on several IPC channels.");
   226   SurfaceDescriptor desc;
   227   if (!ToSurfaceDescriptor(desc)) {
   228     return false;
   229   }
   231   mActor = static_cast<TextureChild*>(aForwarder->CreateTexture(desc, GetFlags()));
   232   MOZ_ASSERT(mActor);
   233   mActor->mForwarder = aForwarder;
   234   mActor->mTextureClient = this;
   235   mShared = true;
   236   return mActor->IPCOpen();
   237 }
   239 PTextureChild*
   240 TextureClient::GetIPDLActor()
   241 {
   242   return mActor;
   243 }
   245 #ifdef MOZ_WIDGET_GONK
   246 static bool
   247 DisableGralloc(SurfaceFormat aFormat, const gfx::IntSize& aSizeHint)
   248 {
   249   if (aFormat == gfx::SurfaceFormat::A8) {
   250     return true;
   251   }
   253 #if ANDROID_VERSION <= 15
   254   // Adreno 200 has a problem of drawing gralloc buffer width less than 64 and
   255   // drawing gralloc buffer with a height 9px-16px.
   256   // See Bug 983971.
   257   if (aSizeHint.width < 64 || aSizeHint.height < 32) {
   258     return true;
   259   }
   260 #endif
   262   return false;
   263 }
   264 #endif
   266 // static
   267 TemporaryRef<TextureClient>
   268 TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
   269                                              SurfaceFormat aFormat,
   270                                              TextureFlags aTextureFlags,
   271                                              gfx::BackendType aMoz2DBackend,
   272                                              const gfx::IntSize& aSizeHint)
   273 {
   274   if (aMoz2DBackend == gfx::BackendType::NONE) {
   275     aMoz2DBackend = gfxPlatform::GetPlatform()->GetContentBackend();
   276   }
   278   RefPtr<TextureClient> result;
   280 #if defined(MOZ_WIDGET_GONK) || defined(XP_WIN)
   281   int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
   282 #endif
   284 #ifdef XP_WIN
   285   LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
   286   if (parentBackend == LayersBackend::LAYERS_D3D11 &&
   287       (aMoz2DBackend == gfx::BackendType::DIRECT2D ||
   288         aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) &&
   289       gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
   290       aSizeHint.width <= maxTextureSize &&
   291       aSizeHint.height <= maxTextureSize &&
   292       !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
   293     result = new TextureClientD3D11(aFormat, aTextureFlags);
   294   }
   295   if (parentBackend == LayersBackend::LAYERS_D3D9 &&
   296       aMoz2DBackend == gfx::BackendType::CAIRO &&
   297       aAllocator->IsSameProcess() &&
   298       aSizeHint.width <= maxTextureSize &&
   299       aSizeHint.height <= maxTextureSize &&
   300       !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
   301     if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
   302       result = new DIBTextureClientD3D9(aFormat, aTextureFlags);
   303     } else {
   304       result = new CairoTextureClientD3D9(aFormat, aTextureFlags);
   305     }
   306   }
   307 #endif
   309 #ifdef MOZ_X11
   310   LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
   311   gfxSurfaceType type =
   312     gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();
   314   if (parentBackend == LayersBackend::LAYERS_BASIC &&
   315       aMoz2DBackend == gfx::BackendType::CAIRO &&
   316       type == gfxSurfaceType::Xlib &&
   317       !(aTextureFlags & TEXTURE_ALLOC_FALLBACK))
   318   {
   319     result = new TextureClientX11(aFormat, aTextureFlags);
   320   }
   321 #ifdef GL_PROVIDER_GLX
   322   if (parentBackend == LayersBackend::LAYERS_OPENGL &&
   323       type == gfxSurfaceType::Xlib &&
   324       !(aTextureFlags & TEXTURE_ALLOC_FALLBACK) &&
   325       aFormat != SurfaceFormat::A8 &&
   326       gl::sGLXLibrary.UseTextureFromPixmap())
   327   {
   328     result = new TextureClientX11(aFormat, aTextureFlags);
   329   }
   330 #endif
   331 #endif
   333 #ifdef MOZ_WIDGET_GONK
   334   if (!DisableGralloc(aFormat, aSizeHint)) {
   335     // Don't allow Gralloc texture clients to exceed the maximum texture size.
   336     // BufferTextureClients have code to handle tiling the surface client-side.
   337     if (aSizeHint.width <= maxTextureSize && aSizeHint.height <= maxTextureSize) {
   338       result = new GrallocTextureClientOGL(aAllocator, aFormat, aMoz2DBackend,
   339                                            aTextureFlags);
   340     }
   341   }
   342 #endif
   344   // Can't do any better than a buffer texture client.
   345   if (!result) {
   346     result = CreateBufferTextureClient(aAllocator, aFormat, aTextureFlags, aMoz2DBackend);
   347   }
   349   MOZ_ASSERT(!result || result->CanExposeDrawTarget(), "texture cannot expose a DrawTarget?");
   350   return result;
   351 }
   353 // static
   354 TemporaryRef<BufferTextureClient>
   355 TextureClient::CreateBufferTextureClient(ISurfaceAllocator* aAllocator,
   356                                          SurfaceFormat aFormat,
   357                                          TextureFlags aTextureFlags,
   358                                          gfx::BackendType aMoz2DBackend)
   359 {
   360   if (gfxPlatform::GetPlatform()->PreferMemoryOverShmem()) {
   361     RefPtr<BufferTextureClient> result = new MemoryTextureClient(aAllocator, aFormat,
   362                                                                  aMoz2DBackend,
   363                                                                  aTextureFlags);
   364     return result.forget();
   365   }
   366   RefPtr<BufferTextureClient> result = new ShmemTextureClient(aAllocator, aFormat,
   367                                                               aMoz2DBackend,
   368                                                               aTextureFlags);
   369   return result.forget();
   370 }
   373 class ShmemTextureClientData : public TextureClientData
   374 {
   375 public:
   376   ShmemTextureClientData(ipc::Shmem& aShmem)
   377   : mShmem(aShmem)
   378   {
   379     MOZ_COUNT_CTOR(ShmemTextureClientData);
   380   }
   382   ~ShmemTextureClientData()
   383   {
   384     MOZ_COUNT_CTOR(ShmemTextureClientData);
   385   }
   387   virtual void DeallocateSharedData(ISurfaceAllocator* allocator)
   388   {
   389     allocator->DeallocShmem(mShmem);
   390     mShmem = ipc::Shmem();
   391   }
   393 private:
   394   ipc::Shmem mShmem;
   395 };
   397 class MemoryTextureClientData : public TextureClientData
   398 {
   399 public:
   400   MemoryTextureClientData(uint8_t* aBuffer)
   401   : mBuffer(aBuffer)
   402   {
   403     MOZ_COUNT_CTOR(MemoryTextureClientData);
   404   }
   406   ~MemoryTextureClientData()
   407   {
   408     MOZ_ASSERT(!mBuffer, "Forgot to deallocate the shared texture data?");
   409     MOZ_COUNT_DTOR(MemoryTextureClientData);
   410   }
   412   virtual void DeallocateSharedData(ISurfaceAllocator*)
   413   {
   414     delete[] mBuffer;
   415     mBuffer = nullptr;
   416   }
   418 private:
   419   uint8_t* mBuffer;
   420 };
   422 TextureClientData*
   423 MemoryTextureClient::DropTextureData()
   424 {
   425   if (!mBuffer) {
   426     return nullptr;
   427   }
   428   TextureClientData* result = new MemoryTextureClientData(mBuffer);
   429   MarkInvalid();
   430   mBuffer = nullptr;
   431   return result;
   432 }
   434 TextureClientData*
   435 ShmemTextureClient::DropTextureData()
   436 {
   437   if (!mShmem.IsReadable()) {
   438     return nullptr;
   439   }
   440   TextureClientData* result = new ShmemTextureClientData(mShmem);
   441   MarkInvalid();
   442   mShmem = ipc::Shmem();
   443   return result;
   444 }
   446 TextureClient::TextureClient(TextureFlags aFlags)
   447   : mFlags(aFlags)
   448   , mShared(false)
   449   , mValid(true)
   450 {}
   452 TextureClient::~TextureClient()
   453 {
   454   // All the destruction code that may lead to virtual method calls must
   455   // be in Finalize() which is called just before the destructor.
   456 }
   458 void TextureClient::ForceRemove()
   459 {
   460   if (mValid && mActor) {
   461     if (GetFlags() & TEXTURE_DEALLOCATE_CLIENT) {
   462       mActor->SetTextureData(DropTextureData());
   463       if (mActor->IPCOpen()) {
   464         mActor->SendRemoveTextureSync();
   465       }
   466       mActor->DeleteTextureData();
   467     } else {
   468       if (mActor->IPCOpen()) {
   469         mActor->SendRemoveTexture();
   470       }
   471     }
   472   }
   473   MarkInvalid();
   474 }
   476 bool TextureClient::CopyToTextureClient(TextureClient* aTarget,
   477                                         const gfx::IntRect* aRect,
   478                                         const gfx::IntPoint* aPoint)
   479 {
   480   MOZ_ASSERT(IsLocked());
   481   MOZ_ASSERT(aTarget->IsLocked());
   483   if (!aTarget->CanExposeDrawTarget() || !CanExposeDrawTarget()) {
   484     return false;
   485   }
   487   RefPtr<DrawTarget> destinationTarget = aTarget->GetAsDrawTarget();
   488   RefPtr<DrawTarget> sourceTarget = GetAsDrawTarget();
   489   RefPtr<gfx::SourceSurface> source = sourceTarget->Snapshot();
   490   destinationTarget->CopySurface(source,
   491                                  aRect ? *aRect : gfx::IntRect(gfx::IntPoint(0, 0), GetSize()),
   492                                  aPoint ? *aPoint : gfx::IntPoint(0, 0));
   493   destinationTarget = nullptr;
   494   source = nullptr;
   495   sourceTarget = nullptr;
   497   return true;
   498 }
   500 void
   501 TextureClient::Finalize()
   502 {
   503   MOZ_ASSERT(!IsLocked());
   504   // Always make a temporary strong reference to the actor before we use it,
   505   // in case TextureChild::ActorDestroy might null mActor concurrently.
   506   RefPtr<TextureChild> actor = mActor;
   508   if (actor) {
   509     // The actor has a raw pointer to us, actor->mTextureClient. 
   510     // Null it before RemoveTexture calls to avoid invalid actor->mTextureClient
   511     // when calling TextureChild::ActorDestroy()
   512     actor->mTextureClient = nullptr;
   513     // this will call ForceRemove in the right thread, using a sync proxy if needed
   514     if (actor->GetForwarder()) {
   515       actor->GetForwarder()->RemoveTexture(this);
   516     }
   517   }
   518 }
   520 bool
   521 TextureClient::ShouldDeallocateInDestructor() const
   522 {
   523   if (!IsAllocated()) {
   524     return false;
   525   }
   527   // If we're meant to be deallocated by the host,
   528   // but we haven't been shared yet, then we should
   529   // deallocate on the client instead.
   530   return !IsSharedWithCompositor();
   531 }
   533 bool
   534 ShmemTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor)
   535 {
   536   MOZ_ASSERT(IsValid());
   537   if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
   538     return false;
   539   }
   541   aDescriptor = SurfaceDescriptorShmem(mShmem, GetFormat());
   543   return true;
   544 }
   546 bool
   547 ShmemTextureClient::Allocate(uint32_t aSize)
   548 {
   549   MOZ_ASSERT(mValid);
   550   ipc::SharedMemory::SharedMemoryType memType = OptimalShmemType();
   551   mAllocated = GetAllocator()->AllocUnsafeShmem(aSize, memType, &mShmem);
   552   return mAllocated;
   553 }
   555 uint8_t*
   556 ShmemTextureClient::GetBuffer() const
   557 {
   558   MOZ_ASSERT(IsValid());
   559   if (mAllocated) {
   560     return mShmem.get<uint8_t>();
   561   }
   562   return nullptr;
   563 }
   565 size_t
   566 ShmemTextureClient::GetBufferSize() const
   567 {
   568   MOZ_ASSERT(IsValid());
   569   return mShmem.Size<uint8_t>();
   570 }
   572 ShmemTextureClient::ShmemTextureClient(ISurfaceAllocator* aAllocator,
   573                                        gfx::SurfaceFormat aFormat,
   574                                        gfx::BackendType aMoz2DBackend,
   575                                        TextureFlags aFlags)
   576   : BufferTextureClient(aAllocator, aFormat, aMoz2DBackend, aFlags)
   577   , mAllocated(false)
   578 {
   579   MOZ_COUNT_CTOR(ShmemTextureClient);
   580 }
   582 ShmemTextureClient::~ShmemTextureClient()
   583 {
   584   MOZ_COUNT_DTOR(ShmemTextureClient);
   585   if (ShouldDeallocateInDestructor()) {
   586     // if the buffer has never been shared we must deallocate it or ir would
   587     // leak.
   588     GetAllocator()->DeallocShmem(mShmem);
   589   }
   590 }
   592 bool
   593 MemoryTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor)
   594 {
   595   MOZ_ASSERT(IsValid());
   596   if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
   597     return false;
   598   }
   599   aDescriptor = SurfaceDescriptorMemory(reinterpret_cast<uintptr_t>(mBuffer),
   600                                         GetFormat());
   601   return true;
   602 }
   604 bool
   605 MemoryTextureClient::Allocate(uint32_t aSize)
   606 {
   607   MOZ_ASSERT(!mBuffer);
   608   static const fallible_t fallible = fallible_t();
   609   mBuffer = new(fallible) uint8_t[aSize];
   610   if (!mBuffer) {
   611     NS_WARNING("Failed to allocate buffer");
   612     return false;
   613   }
   614   GfxMemoryImageReporter::DidAlloc(mBuffer);
   615   mBufSize = aSize;
   616   return true;
   617 }
   619 MemoryTextureClient::MemoryTextureClient(ISurfaceAllocator* aAllocator,
   620                                          gfx::SurfaceFormat aFormat,
   621                                          gfx::BackendType aMoz2DBackend,
   622                                          TextureFlags aFlags)
   623   : BufferTextureClient(aAllocator, aFormat, aMoz2DBackend, aFlags)
   624   , mBuffer(nullptr)
   625   , mBufSize(0)
   626 {
   627   MOZ_COUNT_CTOR(MemoryTextureClient);
   628 }
   630 MemoryTextureClient::~MemoryTextureClient()
   631 {
   632   MOZ_COUNT_DTOR(MemoryTextureClient);
   633   if (mBuffer && ShouldDeallocateInDestructor()) {
   634     // if the buffer has never been shared we must deallocate it or it would
   635     // leak.
   636     GfxMemoryImageReporter::WillFree(mBuffer);
   637     delete [] mBuffer;
   638   }
   639 }
   641 BufferTextureClient::BufferTextureClient(ISurfaceAllocator* aAllocator,
   642                                          gfx::SurfaceFormat aFormat,
   643                                          gfx::BackendType aMoz2DBackend,
   644                                          TextureFlags aFlags)
   645   : TextureClient(aFlags)
   646   , mAllocator(aAllocator)
   647   , mFormat(aFormat)
   648   , mBackend(aMoz2DBackend)
   649   , mOpenMode(0)
   650   , mUsingFallbackDrawTarget(false)
   651   , mLocked(false)
   652 {}
   654 BufferTextureClient::~BufferTextureClient()
   655 {}
   657 ISurfaceAllocator*
   658 BufferTextureClient::GetAllocator() const
   659 {
   660   return mAllocator;
   661 }
   663 bool
   664 BufferTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
   665 {
   666   MOZ_ASSERT(IsValid());
   667   MOZ_ASSERT(mFormat != gfx::SurfaceFormat::YUV, "This textureClient cannot use YCbCr data");
   668   MOZ_ASSERT(aSize.width * aSize.height);
   670   int bufSize
   671     = ImageDataSerializer::ComputeMinBufferSize(aSize, mFormat);
   672   if (!Allocate(bufSize)) {
   673     return false;
   674   }
   676   if (aFlags & ALLOC_CLEAR_BUFFER) {
   677     memset(GetBuffer(), 0, bufSize);
   678   }
   680   ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
   681   serializer.InitializeBufferInfo(aSize, mFormat);
   682   mSize = aSize;
   683   return true;
   684 }
   686 TemporaryRef<gfx::DrawTarget>
   687 BufferTextureClient::GetAsDrawTarget()
   688 {
   689   MOZ_ASSERT(IsValid());
   690   MOZ_ASSERT(mLocked, "GetAsDrawTarget should be called on locked textures only");
   692   if (mDrawTarget) {
   693     return mDrawTarget;
   694   }
   696   ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
   697   if (!serializer.IsValid()) {
   698     return nullptr;
   699   }
   701   MOZ_ASSERT(mUsingFallbackDrawTarget == false);
   702   mDrawTarget = serializer.GetAsDrawTarget(mBackend);
   703   if (mDrawTarget) {
   704     return mDrawTarget;
   705   }
   707   // fallback path, probably because the Moz2D backend can't create a
   708   // DrawTarget around raw memory. This is going to be slow :(
   709   mDrawTarget = gfx::Factory::CreateDrawTarget(mBackend, serializer.GetSize(),
   710                                                serializer.GetFormat());
   711   if (!mDrawTarget) {
   712     return nullptr;
   713   }
   715   mUsingFallbackDrawTarget = true;
   716   if (mOpenMode & OPEN_READ) {
   717     RefPtr<DataSourceSurface> surface = serializer.GetAsSurface();
   718     IntRect rect(0, 0, surface->GetSize().width, surface->GetSize().height);
   719     mDrawTarget->CopySurface(surface, rect, IntPoint(0,0));
   720   }
   721   return mDrawTarget;
   722 }
   724 bool
   725 BufferTextureClient::Lock(OpenMode aMode)
   726 {
   727   MOZ_ASSERT(!mLocked, "The TextureClient is already Locked!");
   728   mOpenMode = aMode;
   729   mLocked = IsValid() && IsAllocated();;
   730   return mLocked;
   731 }
   733 void
   734 BufferTextureClient::Unlock()
   735 {
   736   MOZ_ASSERT(mLocked, "The TextureClient is already Unlocked!");
   737   mLocked = false;
   738   if (!mDrawTarget) {
   739     mUsingFallbackDrawTarget = false;
   740     return;
   741   }
   743   // see the comment on TextureClient::GetAsDrawTarget.
   744   // This DrawTarget is internal to the TextureClient and is only exposed to the
   745   // outside world between Lock() and Unlock(). This assertion checks that no outside
   746   // reference remains by the time Unlock() is called.
   747   MOZ_ASSERT(mDrawTarget->refCount() == 1);
   749   mDrawTarget->Flush();
   750   if (mUsingFallbackDrawTarget && (mOpenMode & OPEN_WRITE)) {
   751     // When we are using a fallback DrawTarget, it means we could not create
   752     // a DrawTarget wrapping the TextureClient's shared memory. In this scenario
   753     // we need to put the content of the fallback draw target back into our shared
   754     // memory.
   755     RefPtr<SourceSurface> snapshot = mDrawTarget->Snapshot();
   756     RefPtr<DataSourceSurface> surface = snapshot->GetDataSurface();
   757     ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
   758     if (!serializer.IsValid() || serializer.GetSize() != surface->GetSize()) {
   759       NS_WARNING("Could not write the data back into the texture.");
   760       mDrawTarget = nullptr;
   761       mUsingFallbackDrawTarget = false;
   762       return;
   763     }
   764     MOZ_ASSERT(surface->GetSize() == serializer.GetSize());
   765     MOZ_ASSERT(surface->GetFormat() == serializer.GetFormat());
   766     int bpp = BytesPerPixel(surface->GetFormat());
   767     for (int i = 0; i < surface->GetSize().height; ++i) {
   768       memcpy(serializer.GetData() + i*serializer.GetStride(),
   769              surface->GetData() + i*surface->Stride(),
   770              surface->GetSize().width * bpp);
   771     }
   772   }
   773   mDrawTarget = nullptr;
   774   mUsingFallbackDrawTarget = false;
   775 }
   777 bool
   778 BufferTextureClient::UpdateYCbCr(const PlanarYCbCrData& aData)
   779 {
   780   MOZ_ASSERT(mLocked);
   781   MOZ_ASSERT(mFormat == gfx::SurfaceFormat::YUV, "This textureClient can only use YCbCr data");
   782   MOZ_ASSERT(!IsImmutable());
   783   MOZ_ASSERT(IsValid());
   784   MOZ_ASSERT(aData.mCbSkip == aData.mCrSkip);
   786   YCbCrImageDataSerializer serializer(GetBuffer(), GetBufferSize());
   787   MOZ_ASSERT(serializer.IsValid());
   788   if (!serializer.CopyData(aData.mYChannel, aData.mCbChannel, aData.mCrChannel,
   789                            aData.mYSize, aData.mYStride,
   790                            aData.mCbCrSize, aData.mCbCrStride,
   791                            aData.mYSkip, aData.mCbSkip)) {
   792     NS_WARNING("Failed to copy image data!");
   793     return false;
   794   }
   796   if (TextureRequiresLocking(mFlags)) {
   797     // We don't have support for proper locking yet, so we'll
   798     // have to be immutable instead.
   799     MarkImmutable();
   800   }
   801   return true;
   802 }
   804 bool
   805 BufferTextureClient::AllocateForYCbCr(gfx::IntSize aYSize,
   806                                       gfx::IntSize aCbCrSize,
   807                                       StereoMode aStereoMode)
   808 {
   809   MOZ_ASSERT(IsValid());
   811   size_t bufSize = YCbCrImageDataSerializer::ComputeMinBufferSize(aYSize,
   812                                                                   aCbCrSize);
   813   if (!Allocate(bufSize)) {
   814     return false;
   815   }
   816   YCbCrImageDataSerializer serializer(GetBuffer(), GetBufferSize());
   817   serializer.InitializeBufferInfo(aYSize,
   818                                   aCbCrSize,
   819                                   aStereoMode);
   820   mSize = aYSize;
   821   return true;
   822 }
   824 }
   825 }

mercurial