Bug 1024144 - Deliver acquire fence to HwComposer r=sushil,nical
[gecko.git] / gfx / layers / opengl / GrallocTextureHost.cpp
blobebeae564be115d5289e4472dd8726d5edb3b00df
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 "base/process.h"
7 #include "GLContext.h"
8 #include "gfx2DGlue.h"
9 #include <ui/GraphicBuffer.h>
10 #include "GrallocImages.h" // for GrallocImage
11 #include "mozilla/layers/GrallocTextureHost.h"
12 #include "mozilla/layers/CompositorOGL.h"
13 #include "mozilla/layers/SharedBufferManagerParent.h"
14 #include "EGLImageHelpers.h"
15 #include "GLReadTexImageHelper.h"
17 namespace mozilla {
18 namespace layers {
20 using namespace android;
22 static gfx::SurfaceFormat
23 SurfaceFormatForAndroidPixelFormat(android::PixelFormat aFormat,
24 TextureFlags aFlags)
26 bool swapRB = bool(aFlags & TextureFlags::RB_SWAPPED);
27 switch (aFormat) {
28 case android::PIXEL_FORMAT_BGRA_8888:
29 return swapRB ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::B8G8R8A8;
30 case android::PIXEL_FORMAT_RGBA_8888:
31 return swapRB ? gfx::SurfaceFormat::B8G8R8A8 : gfx::SurfaceFormat::R8G8B8A8;
32 case android::PIXEL_FORMAT_RGBX_8888:
33 return swapRB ? gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::R8G8B8X8;
34 case android::PIXEL_FORMAT_RGB_565:
35 return gfx::SurfaceFormat::R5G6B5;
36 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
37 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
38 case HAL_PIXEL_FORMAT_YCbCr_422_I:
39 case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
40 case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
41 case HAL_PIXEL_FORMAT_YV12:
42 return gfx::SurfaceFormat::R8G8B8A8; // yup, use SurfaceFormat::R8G8B8A8 even though it's a YUV texture. This is an external texture.
43 default:
44 if (aFormat >= 0x100 && aFormat <= 0x1FF) {
45 // Reserved range for HAL specific formats.
46 return gfx::SurfaceFormat::R8G8B8A8;
47 } else {
48 // This is not super-unreachable, there's a bunch of hypothetical pixel
49 // formats we don't deal with.
50 // We only want to abort in debug builds here, since if we crash here
51 // we'll take down the compositor process and thus the phone. This seems
52 // like undesirable behaviour. We'd rather have a subtle artifact.
53 printf_stderr(" xxxxx unknow android format %i\n", (int)aFormat);
54 MOZ_ASSERT(false, "Unknown Android pixel format.");
55 return gfx::SurfaceFormat::UNKNOWN;
60 static GLenum
61 TextureTargetForAndroidPixelFormat(android::PixelFormat aFormat)
63 switch (aFormat) {
64 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
65 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
66 case HAL_PIXEL_FORMAT_YCbCr_422_I:
67 case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
68 case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
69 case HAL_PIXEL_FORMAT_YV12:
70 return LOCAL_GL_TEXTURE_EXTERNAL;
71 case android::PIXEL_FORMAT_BGRA_8888:
72 case android::PIXEL_FORMAT_RGBA_8888:
73 case android::PIXEL_FORMAT_RGBX_8888:
74 case android::PIXEL_FORMAT_RGB_565:
75 return LOCAL_GL_TEXTURE_2D;
76 default:
77 if (aFormat >= 0x100 && aFormat <= 0x1FF) {
78 // Reserved range for HAL specific formats.
79 return LOCAL_GL_TEXTURE_EXTERNAL;
80 } else {
81 // This is not super-unreachable, there's a bunch of hypothetical pixel
82 // formats we don't deal with.
83 // We only want to abort in debug builds here, since if we crash here
84 // we'll take down the compositor process and thus the phone. This seems
85 // like undesirable behaviour. We'd rather have a subtle artifact.
86 MOZ_ASSERT(false, "Unknown Android pixel format.");
87 return LOCAL_GL_TEXTURE_EXTERNAL;
92 GrallocTextureSourceOGL::GrallocTextureSourceOGL(CompositorOGL* aCompositor,
93 GrallocTextureHostOGL* aTextureHost,
94 android::GraphicBuffer* aGraphicBuffer,
95 gfx::SurfaceFormat aFormat)
96 : mCompositor(aCompositor)
97 , mTextureHost(aTextureHost)
98 , mGraphicBuffer(aGraphicBuffer)
99 , mEGLImage(0)
100 , mFormat(aFormat)
101 , mNeedsReset(true)
103 MOZ_ASSERT(mGraphicBuffer.get());
106 GrallocTextureSourceOGL::~GrallocTextureSourceOGL()
108 DeallocateDeviceData();
109 mCompositor = nullptr;
112 void
113 GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter)
116 * The job of this function is to ensure that the texture is tied to the
117 * android::GraphicBuffer, so that texturing will source the GraphicBuffer.
119 * To this effect we create an EGLImage wrapping this GraphicBuffer,
120 * using EGLImageCreateFromNativeBuffer, and then we tie this EGLImage to our
121 * texture using fEGLImageTargetTexture2D.
123 MOZ_ASSERT(gl());
124 if (!IsValid()) {
125 return;
127 gl()->MakeCurrent();
129 GLuint tex = GetGLTexture();
130 GLuint textureTarget = GetTextureTarget();
132 gl()->fActiveTexture(aTextureUnit);
133 gl()->fBindTexture(textureTarget, tex);
135 if (mCompositableBackendData) {
136 // There are two paths for locking/unlocking - if mCompositableBackendData is
137 // set, we use the texture on there, otherwise we use
138 // CompositorBackendSpecificData from the compositor and bind the EGLImage
139 // only in Lock().
140 if (!mEGLImage) {
141 mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
143 BindEGLImage();
146 ApplyFilterToBoundTexture(gl(), aFilter, textureTarget);
148 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
149 if (mTextureHost) {
150 // Wait until it's ready.
151 mTextureHost->WaitAcquireFenceSyncComplete();
153 #endif
156 void GrallocTextureSourceOGL::Lock()
158 if (mCompositableBackendData) return;
160 MOZ_ASSERT(IsValid());
162 mTexture = mCompositor->GetTemporaryTexture(GetTextureTarget(), LOCAL_GL_TEXTURE0);
164 GLuint textureTarget = GetTextureTarget();
166 gl()->MakeCurrent();
167 gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
168 gl()->fBindTexture(textureTarget, mTexture);
169 if (!mEGLImage) {
170 mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
172 gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
175 bool
176 GrallocTextureSourceOGL::IsValid() const
178 return !!gl() && !!mGraphicBuffer.get() && (!!mCompositor || !!mCompositableBackendData);
181 gl::GLContext*
182 GrallocTextureSourceOGL::gl() const
184 return mCompositor ? mCompositor->gl() : nullptr;
187 void
188 GrallocTextureSourceOGL::SetCompositor(Compositor* aCompositor)
190 if (mCompositor && !aCompositor) {
191 DeallocateDeviceData();
193 mCompositor = static_cast<CompositorOGL*>(aCompositor);
197 GLenum
198 GrallocTextureSourceOGL::GetTextureTarget() const
200 MOZ_ASSERT(gl());
201 MOZ_ASSERT(mGraphicBuffer.get());
203 if (!gl() || !mGraphicBuffer.get()) {
204 return LOCAL_GL_TEXTURE_EXTERNAL;
207 // SGX has a quirk that only TEXTURE_EXTERNAL works and any other value will
208 // result in black pixels when trying to draw from bound textures.
209 // Unfortunately, using TEXTURE_EXTERNAL on Adreno has a terrible effect on
210 // performance.
211 // See Bug 950050.
212 if (gl()->Renderer() == gl::GLRenderer::SGX530 ||
213 gl()->Renderer() == gl::GLRenderer::SGX540) {
214 return LOCAL_GL_TEXTURE_EXTERNAL;
217 return TextureTargetForAndroidPixelFormat(mGraphicBuffer->getPixelFormat());
220 void
221 GrallocTextureSourceOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
223 if (!aBackendData) {
224 DeallocateDeviceData();
225 // Update mCompositableBackendData after calling DeallocateDeviceData().
226 mCompositableBackendData = nullptr;
227 return;
230 if (mCompositableBackendData != aBackendData) {
231 mNeedsReset = true;
234 if (!mNeedsReset) {
235 // Update binding to the EGLImage
236 gl()->MakeCurrent();
237 GLuint tex = GetGLTexture();
238 GLuint textureTarget = GetTextureTarget();
239 gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
240 gl()->fBindTexture(textureTarget, tex);
241 BindEGLImage();
242 return;
245 if (!mCompositor) {
246 mCompositableBackendData = aBackendData;
247 return;
250 // delete old EGLImage
251 DeallocateDeviceData();
253 // Update mCompositableBackendData after calling DeallocateDeviceData().
254 mCompositableBackendData = aBackendData;
256 gl()->MakeCurrent();
257 GLuint tex = GetGLTexture();
258 GLuint textureTarget = GetTextureTarget();
260 gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
261 gl()->fBindTexture(textureTarget, tex);
262 // create new EGLImage
263 mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
264 BindEGLImage();
265 mNeedsReset = false;
268 gfx::IntSize
269 GrallocTextureSourceOGL::GetSize() const
271 if (!IsValid()) {
272 NS_WARNING("Trying to access the size of an invalid GrallocTextureSourceOGL");
273 return gfx::IntSize(0, 0);
275 return gfx::IntSize(mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight());
278 void
279 GrallocTextureSourceOGL::DeallocateDeviceData()
281 if (mEGLImage) {
282 MOZ_ASSERT(gl());
283 gl()->MakeCurrent();
284 if (mCompositableBackendData) {
285 CompositableDataGonkOGL* backend = static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get());
286 backend->ClearBoundEGLImage(mEGLImage);
288 EGLImageDestroy(gl(), mEGLImage);
289 mEGLImage = EGL_NO_IMAGE;
293 GrallocTextureHostOGL::GrallocTextureHostOGL(TextureFlags aFlags,
294 const NewSurfaceDescriptorGralloc& aDescriptor)
295 : TextureHost(aFlags)
297 gfx::SurfaceFormat format = gfx::SurfaceFormat::UNKNOWN;
298 mGrallocHandle = aDescriptor;
300 android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
301 MOZ_ASSERT(graphicBuffer);
303 mSize = aDescriptor.size();
304 if (graphicBuffer) {
305 format =
306 SurfaceFormatForAndroidPixelFormat(graphicBuffer->getPixelFormat(),
307 aFlags & TextureFlags::RB_SWAPPED);
308 } else {
309 NS_WARNING("gralloc buffer is nullptr");
311 mTextureSource = new GrallocTextureSourceOGL(nullptr,
312 this,
313 graphicBuffer,
314 format);
317 GrallocTextureHostOGL::~GrallocTextureHostOGL()
319 mTextureSource = nullptr;
322 void
323 GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor)
325 mTextureSource->SetCompositor(static_cast<CompositorOGL*>(aCompositor));
328 bool
329 GrallocTextureHostOGL::Lock()
331 if (IsValid()) {
332 mTextureSource->Lock();
333 return true;
335 return false;
338 void
339 GrallocTextureHostOGL::Unlock()
341 // Unlock is done internally by binding the texture to another gralloc buffer
344 bool
345 GrallocTextureHostOGL::IsValid() const
347 return mTextureSource->IsValid();
350 gfx::SurfaceFormat
351 GrallocTextureHostOGL::GetFormat() const
353 return mTextureSource->GetFormat();
356 void
357 GrallocTextureHostOGL::DeallocateSharedData()
359 if (mTextureSource) {
360 mTextureSource->ForgetBuffer();
362 if (mGrallocHandle.buffer().type() != SurfaceDescriptor::Tnull_t) {
363 MaybeMagicGrallocBufferHandle handle = mGrallocHandle.buffer();
364 base::ProcessId owner;
365 if (handle.type() == MaybeMagicGrallocBufferHandle::TGrallocBufferRef) {
366 owner = handle.get_GrallocBufferRef().mOwner;
368 else {
369 owner = handle.get_MagicGrallocBufferHandle().mRef.mOwner;
372 SharedBufferManagerParent::GetInstance(owner)->DropGrallocBuffer(mGrallocHandle);
376 void
377 GrallocTextureHostOGL::ForgetSharedData()
379 if (mTextureSource) {
380 mTextureSource->ForgetBuffer();
384 void
385 GrallocTextureHostOGL::DeallocateDeviceData()
387 mTextureSource->DeallocateDeviceData();
390 LayerRenderState
391 GrallocTextureHostOGL::GetRenderState()
393 if (IsValid()) {
394 LayerRenderStateFlags flags = LayerRenderStateFlags::LAYER_RENDER_STATE_DEFAULT;
395 if (mFlags & TextureFlags::NEEDS_Y_FLIP) {
396 flags |= LayerRenderStateFlags::Y_FLIPPED;
398 if (mFlags & TextureFlags::RB_SWAPPED) {
399 flags |= LayerRenderStateFlags::FORMAT_RB_SWAP;
401 return LayerRenderState(mTextureSource->mGraphicBuffer.get(),
402 gfx::ThebesIntSize(mSize),
403 flags,
404 this);
407 return LayerRenderState();
410 TemporaryRef<gfx::DataSourceSurface>
411 GrallocTextureHostOGL::GetAsSurface() {
412 return mTextureSource ? mTextureSource->GetAsSurface()
413 : nullptr;
416 TemporaryRef<gfx::DataSourceSurface>
417 GrallocTextureSourceOGL::GetAsSurface() {
418 if (!IsValid()) {
419 return nullptr;
421 gl()->MakeCurrent();
423 GLuint tex = GetGLTexture();
424 gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
425 gl()->fBindTexture(GetTextureTarget(), tex);
426 if (!mEGLImage) {
427 mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
429 BindEGLImage();
431 RefPtr<gfx::DataSourceSurface> surf =
432 IsValid() ? ReadBackSurface(gl(), tex, false, GetFormat())
433 : nullptr;
435 gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
436 return surf.forget();
439 GLuint
440 GrallocTextureSourceOGL::GetGLTexture()
442 if (mCompositableBackendData) {
443 mCompositableBackendData->SetCompositor(mCompositor);
444 return static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->GetTexture();
447 return mTexture;
450 void
451 GrallocTextureSourceOGL::BindEGLImage()
453 if (mCompositableBackendData) {
454 CompositableDataGonkOGL* backend = static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get());
455 backend->BindEGLImage(GetTextureTarget(), mEGLImage);
456 } else {
457 gl()->fEGLImageTargetTexture2D(GetTextureTarget(), mEGLImage);
461 void
462 GrallocTextureHostOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
464 mCompositableBackendData = aBackendData;
465 if (mTextureSource) {
466 mTextureSource->SetCompositableBackendSpecificData(aBackendData);
470 } // namepsace layers
471 } // namepsace mozilla