Files
tubestation/gfx/layers/opengl/TextureHostOGL.cpp
Iris Hsiao 3cea13a680 Backed out 11 changesets (bug 1322650) for media test failures on android. a=backout
Backed out changeset 31bd912fba54 (bug 1322650)
Backed out changeset 4d486c7469eb (bug 1322650)
Backed out changeset 4cf8f4d5064c (bug 1322650)
Backed out changeset 3cb108f7492f (bug 1322650)
Backed out changeset bd53533c108e (bug 1322650)
Backed out changeset 3522917d8f10 (bug 1322650)
Backed out changeset 2c2c1e33eccc (bug 1322650)
Backed out changeset 2f19977cd6ab (bug 1322650)
Backed out changeset 4519296a323e (bug 1322650)
Backed out changeset e56e5e1c8786 (bug 1322650)
Backed out changeset 96fe52231b57 (bug 1322650)
2017-05-12 10:21:14 +08:00

741 lines
20 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 "TextureHostOGL.h"
#include "EGLUtils.h"
#include "GLContext.h" // for GLContext, etc
#include "GLLibraryEGL.h" // for GLLibraryEGL
#include "GLUploadHelpers.h"
#include "GLReadTexImageHelper.h"
#include "gfx2DGlue.h" // for ContentForFormat, etc
#include "mozilla/gfx/2D.h" // for DataSourceSurface
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/Logging.h" // for gfxCriticalError
#include "mozilla/layers/ISurfaceAllocator.h"
#include "nsRegion.h" // for nsIntRegion
#include "AndroidSurfaceTexture.h"
#include "GfxTexturesReporter.h" // for GfxTexturesReporter
#include "GLBlitTextureImageHelper.h"
#include "GeckoProfiler.h"
#ifdef XP_MACOSX
#include "mozilla/layers/MacIOSurfaceTextureHostOGL.h"
#endif
#ifdef GL_PROVIDER_GLX
#include "mozilla/layers/X11TextureHost.h"
#endif
using namespace mozilla::gl;
using namespace mozilla::gfx;
namespace mozilla {
namespace layers {
class Compositor;
already_AddRefed<TextureHost>
CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
ISurfaceAllocator* aDeallocator,
LayersBackend aBackend,
TextureFlags aFlags)
{
RefPtr<TextureHost> result;
switch (aDesc.type()) {
case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
result = CreateBackendIndependentTextureHost(aDesc,
aDeallocator,
aBackend,
aFlags);
break;
}
#ifdef MOZ_WIDGET_ANDROID
case SurfaceDescriptor::TSurfaceTextureDescriptor: {
const SurfaceTextureDescriptor& desc = aDesc.get_SurfaceTextureDescriptor();
result = new SurfaceTextureHost(aFlags,
(AndroidSurfaceTexture*)desc.surfTex(),
desc.size());
break;
}
#endif
case SurfaceDescriptor::TEGLImageDescriptor: {
const EGLImageDescriptor& desc = aDesc.get_EGLImageDescriptor();
result = new EGLImageTextureHost(aFlags,
(EGLImage)desc.image(),
(EGLSync)desc.fence(),
desc.size(),
desc.hasAlpha());
break;
}
#ifdef XP_MACOSX
case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
const SurfaceDescriptorMacIOSurface& desc =
aDesc.get_SurfaceDescriptorMacIOSurface();
result = new MacIOSurfaceTextureHostOGL(aFlags, desc);
break;
}
#endif
#ifdef GL_PROVIDER_GLX
case SurfaceDescriptor::TSurfaceDescriptorX11: {
const auto& desc = aDesc.get_SurfaceDescriptorX11();
result = new X11TextureHost(aFlags, desc);
break;
}
#endif
case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture: {
const auto& desc = aDesc.get_SurfaceDescriptorSharedGLTexture();
result = new GLTextureHost(aFlags, desc.texture(),
desc.target(),
(GLsync)desc.fence(),
desc.size(),
desc.hasAlpha());
break;
}
default: return nullptr;
}
return result.forget();
}
static gl::TextureImage::Flags
FlagsToGLFlags(TextureFlags aFlags)
{
uint32_t result = TextureImage::NoFlags;
if (aFlags & TextureFlags::USE_NEAREST_FILTER)
result |= TextureImage::UseNearestFilter;
if (aFlags & TextureFlags::ORIGIN_BOTTOM_LEFT)
result |= TextureImage::OriginBottomLeft;
if (aFlags & TextureFlags::DISALLOW_BIGIMAGE)
result |= TextureImage::DisallowBigImage;
return static_cast<gl::TextureImage::Flags>(result);
}
bool
TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
nsIntRegion* aDestRegion,
gfx::IntPoint* aSrcOffset)
{
GLContext *gl = mGL;
MOZ_ASSERT(gl);
if (!gl || !gl->MakeCurrent()) {
NS_WARNING("trying to update TextureImageTextureSourceOGL without a GLContext");
return false;
}
if (!aSurface) {
gfxCriticalError() << "Invalid surface for OGL update";
return false;
}
MOZ_ASSERT(aSurface);
IntSize size = aSurface->GetSize();
if (!mTexImage ||
(mTexImage->GetSize() != size && !aSrcOffset) ||
mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) {
if (mFlags & TextureFlags::DISALLOW_BIGIMAGE) {
GLint maxTextureSize;
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTextureSize);
if (size.width > maxTextureSize || size.height > maxTextureSize) {
NS_WARNING("Texture exceeds maximum texture size, refusing upload");
return false;
}
// Explicitly use CreateBasicTextureImage instead of CreateTextureImage,
// because CreateTextureImage might still choose to create a tiled
// texture image.
mTexImage = CreateBasicTextureImage(gl, size,
gfx::ContentForFormat(aSurface->GetFormat()),
LOCAL_GL_CLAMP_TO_EDGE,
FlagsToGLFlags(mFlags));
} else {
// XXX - clarify which size we want to use. IncrementalContentHost will
// require the size of the destination surface to be different from
// the size of aSurface.
// See bug 893300 (tracks the implementation of ContentHost for new textures).
mTexImage = CreateTextureImage(gl,
size,
gfx::ContentForFormat(aSurface->GetFormat()),
LOCAL_GL_CLAMP_TO_EDGE,
FlagsToGLFlags(mFlags),
SurfaceFormatToImageFormat(aSurface->GetFormat()));
}
ClearCachedFilter();
if (aDestRegion &&
!aSrcOffset &&
!aDestRegion->IsEqual(gfx::IntRect(0, 0, size.width, size.height))) {
// UpdateFromDataSource will ignore our specified aDestRegion since the texture
// hasn't been allocated with glTexImage2D yet. Call Resize() to force the
// allocation (full size, but no upload), and then we'll only upload the pixels
// we care about below.
mTexImage->Resize(size);
}
}
mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset);
return true;
}
void
TextureImageTextureSourceOGL::EnsureBuffer(const IntSize& aSize,
gfxContentType aContentType)
{
if (!mTexImage ||
mTexImage->GetSize() != aSize ||
mTexImage->GetContentType() != aContentType) {
mTexImage = CreateTextureImage(mGL,
aSize,
aContentType,
LOCAL_GL_CLAMP_TO_EDGE,
FlagsToGLFlags(mFlags));
}
mTexImage->Resize(aSize);
}
void
TextureImageTextureSourceOGL::SetTextureSourceProvider(TextureSourceProvider* aProvider)
{
GLContext* newGL = aProvider ? aProvider->GetGLContext() : nullptr;
if (!newGL || mGL != newGL) {
DeallocateDeviceData();
}
mGL = newGL;
}
gfx::IntSize
TextureImageTextureSourceOGL::GetSize() const
{
if (mTexImage) {
if (mIterating) {
return mTexImage->GetTileRect().Size();
}
return mTexImage->GetSize();
}
NS_WARNING("Trying to query the size of an empty TextureSource.");
return gfx::IntSize(0, 0);
}
gfx::SurfaceFormat
TextureImageTextureSourceOGL::GetFormat() const
{
if (mTexImage) {
return mTexImage->GetTextureFormat();
}
NS_WARNING("Trying to query the format of an empty TextureSource.");
return gfx::SurfaceFormat::UNKNOWN;
}
gfx::IntRect TextureImageTextureSourceOGL::GetTileRect()
{
return mTexImage->GetTileRect();
}
void
TextureImageTextureSourceOGL::BindTexture(GLenum aTextureUnit,
gfx::SamplingFilter aSamplingFilter)
{
MOZ_ASSERT(mTexImage,
"Trying to bind a TextureSource that does not have an underlying GL texture.");
mTexImage->BindTexture(aTextureUnit);
SetSamplingFilter(mGL, aSamplingFilter);
}
////////////////////////////////////////////////////////////////////////
// GLTextureSource
GLTextureSource::GLTextureSource(TextureSourceProvider* aProvider,
GLuint aTextureHandle,
GLenum aTarget,
gfx::IntSize aSize,
gfx::SurfaceFormat aFormat,
bool aExternallyOwned)
: mGL(aProvider->GetGLContext())
, mTextureHandle(aTextureHandle)
, mTextureTarget(aTarget)
, mSize(aSize)
, mFormat(aFormat)
, mExternallyOwned(aExternallyOwned)
{
MOZ_COUNT_CTOR(GLTextureSource);
}
GLTextureSource::~GLTextureSource()
{
MOZ_COUNT_DTOR(GLTextureSource);
if (!mExternallyOwned) {
DeleteTextureHandle();
}
}
void
GLTextureSource::DeallocateDeviceData()
{
if (!mExternallyOwned) {
DeleteTextureHandle();
}
}
void
GLTextureSource::DeleteTextureHandle()
{
GLContext* gl = this->gl();
if (mTextureHandle != 0 && gl && gl->MakeCurrent()) {
gl->fDeleteTextures(1, &mTextureHandle);
}
mTextureHandle = 0;
}
void
GLTextureSource::BindTexture(GLenum aTextureUnit,
gfx::SamplingFilter aSamplingFilter)
{
MOZ_ASSERT(mTextureHandle != 0);
GLContext* gl = this->gl();
if (!gl || !gl->MakeCurrent()) {
return;
}
gl->fActiveTexture(aTextureUnit);
gl->fBindTexture(mTextureTarget, mTextureHandle);
ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget);
}
void
GLTextureSource::SetTextureSourceProvider(TextureSourceProvider* aProvider)
{
GLContext* newGL = aProvider ? aProvider->GetGLContext() : nullptr;
if (!newGL) {
mGL = newGL;
} else if (mGL != newGL) {
gfxCriticalError() << "GLTextureSource does not support changing compositors";
}
if (mNextSibling) {
mNextSibling->SetTextureSourceProvider(aProvider);
}
}
bool
GLTextureSource::IsValid() const
{
return !!gl() && mTextureHandle != 0;
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// SurfaceTextureHost
#ifdef MOZ_WIDGET_ANDROID
SurfaceTextureSource::SurfaceTextureSource(TextureSourceProvider* aProvider,
AndroidSurfaceTexture* aSurfTex,
gfx::SurfaceFormat aFormat,
GLenum aTarget,
GLenum aWrapMode,
gfx::IntSize aSize)
: mGL(aProvider->GetGLContext())
, mSurfTex(aSurfTex)
, mFormat(aFormat)
, mTextureTarget(aTarget)
, mWrapMode(aWrapMode)
, mSize(aSize)
{
}
void
SurfaceTextureSource::BindTexture(GLenum aTextureUnit,
gfx::SamplingFilter aSamplingFilter)
{
MOZ_ASSERT(mSurfTex);
GLContext* gl = this->gl();
if (!gl || !gl->MakeCurrent()) {
NS_WARNING("Trying to bind a texture without a GLContext");
return;
}
gl->fActiveTexture(aTextureUnit);
// SurfaceTexture spams us if there are any existing GL errors, so
// we'll clear them here in order to avoid that.
gl->FlushErrors();
mSurfTex->UpdateTexImage();
ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget);
}
void
SurfaceTextureSource::SetTextureSourceProvider(TextureSourceProvider* aProvider)
{
GLContext* newGL = aProvider->GetGLContext();
if (!newGL || mGL != newGL) {
DeallocateDeviceData();
return;
}
mGL = newGL;
}
bool
SurfaceTextureSource::IsValid() const
{
return !!gl();
}
gfx::Matrix4x4
SurfaceTextureSource::GetTextureTransform()
{
MOZ_ASSERT(mSurfTex);
gfx::Matrix4x4 ret;
mSurfTex->GetTransformMatrix(ret);
return ret;
}
void
SurfaceTextureSource::DeallocateDeviceData()
{
mSurfTex = nullptr;
}
////////////////////////////////////////////////////////////////////////
SurfaceTextureHost::SurfaceTextureHost(TextureFlags aFlags,
AndroidSurfaceTexture* aSurfTex,
gfx::IntSize aSize)
: TextureHost(aFlags)
, mSurfTex(aSurfTex)
, mSize(aSize)
{
}
SurfaceTextureHost::~SurfaceTextureHost()
{
}
gl::GLContext*
SurfaceTextureHost::gl() const
{
return mProvider ? mProvider->GetGLContext() : nullptr;
}
bool
SurfaceTextureHost::Lock()
{
MOZ_ASSERT(mSurfTex);
GLContext* gl = this->gl();
if (!gl || !gl->MakeCurrent()) {
return false;
}
if (!mTextureSource) {
gfx::SurfaceFormat format = gfx::SurfaceFormat::R8G8B8A8;
GLenum target = LOCAL_GL_TEXTURE_EXTERNAL;
GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
mTextureSource = new SurfaceTextureSource(mProvider,
mSurfTex,
format,
target,
wrapMode,
mSize);
}
return NS_SUCCEEDED(mSurfTex->Attach(gl));
}
void
SurfaceTextureHost::Unlock()
{
MOZ_ASSERT(mSurfTex);
mSurfTex->Detach();
}
void
SurfaceTextureHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
{
if (mProvider != aProvider) {
if (!aProvider || !aProvider->GetGLContext()) {
DeallocateDeviceData();
return;
}
mProvider = aProvider;
}
if (mTextureSource) {
mTextureSource->SetTextureSourceProvider(aProvider);
}
}
gfx::SurfaceFormat
SurfaceTextureHost::GetFormat() const
{
return mTextureSource ? mTextureSource->GetFormat() : gfx::SurfaceFormat::UNKNOWN;
}
void
SurfaceTextureHost::DeallocateDeviceData()
{
if (mTextureSource) {
mTextureSource->DeallocateDeviceData();
}
mSurfTex = nullptr;
}
#endif // MOZ_WIDGET_ANDROID
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// EGLImage
EGLImageTextureSource::EGLImageTextureSource(TextureSourceProvider* aProvider,
EGLImage aImage,
gfx::SurfaceFormat aFormat,
GLenum aTarget,
GLenum aWrapMode,
gfx::IntSize aSize)
: mImage(aImage)
, mFormat(aFormat)
, mTextureTarget(aTarget)
, mWrapMode(aWrapMode)
, mSize(aSize)
{
MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D ||
mTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL);
SetTextureSourceProvider(aProvider);
}
void
EGLImageTextureSource::BindTexture(GLenum aTextureUnit,
gfx::SamplingFilter aSamplingFilter)
{
GLContext* gl = this->gl();
if (!gl || !gl->MakeCurrent()) {
NS_WARNING("Trying to bind a texture without a GLContext");
return;
}
MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl),
"EGLImage not supported or disabled in runtime");
GLuint tex = mCompositor->GetTemporaryTexture(mTextureTarget, aTextureUnit);
gl->fActiveTexture(aTextureUnit);
gl->fBindTexture(mTextureTarget, tex);
gl->fEGLImageTargetTexture2D(mTextureTarget, mImage);
ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget);
}
void
EGLImageTextureSource::SetTextureSourceProvider(TextureSourceProvider* aProvider)
{
if (mCompositor == aProvider) {
return;
}
if (!aProvider) {
mGL = nullptr;
mCompositor = nullptr;
return;
}
mGL = aProvider->GetGLContext();
if (Compositor* compositor = aProvider->AsCompositor()) {
mCompositor = compositor->AsCompositorOGL();
}
}
bool
EGLImageTextureSource::IsValid() const
{
return !!gl();
}
gfx::Matrix4x4
EGLImageTextureSource::GetTextureTransform()
{
gfx::Matrix4x4 ret;
return ret;
}
////////////////////////////////////////////////////////////////////////
EGLImageTextureHost::EGLImageTextureHost(TextureFlags aFlags,
EGLImage aImage,
EGLSync aSync,
gfx::IntSize aSize,
bool hasAlpha)
: TextureHost(aFlags)
, mImage(aImage)
, mSync(aSync)
, mSize(aSize)
, mHasAlpha(hasAlpha)
{}
EGLImageTextureHost::~EGLImageTextureHost()
{}
gl::GLContext*
EGLImageTextureHost::gl() const
{
return mProvider ? mProvider ->GetGLContext() : nullptr;
}
bool
EGLImageTextureHost::Lock()
{
GLContext* gl = this->gl();
if (!gl || !gl->MakeCurrent()) {
return false;
}
EGLint status = LOCAL_EGL_CONDITION_SATISFIED;
if (mSync) {
MOZ_ASSERT(sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync));
status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSync, 0, LOCAL_EGL_FOREVER);
}
if (status != LOCAL_EGL_CONDITION_SATISFIED) {
MOZ_ASSERT(status != 0,
"ClientWaitSync generated an error. Has mSync already been destroyed?");
return false;
}
if (!mTextureSource) {
gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8
: gfx::SurfaceFormat::R8G8B8X8;
GLenum target = gl->GetPreferredEGLImageTextureTarget();
GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
mTextureSource = new EGLImageTextureSource(mProvider,
mImage,
format,
target,
wrapMode,
mSize);
}
return true;
}
void
EGLImageTextureHost::Unlock()
{
}
void
EGLImageTextureHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
{
if (mProvider != aProvider) {
if (!aProvider || !aProvider->GetGLContext()) {
mProvider = nullptr;
mTextureSource = nullptr;
return;
}
mProvider = aProvider;
}
if (mTextureSource) {
mTextureSource->SetTextureSourceProvider(aProvider);
}
}
gfx::SurfaceFormat
EGLImageTextureHost::GetFormat() const
{
MOZ_ASSERT(mTextureSource);
return mTextureSource ? mTextureSource->GetFormat() : gfx::SurfaceFormat::UNKNOWN;
}
//
GLTextureHost::GLTextureHost(TextureFlags aFlags,
GLuint aTextureHandle,
GLenum aTarget,
GLsync aSync,
gfx::IntSize aSize,
bool aHasAlpha)
: TextureHost(aFlags)
, mTexture(aTextureHandle)
, mTarget(aTarget)
, mSync(aSync)
, mSize(aSize)
, mHasAlpha(aHasAlpha)
{}
GLTextureHost::~GLTextureHost()
{}
gl::GLContext*
GLTextureHost::gl() const
{
return mProvider ? mProvider->GetGLContext() : nullptr;
}
bool
GLTextureHost::Lock()
{
GLContext* gl = this->gl();
if (!gl || !gl->MakeCurrent()) {
return false;
}
if (mSync) {
if (!gl->MakeCurrent()) {
return false;
}
gl->fWaitSync(mSync, 0, LOCAL_GL_TIMEOUT_IGNORED);
gl->fDeleteSync(mSync);
mSync = 0;
}
if (!mTextureSource) {
gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8
: gfx::SurfaceFormat::R8G8B8X8;
mTextureSource = new GLTextureSource(mProvider,
mTexture,
mTarget,
mSize,
format,
false /* owned by the client */);
}
return true;
}
void
GLTextureHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
{
if (mProvider != aProvider) {
if (!aProvider || !aProvider->GetGLContext()) {
mProvider = nullptr;
mTextureSource = nullptr;
return;
}
mProvider = aProvider;
}
if (mTextureSource) {
mTextureSource->SetTextureSourceProvider(aProvider);
}
}
gfx::SurfaceFormat
GLTextureHost::GetFormat() const
{
MOZ_ASSERT(mTextureSource);
return mTextureSource ? mTextureSource->GetFormat() : gfx::SurfaceFormat::UNKNOWN;
}
} // namespace layers
} // namespace mozilla