Merge mozilla-central to autoland. CLOSED TREE
[gecko.git] / gfx / layers / MacIOSurfaceImage.cpp
blob37cd0ea81fdc9a2b9c12bf60edf3c628f5437dc2
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/. */
7 #include "MacIOSurfaceHelpers.h"
8 #include "MacIOSurfaceImage.h"
9 #include "gfxPlatform.h"
10 #include "mozilla/layers/CompositableClient.h"
11 #include "mozilla/layers/CompositableForwarder.h"
12 #include "mozilla/layers/MacIOSurfaceTextureClientOGL.h"
13 #include "mozilla/layers/TextureForwarder.h"
14 #include "mozilla/StaticPrefs_layers.h"
15 #include "mozilla/UniquePtr.h"
16 #include "mozilla/Unused.h"
17 #include "YCbCrUtils.h"
19 using namespace mozilla::layers;
20 using namespace mozilla::gfx;
22 TextureClient* MacIOSurfaceImage::GetTextureClient(
23 KnowsCompositor* aKnowsCompositor) {
24 if (!mTextureClient) {
25 BackendType backend = BackendType::NONE;
26 TextureFlags flags =
27 IsDRM() ? TextureFlags::DRM_SOURCE : TextureFlags::DEFAULT;
28 mTextureClient = TextureClient::CreateWithData(
29 MacIOSurfaceTextureData::Create(mSurface, backend), flags,
30 aKnowsCompositor->GetTextureForwarder());
32 return mTextureClient;
35 ColorDepth MacIOSurfaceImage::GetColorDepth() const {
36 if (!mSurface) {
37 return gfx::ColorDepth::COLOR_8;
39 return mSurface->GetColorDepth();
42 already_AddRefed<SourceSurface> MacIOSurfaceImage::GetAsSourceSurface() {
43 return CreateSourceSurfaceFromMacIOSurface(mSurface);
46 nsresult MacIOSurfaceImage::BuildSurfaceDescriptorBuffer(
47 SurfaceDescriptorBuffer& aSdBuffer, BuildSdbFlags aFlags,
48 const std::function<MemoryOrShmem(uint32_t)>& aAllocate) {
49 return CreateSurfaceDescriptorBufferFromMacIOSurface(mSurface, aSdBuffer,
50 aFlags, aAllocate);
53 static inline uint16_t safeShift10BitBy6(const uint16_t& a10BitLSB) {
54 // a10BitLSB is a 10-bit value packed into the least significant bits of
55 // a 16 bit value. This function asserts that the 6 MSBs are zero, then
56 // shifts the 10 LSBs by 6 to become the MSBs.
57 MOZ_ASSERT((a10BitLSB & 0b1111'1100'0000'0000) == 0);
58 return a10BitLSB << 6;
61 bool MacIOSurfaceImage::SetData(ImageContainer* aContainer,
62 const PlanarYCbCrData& aData) {
63 MOZ_ASSERT(!mSurface);
65 if (aData.mYSkip != 0 || aData.mCbSkip != 0 || aData.mCrSkip != 0 ||
66 !(aData.mYUVColorSpace == YUVColorSpace::BT601 ||
67 aData.mYUVColorSpace == YUVColorSpace::BT709 ||
68 aData.mYUVColorSpace == YUVColorSpace::BT2020) ||
69 !(aData.mColorRange == ColorRange::FULL ||
70 aData.mColorRange == ColorRange::LIMITED) ||
71 !(aData.mColorDepth == ColorDepth::COLOR_8 ||
72 aData.mColorDepth == ColorDepth::COLOR_10)) {
73 return false;
76 // We can only support 4:2:2 and 4:2:0 formats currently.
77 switch (aData.mChromaSubsampling) {
78 case ChromaSubsampling::HALF_WIDTH:
79 case ChromaSubsampling::HALF_WIDTH_AND_HEIGHT:
80 break;
81 default:
82 return false;
85 RefPtr<MacIOSurfaceRecycleAllocator> allocator =
86 aContainer->GetMacIOSurfaceRecycleAllocator();
88 auto ySize = aData.YDataSize();
89 auto cbcrSize = aData.CbCrDataSize();
90 RefPtr<MacIOSurface> surf = allocator->Allocate(
91 ySize, cbcrSize, aData.mYUVColorSpace, aData.mTransferFunction,
92 aData.mColorRange, aData.mColorDepth);
94 surf->Lock(false);
96 if (surf->GetFormat() == SurfaceFormat::YUV422) {
97 // If the CbCrSize's height is half of the YSize's height, then we'll
98 // need to duplicate the CbCr data on every second row.
99 size_t heightScale = ySize.height / cbcrSize.height;
101 // The underlying IOSurface has format
102 // kCVPixelFormatType_422YpCbCr8FullRange or
103 // kCVPixelFormatType_422YpCbCr8_yuvs, which uses a 4:2:2 Y`0 Cb Y`1 Cr
104 // layout. See CVPixelBuffer.h for the full list of format descriptions.
105 MOZ_ASSERT(ySize.height > 0);
106 uint8_t* dst = (uint8_t*)surf->GetBaseAddressOfPlane(0);
107 size_t stride = surf->GetBytesPerRow(0);
108 for (size_t i = 0; i < (size_t)ySize.height; i++) {
109 // Compute the row addresses. If the input was 4:2:0, then
110 // we divide i by 2, so that each source row of CbCr maps to
111 // two dest rows.
112 uint8_t* rowYSrc = aData.mYChannel + aData.mYStride * i;
113 uint8_t* rowCbSrc =
114 aData.mCbChannel + aData.mCbCrStride * (i / heightScale);
115 uint8_t* rowCrSrc =
116 aData.mCrChannel + aData.mCbCrStride * (i / heightScale);
117 uint8_t* rowDst = dst + stride * i;
119 // Iterate across the CbCr width (which we have guaranteed to be half of
120 // the surface width), and write two 16bit pixels each time.
121 for (size_t j = 0; j < (size_t)cbcrSize.width; j++) {
122 *rowDst = *rowYSrc;
123 rowDst++;
124 rowYSrc++;
126 *rowDst = *rowCbSrc;
127 rowDst++;
128 rowCbSrc++;
130 *rowDst = *rowYSrc;
131 rowDst++;
132 rowYSrc++;
134 *rowDst = *rowCrSrc;
135 rowDst++;
136 rowCrSrc++;
139 } else if (surf->GetFormat() == SurfaceFormat::NV12) {
140 MOZ_ASSERT(ySize.height > 0);
141 uint8_t* dst = (uint8_t*)surf->GetBaseAddressOfPlane(0);
142 size_t stride = surf->GetBytesPerRow(0);
143 for (size_t i = 0; i < (size_t)ySize.height; i++) {
144 uint8_t* rowSrc = aData.mYChannel + aData.mYStride * i;
145 uint8_t* rowDst = dst + stride * i;
146 memcpy(rowDst, rowSrc, ySize.width);
149 // Copy and interleave the Cb and Cr channels.
150 MOZ_ASSERT(cbcrSize.height > 0);
151 dst = (uint8_t*)surf->GetBaseAddressOfPlane(1);
152 stride = surf->GetBytesPerRow(1);
153 for (size_t i = 0; i < (size_t)cbcrSize.height; i++) {
154 uint8_t* rowCbSrc = aData.mCbChannel + aData.mCbCrStride * i;
155 uint8_t* rowCrSrc = aData.mCrChannel + aData.mCbCrStride * i;
156 uint8_t* rowDst = dst + stride * i;
158 for (size_t j = 0; j < (size_t)cbcrSize.width; j++) {
159 *rowDst = *rowCbSrc;
160 rowDst++;
161 rowCbSrc++;
163 *rowDst = *rowCrSrc;
164 rowDst++;
165 rowCrSrc++;
168 } else if (surf->GetFormat() == SurfaceFormat::P010) {
169 MOZ_ASSERT(ySize.height > 0);
170 auto dst = reinterpret_cast<uint16_t*>(surf->GetBaseAddressOfPlane(0));
171 size_t stride = surf->GetBytesPerRow(0) / 2;
172 for (size_t i = 0; i < (size_t)ySize.height; i++) {
173 auto rowSrc = reinterpret_cast<const uint16_t*>(aData.mYChannel +
174 aData.mYStride * i);
175 auto rowDst = dst + stride * i;
177 for (const auto j : IntegerRange(ySize.width)) {
178 Unused << j;
180 *rowDst = safeShift10BitBy6(*rowSrc);
181 rowDst++;
182 rowSrc++;
186 // Copy and interleave the Cb and Cr channels.
187 MOZ_ASSERT(cbcrSize.height > 0);
188 dst = (uint16_t*)surf->GetBaseAddressOfPlane(1);
189 stride = surf->GetBytesPerRow(1) / 2;
190 for (size_t i = 0; i < (size_t)cbcrSize.height; i++) {
191 uint16_t* rowCbSrc =
192 (uint16_t*)(aData.mCbChannel + aData.mCbCrStride * i);
193 uint16_t* rowCrSrc =
194 (uint16_t*)(aData.mCrChannel + aData.mCbCrStride * i);
195 uint16_t* rowDst = dst + stride * i;
197 for (const auto j : IntegerRange(cbcrSize.width)) {
198 Unused << j;
200 *rowDst = safeShift10BitBy6(*rowCbSrc);
201 rowDst++;
202 rowCbSrc++;
204 *rowDst = safeShift10BitBy6(*rowCrSrc);
205 rowDst++;
206 rowCrSrc++;
211 surf->Unlock(false);
212 mSurface = surf;
213 mPictureRect = aData.mPictureRect;
214 return true;
217 already_AddRefed<MacIOSurface> MacIOSurfaceRecycleAllocator::Allocate(
218 const gfx::IntSize aYSize, const gfx::IntSize& aCbCrSize,
219 gfx::YUVColorSpace aYUVColorSpace, gfx::TransferFunction aTransferFunction,
220 gfx::ColorRange aColorRange, gfx::ColorDepth aColorDepth) {
221 nsTArray<CFTypeRefPtr<IOSurfaceRef>> surfaces = std::move(mSurfaces);
222 RefPtr<MacIOSurface> result;
223 for (auto& surf : surfaces) {
224 // If the surface size has changed, then discard any surfaces of the old
225 // size.
226 if (::IOSurfaceGetWidthOfPlane(surf.get(), 0) != (size_t)aYSize.width ||
227 ::IOSurfaceGetHeightOfPlane(surf.get(), 0) != (size_t)aYSize.height) {
228 continue;
231 // Only construct a MacIOSurface object when we find one that isn't
232 // in-use, since the constructor adds a usage ref.
233 if (!result && !::IOSurfaceIsInUse(surf.get())) {
234 result = new MacIOSurface(surf, false, aYUVColorSpace);
237 mSurfaces.AppendElement(surf);
240 if (!result) {
241 if (StaticPrefs::layers_iosurfaceimage_use_nv12_AtStartup()) {
242 result = MacIOSurface::CreateNV12OrP010Surface(
243 aYSize, aCbCrSize, aYUVColorSpace, aTransferFunction, aColorRange,
244 aColorDepth);
245 } else {
246 result = MacIOSurface::CreateYUV422Surface(aYSize, aYUVColorSpace,
247 aColorRange);
250 if (mSurfaces.Length() <
251 StaticPrefs::layers_iosurfaceimage_recycle_limit()) {
252 mSurfaces.AppendElement(result->GetIOSurfaceRef());
256 return result.forget();