mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-10 17:24:29 +00:00
Bug 1092294 - Use SurfaceTextures for painted content on android (preffed off). r=nical,snorp
Add a new TextureClientData type, AndroidNativeWindowTextureData, backed by a SurfaceTexture in single-buffer mode. It uses the NativeWindow API, which provides producer-side access to the buffer. This provides a DrawTarget which can be used to paint directly in to the SurfaceTexture, which can then be composited using a SurfaceTextureHost. Due to API restrictions it is not possible to read from a NativeWindow while the corresponding SurfaceTexture has ownership of the buffer. TiledContentClient now handles that by painting the additional region that it cannot copy from the front buffer, if required. MozReview-Commit-ID: 1NZq6MQqwFq --HG-- extra : rebase_source : 9d1db721d4892f3df033d43127489a85421e8863
This commit is contained in:
parent
8c8b85caa1
commit
21b5b6db95
@ -274,7 +274,12 @@ SharedSurface_SurfaceTexture::WaitForBufferOwnership()
|
||||
bool
|
||||
SharedSurface_SurfaceTexture::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
|
||||
{
|
||||
*out_descriptor = layers::SurfaceTextureDescriptor(mSurface->GetHandle(), mSize, false /* NOT continuous */);
|
||||
*out_descriptor =
|
||||
layers::SurfaceTextureDescriptor(mSurface->GetHandle(),
|
||||
mSize,
|
||||
gfx::SurfaceFormat::R8G8B8A8,
|
||||
false /* NOT continuous */,
|
||||
false /* Do not ignore transform */);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -151,6 +151,15 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
extraPainted,
|
||||
&backBufferOnWhite);
|
||||
|
||||
// Mark the area we need to paint in the back buffer as invalid in the
|
||||
// front buffer as they will become out of sync.
|
||||
mTile.mInvalidFront.OrWith(tileDirtyRegion);
|
||||
|
||||
// Add backbuffer's invalid region to the dirty region to be painted.
|
||||
// This will be empty if we were able to copy from the front in to the back.
|
||||
paintRegion.OrWith(mTile.mInvalidBack.MovedBy(mTilingOrigin));
|
||||
tileDirtyRegion.OrWith(mTile.mInvalidBack);
|
||||
|
||||
mTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(extraPainted.GetBounds());
|
||||
|
||||
extraPainted.MoveBy(mTilingOrigin);
|
||||
@ -198,26 +207,26 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
|
||||
discardedFrontBuffer->CopyToTextureClient(backBuffer, &rect, &dest);
|
||||
}
|
||||
}
|
||||
|
||||
if (discardedFrontBufferOnWhite && backBufferOnWhite) {
|
||||
TextureClientAutoLock frontOnWhiteLock(discardedFrontBufferOnWhite,
|
||||
OpenMode::OPEN_READ);
|
||||
if (frontOnWhiteLock.Succeeded()) {
|
||||
for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
|
||||
const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
|
||||
if (discardedFrontBufferOnWhite && backBufferOnWhite) {
|
||||
TextureClientAutoLock frontOnWhiteLock(discardedFrontBufferOnWhite,
|
||||
OpenMode::OPEN_READ);
|
||||
if (frontOnWhiteLock.Succeeded()) {
|
||||
for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
|
||||
const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
|
||||
|
||||
discardedFrontBufferOnWhite->CopyToTextureClient(backBufferOnWhite,
|
||||
&rect, &dest);
|
||||
discardedFrontBufferOnWhite->CopyToTextureClient(backBufferOnWhite,
|
||||
&rect, &dest);
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str());
|
||||
|
||||
// We don't need to repaint valid content that was just copied.
|
||||
paintRegion.SubOut(copyableRegion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str());
|
||||
|
||||
// We don't need to repaint valid content that was just copied.
|
||||
paintRegion.SubOut(copyableRegion);
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,10 +246,6 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
|
||||
}
|
||||
|
||||
// Mark the area we just drew into the back buffer as invalid in the front buffer as they're
|
||||
// now out of sync.
|
||||
mTile.mInvalidFront.OrWith(tileDirtyRegion);
|
||||
|
||||
// The new buffer is now validated, remove the dirty region from it.
|
||||
mTile.mInvalidBack.SubOut(tileDirtyRegion);
|
||||
|
||||
|
@ -502,8 +502,11 @@ TextureClient::Lock(OpenMode aMode)
|
||||
return mOpenMode == aMode;
|
||||
}
|
||||
|
||||
if (aMode & OpenMode::OPEN_WRITE && !TryReadLock()) {
|
||||
NS_WARNING("Attempt to Lock a texture that is being read by the compositor!");
|
||||
if ((aMode & OpenMode::OPEN_WRITE || !mInfo.canConcurrentlyReadLock) && !TryReadLock()) {
|
||||
// Only warn if attempting to write. Attempting to read is acceptable usage.
|
||||
if (aMode & OpenMode::OPEN_WRITE) {
|
||||
NS_WARNING("Attempt to Lock a texture that is being read by the compositor!");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -594,6 +597,10 @@ TextureClient::EnableReadLock()
|
||||
bool
|
||||
TextureClient::SerializeReadLock(ReadLockDescriptor& aDescriptor)
|
||||
{
|
||||
if (mData) {
|
||||
mData->OnForwardedToHost();
|
||||
}
|
||||
|
||||
if (mReadLock && mUpdated) {
|
||||
// Take a read lock on behalf of the TextureHost. The latter will unlock
|
||||
// after the shared data is available again for drawing.
|
||||
@ -1124,6 +1131,12 @@ TextureClient::CreateForDrawing(TextureForwarder* aAllocator,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
if (!data && gfxPrefs::UseSurfaceTextureTextures()) {
|
||||
data = AndroidNativeWindowTextureData::Create(aSize, aFormat);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (data) {
|
||||
return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
|
||||
}
|
||||
|
@ -236,6 +236,7 @@ public:
|
||||
bool hasSynchronization;
|
||||
bool supportsMoz2D;
|
||||
bool canExposeMappedData;
|
||||
bool canConcurrentlyReadLock;
|
||||
|
||||
Info()
|
||||
: format(gfx::SurfaceFormat::UNKNOWN)
|
||||
@ -243,6 +244,7 @@ public:
|
||||
, hasSynchronization(false)
|
||||
, supportsMoz2D(false)
|
||||
, canExposeMappedData(false)
|
||||
, canConcurrentlyReadLock(true)
|
||||
{}
|
||||
};
|
||||
|
||||
@ -270,6 +272,8 @@ public:
|
||||
virtual bool Serialize(SurfaceDescriptor& aDescriptor) = 0;
|
||||
virtual void GetSubDescriptor(GPUVideoSubDescriptor* aOutDesc) { }
|
||||
|
||||
virtual void OnForwardedToHost() {}
|
||||
|
||||
virtual TextureData*
|
||||
CreateSimilar(LayersIPCChannel* aAllocator,
|
||||
LayersBackend aLayersBackend,
|
||||
|
@ -480,7 +480,6 @@ CopyFrontToBack(TextureClient* aFront,
|
||||
{
|
||||
TextureClientAutoLock frontLock(aFront, OpenMode::OPEN_READ);
|
||||
if (!frontLock.Succeeded()) {
|
||||
gfxCriticalError() << "[Tiling:Client] Failed to lock the tile's front buffer";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -524,14 +523,14 @@ TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
|
||||
// region, but we can reevaluate this if it becomes an issue.
|
||||
const IntRect rectToCopy = regionToCopy.GetBounds();
|
||||
gfx::IntRect gfxRectToCopy(rectToCopy.x, rectToCopy.y, rectToCopy.Width(), rectToCopy.Height());
|
||||
CopyFrontToBack(mFrontBuffer, mBackBuffer, gfxRectToCopy);
|
||||
|
||||
if (mBackBufferOnWhite) {
|
||||
MOZ_ASSERT(mFrontBufferOnWhite);
|
||||
CopyFrontToBack(mFrontBufferOnWhite, mBackBufferOnWhite, gfxRectToCopy);
|
||||
if (CopyFrontToBack(mFrontBuffer, mBackBuffer, gfxRectToCopy)) {
|
||||
if (mBackBufferOnWhite) {
|
||||
MOZ_ASSERT(mFrontBufferOnWhite);
|
||||
if (CopyFrontToBack(mFrontBufferOnWhite, mBackBufferOnWhite, gfxRectToCopy)) {
|
||||
mInvalidBack.SetEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mInvalidBack.SetEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -951,13 +950,15 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
|
||||
|
||||
oldRetainedTiles.Clear();
|
||||
|
||||
if (!aPaintRegion.IsEmpty()) {
|
||||
nsIntRegion paintRegion = aPaintRegion;
|
||||
nsIntRegion dirtyRegion = aDirtyRegion;
|
||||
if (!paintRegion.IsEmpty()) {
|
||||
for (size_t i = 0; i < newTileCount; ++i) {
|
||||
const TileIntPoint tilePosition = newTiles.TilePosition(i);
|
||||
|
||||
IntPoint tileOffset = GetTileOffset(tilePosition);
|
||||
nsIntRegion tileDrawRegion = IntRect(tileOffset, scaledTileSize);
|
||||
tileDrawRegion.AndWith(aPaintRegion);
|
||||
tileDrawRegion.AndWith(paintRegion);
|
||||
|
||||
if (tileDrawRegion.IsEmpty()) {
|
||||
continue;
|
||||
@ -967,6 +968,10 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
|
||||
if (!ValidateTile(tile, GetTileOffset(tilePosition), tileDrawRegion)) {
|
||||
gfxCriticalError() << "ValidateTile failed";
|
||||
}
|
||||
|
||||
// Validating the tile may have required more to be painted.
|
||||
paintRegion.OrWith(tileDrawRegion);
|
||||
dirtyRegion.OrWith(tileDrawRegion);
|
||||
}
|
||||
|
||||
if (!mMoz2DTiles.empty()) {
|
||||
@ -988,7 +993,7 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
|
||||
ctx->SetMatrix(
|
||||
ctx->CurrentMatrix().PreScale(mResolution, mResolution).PreTranslate(ThebesPoint(-mTilingOrigin)));
|
||||
|
||||
mCallback(&mPaintedLayer, ctx, aPaintRegion, aDirtyRegion,
|
||||
mCallback(&mPaintedLayer, ctx, paintRegion, dirtyRegion,
|
||||
DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
|
||||
mMoz2DTiles.clear();
|
||||
// Reset:
|
||||
@ -1015,7 +1020,7 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
|
||||
GetTileSize().width, GetTileSize().height);
|
||||
|
||||
nsIntRegion tileDrawRegion = IntRect(tileOffset, scaledTileSize);
|
||||
tileDrawRegion.AndWith(aPaintRegion);
|
||||
tileDrawRegion.AndWith(paintRegion);
|
||||
|
||||
nsIntRegion tileValidRegion = mValidRegion;
|
||||
tileValidRegion.OrWith(tileDrawRegion);
|
||||
@ -1035,13 +1040,13 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
|
||||
|
||||
mTiles = newTiles;
|
||||
mValidRegion = newValidRegion;
|
||||
mPaintedRegion.OrWith(aPaintRegion);
|
||||
mPaintedRegion.OrWith(paintRegion);
|
||||
}
|
||||
|
||||
bool
|
||||
ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
|
||||
const nsIntPoint& aTileOrigin,
|
||||
const nsIntRegion& aDirtyRegion)
|
||||
nsIntRegion& aDirtyRegion)
|
||||
{
|
||||
AUTO_PROFILER_LABEL("ClientMultiTiledLayerBuffer::ValidateTile", GRAPHICS);
|
||||
|
||||
@ -1074,6 +1079,19 @@ ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
|
||||
extraPainted,
|
||||
&backBufferOnWhite);
|
||||
|
||||
// Mark the area we need to paint in the back buffer as invalid in the
|
||||
// front buffer as they will become out of sync.
|
||||
aTile.mInvalidFront.OrWith(offsetScaledDirtyRegion);
|
||||
|
||||
// Add backbuffer's invalid region to the dirty region to be painted.
|
||||
// This will be empty if we were able to copy from the front in to the back.
|
||||
nsIntRegion invalidBack = aTile.mInvalidBack;
|
||||
invalidBack.MoveBy(aTileOrigin);
|
||||
invalidBack.ScaleInverseRoundOut(mResolution, mResolution);
|
||||
invalidBack.AndWith(mNewValidRegion);
|
||||
aDirtyRegion.OrWith(invalidBack);
|
||||
offsetScaledDirtyRegion.OrWith(aTile.mInvalidBack);
|
||||
|
||||
aTile.mUpdateRect = offsetScaledDirtyRegion.GetBounds().Union(extraPainted.GetBounds());
|
||||
|
||||
extraPainted.MoveBy(aTileOrigin);
|
||||
@ -1103,16 +1121,9 @@ ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
|
||||
mTilingOrigin.x = std::min(mTilingOrigin.x, moz2DTile.mTileOrigin.x);
|
||||
mTilingOrigin.y = std::min(mTilingOrigin.y, moz2DTile.mTileOrigin.y);
|
||||
|
||||
for (auto iter = aDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const IntRect& dirtyRect = iter.Get();
|
||||
gfx::Rect drawRect(dirtyRect.x - aTileOrigin.x,
|
||||
dirtyRect.y - aTileOrigin.y,
|
||||
dirtyRect.Width(),
|
||||
dirtyRect.Height());
|
||||
drawRect.Scale(mResolution);
|
||||
|
||||
// Mark the newly updated area as invalid in the front buffer
|
||||
aTile.mInvalidFront.Or(aTile.mInvalidFront, IntRect::RoundOut(drawRect));
|
||||
for (auto iter = offsetScaledDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const gfx::Rect drawRect(iter.Get().x, iter.Get().y,
|
||||
iter.Get().width, iter.Get().height);
|
||||
|
||||
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
|
||||
dt->FillRect(drawRect, ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
|
||||
|
@ -412,8 +412,8 @@ public:
|
||||
protected:
|
||||
bool ValidateTile(TileClient& aTile,
|
||||
const nsIntPoint& aTileRect,
|
||||
const nsIntRegion& dirtyRect);
|
||||
|
||||
nsIntRegion& aDirtyRegion);
|
||||
|
||||
void Update(const nsIntRegion& aNewValidRegion,
|
||||
const nsIntRegion& aPaintRegion,
|
||||
const nsIntRegion& aDirtyRegion);
|
||||
|
@ -62,7 +62,9 @@ struct SurfaceDescriptorMacIOSurface {
|
||||
struct SurfaceTextureDescriptor {
|
||||
uint64_t handle;
|
||||
IntSize size;
|
||||
SurfaceFormat format;
|
||||
bool continuous;
|
||||
bool ignoreTransform;
|
||||
};
|
||||
|
||||
struct EGLImageDescriptor {
|
||||
|
@ -866,7 +866,10 @@ CompositorOGL::GetShaderConfigFor(Effect *aEffect,
|
||||
TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
|
||||
MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL,
|
||||
source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
|
||||
source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8);
|
||||
source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 ||
|
||||
source->GetFormat() == gfx::SurfaceFormat::B8G8R8A8 ||
|
||||
source->GetFormat() == gfx::SurfaceFormat::B8G8R8X8 ||
|
||||
source->GetFormat() == gfx::SurfaceFormat::R5G6B5_UINT16);
|
||||
MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
|
||||
source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 ||
|
||||
|
@ -8,9 +8,16 @@
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/layers/TextureClientOGL.h"
|
||||
#include "mozilla/gfx/2D.h" // for Factory
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "GLLibraryEGL.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
#include <jni.h>
|
||||
#include <android/native_window.h>
|
||||
#include <android/native_window_jni.h>
|
||||
#endif
|
||||
|
||||
using namespace mozilla::gl;
|
||||
|
||||
namespace mozilla {
|
||||
@ -67,11 +74,171 @@ AndroidSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
bool
|
||||
AndroidSurfaceTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
aOutDescriptor = SurfaceTextureDescriptor(mHandle, mSize, mContinuous);
|
||||
aOutDescriptor = SurfaceTextureDescriptor(mHandle,
|
||||
mSize,
|
||||
gfx::SurfaceFormat::R8G8B8A8,
|
||||
mContinuous,
|
||||
false /* do not ignore transform */);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // MOZ_WIDGET_ANDROID
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// AndroidNativeWindow
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
|
||||
AndroidNativeWindowTextureData*
|
||||
AndroidNativeWindowTextureData::Create(gfx::IntSize aSize,
|
||||
SurfaceFormat aFormat)
|
||||
{
|
||||
if (aFormat != SurfaceFormat::R8G8B8A8 &&
|
||||
aFormat != SurfaceFormat::R8G8B8X8 &&
|
||||
aFormat != SurfaceFormat::B8G8R8A8 &&
|
||||
aFormat != SurfaceFormat::B8G8R8X8 &&
|
||||
aFormat != SurfaceFormat::R5G6B5_UINT16) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto surface = java::GeckoSurface::LocalRef(
|
||||
java::SurfaceAllocator::AcquireSurface(aSize.width, aSize.height,
|
||||
true /* single-buffer mode */));
|
||||
if (surface) {
|
||||
return new AndroidNativeWindowTextureData(surface, aSize, aFormat);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AndroidNativeWindowTextureData::AndroidNativeWindowTextureData(java::GeckoSurface::Param aSurface,
|
||||
gfx::IntSize aSize,
|
||||
SurfaceFormat aFormat)
|
||||
: mSurface(aSurface)
|
||||
, mIsLocked(false)
|
||||
, mSize(aSize)
|
||||
, mFormat(aFormat)
|
||||
{
|
||||
mNativeWindow = ANativeWindow_fromSurface(jni::GetEnvForThread(),
|
||||
mSurface.Get());
|
||||
MOZ_ASSERT(mNativeWindow, "Failed to create NativeWindow.");
|
||||
|
||||
// SurfaceTextures don't technically support BGR, but we can just pretend to be RGB.
|
||||
int32_t format = WINDOW_FORMAT_RGBA_8888;
|
||||
switch (aFormat) {
|
||||
case SurfaceFormat::R8G8B8A8:
|
||||
case SurfaceFormat::B8G8R8A8:
|
||||
format = WINDOW_FORMAT_RGBA_8888;
|
||||
break;
|
||||
|
||||
case SurfaceFormat::R8G8B8X8:
|
||||
case SurfaceFormat::B8G8R8X8:
|
||||
format = WINDOW_FORMAT_RGBX_8888;
|
||||
break;
|
||||
|
||||
case SurfaceFormat::R5G6B5_UINT16:
|
||||
format = WINDOW_FORMAT_RGB_565;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unsupported AndroidNativeWindowTextureData format.");
|
||||
}
|
||||
|
||||
DebugOnly<int32_t> r = ANativeWindow_setBuffersGeometry(mNativeWindow,
|
||||
mSize.width,
|
||||
mSize.height,
|
||||
format);
|
||||
MOZ_ASSERT(r == 0, "ANativeWindow_setBuffersGeometry failed.");
|
||||
|
||||
// Ideally here we'd call ANativeWindow_setBuffersTransform() with the
|
||||
// identity transform, but that is only available on api level >= 26.
|
||||
// Instead use the SurfaceDescriptor's ignoreTransform flag when serializing.
|
||||
}
|
||||
|
||||
void
|
||||
AndroidNativeWindowTextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
{
|
||||
aInfo.size = mSize;
|
||||
aInfo.format = mFormat;
|
||||
aInfo.hasIntermediateBuffer = false;
|
||||
aInfo.hasSynchronization = false;
|
||||
aInfo.supportsMoz2D = true;
|
||||
aInfo.canExposeMappedData = false;
|
||||
aInfo.canConcurrentlyReadLock = false;
|
||||
}
|
||||
|
||||
bool
|
||||
AndroidNativeWindowTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
aOutDescriptor = SurfaceTextureDescriptor(mSurface->GetHandle(),
|
||||
mSize,
|
||||
mFormat,
|
||||
false /* not continuous */,
|
||||
true /* ignore transform */);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
AndroidNativeWindowTextureData::Lock(OpenMode)
|
||||
{
|
||||
// ANativeWindows can only be locked and unlocked a single time, after which
|
||||
// we must wait until they receive ownership back from the host.
|
||||
// Therefore we must only actually call ANativeWindow_lock() once per cycle.
|
||||
if (!mIsLocked) {
|
||||
int32_t r = ANativeWindow_lock(mNativeWindow, &mBuffer, nullptr);
|
||||
if (r < 0) {
|
||||
MOZ_CRASH("ANativeWindow_lock failed\n.");
|
||||
return false;
|
||||
}
|
||||
mIsLocked = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
AndroidNativeWindowTextureData::Unlock()
|
||||
{
|
||||
// The TextureClient may want to call Lock again before handing ownership
|
||||
// to the host, so we cannot call ANativeWindow_unlockAndPost yet.
|
||||
}
|
||||
|
||||
void
|
||||
AndroidNativeWindowTextureData::Forget(LayersIPCChannel*)
|
||||
{
|
||||
MOZ_ASSERT(!mIsLocked, "ANativeWindow should not be released while locked.\n");
|
||||
ANativeWindow_release(mNativeWindow);
|
||||
mNativeWindow = nullptr;
|
||||
java::SurfaceAllocator::DisposeSurface(mSurface);
|
||||
mSurface = nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<DrawTarget>
|
||||
AndroidNativeWindowTextureData::BorrowDrawTarget()
|
||||
{
|
||||
const int bpp = (mFormat == SurfaceFormat::R5G6B5_UINT16) ? 2 : 4;
|
||||
|
||||
return gfx::Factory::CreateDrawTargetForData(
|
||||
gfx::BackendType::SKIA,
|
||||
static_cast<unsigned char*>(mBuffer.bits),
|
||||
IntSize(mBuffer.width, mBuffer.height),
|
||||
mBuffer.stride * bpp,
|
||||
mFormat,
|
||||
true);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidNativeWindowTextureData::OnForwardedToHost()
|
||||
{
|
||||
if (mIsLocked) {
|
||||
int32_t r = ANativeWindow_unlockAndPost(mNativeWindow);
|
||||
if (r < 0) {
|
||||
MOZ_CRASH("ANativeWindow_unlockAndPost failed\n.");
|
||||
}
|
||||
mIsLocked = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MOZ_WIDGET_ANDROID
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
@ -16,6 +16,10 @@
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
|
||||
#include "AndroidSurfaceTexture.h"
|
||||
#include "AndroidNativeWindow.h"
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
#include "GeneratedJNIWrappers.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -58,6 +62,45 @@ protected:
|
||||
|
||||
#endif // MOZ_WIDGET_ANDROID
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
|
||||
class AndroidNativeWindowTextureData : public TextureData
|
||||
{
|
||||
public:
|
||||
static AndroidNativeWindowTextureData* Create(gfx::IntSize aSize, SurfaceFormat aFormat);
|
||||
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const override;
|
||||
|
||||
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
virtual bool Lock(OpenMode) override;
|
||||
virtual void Unlock() override;
|
||||
|
||||
virtual void Forget(LayersIPCChannel*) override;
|
||||
virtual void Deallocate(LayersIPCChannel*) override {}
|
||||
|
||||
virtual already_AddRefed<DrawTarget> BorrowDrawTarget() override;
|
||||
|
||||
virtual void OnForwardedToHost() override;
|
||||
|
||||
protected:
|
||||
AndroidNativeWindowTextureData(java::GeckoSurface::Param aSurface,
|
||||
gfx::IntSize aSize,
|
||||
SurfaceFormat aFormat);
|
||||
|
||||
private:
|
||||
java::GeckoSurface::GlobalRef mSurface;
|
||||
ANativeWindow* mNativeWindow;
|
||||
ANativeWindow_Buffer mBuffer;
|
||||
// Keeps track of whether the underlying NativeWindow is actually locked.
|
||||
bool mIsLocked;
|
||||
|
||||
const gfx::IntSize mSize;
|
||||
const SurfaceFormat mFormat;
|
||||
};
|
||||
|
||||
#endif // MOZ_WIDGET_ANDROID
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -62,7 +62,9 @@ CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
|
||||
result = new SurfaceTextureHost(aFlags,
|
||||
surfaceTexture,
|
||||
desc.size(),
|
||||
desc.continuous());
|
||||
desc.format(),
|
||||
desc.continuous(),
|
||||
desc.ignoreTransform());
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -343,13 +345,15 @@ SurfaceTextureSource::SurfaceTextureSource(TextureSourceProvider* aProvider,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
GLenum aTarget,
|
||||
GLenum aWrapMode,
|
||||
gfx::IntSize aSize)
|
||||
gfx::IntSize aSize,
|
||||
bool aIgnoreTransform)
|
||||
: mGL(aProvider->GetGLContext())
|
||||
, mSurfTex(aSurfTex)
|
||||
, mFormat(aFormat)
|
||||
, mTextureTarget(aTarget)
|
||||
, mWrapMode(aWrapMode)
|
||||
, mSize(aSize)
|
||||
, mIgnoreTransform(aIgnoreTransform)
|
||||
{
|
||||
}
|
||||
|
||||
@ -395,8 +399,14 @@ SurfaceTextureSource::GetTextureTransform()
|
||||
|
||||
gfx::Matrix4x4 ret;
|
||||
|
||||
const auto& surf = java::sdk::SurfaceTexture::LocalRef(java::sdk::SurfaceTexture::Ref::From(mSurfTex));
|
||||
AndroidSurfaceTexture::GetTransformMatrix(surf, ret);
|
||||
// GetTransformMatrix() returns the transform set by the producer side of
|
||||
// the SurfaceTexture. We should ignore this if we know the transform should
|
||||
// be identity but the producer couldn't set it correctly, like is the
|
||||
// case for AndroidNativeWindowTextureData.
|
||||
if (!mIgnoreTransform) {
|
||||
const auto& surf = java::sdk::SurfaceTexture::LocalRef(java::sdk::SurfaceTexture::Ref::From(mSurfTex));
|
||||
AndroidSurfaceTexture::GetTransformMatrix(surf, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -412,11 +422,15 @@ SurfaceTextureSource::DeallocateDeviceData()
|
||||
SurfaceTextureHost::SurfaceTextureHost(TextureFlags aFlags,
|
||||
mozilla::java::GeckoSurfaceTexture::Ref& aSurfTex,
|
||||
gfx::IntSize aSize,
|
||||
bool aContinuousUpdate)
|
||||
gfx::SurfaceFormat aFormat,
|
||||
bool aContinuousUpdate,
|
||||
bool aIgnoreTransform)
|
||||
: TextureHost(aFlags)
|
||||
, mSurfTex(aSurfTex)
|
||||
, mSize(aSize)
|
||||
, mFormat(aFormat)
|
||||
, mContinuousUpdate(aContinuousUpdate)
|
||||
, mIgnoreTransform(aIgnoreTransform)
|
||||
{
|
||||
if (!mSurfTex) {
|
||||
return;
|
||||
@ -476,15 +490,15 @@ SurfaceTextureHost::Lock()
|
||||
}
|
||||
|
||||
if (!mTextureSource) {
|
||||
gfx::SurfaceFormat format = gfx::SurfaceFormat::R8G8B8A8;
|
||||
GLenum target = LOCAL_GL_TEXTURE_EXTERNAL; // This is required by SurfaceTexture
|
||||
GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
|
||||
mTextureSource = new SurfaceTextureSource(mProvider,
|
||||
mSurfTex,
|
||||
format,
|
||||
mFormat,
|
||||
target,
|
||||
wrapMode,
|
||||
mSize);
|
||||
mSize,
|
||||
mIgnoreTransform);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -519,7 +533,7 @@ SurfaceTextureHost::NotifyNotUsed()
|
||||
gfx::SurfaceFormat
|
||||
SurfaceTextureHost::GetFormat() const
|
||||
{
|
||||
return mTextureSource ? mTextureSource->GetFormat() : gfx::SurfaceFormat::UNKNOWN;
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -347,7 +347,8 @@ public:
|
||||
gfx::SurfaceFormat aFormat,
|
||||
GLenum aTarget,
|
||||
GLenum aWrapMode,
|
||||
gfx::IntSize aSize);
|
||||
gfx::IntSize aSize,
|
||||
bool aIgnoreTransform);
|
||||
|
||||
virtual const char* Name() const override { return "SurfaceTextureSource"; }
|
||||
|
||||
@ -383,6 +384,7 @@ protected:
|
||||
const GLenum mTextureTarget;
|
||||
const GLenum mWrapMode;
|
||||
const gfx::IntSize mSize;
|
||||
const bool mIgnoreTransform;
|
||||
};
|
||||
|
||||
class SurfaceTextureHost : public TextureHost
|
||||
@ -391,7 +393,9 @@ public:
|
||||
SurfaceTextureHost(TextureFlags aFlags,
|
||||
mozilla::java::GeckoSurfaceTexture::Ref& aSurfTex,
|
||||
gfx::IntSize aSize,
|
||||
bool aContinuousUpdate);
|
||||
gfx::SurfaceFormat aFormat,
|
||||
bool aContinuousUpdate,
|
||||
bool aIgnoreTransform);
|
||||
|
||||
virtual ~SurfaceTextureHost();
|
||||
|
||||
@ -427,7 +431,9 @@ public:
|
||||
protected:
|
||||
mozilla::java::GeckoSurfaceTexture::GlobalRef mSurfTex;
|
||||
const gfx::IntSize mSize;
|
||||
const gfx::SurfaceFormat mFormat;
|
||||
bool mContinuousUpdate;
|
||||
const bool mIgnoreTransform;
|
||||
RefPtr<CompositorOGL> mCompositor;
|
||||
RefPtr<SurfaceTextureSource> mTextureSource;
|
||||
};
|
||||
|
@ -491,6 +491,7 @@ private:
|
||||
DECL_GFX_PREF(Live, "gfx.use-glx-texture-from-pixmap", UseGLXTextureFromPixmap, bool, false);
|
||||
DECL_GFX_PREF(Once, "gfx.use-iosurface-textures", UseIOSurfaceTextures, bool, false);
|
||||
DECL_GFX_PREF(Once, "gfx.use-mutex-on-present", UseMutexOnPresent, bool, false);
|
||||
DECL_GFX_PREF(Once, "gfx.use-surfacetexture-textures", UseSurfaceTextureTextures, bool, false);
|
||||
// These times should be in milliseconds
|
||||
DECL_GFX_PREF(Once, "gfx.touch.resample.delay-threshold", TouchResampleVsyncDelayThreshold, int32_t, 20);
|
||||
DECL_GFX_PREF(Once, "gfx.touch.resample.max-predict", TouchResampleMaxPredict, int32_t, 8);
|
||||
|
@ -333,6 +333,9 @@ pref("gfx.android.rgb16.force", false);
|
||||
// Allow GLContexts to be attached/detached from SurfaceTextures
|
||||
pref("gfx.SurfaceTexture.detach.enabled", true);
|
||||
|
||||
// Use SurfaceTextures as preferred backend for TextureClient/Host
|
||||
pref("gfx.use-surfacetexture-textures", false);
|
||||
|
||||
// don't allow JS to move and resize existing windows
|
||||
pref("dom.disable_window_move_resize", true);
|
||||
|
||||
|
@ -80,9 +80,13 @@ public final class GeckoSurfaceTexture extends SurfaceTexture {
|
||||
return;
|
||||
}
|
||||
|
||||
super.releaseTexImage();
|
||||
if (mListener != null) {
|
||||
mListener.onReleaseTexImage();
|
||||
try {
|
||||
super.releaseTexImage();
|
||||
if (mListener != null) {
|
||||
mListener.onReleaseTexImage();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.w(LOGTAG, "releaseTexImage() failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user