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 "SharedPlanarYCbCrImage.h"
8 #include <stddef.h>                    // for size_t
9 #include <stdio.h>                     // for printf
10 #include "gfx2DGlue.h"                 // for Moz2D transition helpers
11 #include "ISurfaceAllocator.h"         // for ISurfaceAllocator, etc
12 #include "mozilla/Assertions.h"        // for MOZ_ASSERT, etc
13 #include "mozilla/gfx/Types.h"         // for SurfaceFormat::SurfaceFormat::YUV
14 #include "mozilla/ipc/SharedMemory.h"  // for SharedMemory, etc
15 #include "mozilla/layers/ImageClient.h"     // for ImageClient
16 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
17 #include "mozilla/layers/TextureClient.h"
18 #include "mozilla/layers/TextureClientRecycleAllocator.h"
19 #include "mozilla/layers/BufferTexture.h"
20 #include "mozilla/layers/ImageDataSerializer.h"
21 #include "mozilla/layers/ImageBridgeChild.h"  // for ImageBridgeChild
22 #include "mozilla/mozalloc.h"                 // for operator delete
23 #include "nsISupportsImpl.h"                  // for Image::AddRef
24 #include "mozilla/ipc/Shmem.h"
25 
26 namespace mozilla {
27 namespace layers {
28 
29 using namespace mozilla::ipc;
30 
SharedPlanarYCbCrImage(ImageClient * aCompositable)31 SharedPlanarYCbCrImage::SharedPlanarYCbCrImage(ImageClient* aCompositable)
32     : mCompositable(aCompositable) {
33   MOZ_COUNT_CTOR(SharedPlanarYCbCrImage);
34 }
35 
SharedPlanarYCbCrImage(TextureClientRecycleAllocator * aRecycleAllocator)36 SharedPlanarYCbCrImage::SharedPlanarYCbCrImage(
37     TextureClientRecycleAllocator* aRecycleAllocator)
38     : mRecycleAllocator(aRecycleAllocator) {
39   MOZ_COUNT_CTOR(SharedPlanarYCbCrImage);
40 }
41 
~SharedPlanarYCbCrImage()42 SharedPlanarYCbCrImage::~SharedPlanarYCbCrImage() {
43   MOZ_COUNT_DTOR(SharedPlanarYCbCrImage);
44 }
45 
RecycleAllocator()46 TextureClientRecycleAllocator* SharedPlanarYCbCrImage::RecycleAllocator() {
47   static const uint32_t MAX_POOLED_VIDEO_COUNT = 5;
48 
49   if (!mRecycleAllocator && mCompositable) {
50     if (!mCompositable->HasTextureClientRecycler()) {
51       // Initialize TextureClientRecycler
52       mCompositable->GetTextureClientRecycler()->SetMaxPoolSize(
53           MAX_POOLED_VIDEO_COUNT);
54     }
55     mRecycleAllocator = mCompositable->GetTextureClientRecycler();
56   }
57   return mRecycleAllocator;
58 }
59 
SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const60 size_t SharedPlanarYCbCrImage::SizeOfExcludingThis(
61     MallocSizeOf aMallocSizeOf) const {
62   // NB: Explicitly skipping mTextureClient, the memory is already reported
63   //     at time of allocation in GfxMemoryImageReporter.
64   // Not owned:
65   // - mCompositable
66   return 0;
67 }
68 
GetTextureClient(KnowsCompositor * aKnowsCompositor)69 TextureClient* SharedPlanarYCbCrImage::GetTextureClient(
70     KnowsCompositor* aKnowsCompositor) {
71   return mTextureClient.get();
72 }
73 
74 already_AddRefed<gfx::SourceSurface>
GetAsSourceSurface()75 SharedPlanarYCbCrImage::GetAsSourceSurface() {
76   if (!IsValid()) {
77     NS_WARNING("Can't get as surface");
78     return nullptr;
79   }
80   return PlanarYCbCrImage::GetAsSourceSurface();
81 }
82 
CopyData(const PlanarYCbCrData & aData)83 bool SharedPlanarYCbCrImage::CopyData(const PlanarYCbCrData& aData) {
84   // If mTextureClient has not already been allocated (through Allocate(aData))
85   // allocate it. This code path is slower than the one used when Allocate has
86   // been called since it will trigger a full copy.
87   PlanarYCbCrData data = aData;
88   if (!mTextureClient && !Allocate(data)) {
89     return false;
90   }
91 
92   TextureClientAutoLock autoLock(mTextureClient, OpenMode::OPEN_WRITE_ONLY);
93   if (!autoLock.Succeeded()) {
94     MOZ_ASSERT(false, "Failed to lock the texture.");
95     return false;
96   }
97 
98   if (!UpdateYCbCrTextureClient(mTextureClient, aData)) {
99     MOZ_ASSERT(false, "Failed to copy YCbCr data into the TextureClient");
100     return false;
101   }
102   mTextureClient->MarkImmutable();
103   return true;
104 }
105 
AdoptData(const Data & aData)106 bool SharedPlanarYCbCrImage::AdoptData(const Data& aData) {
107   MOZ_ASSERT(false, "This shouldn't be used.");
108   return false;
109 }
110 
CreateEmptyBuffer(const Data & aData)111 bool SharedPlanarYCbCrImage::CreateEmptyBuffer(const Data& aData) {
112   auto data = aData;
113   return Allocate(data);
114 }
115 
IsValid() const116 bool SharedPlanarYCbCrImage::IsValid() const {
117   return mTextureClient && mTextureClient->IsValid();
118 }
119 
Allocate(PlanarYCbCrData & aData)120 bool SharedPlanarYCbCrImage::Allocate(PlanarYCbCrData& aData) {
121   MOZ_ASSERT(!mTextureClient, "This image already has allocated data");
122 
123   TextureFlags flags =
124       mCompositable ? mCompositable->GetTextureFlags() : TextureFlags::DEFAULT;
125   {
126     YCbCrTextureClientAllocationHelper helper(aData, flags);
127     mTextureClient = RecycleAllocator()->CreateOrRecycle(helper);
128   }
129 
130   if (!mTextureClient) {
131     NS_WARNING("SharedPlanarYCbCrImage::Allocate failed.");
132     return false;
133   }
134 
135   MappedYCbCrTextureData mapped;
136   // The locking here is sort of a lie. The SharedPlanarYCbCrImage just pulls
137   // pointers out of the TextureClient and keeps them around, which works only
138   // because the underlyin BufferTextureData is always mapped in memory even
139   // outside of the lock/unlock interval. That's sad and new code should follow
140   // this example.
141   if (!mTextureClient->Lock(OpenMode::OPEN_READ) ||
142       !mTextureClient->BorrowMappedYCbCrData(mapped)) {
143     MOZ_CRASH("GFX: Cannot lock or borrow mapped YCbCr");
144   }
145 
146   aData.mYChannel = mapped.y.data;
147   aData.mCbChannel = mapped.cb.data;
148   aData.mCrChannel = mapped.cr.data;
149 
150   // copy some of aData's values in mData (most of them)
151   mData.mYChannel = aData.mYChannel;
152   mData.mCbChannel = aData.mCbChannel;
153   mData.mCrChannel = aData.mCrChannel;
154   mData.mYSize = aData.mYSize;
155   mData.mCbCrSize = aData.mCbCrSize;
156   mData.mPicX = aData.mPicX;
157   mData.mPicY = aData.mPicY;
158   mData.mPicSize = aData.mPicSize;
159   mData.mStereoMode = aData.mStereoMode;
160   mData.mYUVColorSpace = aData.mYUVColorSpace;
161   mData.mColorDepth = aData.mColorDepth;
162   // those members are not always equal to aData's, due to potentially different
163   // packing.
164   mData.mYSkip = 0;
165   mData.mCbSkip = 0;
166   mData.mCrSkip = 0;
167   mData.mYStride = aData.mYStride;
168   mData.mCbCrStride = aData.mCbCrStride;
169 
170   // do not set mBuffer like in PlanarYCbCrImage because the later
171   // will try to manage this memory without knowing it belongs to a
172   // shmem.
173   mBufferSize = ImageDataSerializer::ComputeYCbCrBufferSize(
174       mData.mYSize, mData.mYStride, mData.mCbCrSize, mData.mCbCrStride);
175   mSize = mData.mPicSize;
176   mOrigin = gfx::IntPoint(aData.mPicX, aData.mPicY);
177 
178   mTextureClient->Unlock();
179 
180   return mBufferSize > 0;
181 }
182 
183 }  // namespace layers
184 }  // namespace mozilla
185