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 "DMABUFTextureHostOGL.h"
8 #include "mozilla/widget/DMABufSurface.h"
9 #include "mozilla/webrender/RenderDMABUFTextureHost.h"
10 #include "mozilla/webrender/RenderThread.h"
11 #include "mozilla/webrender/WebRenderAPI.h"
12 #include "GLContextEGL.h"
13
14 namespace mozilla::layers {
15
DMABUFTextureHostOGL(TextureFlags aFlags,const SurfaceDescriptor & aDesc)16 DMABUFTextureHostOGL::DMABUFTextureHostOGL(TextureFlags aFlags,
17 const SurfaceDescriptor& aDesc)
18 : TextureHost(aFlags) {
19 MOZ_COUNT_CTOR(DMABUFTextureHostOGL);
20
21 // DMABufSurface::CreateDMABufSurface() can fail, for instance when we're run
22 // out of file descriptors.
23 mSurface =
24 DMABufSurface::CreateDMABufSurface(aDesc.get_SurfaceDescriptorDMABuf());
25 }
26
~DMABUFTextureHostOGL()27 DMABUFTextureHostOGL::~DMABUFTextureHostOGL() {
28 MOZ_COUNT_DTOR(DMABUFTextureHostOGL);
29 }
30
CreateTextureSourceForPlane(size_t aPlane)31 GLTextureSource* DMABUFTextureHostOGL::CreateTextureSourceForPlane(
32 size_t aPlane) {
33 if (!mSurface) {
34 return nullptr;
35 }
36
37 if (!mSurface->GetTexture(aPlane)) {
38 if (!mSurface->CreateTexture(gl(), aPlane)) {
39 return nullptr;
40 }
41 }
42
43 return new GLTextureSource(
44 mProvider, mSurface->GetTexture(aPlane), LOCAL_GL_TEXTURE_2D,
45 gfx::IntSize(mSurface->GetWidth(aPlane), mSurface->GetHeight(aPlane)),
46 // XXX: This isn't really correct (but isn't used), we should be using the
47 // format of the individual plane, not of the whole buffer.
48 mSurface->GetFormatGL());
49 }
50
Lock()51 bool DMABUFTextureHostOGL::Lock() {
52 if (!gl() || !gl()->MakeCurrent() || !mSurface) {
53 return false;
54 }
55
56 if (!mTextureSource) {
57 mTextureSource = CreateTextureSourceForPlane(0);
58
59 RefPtr<TextureSource> prev = mTextureSource;
60 for (size_t i = 1; i < mSurface->GetTextureCount(); i++) {
61 RefPtr<TextureSource> next = CreateTextureSourceForPlane(i);
62 prev->SetNextSibling(next);
63 prev = next;
64 }
65 }
66
67 mSurface->FenceWait();
68 return true;
69 }
70
Unlock()71 void DMABUFTextureHostOGL::Unlock() {}
72
SetTextureSourceProvider(TextureSourceProvider * aProvider)73 void DMABUFTextureHostOGL::SetTextureSourceProvider(
74 TextureSourceProvider* aProvider) {
75 if (!aProvider || !aProvider->GetGLContext()) {
76 mTextureSource = nullptr;
77 mProvider = nullptr;
78 return;
79 }
80
81 mProvider = aProvider;
82
83 if (mTextureSource) {
84 mTextureSource->SetTextureSourceProvider(aProvider);
85 }
86 }
87
GetFormat() const88 gfx::SurfaceFormat DMABUFTextureHostOGL::GetFormat() const {
89 if (!mSurface) {
90 return gfx::SurfaceFormat::UNKNOWN;
91 }
92 return mSurface->GetFormat();
93 }
94
GetYUVColorSpace() const95 gfx::YUVColorSpace DMABUFTextureHostOGL::GetYUVColorSpace() const {
96 if (!mSurface) {
97 return gfx::YUVColorSpace::Identity;
98 }
99 return mSurface->GetYUVColorSpace();
100 }
101
GetColorRange() const102 gfx::ColorRange DMABUFTextureHostOGL::GetColorRange() const {
103 if (!mSurface) {
104 return gfx::ColorRange::LIMITED;
105 }
106 return mSurface->IsFullRange() ? gfx::ColorRange::FULL
107 : gfx::ColorRange::LIMITED;
108 }
109
NumSubTextures()110 uint32_t DMABUFTextureHostOGL::NumSubTextures() {
111 return mSurface ? mSurface->GetTextureCount() : 0;
112 }
113
GetSize() const114 gfx::IntSize DMABUFTextureHostOGL::GetSize() const {
115 if (!mSurface) {
116 return gfx::IntSize();
117 }
118 return gfx::IntSize(mSurface->GetWidth(), mSurface->GetHeight());
119 }
120
gl() const121 gl::GLContext* DMABUFTextureHostOGL::gl() const {
122 return mProvider ? mProvider->GetGLContext() : nullptr;
123 }
124
CreateRenderTexture(const wr::ExternalImageId & aExternalImageId)125 void DMABUFTextureHostOGL::CreateRenderTexture(
126 const wr::ExternalImageId& aExternalImageId) {
127 if (!mSurface) {
128 return;
129 }
130 RefPtr<wr::RenderTextureHost> texture =
131 new wr::RenderDMABUFTextureHost(mSurface);
132 wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(aExternalImageId),
133 texture.forget());
134 }
135
PushResourceUpdates(wr::TransactionBuilder & aResources,ResourceUpdateOp aOp,const Range<wr::ImageKey> & aImageKeys,const wr::ExternalImageId & aExtID)136 void DMABUFTextureHostOGL::PushResourceUpdates(
137 wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
138 const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
139 if (!mSurface) {
140 return;
141 }
142
143 auto method = aOp == TextureHost::ADD_IMAGE
144 ? &wr::TransactionBuilder::AddExternalImage
145 : &wr::TransactionBuilder::UpdateExternalImage;
146 auto imageType =
147 wr::ExternalImageType::TextureHandle(wr::ImageBufferKind::Texture2D);
148
149 switch (mSurface->GetFormat()) {
150 case gfx::SurfaceFormat::R8G8B8X8:
151 case gfx::SurfaceFormat::R8G8B8A8:
152 case gfx::SurfaceFormat::B8G8R8X8:
153 case gfx::SurfaceFormat::B8G8R8A8: {
154 MOZ_ASSERT(aImageKeys.length() == 1);
155 // XXX Add RGBA handling. Temporary hack to avoid crash
156 // With BGRA format setting, rendering works without problem.
157 wr::ImageDescriptor descriptor(GetSize(), mSurface->GetFormat());
158 (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
159 break;
160 }
161 case gfx::SurfaceFormat::NV12: {
162 MOZ_ASSERT(aImageKeys.length() == 2);
163 MOZ_ASSERT(mSurface->GetTextureCount() == 2);
164 wr::ImageDescriptor descriptor0(
165 gfx::IntSize(mSurface->GetWidth(0), mSurface->GetHeight(0)),
166 gfx::SurfaceFormat::A8);
167 wr::ImageDescriptor descriptor1(
168 gfx::IntSize(mSurface->GetWidth(1), mSurface->GetHeight(1)),
169 gfx::SurfaceFormat::R8G8);
170 (aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0);
171 (aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1);
172 break;
173 }
174 case gfx::SurfaceFormat::YUV: {
175 MOZ_ASSERT(aImageKeys.length() == 3);
176 MOZ_ASSERT(mSurface->GetTextureCount() == 3);
177 wr::ImageDescriptor descriptor0(
178 gfx::IntSize(mSurface->GetWidth(0), mSurface->GetHeight(0)),
179 gfx::SurfaceFormat::A8);
180 wr::ImageDescriptor descriptor1(
181 gfx::IntSize(mSurface->GetWidth(1), mSurface->GetHeight(1)),
182 gfx::SurfaceFormat::A8);
183 (aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0);
184 (aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1);
185 (aResources.*method)(aImageKeys[2], descriptor1, aExtID, imageType, 2);
186 break;
187 }
188 default: {
189 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
190 }
191 }
192 }
193
PushDisplayItems(wr::DisplayListBuilder & aBuilder,const wr::LayoutRect & aBounds,const wr::LayoutRect & aClip,wr::ImageRendering aFilter,const Range<wr::ImageKey> & aImageKeys,PushDisplayItemFlagSet aFlags)194 void DMABUFTextureHostOGL::PushDisplayItems(
195 wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds,
196 const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
197 const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) {
198 if (!mSurface) {
199 return;
200 }
201 bool preferCompositorSurface =
202 aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE);
203 switch (mSurface->GetFormat()) {
204 case gfx::SurfaceFormat::R8G8B8X8:
205 case gfx::SurfaceFormat::R8G8B8A8:
206 case gfx::SurfaceFormat::B8G8R8A8:
207 case gfx::SurfaceFormat::B8G8R8X8: {
208 MOZ_ASSERT(aImageKeys.length() == 1);
209 aBuilder.PushImage(aBounds, aClip, true, aFilter, aImageKeys[0],
210 !(mFlags & TextureFlags::NON_PREMULTIPLIED),
211 wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f},
212 preferCompositorSurface);
213 break;
214 }
215 case gfx::SurfaceFormat::NV12: {
216 MOZ_ASSERT(aImageKeys.length() == 2);
217 MOZ_ASSERT(mSurface->GetTextureCount() == 2);
218 // Those images can only be generated at present by the VAAPI H264 decoder
219 // which only supports 8 bits color depth.
220 aBuilder.PushNV12Image(aBounds, aClip, true, aImageKeys[0], aImageKeys[1],
221 wr::ColorDepth::Color8,
222 wr::ToWrYuvColorSpace(GetYUVColorSpace()),
223 wr::ToWrColorRange(GetColorRange()), aFilter,
224 preferCompositorSurface);
225 break;
226 }
227 case gfx::SurfaceFormat::YUV: {
228 MOZ_ASSERT(aImageKeys.length() == 3);
229 MOZ_ASSERT(mSurface->GetTextureCount() == 3);
230 // Those images can only be generated at present by the VAAPI vp8 decoder
231 // which only supports 8 bits color depth.
232 aBuilder.PushYCbCrPlanarImage(
233 aBounds, aClip, true, aImageKeys[0], aImageKeys[1], aImageKeys[2],
234 wr::ColorDepth::Color8, wr::ToWrYuvColorSpace(GetYUVColorSpace()),
235 wr::ToWrColorRange(GetColorRange()), aFilter,
236 preferCompositorSurface);
237 break;
238 }
239 default: {
240 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
241 }
242 }
243 }
244
245 } // namespace mozilla::layers
246