Backed out changeset 046c061d91c2 (bug 989144) Backed out changeset 3f1b41adeaef (bug 987311) Backed out changeset 8d5a171564bd (bug 987311) Backed out changeset dcc0d016de7a (bug 987311) Backed out changeset 27f338fbc835 (bug 989027) Backed out changeset 4a67f5144ea4 (bug 989027) Backed out changeset 62ba0a377450 (bug 987311) Backed out changeset 6a2542a5c865 (bug 987311) Backed out changeset 1dfd9a457f34 (bug 987311)
444 lines
12 KiB
C++
444 lines
12 KiB
C++
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
// * This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "GLContext.h"
|
|
#include "gfx2DGlue.h"
|
|
#include <ui/GraphicBuffer.h>
|
|
#include "GrallocImages.h" // for GrallocImage
|
|
#include "mozilla/layers/GrallocTextureHost.h"
|
|
#include "mozilla/layers/CompositorOGL.h"
|
|
#include "EGLImageHelpers.h"
|
|
#include "GLReadTexImageHelper.h"
|
|
|
|
namespace mozilla {
|
|
namespace layers {
|
|
|
|
using namespace android;
|
|
|
|
static gfx::SurfaceFormat
|
|
SurfaceFormatForAndroidPixelFormat(android::PixelFormat aFormat,
|
|
bool swapRB = false)
|
|
{
|
|
switch (aFormat) {
|
|
case android::PIXEL_FORMAT_BGRA_8888:
|
|
return swapRB ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::B8G8R8A8;
|
|
case android::PIXEL_FORMAT_RGBA_8888:
|
|
return swapRB ? gfx::SurfaceFormat::B8G8R8A8 : gfx::SurfaceFormat::R8G8B8A8;
|
|
case android::PIXEL_FORMAT_RGBX_8888:
|
|
return swapRB ? gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::R8G8B8X8;
|
|
case android::PIXEL_FORMAT_RGB_565:
|
|
return gfx::SurfaceFormat::R5G6B5;
|
|
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
|
|
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
|
|
case HAL_PIXEL_FORMAT_YCbCr_422_I:
|
|
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
|
|
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
|
|
case HAL_PIXEL_FORMAT_YV12:
|
|
return gfx::SurfaceFormat::R8G8B8A8; // yup, use SurfaceFormat::R8G8B8A8 even though it's a YUV texture. This is an external texture.
|
|
default:
|
|
if (aFormat >= 0x100 && aFormat <= 0x1FF) {
|
|
// Reserved range for HAL specific formats.
|
|
return gfx::SurfaceFormat::R8G8B8A8;
|
|
} else {
|
|
// This is not super-unreachable, there's a bunch of hypothetical pixel
|
|
// formats we don't deal with.
|
|
// We only want to abort in debug builds here, since if we crash here
|
|
// we'll take down the compositor process and thus the phone. This seems
|
|
// like undesirable behaviour. We'd rather have a subtle artifact.
|
|
printf_stderr(" xxxxx unknow android format %i\n", (int)aFormat);
|
|
MOZ_ASSERT(false, "Unknown Android pixel format.");
|
|
return gfx::SurfaceFormat::UNKNOWN;
|
|
}
|
|
}
|
|
}
|
|
|
|
static GLenum
|
|
TextureTargetForAndroidPixelFormat(android::PixelFormat aFormat)
|
|
{
|
|
switch (aFormat) {
|
|
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
|
|
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
|
|
case HAL_PIXEL_FORMAT_YCbCr_422_I:
|
|
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
|
|
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
|
|
case HAL_PIXEL_FORMAT_YV12:
|
|
return LOCAL_GL_TEXTURE_EXTERNAL;
|
|
case android::PIXEL_FORMAT_BGRA_8888:
|
|
case android::PIXEL_FORMAT_RGBA_8888:
|
|
case android::PIXEL_FORMAT_RGBX_8888:
|
|
case android::PIXEL_FORMAT_RGB_565:
|
|
return LOCAL_GL_TEXTURE_2D;
|
|
default:
|
|
if (aFormat >= 0x100 && aFormat <= 0x1FF) {
|
|
// Reserved range for HAL specific formats.
|
|
return LOCAL_GL_TEXTURE_EXTERNAL;
|
|
} else {
|
|
// This is not super-unreachable, there's a bunch of hypothetical pixel
|
|
// formats we don't deal with.
|
|
// We only want to abort in debug builds here, since if we crash here
|
|
// we'll take down the compositor process and thus the phone. This seems
|
|
// like undesirable behaviour. We'd rather have a subtle artifact.
|
|
MOZ_ASSERT(false, "Unknown Android pixel format.");
|
|
return LOCAL_GL_TEXTURE_EXTERNAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
GrallocTextureSourceOGL::GrallocTextureSourceOGL(CompositorOGL* aCompositor,
|
|
android::GraphicBuffer* aGraphicBuffer,
|
|
gfx::SurfaceFormat aFormat)
|
|
: mCompositor(aCompositor)
|
|
, mGraphicBuffer(aGraphicBuffer)
|
|
, mEGLImage(0)
|
|
, mFormat(aFormat)
|
|
, mNeedsReset(true)
|
|
{
|
|
MOZ_ASSERT(mGraphicBuffer.get());
|
|
}
|
|
|
|
GrallocTextureSourceOGL::~GrallocTextureSourceOGL()
|
|
{
|
|
DeallocateDeviceData();
|
|
mCompositor = nullptr;
|
|
}
|
|
|
|
void
|
|
GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter)
|
|
{
|
|
/*
|
|
* The job of this function is to ensure that the texture is tied to the
|
|
* android::GraphicBuffer, so that texturing will source the GraphicBuffer.
|
|
*
|
|
* To this effect we create an EGLImage wrapping this GraphicBuffer,
|
|
* using EGLImageCreateFromNativeBuffer, and then we tie this EGLImage to our
|
|
* texture using fEGLImageTargetTexture2D.
|
|
*/
|
|
MOZ_ASSERT(gl());
|
|
if (!IsValid()) {
|
|
return;
|
|
}
|
|
gl()->MakeCurrent();
|
|
|
|
GLuint tex = GetGLTexture();
|
|
GLuint textureTarget = GetTextureTarget();
|
|
|
|
gl()->fActiveTexture(aTextureUnit);
|
|
gl()->fBindTexture(textureTarget, tex);
|
|
|
|
if (mCompositableBackendData) {
|
|
// There are two paths for locking/unlocking - if mCompositableBackendData is
|
|
// set, we use the texture on there, otherwise we use
|
|
// CompositorBackendSpecificData from the compositor and bind the EGLImage
|
|
// only in Lock().
|
|
if (!mEGLImage) {
|
|
mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
|
|
}
|
|
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
|
|
}
|
|
|
|
ApplyFilterToBoundTexture(gl(), aFilter, textureTarget);
|
|
}
|
|
|
|
void GrallocTextureSourceOGL::Lock()
|
|
{
|
|
if (mCompositableBackendData) return;
|
|
|
|
MOZ_ASSERT(IsValid());
|
|
|
|
mTexture = mCompositor->GetTemporaryTexture(GetTextureTarget(), LOCAL_GL_TEXTURE0);
|
|
|
|
GLuint textureTarget = GetTextureTarget();
|
|
|
|
gl()->MakeCurrent();
|
|
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
|
gl()->fBindTexture(textureTarget, mTexture);
|
|
if (!mEGLImage) {
|
|
mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
|
|
}
|
|
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
|
|
}
|
|
|
|
bool
|
|
GrallocTextureSourceOGL::IsValid() const
|
|
{
|
|
return !!gl() && !!mGraphicBuffer.get() && (!!mCompositor || !!mCompositableBackendData);
|
|
}
|
|
|
|
gl::GLContext*
|
|
GrallocTextureSourceOGL::gl() const
|
|
{
|
|
return mCompositor ? mCompositor->gl() : nullptr;
|
|
}
|
|
|
|
void
|
|
GrallocTextureSourceOGL::SetCompositor(Compositor* aCompositor)
|
|
{
|
|
if (mCompositor && !aCompositor) {
|
|
DeallocateDeviceData();
|
|
}
|
|
mCompositor = static_cast<CompositorOGL*>(aCompositor);
|
|
}
|
|
|
|
|
|
GLenum
|
|
GrallocTextureSourceOGL::GetTextureTarget() const
|
|
{
|
|
MOZ_ASSERT(gl());
|
|
MOZ_ASSERT(mGraphicBuffer.get());
|
|
|
|
if (!gl() || !mGraphicBuffer.get()) {
|
|
return LOCAL_GL_TEXTURE_EXTERNAL;
|
|
}
|
|
|
|
// SGX has a quirk that only TEXTURE_EXTERNAL works and any other value will
|
|
// result in black pixels when trying to draw from bound textures.
|
|
// Unfortunately, using TEXTURE_EXTERNAL on Adreno has a terrible effect on
|
|
// performance.
|
|
// See Bug 950050.
|
|
if (gl()->Renderer() == gl::GLRenderer::SGX530 ||
|
|
gl()->Renderer() == gl::GLRenderer::SGX540) {
|
|
return LOCAL_GL_TEXTURE_EXTERNAL;
|
|
}
|
|
|
|
return TextureTargetForAndroidPixelFormat(mGraphicBuffer->getPixelFormat());
|
|
}
|
|
|
|
void
|
|
GrallocTextureSourceOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
|
|
{
|
|
if (!aBackendData) {
|
|
mCompositableBackendData = nullptr;
|
|
DeallocateDeviceData();
|
|
return;
|
|
}
|
|
|
|
if (mCompositableBackendData != aBackendData) {
|
|
mNeedsReset = true;
|
|
}
|
|
|
|
if (!mNeedsReset) {
|
|
// Update binding to the EGLImage
|
|
gl()->MakeCurrent();
|
|
GLuint tex = GetGLTexture();
|
|
GLuint textureTarget = GetTextureTarget();
|
|
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
|
gl()->fBindTexture(textureTarget, tex);
|
|
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
|
|
return;
|
|
}
|
|
|
|
mCompositableBackendData = aBackendData;
|
|
|
|
if (!mCompositor) {
|
|
return;
|
|
}
|
|
|
|
// delete old EGLImage
|
|
DeallocateDeviceData();
|
|
|
|
gl()->MakeCurrent();
|
|
GLuint tex = GetGLTexture();
|
|
GLuint textureTarget = GetTextureTarget();
|
|
|
|
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
|
gl()->fBindTexture(textureTarget, tex);
|
|
// create new EGLImage
|
|
mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
|
|
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
|
|
mNeedsReset = false;
|
|
}
|
|
|
|
gfx::IntSize
|
|
GrallocTextureSourceOGL::GetSize() const
|
|
{
|
|
if (!IsValid()) {
|
|
NS_WARNING("Trying to access the size of an invalid GrallocTextureSourceOGL");
|
|
return gfx::IntSize(0, 0);
|
|
}
|
|
return gfx::IntSize(mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight());
|
|
}
|
|
|
|
void
|
|
GrallocTextureSourceOGL::DeallocateDeviceData()
|
|
{
|
|
if (mEGLImage) {
|
|
MOZ_ASSERT(gl());
|
|
gl()->MakeCurrent();
|
|
EGLImageDestroy(gl(), mEGLImage);
|
|
mEGLImage = EGL_NO_IMAGE;
|
|
}
|
|
}
|
|
|
|
GrallocTextureHostOGL::GrallocTextureHostOGL(TextureFlags aFlags,
|
|
const NewSurfaceDescriptorGralloc& aDescriptor)
|
|
: TextureHost(aFlags)
|
|
{
|
|
android::GraphicBuffer* graphicBuffer = nullptr;
|
|
gfx::SurfaceFormat format = gfx::SurfaceFormat::UNKNOWN;
|
|
|
|
mSize = aDescriptor.size();
|
|
mGrallocActor =
|
|
static_cast<GrallocBufferActor*>(aDescriptor.bufferParent());
|
|
|
|
if (mGrallocActor) {
|
|
mGrallocActor->AddTextureHost(this);
|
|
graphicBuffer = mGrallocActor->GetGraphicBuffer();
|
|
}
|
|
|
|
if (graphicBuffer) {
|
|
format =
|
|
SurfaceFormatForAndroidPixelFormat(graphicBuffer->getPixelFormat(),
|
|
aFlags & TEXTURE_RB_SWAPPED);
|
|
}
|
|
mTextureSource = new GrallocTextureSourceOGL(nullptr,
|
|
graphicBuffer,
|
|
format);
|
|
}
|
|
|
|
GrallocTextureHostOGL::~GrallocTextureHostOGL()
|
|
{
|
|
mTextureSource = nullptr;
|
|
if (mGrallocActor) {
|
|
mGrallocActor->RemoveTextureHost();
|
|
mGrallocActor = nullptr;
|
|
}
|
|
}
|
|
|
|
void
|
|
GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor)
|
|
{
|
|
mTextureSource->SetCompositor(static_cast<CompositorOGL*>(aCompositor));
|
|
}
|
|
|
|
bool
|
|
GrallocTextureHostOGL::Lock()
|
|
{
|
|
if (IsValid()) {
|
|
mTextureSource->Lock();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void
|
|
GrallocTextureHostOGL::Unlock()
|
|
{
|
|
// Unlock is done internally by binding the texture to another gralloc buffer
|
|
}
|
|
|
|
bool
|
|
GrallocTextureHostOGL::IsValid() const
|
|
{
|
|
return mTextureSource->IsValid();
|
|
}
|
|
|
|
gfx::SurfaceFormat
|
|
GrallocTextureHostOGL::GetFormat() const
|
|
{
|
|
return mTextureSource->GetFormat();
|
|
}
|
|
|
|
void
|
|
GrallocTextureHostOGL::DeallocateSharedData()
|
|
{
|
|
if (mTextureSource) {
|
|
mTextureSource->ForgetBuffer();
|
|
}
|
|
if (mGrallocActor) {
|
|
PGrallocBufferParent::Send__delete__(mGrallocActor);
|
|
}
|
|
}
|
|
|
|
void
|
|
GrallocTextureHostOGL::ForgetSharedData()
|
|
{
|
|
if (mTextureSource) {
|
|
mTextureSource->ForgetBuffer();
|
|
}
|
|
}
|
|
|
|
void
|
|
GrallocTextureHostOGL::DeallocateDeviceData()
|
|
{
|
|
mTextureSource->DeallocateDeviceData();
|
|
}
|
|
|
|
LayerRenderState
|
|
GrallocTextureHostOGL::GetRenderState()
|
|
{
|
|
if (IsValid()) {
|
|
uint32_t flags = 0;
|
|
if (mFlags & TEXTURE_NEEDS_Y_FLIP) {
|
|
flags |= LAYER_RENDER_STATE_Y_FLIPPED;
|
|
}
|
|
if (mFlags & TEXTURE_RB_SWAPPED) {
|
|
flags |= LAYER_RENDER_STATE_FORMAT_RB_SWAP;
|
|
}
|
|
return LayerRenderState(mTextureSource->mGraphicBuffer.get(),
|
|
gfx::ThebesIntSize(mSize),
|
|
flags,
|
|
this);
|
|
}
|
|
|
|
return LayerRenderState();
|
|
}
|
|
|
|
TemporaryRef<gfx::DataSourceSurface>
|
|
GrallocTextureHostOGL::GetAsSurface() {
|
|
return mTextureSource ? mTextureSource->GetAsSurface()
|
|
: nullptr;
|
|
}
|
|
|
|
TemporaryRef<gfx::DataSourceSurface>
|
|
GrallocTextureSourceOGL::GetAsSurface() {
|
|
if (!IsValid()) {
|
|
return nullptr;
|
|
}
|
|
gl()->MakeCurrent();
|
|
|
|
GLuint tex = GetGLTexture();
|
|
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
|
gl()->fBindTexture(GetTextureTarget(), tex);
|
|
if (!mEGLImage) {
|
|
mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
|
|
}
|
|
gl()->fEGLImageTargetTexture2D(GetTextureTarget(), mEGLImage);
|
|
|
|
RefPtr<gfx::DataSourceSurface> surf =
|
|
IsValid() ? ReadBackSurface(gl(), tex, false, GetFormat())
|
|
: nullptr;
|
|
|
|
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
|
return surf.forget();
|
|
}
|
|
|
|
GLuint
|
|
GrallocTextureSourceOGL::GetGLTexture()
|
|
{
|
|
if (mCompositableBackendData) {
|
|
mCompositableBackendData->SetCompositor(mCompositor);
|
|
return static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->GetTexture();
|
|
}
|
|
|
|
return mTexture;
|
|
}
|
|
|
|
void
|
|
GrallocTextureHostOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
|
|
{
|
|
mCompositableBackendData = aBackendData;
|
|
if (mTextureSource) {
|
|
mTextureSource->SetCompositableBackendSpecificData(aBackendData);
|
|
}
|
|
// Register this object to CompositableBackendSpecificData
|
|
// as current TextureHost.
|
|
if (aBackendData) {
|
|
aBackendData->SetCurrentReleaseFenceTexture(this);
|
|
}
|
|
}
|
|
|
|
} // namepsace layers
|
|
} // namepsace mozilla
|