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 "YCbCrUtils.h"
18 using namespace mozilla::layers
;
19 using namespace mozilla::gfx
;
21 TextureClient
* MacIOSurfaceImage::GetTextureClient(
22 KnowsCompositor
* aKnowsCompositor
) {
23 if (!mTextureClient
) {
24 BackendType backend
= BackendType::NONE
;
25 mTextureClient
= TextureClient::CreateWithData(
26 MacIOSurfaceTextureData::Create(mSurface
, backend
),
27 TextureFlags::DEFAULT
, aKnowsCompositor
->GetTextureForwarder());
29 return mTextureClient
;
32 already_AddRefed
<SourceSurface
> MacIOSurfaceImage::GetAsSourceSurface() {
33 return CreateSourceSurfaceFromMacIOSurface(mSurface
);
36 bool MacIOSurfaceImage::SetData(ImageContainer
* aContainer
,
37 const PlanarYCbCrData
& aData
) {
38 MOZ_ASSERT(!mSurface
);
40 if (aData
.mYSkip
!= 0 || aData
.mCbSkip
!= 0 || aData
.mCrSkip
!= 0 ||
41 !(aData
.mYUVColorSpace
== YUVColorSpace::BT601
||
42 aData
.mYUVColorSpace
== YUVColorSpace::BT709
) ||
43 !(aData
.mColorRange
== ColorRange::FULL
||
44 aData
.mColorRange
== ColorRange::LIMITED
) ||
45 aData
.mColorDepth
!= ColorDepth::COLOR_8
) {
49 if (aData
.mCbCrSize
.width
* 2 != aData
.mYSize
.width
) {
53 // We can only support 4:2:2 and 4:2:0 formats currently.
54 if (aData
.mCbCrSize
.height
!= aData
.mYSize
.height
&&
55 aData
.mCbCrSize
.height
* 2 != aData
.mYSize
.height
) {
59 RefPtr
<MacIOSurfaceRecycleAllocator
> allocator
=
60 aContainer
->GetMacIOSurfaceRecycleAllocator();
62 RefPtr
<MacIOSurface
> surf
= allocator
->Allocate(
63 aData
.mYSize
, aData
.mCbCrSize
, aData
.mYUVColorSpace
, aData
.mColorRange
);
67 // If the CbCrSize's height is half of the YSize's height, then we'll
68 // need to duplicate the CbCr data on every second row.
69 size_t heightScale
= aData
.mYSize
.height
/ aData
.mCbCrSize
.height
;
71 MOZ_ASSERT(surf
->GetFormat() == SurfaceFormat::YUV422
);
73 // The underlying IOSurface has format kCVPixelFormatType_422YpCbCr8FullRange
74 // or kCVPixelFormatType_422YpCbCr8_yuvs, which uses a 4:2:2 Y`0 Cb Y`1 Cr
75 // layout. See CVPixelBuffer.h for the full list of format descriptions.
76 MOZ_ASSERT(aData
.mYSize
.height
> 0);
77 uint8_t* dst
= (uint8_t*)surf
->GetBaseAddressOfPlane(0);
78 size_t stride
= surf
->GetBytesPerRow(0);
79 for (size_t i
= 0; i
< (size_t)aData
.mYSize
.height
; i
++) {
80 // Compute the row addresses. If the input was 4:2:0, then
81 // we divide i by 2, so that each source row of CbCr maps to
83 uint8_t* rowYSrc
= aData
.mYChannel
+ aData
.mYStride
* i
;
85 aData
.mCbChannel
+ aData
.mCbCrStride
* (i
/ heightScale
);
87 aData
.mCrChannel
+ aData
.mCbCrStride
* (i
/ heightScale
);
88 uint8_t* rowDst
= dst
+ stride
* i
;
90 // Iterate across the CbCr width (which we have guaranteed to be half of
91 // the surface width), and write two 16bit pixels each time.
92 for (size_t j
= 0; j
< (size_t)aData
.mCbCrSize
.width
; j
++) {
113 mPictureRect
= aData
.GetPictureRect();
117 already_AddRefed
<MacIOSurface
> MacIOSurfaceRecycleAllocator::Allocate(
118 const gfx::IntSize aYSize
, const gfx::IntSize
& aCbCrSize
,
119 gfx::YUVColorSpace aYUVColorSpace
, gfx::ColorRange aColorRange
) {
120 nsTArray
<CFTypeRefPtr
<IOSurfaceRef
>> surfaces
= std::move(mSurfaces
);
121 RefPtr
<MacIOSurface
> result
;
122 for (auto& surf
: surfaces
) {
123 // If the surface size has changed, then discard any surfaces of the old
125 if (::IOSurfaceGetWidthOfPlane(surf
.get(), 0) != (size_t)aYSize
.width
||
126 ::IOSurfaceGetHeightOfPlane(surf
.get(), 0) != (size_t)aYSize
.height
) {
130 // Only construct a MacIOSurface object when we find one that isn't
131 // in-use, since the constructor adds a usage ref.
132 if (!result
&& !::IOSurfaceIsInUse(surf
.get())) {
133 result
= new MacIOSurface(surf
, 1.0, false, aYUVColorSpace
);
136 mSurfaces
.AppendElement(surf
);
141 MacIOSurface::CreateYUV422Surface(aYSize
, aYUVColorSpace
, aColorRange
);
143 if (mSurfaces
.Length() <
144 StaticPrefs::layers_iosurfaceimage_recycle_limit()) {
145 mSurfaces
.AppendElement(result
->GetIOSurfaceRef());
149 return result
.forget();