1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/opengl/GrallocTextureHost.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,443 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 +// * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "GLContext.h" 1.10 +#include "gfx2DGlue.h" 1.11 +#include <ui/GraphicBuffer.h> 1.12 +#include "GrallocImages.h" // for GrallocImage 1.13 +#include "mozilla/layers/GrallocTextureHost.h" 1.14 +#include "mozilla/layers/CompositorOGL.h" 1.15 +#include "EGLImageHelpers.h" 1.16 +#include "GLReadTexImageHelper.h" 1.17 + 1.18 +namespace mozilla { 1.19 +namespace layers { 1.20 + 1.21 +using namespace android; 1.22 + 1.23 +static gfx::SurfaceFormat 1.24 +SurfaceFormatForAndroidPixelFormat(android::PixelFormat aFormat, 1.25 + bool swapRB = false) 1.26 +{ 1.27 + switch (aFormat) { 1.28 + case android::PIXEL_FORMAT_BGRA_8888: 1.29 + return swapRB ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::B8G8R8A8; 1.30 + case android::PIXEL_FORMAT_RGBA_8888: 1.31 + return swapRB ? gfx::SurfaceFormat::B8G8R8A8 : gfx::SurfaceFormat::R8G8B8A8; 1.32 + case android::PIXEL_FORMAT_RGBX_8888: 1.33 + return swapRB ? gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::R8G8B8X8; 1.34 + case android::PIXEL_FORMAT_RGB_565: 1.35 + return gfx::SurfaceFormat::R5G6B5; 1.36 + case HAL_PIXEL_FORMAT_YCbCr_422_SP: 1.37 + case HAL_PIXEL_FORMAT_YCrCb_420_SP: 1.38 + case HAL_PIXEL_FORMAT_YCbCr_422_I: 1.39 + case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: 1.40 + case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: 1.41 + case HAL_PIXEL_FORMAT_YV12: 1.42 + return gfx::SurfaceFormat::R8G8B8A8; // yup, use SurfaceFormat::R8G8B8A8 even though it's a YUV texture. This is an external texture. 1.43 + default: 1.44 + if (aFormat >= 0x100 && aFormat <= 0x1FF) { 1.45 + // Reserved range for HAL specific formats. 1.46 + return gfx::SurfaceFormat::R8G8B8A8; 1.47 + } else { 1.48 + // This is not super-unreachable, there's a bunch of hypothetical pixel 1.49 + // formats we don't deal with. 1.50 + // We only want to abort in debug builds here, since if we crash here 1.51 + // we'll take down the compositor process and thus the phone. This seems 1.52 + // like undesirable behaviour. We'd rather have a subtle artifact. 1.53 + printf_stderr(" xxxxx unknow android format %i\n", (int)aFormat); 1.54 + MOZ_ASSERT(false, "Unknown Android pixel format."); 1.55 + return gfx::SurfaceFormat::UNKNOWN; 1.56 + } 1.57 + } 1.58 +} 1.59 + 1.60 +static GLenum 1.61 +TextureTargetForAndroidPixelFormat(android::PixelFormat aFormat) 1.62 +{ 1.63 + switch (aFormat) { 1.64 + case HAL_PIXEL_FORMAT_YCbCr_422_SP: 1.65 + case HAL_PIXEL_FORMAT_YCrCb_420_SP: 1.66 + case HAL_PIXEL_FORMAT_YCbCr_422_I: 1.67 + case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: 1.68 + case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: 1.69 + case HAL_PIXEL_FORMAT_YV12: 1.70 + return LOCAL_GL_TEXTURE_EXTERNAL; 1.71 + case android::PIXEL_FORMAT_BGRA_8888: 1.72 + case android::PIXEL_FORMAT_RGBA_8888: 1.73 + case android::PIXEL_FORMAT_RGBX_8888: 1.74 + case android::PIXEL_FORMAT_RGB_565: 1.75 + return LOCAL_GL_TEXTURE_2D; 1.76 + default: 1.77 + if (aFormat >= 0x100 && aFormat <= 0x1FF) { 1.78 + // Reserved range for HAL specific formats. 1.79 + return LOCAL_GL_TEXTURE_EXTERNAL; 1.80 + } else { 1.81 + // This is not super-unreachable, there's a bunch of hypothetical pixel 1.82 + // formats we don't deal with. 1.83 + // We only want to abort in debug builds here, since if we crash here 1.84 + // we'll take down the compositor process and thus the phone. This seems 1.85 + // like undesirable behaviour. We'd rather have a subtle artifact. 1.86 + MOZ_ASSERT(false, "Unknown Android pixel format."); 1.87 + return LOCAL_GL_TEXTURE_EXTERNAL; 1.88 + } 1.89 + } 1.90 +} 1.91 + 1.92 +GrallocTextureSourceOGL::GrallocTextureSourceOGL(CompositorOGL* aCompositor, 1.93 + android::GraphicBuffer* aGraphicBuffer, 1.94 + gfx::SurfaceFormat aFormat) 1.95 + : mCompositor(aCompositor) 1.96 + , mGraphicBuffer(aGraphicBuffer) 1.97 + , mEGLImage(0) 1.98 + , mFormat(aFormat) 1.99 + , mNeedsReset(true) 1.100 +{ 1.101 + MOZ_ASSERT(mGraphicBuffer.get()); 1.102 +} 1.103 + 1.104 +GrallocTextureSourceOGL::~GrallocTextureSourceOGL() 1.105 +{ 1.106 + DeallocateDeviceData(); 1.107 + mCompositor = nullptr; 1.108 +} 1.109 + 1.110 +void 1.111 +GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter) 1.112 +{ 1.113 + /* 1.114 + * The job of this function is to ensure that the texture is tied to the 1.115 + * android::GraphicBuffer, so that texturing will source the GraphicBuffer. 1.116 + * 1.117 + * To this effect we create an EGLImage wrapping this GraphicBuffer, 1.118 + * using EGLImageCreateFromNativeBuffer, and then we tie this EGLImage to our 1.119 + * texture using fEGLImageTargetTexture2D. 1.120 + */ 1.121 + MOZ_ASSERT(gl()); 1.122 + if (!IsValid()) { 1.123 + return; 1.124 + } 1.125 + gl()->MakeCurrent(); 1.126 + 1.127 + GLuint tex = GetGLTexture(); 1.128 + GLuint textureTarget = GetTextureTarget(); 1.129 + 1.130 + gl()->fActiveTexture(aTextureUnit); 1.131 + gl()->fBindTexture(textureTarget, tex); 1.132 + 1.133 + if (mCompositableBackendData) { 1.134 + // There are two paths for locking/unlocking - if mCompositableBackendData is 1.135 + // set, we use the texture on there, otherwise we use 1.136 + // CompositorBackendSpecificData from the compositor and bind the EGLImage 1.137 + // only in Lock(). 1.138 + if (!mEGLImage) { 1.139 + mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer()); 1.140 + } 1.141 + gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage); 1.142 + } 1.143 + 1.144 + ApplyFilterToBoundTexture(gl(), aFilter, textureTarget); 1.145 +} 1.146 + 1.147 +void GrallocTextureSourceOGL::Lock() 1.148 +{ 1.149 + if (mCompositableBackendData) return; 1.150 + 1.151 + MOZ_ASSERT(IsValid()); 1.152 + 1.153 + mTexture = mCompositor->GetTemporaryTexture(GetTextureTarget(), LOCAL_GL_TEXTURE0); 1.154 + 1.155 + GLuint textureTarget = GetTextureTarget(); 1.156 + 1.157 + gl()->MakeCurrent(); 1.158 + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); 1.159 + gl()->fBindTexture(textureTarget, mTexture); 1.160 + if (!mEGLImage) { 1.161 + mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer()); 1.162 + } 1.163 + gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage); 1.164 +} 1.165 + 1.166 +bool 1.167 +GrallocTextureSourceOGL::IsValid() const 1.168 +{ 1.169 + return !!gl() && !!mGraphicBuffer.get() && (!!mCompositor || !!mCompositableBackendData); 1.170 +} 1.171 + 1.172 +gl::GLContext* 1.173 +GrallocTextureSourceOGL::gl() const 1.174 +{ 1.175 + return mCompositor ? mCompositor->gl() : nullptr; 1.176 +} 1.177 + 1.178 +void 1.179 +GrallocTextureSourceOGL::SetCompositor(Compositor* aCompositor) 1.180 +{ 1.181 + if (mCompositor && !aCompositor) { 1.182 + DeallocateDeviceData(); 1.183 + } 1.184 + mCompositor = static_cast<CompositorOGL*>(aCompositor); 1.185 +} 1.186 + 1.187 + 1.188 +GLenum 1.189 +GrallocTextureSourceOGL::GetTextureTarget() const 1.190 +{ 1.191 + MOZ_ASSERT(gl()); 1.192 + MOZ_ASSERT(mGraphicBuffer.get()); 1.193 + 1.194 + if (!gl() || !mGraphicBuffer.get()) { 1.195 + return LOCAL_GL_TEXTURE_EXTERNAL; 1.196 + } 1.197 + 1.198 + // SGX has a quirk that only TEXTURE_EXTERNAL works and any other value will 1.199 + // result in black pixels when trying to draw from bound textures. 1.200 + // Unfortunately, using TEXTURE_EXTERNAL on Adreno has a terrible effect on 1.201 + // performance. 1.202 + // See Bug 950050. 1.203 + if (gl()->Renderer() == gl::GLRenderer::SGX530 || 1.204 + gl()->Renderer() == gl::GLRenderer::SGX540) { 1.205 + return LOCAL_GL_TEXTURE_EXTERNAL; 1.206 + } 1.207 + 1.208 + return TextureTargetForAndroidPixelFormat(mGraphicBuffer->getPixelFormat()); 1.209 +} 1.210 + 1.211 +void 1.212 +GrallocTextureSourceOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) 1.213 +{ 1.214 + if (!aBackendData) { 1.215 + mCompositableBackendData = nullptr; 1.216 + DeallocateDeviceData(); 1.217 + return; 1.218 + } 1.219 + 1.220 + if (mCompositableBackendData != aBackendData) { 1.221 + mNeedsReset = true; 1.222 + } 1.223 + 1.224 + if (!mNeedsReset) { 1.225 + // Update binding to the EGLImage 1.226 + gl()->MakeCurrent(); 1.227 + GLuint tex = GetGLTexture(); 1.228 + GLuint textureTarget = GetTextureTarget(); 1.229 + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); 1.230 + gl()->fBindTexture(textureTarget, tex); 1.231 + gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage); 1.232 + return; 1.233 + } 1.234 + 1.235 + mCompositableBackendData = aBackendData; 1.236 + 1.237 + if (!mCompositor) { 1.238 + return; 1.239 + } 1.240 + 1.241 + // delete old EGLImage 1.242 + DeallocateDeviceData(); 1.243 + 1.244 + gl()->MakeCurrent(); 1.245 + GLuint tex = GetGLTexture(); 1.246 + GLuint textureTarget = GetTextureTarget(); 1.247 + 1.248 + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); 1.249 + gl()->fBindTexture(textureTarget, tex); 1.250 + // create new EGLImage 1.251 + mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer()); 1.252 + gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage); 1.253 + mNeedsReset = false; 1.254 +} 1.255 + 1.256 +gfx::IntSize 1.257 +GrallocTextureSourceOGL::GetSize() const 1.258 +{ 1.259 + if (!IsValid()) { 1.260 + NS_WARNING("Trying to access the size of an invalid GrallocTextureSourceOGL"); 1.261 + return gfx::IntSize(0, 0); 1.262 + } 1.263 + return gfx::IntSize(mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight()); 1.264 +} 1.265 + 1.266 +void 1.267 +GrallocTextureSourceOGL::DeallocateDeviceData() 1.268 +{ 1.269 + if (mEGLImage) { 1.270 + MOZ_ASSERT(gl()); 1.271 + gl()->MakeCurrent(); 1.272 + EGLImageDestroy(gl(), mEGLImage); 1.273 + mEGLImage = EGL_NO_IMAGE; 1.274 + } 1.275 +} 1.276 + 1.277 +GrallocTextureHostOGL::GrallocTextureHostOGL(TextureFlags aFlags, 1.278 + const NewSurfaceDescriptorGralloc& aDescriptor) 1.279 + : TextureHost(aFlags) 1.280 +{ 1.281 + android::GraphicBuffer* graphicBuffer = nullptr; 1.282 + gfx::SurfaceFormat format = gfx::SurfaceFormat::UNKNOWN; 1.283 + 1.284 + mSize = aDescriptor.size(); 1.285 + mGrallocActor = 1.286 + static_cast<GrallocBufferActor*>(aDescriptor.bufferParent()); 1.287 + 1.288 + if (mGrallocActor) { 1.289 + mGrallocActor->AddTextureHost(this); 1.290 + graphicBuffer = mGrallocActor->GetGraphicBuffer(); 1.291 + } 1.292 + 1.293 + if (graphicBuffer) { 1.294 + format = 1.295 + SurfaceFormatForAndroidPixelFormat(graphicBuffer->getPixelFormat(), 1.296 + aFlags & TEXTURE_RB_SWAPPED); 1.297 + } 1.298 + mTextureSource = new GrallocTextureSourceOGL(nullptr, 1.299 + graphicBuffer, 1.300 + format); 1.301 +} 1.302 + 1.303 +GrallocTextureHostOGL::~GrallocTextureHostOGL() 1.304 +{ 1.305 + mTextureSource = nullptr; 1.306 + if (mGrallocActor) { 1.307 + mGrallocActor->RemoveTextureHost(); 1.308 + mGrallocActor = nullptr; 1.309 + } 1.310 +} 1.311 + 1.312 +void 1.313 +GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor) 1.314 +{ 1.315 + mTextureSource->SetCompositor(static_cast<CompositorOGL*>(aCompositor)); 1.316 +} 1.317 + 1.318 +bool 1.319 +GrallocTextureHostOGL::Lock() 1.320 +{ 1.321 + if (IsValid()) { 1.322 + mTextureSource->Lock(); 1.323 + return true; 1.324 + } 1.325 + return false; 1.326 +} 1.327 + 1.328 +void 1.329 +GrallocTextureHostOGL::Unlock() 1.330 +{ 1.331 + // Unlock is done internally by binding the texture to another gralloc buffer 1.332 +} 1.333 + 1.334 +bool 1.335 +GrallocTextureHostOGL::IsValid() const 1.336 +{ 1.337 + return mTextureSource->IsValid(); 1.338 +} 1.339 + 1.340 +gfx::SurfaceFormat 1.341 +GrallocTextureHostOGL::GetFormat() const 1.342 +{ 1.343 + return mTextureSource->GetFormat(); 1.344 +} 1.345 + 1.346 +void 1.347 +GrallocTextureHostOGL::DeallocateSharedData() 1.348 +{ 1.349 + if (mTextureSource) { 1.350 + mTextureSource->ForgetBuffer(); 1.351 + } 1.352 + if (mGrallocActor) { 1.353 + PGrallocBufferParent::Send__delete__(mGrallocActor); 1.354 + } 1.355 +} 1.356 + 1.357 +void 1.358 +GrallocTextureHostOGL::ForgetSharedData() 1.359 +{ 1.360 + if (mTextureSource) { 1.361 + mTextureSource->ForgetBuffer(); 1.362 + } 1.363 +} 1.364 + 1.365 +void 1.366 +GrallocTextureHostOGL::DeallocateDeviceData() 1.367 +{ 1.368 + mTextureSource->DeallocateDeviceData(); 1.369 +} 1.370 + 1.371 +LayerRenderState 1.372 +GrallocTextureHostOGL::GetRenderState() 1.373 +{ 1.374 + if (IsValid()) { 1.375 + uint32_t flags = 0; 1.376 + if (mFlags & TEXTURE_NEEDS_Y_FLIP) { 1.377 + flags |= LAYER_RENDER_STATE_Y_FLIPPED; 1.378 + } 1.379 + if (mFlags & TEXTURE_RB_SWAPPED) { 1.380 + flags |= LAYER_RENDER_STATE_FORMAT_RB_SWAP; 1.381 + } 1.382 + return LayerRenderState(mTextureSource->mGraphicBuffer.get(), 1.383 + gfx::ThebesIntSize(mSize), 1.384 + flags, 1.385 + this); 1.386 + } 1.387 + 1.388 + return LayerRenderState(); 1.389 +} 1.390 + 1.391 +TemporaryRef<gfx::DataSourceSurface> 1.392 +GrallocTextureHostOGL::GetAsSurface() { 1.393 + return mTextureSource ? mTextureSource->GetAsSurface() 1.394 + : nullptr; 1.395 +} 1.396 + 1.397 +TemporaryRef<gfx::DataSourceSurface> 1.398 +GrallocTextureSourceOGL::GetAsSurface() { 1.399 + if (!IsValid()) { 1.400 + return nullptr; 1.401 + } 1.402 + gl()->MakeCurrent(); 1.403 + 1.404 + GLuint tex = GetGLTexture(); 1.405 + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); 1.406 + gl()->fBindTexture(GetTextureTarget(), tex); 1.407 + if (!mEGLImage) { 1.408 + mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer()); 1.409 + } 1.410 + gl()->fEGLImageTargetTexture2D(GetTextureTarget(), mEGLImage); 1.411 + 1.412 + RefPtr<gfx::DataSourceSurface> surf = 1.413 + IsValid() ? ReadBackSurface(gl(), tex, false, GetFormat()) 1.414 + : nullptr; 1.415 + 1.416 + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); 1.417 + return surf.forget(); 1.418 +} 1.419 + 1.420 +GLuint 1.421 +GrallocTextureSourceOGL::GetGLTexture() 1.422 +{ 1.423 + if (mCompositableBackendData) { 1.424 + mCompositableBackendData->SetCompositor(mCompositor); 1.425 + return static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->GetTexture(); 1.426 + } 1.427 + 1.428 + return mTexture; 1.429 +} 1.430 + 1.431 +void 1.432 +GrallocTextureHostOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) 1.433 +{ 1.434 + mCompositableBackendData = aBackendData; 1.435 + if (mTextureSource) { 1.436 + mTextureSource->SetCompositableBackendSpecificData(aBackendData); 1.437 + } 1.438 + // Register this object to CompositableBackendSpecificData 1.439 + // as current TextureHost. 1.440 + if (aBackendData) { 1.441 + aBackendData->SetCurrentReleaseFenceTexture(this); 1.442 + } 1.443 +} 1.444 + 1.445 +} // namepsace layers 1.446 +} // namepsace mozilla