diff -r 000000000000 -r 6474c204b198 gfx/layers/opengl/TextureHostOGL.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/layers/opengl/TextureHostOGL.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,668 @@ +/* -*- 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 "GLContext.h" // for GLContext, etc +#include "GLSharedHandleHelpers.h" +#include "GLUploadHelpers.h" +#include "GLReadTexImageHelper.h" +#include "SharedSurface.h" // for SharedSurface +#include "SharedSurfaceEGL.h" // for SharedSurface_EGLImage +#include "SharedSurfaceGL.h" // for SharedSurface_GLTexture, etc +#include "SurfaceStream.h" // for SurfaceStream +#include "SurfaceTypes.h" // for SharedSurfaceType, etc +#include "gfx2DGlue.h" // for ContentForFormat, etc +#include "gfxReusableSurfaceWrapper.h" // for gfxReusableSurfaceWrapper +#include "mozilla/gfx/2D.h" // for DataSourceSurface +#include "mozilla/gfx/BaseSize.h" // for BaseSize +#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL +#ifdef MOZ_WIDGET_GONK +# include "GrallocImages.h" // for GrallocImage +# include "EGLImageHelpers.h" +#endif +#include "mozilla/layers/ISurfaceAllocator.h" +#include "mozilla/layers/YCbCrImageDataSerializer.h" +#include "mozilla/layers/GrallocTextureHost.h" +#include "nsPoint.h" // for nsIntPoint +#include "nsRegion.h" // for nsIntRegion +#include "GfxTexturesReporter.h" // for GfxTexturesReporter +#include "GLBlitTextureImageHelper.h" +#ifdef XP_MACOSX +#include "SharedSurfaceIO.h" +#include "mozilla/layers/MacIOSurfaceTextureHostOGL.h" +#endif +#include "GeckoProfiler.h" + +using namespace mozilla::gl; +using namespace mozilla::gfx; + +namespace mozilla { +namespace layers { + +class Compositor; + +TemporaryRef +CreateCompositableBackendSpecificDataOGL() +{ +#ifdef MOZ_WIDGET_GONK + return new CompositableDataGonkOGL(); +#else + return nullptr; +#endif +} + +TemporaryRef +CreateTextureHostOGL(const SurfaceDescriptor& aDesc, + ISurfaceAllocator* aDeallocator, + TextureFlags aFlags) +{ + RefPtr result; + switch (aDesc.type()) { + case SurfaceDescriptor::TSurfaceDescriptorShmem: + case SurfaceDescriptor::TSurfaceDescriptorMemory: { + result = CreateBackendIndependentTextureHost(aDesc, + aDeallocator, aFlags); + break; + } + case SurfaceDescriptor::TSharedTextureDescriptor: { + const SharedTextureDescriptor& desc = aDesc.get_SharedTextureDescriptor(); + result = new SharedTextureHostOGL(aFlags, + desc.shareType(), + desc.handle(), + desc.size(), + desc.inverted()); + break; + } + case SurfaceDescriptor::TSurfaceStreamDescriptor: { + const SurfaceStreamDescriptor& desc = aDesc.get_SurfaceStreamDescriptor(); + result = new StreamTextureHostOGL(aFlags, desc); + break; + } +#ifdef XP_MACOSX + case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: { + const SurfaceDescriptorMacIOSurface& desc = + aDesc.get_SurfaceDescriptorMacIOSurface(); + result = new MacIOSurfaceTextureHostOGL(aFlags, desc); + break; + } +#endif +#ifdef MOZ_WIDGET_GONK + case SurfaceDescriptor::TNewSurfaceDescriptorGralloc: { + const NewSurfaceDescriptorGralloc& desc = + aDesc.get_NewSurfaceDescriptorGralloc(); + result = new GrallocTextureHostOGL(aFlags, desc); + break; + } +#endif + default: return nullptr; + } + return result.forget(); +} + +static gl::TextureImage::Flags +FlagsToGLFlags(TextureFlags aFlags) +{ + uint32_t result = TextureImage::NoFlags; + + if (aFlags & TEXTURE_USE_NEAREST_FILTER) + result |= TextureImage::UseNearestFilter; + if (aFlags & TEXTURE_NEEDS_Y_FLIP) + result |= TextureImage::NeedsYFlip; + if (aFlags & TEXTURE_DISALLOW_BIGIMAGE) + result |= TextureImage::DisallowBigImage; + + return static_cast(result); +} + +GLenum +WrapMode(gl::GLContext *aGl, bool aAllowRepeat) +{ + if (aAllowRepeat && + (aGl->IsExtensionSupported(GLContext::ARB_texture_non_power_of_two) || + aGl->IsExtensionSupported(GLContext::OES_texture_npot))) { + return LOCAL_GL_REPEAT; + } + return LOCAL_GL_CLAMP_TO_EDGE; +} + +CompositableDataGonkOGL::CompositableDataGonkOGL() + : mTexture(0) +{ +} +CompositableDataGonkOGL::~CompositableDataGonkOGL() +{ + DeleteTextureIfPresent(); +} + +gl::GLContext* +CompositableDataGonkOGL::gl() const +{ + return mCompositor ? mCompositor->gl() : nullptr; +} + +void CompositableDataGonkOGL::SetCompositor(Compositor* aCompositor) +{ + mCompositor = static_cast(aCompositor); +} + +void CompositableDataGonkOGL::ClearData() +{ + CompositableBackendSpecificData::ClearData(); + DeleteTextureIfPresent(); +} + +GLuint CompositableDataGonkOGL::GetTexture() +{ + if (!mTexture) { + if (gl()->MakeCurrent()) { + gl()->fGenTextures(1, &mTexture); + } + } + return mTexture; +} + +void +CompositableDataGonkOGL::DeleteTextureIfPresent() +{ + if (mTexture) { + if (gl()->MakeCurrent()) { + gl()->fDeleteTextures(1, &mTexture); + } + mTexture = 0; + } +} + +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 +bool +TextureHostOGL::SetReleaseFence(const android::sp& aReleaseFence) +{ + if (!aReleaseFence.get() || !aReleaseFence->isValid()) { + // HWC might not provide Fence. + // In this case, HWC implicitly handles buffer's fence. + return false; + } + + if (!mReleaseFence.get()) { + mReleaseFence = aReleaseFence; + } else { + android::sp mergedFence = android::Fence::merge( + android::String8::format("TextureHostOGL"), + mReleaseFence, aReleaseFence); + if (!mergedFence.get()) { + // synchronization is broken, the best we can do is hope fences + // signal in order so the new fence will act like a union. + // This error handling is same as android::ConsumerBase does. + mReleaseFence = aReleaseFence; + return false; + } + mReleaseFence = mergedFence; + } + return true; +} + +android::sp +TextureHostOGL::GetAndResetReleaseFence() +{ + // Hold previous ReleaseFence to prevent Fence delivery failure via gecko IPC. + mPrevReleaseFence = mReleaseFence; + // Reset current ReleaseFence. + mReleaseFence = android::Fence::NO_FENCE; + return mPrevReleaseFence; +} +#endif + +bool +TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface, + nsIntRegion* aDestRegion, + gfx::IntPoint* aSrcOffset) +{ + MOZ_ASSERT(mGL); + if (!mGL) { + NS_WARNING("trying to update TextureImageTextureSourceOGL without a GLContext"); + return false; + } + MOZ_ASSERT(aSurface); + + IntSize size = aSurface->GetSize(); + if (!mTexImage || + (mTexImage->GetSize() != size && !aSrcOffset) || + mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) { + if (mFlags & TEXTURE_DISALLOW_BIGIMAGE) { + mTexImage = CreateBasicTextureImage(mGL, size, + gfx::ContentForFormat(aSurface->GetFormat()), + WrapMode(mGL, mFlags & TEXTURE_ALLOW_REPEAT), + FlagsToGLFlags(mFlags), + SurfaceFormatToImageFormat(aSurface->GetFormat())); + } 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(mGL, + size, + gfx::ContentForFormat(aSurface->GetFormat()), + WrapMode(mGL, mFlags & TEXTURE_ALLOW_REPEAT), + FlagsToGLFlags(mFlags), + SurfaceFormatToImageFormat(aSurface->GetFormat())); + } + ClearCachedFilter(); + } + + mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset); + + if (mTexImage->InUpdate()) { + mTexImage->EndUpdate(); + } + return true; +} + +void +TextureImageTextureSourceOGL::EnsureBuffer(const nsIntSize& aSize, + gfxContentType aContentType) +{ + if (!mTexImage || + mTexImage->GetSize() != aSize.ToIntSize() || + mTexImage->GetContentType() != aContentType) { + mTexImage = CreateTextureImage(mGL, + aSize.ToIntSize(), + aContentType, + WrapMode(mGL, mFlags & TEXTURE_ALLOW_REPEAT), + FlagsToGLFlags(mFlags)); + } + mTexImage->Resize(aSize.ToIntSize()); +} + +void +TextureImageTextureSourceOGL::CopyTo(const nsIntRect& aSourceRect, + DataTextureSource *aDest, + const nsIntRect& aDestRect) +{ + MOZ_ASSERT(aDest->AsSourceOGL(), "Incompatible destination type!"); + TextureImageTextureSourceOGL *dest = + aDest->AsSourceOGL()->AsTextureImageTextureSource(); + MOZ_ASSERT(dest, "Incompatible destination type!"); + + mGL->BlitTextureImageHelper()->BlitTextureImage(mTexImage, aSourceRect, + dest->mTexImage, aDestRect); + dest->mTexImage->MarkValid(); +} + +void +TextureImageTextureSourceOGL::SetCompositor(Compositor* aCompositor) +{ + CompositorOGL* glCompositor = static_cast(aCompositor); + + if (!glCompositor || (mGL != glCompositor->gl())) { + DeallocateDeviceData(); + mGL = glCompositor ? glCompositor->gl() : nullptr; + } +} + +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; +} + +nsIntRect TextureImageTextureSourceOGL::GetTileRect() +{ + return ThebesIntRect(mTexImage->GetTileRect()); +} + +void +TextureImageTextureSourceOGL::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter) +{ + MOZ_ASSERT(mTexImage, + "Trying to bind a TextureSource that does not have an underlying GL texture."); + mTexImage->BindTexture(aTextureUnit); + SetFilter(mGL, aFilter); +} + +SharedTextureSourceOGL::SharedTextureSourceOGL(CompositorOGL* aCompositor, + gl::SharedTextureHandle aHandle, + gfx::SurfaceFormat aFormat, + GLenum aTarget, + GLenum aWrapMode, + SharedTextureShareType aShareType, + gfx::IntSize aSize) + : mSize(aSize) + , mCompositor(aCompositor) + , mSharedHandle(aHandle) + , mFormat(aFormat) + , mShareType(aShareType) + , mTextureTarget(aTarget) + , mWrapMode(aWrapMode) +{} + +void +SharedTextureSourceOGL::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter) +{ + if (!gl()) { + NS_WARNING("Trying to bind a texture without a GLContext"); + return; + } + GLuint tex = mCompositor->GetTemporaryTexture(GetTextureTarget(), aTextureUnit); + + gl()->fActiveTexture(aTextureUnit); + gl()->fBindTexture(mTextureTarget, tex); + if (!AttachSharedHandle(gl(), mShareType, mSharedHandle)) { + NS_ERROR("Failed to bind shared texture handle"); + return; + } + ApplyFilterToBoundTexture(gl(), aFilter, mTextureTarget); +} + +void +SharedTextureSourceOGL::DetachSharedHandle() +{ + if (!gl()) { + return; + } + gl::DetachSharedHandle(gl(), mShareType, mSharedHandle); +} + +void +SharedTextureSourceOGL::SetCompositor(Compositor* aCompositor) +{ + mCompositor = static_cast(aCompositor); +} + +bool +SharedTextureSourceOGL::IsValid() const +{ + return !!gl(); +} + +gl::GLContext* +SharedTextureSourceOGL::gl() const +{ + return mCompositor ? mCompositor->gl() : nullptr; +} + +gfx::Matrix4x4 +SharedTextureSourceOGL::GetTextureTransform() +{ + SharedHandleDetails handleDetails; + if (!GetSharedHandleDetails(gl(), mShareType, mSharedHandle, handleDetails)) { + NS_WARNING("Could not get shared handle details"); + return gfx::Matrix4x4(); + } + + return handleDetails.mTextureTransform; +} + +SharedTextureHostOGL::SharedTextureHostOGL(TextureFlags aFlags, + gl::SharedTextureShareType aShareType, + gl::SharedTextureHandle aSharedHandle, + gfx::IntSize aSize, + bool inverted) + : TextureHost(aFlags) + , mSize(aSize) + , mCompositor(nullptr) + , mSharedHandle(aSharedHandle) + , mShareType(aShareType) +{ +} + +SharedTextureHostOGL::~SharedTextureHostOGL() +{ + // If need to deallocate textures, call DeallocateSharedData() before + // the destructor +} + +gl::GLContext* +SharedTextureHostOGL::gl() const +{ + return mCompositor ? mCompositor->gl() : nullptr; +} + +bool +SharedTextureHostOGL::Lock() +{ + if (!mCompositor) { + return false; + } + + if (!mTextureSource) { + // XXX on android GetSharedHandleDetails can call into Java which we'd + // rather not do from the compositor + SharedHandleDetails handleDetails; + if (!GetSharedHandleDetails(gl(), mShareType, mSharedHandle, handleDetails)) { + NS_WARNING("Could not get shared handle details"); + return false; + } + + GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE; + mTextureSource = new SharedTextureSourceOGL(mCompositor, + mSharedHandle, + handleDetails.mTextureFormat, + handleDetails.mTarget, + wrapMode, + mShareType, + mSize); + } + return true; +} + +void +SharedTextureHostOGL::Unlock() +{ + if (!mTextureSource) { + return; + } + mTextureSource->DetachSharedHandle(); +} + +void +SharedTextureHostOGL::SetCompositor(Compositor* aCompositor) +{ + CompositorOGL* glCompositor = static_cast(aCompositor); + mCompositor = glCompositor; + if (mTextureSource) { + mTextureSource->SetCompositor(glCompositor); + } +} + +gfx::SurfaceFormat +SharedTextureHostOGL::GetFormat() const +{ + MOZ_ASSERT(mTextureSource); + return mTextureSource->GetFormat(); +} + +void +StreamTextureSourceOGL::BindTexture(GLenum activetex, gfx::Filter aFilter) +{ + MOZ_ASSERT(gl()); + gl()->fActiveTexture(activetex); + gl()->fBindTexture(mTextureTarget, mTextureHandle); + SetFilter(gl(), aFilter); +} + +bool +StreamTextureSourceOGL::RetrieveTextureFromStream() +{ + gl()->MakeCurrent(); + + SharedSurface* sharedSurf = mStream->SwapConsumer(); + if (!sharedSurf) { + // We don't have a valid surf to show yet. + return false; + } + + gl()->MakeCurrent(); + + mSize = IntSize(sharedSurf->Size().width, sharedSurf->Size().height); + + DataSourceSurface* toUpload = nullptr; + switch (sharedSurf->Type()) { + case SharedSurfaceType::GLTextureShare: { + SharedSurface_GLTexture* glTexSurf = SharedSurface_GLTexture::Cast(sharedSurf); + mTextureHandle = glTexSurf->ConsTexture(gl()); + mTextureTarget = glTexSurf->ConsTextureTarget(); + MOZ_ASSERT(mTextureHandle); + mFormat = sharedSurf->HasAlpha() ? SurfaceFormat::R8G8B8A8 + : SurfaceFormat::R8G8B8X8; + break; + } + case SharedSurfaceType::EGLImageShare: { + SharedSurface_EGLImage* eglImageSurf = + SharedSurface_EGLImage::Cast(sharedSurf); + + eglImageSurf->AcquireConsumerTexture(gl(), &mTextureHandle, &mTextureTarget); + MOZ_ASSERT(mTextureHandle); + mFormat = sharedSurf->HasAlpha() ? SurfaceFormat::R8G8B8A8 + : SurfaceFormat::R8G8B8X8; + break; + } +#ifdef XP_MACOSX + case SharedSurfaceType::IOSurface: { + SharedSurface_IOSurface* glTexSurf = SharedSurface_IOSurface::Cast(sharedSurf); + mTextureHandle = glTexSurf->ConsTexture(gl()); + mTextureTarget = glTexSurf->ConsTextureTarget(); + MOZ_ASSERT(mTextureHandle); + mFormat = sharedSurf->HasAlpha() ? SurfaceFormat::R8G8B8A8 + : SurfaceFormat::R8G8B8X8; + break; + } +#endif + case SharedSurfaceType::Basic: { + toUpload = SharedSurface_Basic::Cast(sharedSurf)->GetData(); + MOZ_ASSERT(toUpload); + break; + } + default: + MOZ_CRASH("Invalid SharedSurface type."); + } + + if (toUpload) { + // mBounds seems to end up as (0,0,0,0) a lot, so don't use it? + nsIntSize size(ThebesIntSize(toUpload->GetSize())); + nsIntRect rect(nsIntPoint(0,0), size); + nsIntRegion bounds(rect); + mFormat = UploadSurfaceToTexture(gl(), + toUpload, + bounds, + mUploadTexture, + true); + mTextureHandle = mUploadTexture; + mTextureTarget = LOCAL_GL_TEXTURE_2D; + } + + MOZ_ASSERT(mTextureHandle); + gl()->fBindTexture(mTextureTarget, mTextureHandle); + gl()->fTexParameteri(mTextureTarget, + LOCAL_GL_TEXTURE_WRAP_S, + LOCAL_GL_CLAMP_TO_EDGE); + gl()->fTexParameteri(mTextureTarget, + LOCAL_GL_TEXTURE_WRAP_T, + LOCAL_GL_CLAMP_TO_EDGE); + + ClearCachedFilter(); + + return true; +} + +void +StreamTextureSourceOGL::DeallocateDeviceData() +{ + if (mUploadTexture) { + MOZ_ASSERT(gl()); + gl()->MakeCurrent(); + gl()->fDeleteTextures(1, &mUploadTexture); + mUploadTexture = 0; + mTextureHandle = 0; + } +} + +gl::GLContext* +StreamTextureSourceOGL::gl() const +{ + return mCompositor ? mCompositor->gl() : nullptr; +} + +void +StreamTextureSourceOGL::SetCompositor(Compositor* aCompositor) +{ + mCompositor = static_cast(aCompositor); +} + +StreamTextureHostOGL::StreamTextureHostOGL(TextureFlags aFlags, + const SurfaceStreamDescriptor& aDesc) + : TextureHost(aFlags) +{ + mStream = SurfaceStream::FromHandle(aDesc.handle()); + MOZ_ASSERT(mStream); +} + +StreamTextureHostOGL::~StreamTextureHostOGL() +{ + // If need to deallocate textures, call DeallocateSharedData() before + // the destructor +} + +bool +StreamTextureHostOGL::Lock() +{ + if (!mCompositor) { + return false; + } + + if (!mTextureSource) { + mTextureSource = new StreamTextureSourceOGL(mCompositor, + mStream); + } + + return mTextureSource->RetrieveTextureFromStream(); +} + +void +StreamTextureHostOGL::Unlock() +{ +} + +void +StreamTextureHostOGL::SetCompositor(Compositor* aCompositor) +{ + CompositorOGL* glCompositor = static_cast(aCompositor); + mCompositor = glCompositor; + if (mTextureSource) { + mTextureSource->SetCompositor(glCompositor); + } +} + +gfx::SurfaceFormat +StreamTextureHostOGL::GetFormat() const +{ + MOZ_ASSERT(mTextureSource); + return mTextureSource->GetFormat(); +} + +gfx::IntSize +StreamTextureHostOGL::GetSize() const +{ + MOZ_ASSERT(mTextureSource); + return mTextureSource->GetSize(); +} + +} // namespace +} // namespace