RenderAndroidHardwareBufferTextureHost.cpp (7791B)
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 "RenderAndroidHardwareBufferTextureHost.h" 8 9 #include "mozilla/layers/AndroidHardwareBuffer.h" 10 #include "mozilla/layers/TextureHostOGL.h" 11 #include "mozilla/webrender/RenderThread.h" 12 #include "mozilla/gfx/2D.h" 13 #include "GLContextEGL.h" 14 #include "GLLibraryEGL.h" 15 #include "GLReadTexImageHelper.h" 16 #include "OGLShaderConfig.h" 17 18 namespace mozilla { 19 namespace wr { 20 21 RenderAndroidHardwareBufferTextureHost::RenderAndroidHardwareBufferTextureHost( 22 layers::AndroidHardwareBuffer* aAndroidHardwareBuffer) 23 : mAndroidHardwareBuffer(aAndroidHardwareBuffer), 24 mEGLImage(EGL_NO_IMAGE), 25 mTextureHandle(0) { 26 MOZ_ASSERT(mAndroidHardwareBuffer); 27 MOZ_COUNT_CTOR_INHERITED(RenderAndroidHardwareBufferTextureHost, 28 RenderTextureHost); 29 } 30 31 RenderAndroidHardwareBufferTextureHost:: 32 ~RenderAndroidHardwareBufferTextureHost() { 33 MOZ_COUNT_DTOR_INHERITED(RenderAndroidHardwareBufferTextureHost, 34 RenderTextureHost); 35 DeleteTextureHandle(); 36 DestroyEGLImage(); 37 } 38 39 gfx::IntSize RenderAndroidHardwareBufferTextureHost::GetSize() const { 40 if (mAndroidHardwareBuffer) { 41 return mAndroidHardwareBuffer->mSize; 42 } 43 return gfx::IntSize(); 44 } 45 46 bool RenderAndroidHardwareBufferTextureHost::EnsureLockable() { 47 if (!mAndroidHardwareBuffer) { 48 return false; 49 } 50 51 auto fenceFd = mAndroidHardwareBuffer->GetAndResetAcquireFence(); 52 if (fenceFd) { 53 const auto& gle = gl::GLContextEGL::Cast(mGL); 54 const auto& egl = gle->mEgl; 55 56 const EGLint attribs[] = {LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, 57 fenceFd.get(), LOCAL_EGL_NONE}; 58 59 EGLSync sync = 60 egl->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); 61 if (sync) { 62 // Release fd here, since it is owned by EGLSync 63 (void)fenceFd.release(); 64 65 if (egl->IsExtensionSupported(gl::EGLExtension::KHR_wait_sync)) { 66 egl->fWaitSync(sync, 0); 67 } else { 68 egl->fClientWaitSync(sync, 0, LOCAL_EGL_FOREVER); 69 } 70 egl->fDestroySync(sync); 71 } else { 72 gfxCriticalNote << "Failed to create EGLSync from acquire fence fd"; 73 } 74 } 75 76 if (mTextureHandle) { 77 return true; 78 } 79 80 if (!mEGLImage) { 81 // XXX add crop handling for video 82 // Should only happen the first time. 83 const auto& gle = gl::GLContextEGL::Cast(mGL); 84 const auto& egl = gle->mEgl; 85 86 const EGLint attrs[] = { 87 LOCAL_EGL_IMAGE_PRESERVED, 88 LOCAL_EGL_TRUE, 89 LOCAL_EGL_NONE, 90 LOCAL_EGL_NONE, 91 }; 92 93 EGLClientBuffer clientBuffer = egl->mLib->fGetNativeClientBufferANDROID( 94 mAndroidHardwareBuffer->GetNativeBuffer()); 95 mEGLImage = egl->fCreateImage( 96 EGL_NO_CONTEXT, LOCAL_EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs); 97 } 98 MOZ_ASSERT(mEGLImage); 99 100 mGL->fGenTextures(1, &mTextureHandle); 101 mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, mTextureHandle); 102 mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL, LOCAL_GL_TEXTURE_WRAP_T, 103 LOCAL_GL_CLAMP_TO_EDGE); 104 mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL, LOCAL_GL_TEXTURE_WRAP_S, 105 LOCAL_GL_CLAMP_TO_EDGE); 106 mGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL, mEGLImage); 107 108 ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0, 109 LOCAL_GL_TEXTURE_EXTERNAL_OES, mTextureHandle); 110 return true; 111 } 112 113 wr::WrExternalImage RenderAndroidHardwareBufferTextureHost::Lock( 114 uint8_t aChannelIndex, gl::GLContext* aGL) { 115 MOZ_ASSERT(aChannelIndex == 0); 116 117 if (mGL.get() != aGL) { 118 if (mGL) { 119 // This should not happen. 120 MOZ_ASSERT_UNREACHABLE("Unexpected GL context"); 121 return InvalidToWrExternalImage(); 122 } 123 mGL = aGL; 124 } 125 126 if (!mGL || !mGL->MakeCurrent()) { 127 return InvalidToWrExternalImage(); 128 } 129 130 if (!EnsureLockable()) { 131 return InvalidToWrExternalImage(); 132 } 133 134 const gfx::IntSize size = GetSize(); 135 return NativeTextureToWrExternalImage(mTextureHandle, 0.0, 0.0, 136 static_cast<float>(size.width), 137 static_cast<float>(size.height)); 138 } 139 140 void RenderAndroidHardwareBufferTextureHost::Unlock() {} 141 142 size_t RenderAndroidHardwareBufferTextureHost::Bytes() { 143 return GetSize().width * GetSize().height * 144 BytesPerPixel(mAndroidHardwareBuffer->mFormat); 145 } 146 147 void RenderAndroidHardwareBufferTextureHost::DeleteTextureHandle() { 148 if (!mTextureHandle) { 149 return; 150 } 151 MOZ_ASSERT(mGL); 152 mGL->fDeleteTextures(1, &mTextureHandle); 153 mTextureHandle = 0; 154 } 155 156 void RenderAndroidHardwareBufferTextureHost::DestroyEGLImage() { 157 if (!mEGLImage) { 158 return; 159 } 160 MOZ_ASSERT(mGL); 161 const auto& gle = gl::GLContextEGL::Cast(mGL); 162 const auto& egl = gle->mEgl; 163 egl->fDestroyImage(mEGLImage); 164 mEGLImage = EGL_NO_IMAGE; 165 } 166 167 gfx::SurfaceFormat RenderAndroidHardwareBufferTextureHost::GetFormat() const { 168 MOZ_ASSERT(mAndroidHardwareBuffer->mFormat == gfx::SurfaceFormat::R8G8B8A8 || 169 mAndroidHardwareBuffer->mFormat == gfx::SurfaceFormat::R8G8B8X8); 170 171 if (mAndroidHardwareBuffer->mFormat == gfx::SurfaceFormat::R8G8B8A8) { 172 return gfx::SurfaceFormat::B8G8R8A8; 173 } 174 175 if (mAndroidHardwareBuffer->mFormat == gfx::SurfaceFormat::R8G8B8X8) { 176 return gfx::SurfaceFormat::B8G8R8X8; 177 } 178 179 gfxCriticalNoteOnce 180 << "Unexpected color format of RenderAndroidSurfaceTextureHost"; 181 182 return gfx::SurfaceFormat::UNKNOWN; 183 } 184 185 already_AddRefed<gfx::DataSourceSurface> 186 RenderAndroidHardwareBufferTextureHost::ReadTexImage() { 187 if (!mGL) { 188 mGL = RenderThread::Get()->SingletonGL(); 189 if (!mGL) { 190 return nullptr; 191 } 192 } 193 194 if (!EnsureLockable()) { 195 return nullptr; 196 } 197 198 /* Allocate resulting image surface */ 199 int32_t stride = GetSize().width * BytesPerPixel(GetFormat()); 200 RefPtr<gfx::DataSourceSurface> surf = 201 gfx::Factory::CreateDataSourceSurfaceWithStride(GetSize(), GetFormat(), 202 stride); 203 if (!surf) { 204 return nullptr; 205 } 206 207 layers::ShaderConfigOGL config = layers::ShaderConfigFromTargetAndFormat( 208 LOCAL_GL_TEXTURE_EXTERNAL, mAndroidHardwareBuffer->mFormat); 209 int shaderConfig = config.mFeatures; 210 211 bool ret = mGL->ReadTexImageHelper()->ReadTexImage( 212 surf, mTextureHandle, LOCAL_GL_TEXTURE_EXTERNAL, GetSize(), 213 gfx::Matrix4x4(), shaderConfig, /* aYInvert */ false); 214 if (!ret) { 215 return nullptr; 216 } 217 218 return surf.forget(); 219 } 220 221 bool RenderAndroidHardwareBufferTextureHost::MapPlane( 222 RenderCompositor* aCompositor, uint8_t aChannelIndex, 223 PlaneInfo& aPlaneInfo) { 224 RefPtr<gfx::DataSourceSurface> readback = ReadTexImage(); 225 if (!readback) { 226 return false; 227 } 228 229 gfx::DataSourceSurface::MappedSurface map; 230 if (!readback->Map(gfx::DataSourceSurface::MapType::READ, &map)) { 231 return false; 232 } 233 234 mReadback = readback; 235 aPlaneInfo.mSize = GetSize(); 236 aPlaneInfo.mStride = map.mStride; 237 aPlaneInfo.mData = map.mData; 238 return true; 239 } 240 241 void RenderAndroidHardwareBufferTextureHost::UnmapPlanes() { 242 if (mReadback) { 243 mReadback->Unmap(); 244 mReadback = nullptr; 245 } 246 } 247 248 RefPtr<layers::TextureSource> 249 RenderAndroidHardwareBufferTextureHost::CreateTextureSource( 250 layers::TextureSourceProvider* aProvider) { 251 return new layers::AndroidHardwareBufferTextureSource( 252 aProvider, mAndroidHardwareBuffer, mAndroidHardwareBuffer->mFormat, 253 LOCAL_GL_TEXTURE_EXTERNAL, LOCAL_GL_CLAMP_TO_EDGE, GetSize()); 254 } 255 256 } // namespace wr 257 } // namespace mozilla